@cdoing/core 0.1.0
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/dist/agents/coordinator.d.ts +114 -0
- package/dist/agents/coordinator.d.ts.map +1 -0
- package/dist/agents/coordinator.js +158 -0
- package/dist/agents/coordinator.js.map +1 -0
- package/dist/context-providers/clipboard.d.ts +13 -0
- package/dist/context-providers/clipboard.d.ts.map +1 -0
- package/dist/context-providers/clipboard.js +53 -0
- package/dist/context-providers/clipboard.js.map +1 -0
- package/dist/context-providers/codebase.d.ts +46 -0
- package/dist/context-providers/codebase.d.ts.map +1 -0
- package/dist/context-providers/codebase.js +273 -0
- package/dist/context-providers/codebase.js.map +1 -0
- package/dist/context-providers/diff.d.ts +18 -0
- package/dist/context-providers/diff.d.ts.map +1 -0
- package/dist/context-providers/diff.js +63 -0
- package/dist/context-providers/diff.js.map +1 -0
- package/dist/context-providers/docs.d.ts +21 -0
- package/dist/context-providers/docs.d.ts.map +1 -0
- package/dist/context-providers/docs.js +180 -0
- package/dist/context-providers/docs.js.map +1 -0
- package/dist/context-providers/file-include.d.ts +13 -0
- package/dist/context-providers/file-include.d.ts.map +1 -0
- package/dist/context-providers/file-include.js +82 -0
- package/dist/context-providers/file-include.js.map +1 -0
- package/dist/context-providers/folder.d.ts +19 -0
- package/dist/context-providers/folder.d.ts.map +1 -0
- package/dist/context-providers/folder.js +130 -0
- package/dist/context-providers/folder.js.map +1 -0
- package/dist/context-providers/git.d.ts +19 -0
- package/dist/context-providers/git.d.ts.map +1 -0
- package/dist/context-providers/git.js +74 -0
- package/dist/context-providers/git.js.map +1 -0
- package/dist/context-providers/index.d.ts +26 -0
- package/dist/context-providers/index.d.ts.map +1 -0
- package/dist/context-providers/index.js +37 -0
- package/dist/context-providers/index.js.map +1 -0
- package/dist/context-providers/open-files.d.ts +25 -0
- package/dist/context-providers/open-files.d.ts.map +1 -0
- package/dist/context-providers/open-files.js +134 -0
- package/dist/context-providers/open-files.js.map +1 -0
- package/dist/context-providers/problems.d.ts +24 -0
- package/dist/context-providers/problems.d.ts.map +1 -0
- package/dist/context-providers/problems.js +97 -0
- package/dist/context-providers/problems.js.map +1 -0
- package/dist/context-providers/registry.d.ts +61 -0
- package/dist/context-providers/registry.d.ts.map +1 -0
- package/dist/context-providers/registry.js +92 -0
- package/dist/context-providers/registry.js.map +1 -0
- package/dist/context-providers/terminal.d.ts +25 -0
- package/dist/context-providers/terminal.d.ts.map +1 -0
- package/dist/context-providers/terminal.js +55 -0
- package/dist/context-providers/terminal.js.map +1 -0
- package/dist/context-providers/tree.d.ts +29 -0
- package/dist/context-providers/tree.d.ts.map +1 -0
- package/dist/context-providers/tree.js +172 -0
- package/dist/context-providers/tree.js.map +1 -0
- package/dist/context-providers/types.d.ts +72 -0
- package/dist/context-providers/types.d.ts.map +1 -0
- package/dist/context-providers/types.js +10 -0
- package/dist/context-providers/types.js.map +1 -0
- package/dist/context-providers/url.d.ts +27 -0
- package/dist/context-providers/url.d.ts.map +1 -0
- package/dist/context-providers/url.js +131 -0
- package/dist/context-providers/url.js.map +1 -0
- package/dist/effort/index.d.ts +78 -0
- package/dist/effort/index.d.ts.map +1 -0
- package/dist/effort/index.js +146 -0
- package/dist/effort/index.js.map +1 -0
- package/dist/hooks/index.d.ts +47 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +151 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +152 -0
- package/dist/index.js.map +1 -0
- package/dist/indexing/chunker.d.ts +25 -0
- package/dist/indexing/chunker.d.ts.map +1 -0
- package/dist/indexing/chunker.js +217 -0
- package/dist/indexing/chunker.js.map +1 -0
- package/dist/indexing/database.d.ts +49 -0
- package/dist/indexing/database.d.ts.map +1 -0
- package/dist/indexing/database.js +287 -0
- package/dist/indexing/database.js.map +1 -0
- package/dist/indexing/index.d.ts +9 -0
- package/dist/indexing/index.d.ts.map +1 -0
- package/dist/indexing/index.js +13 -0
- package/dist/indexing/index.js.map +1 -0
- package/dist/indexing/indexer.d.ts +63 -0
- package/dist/indexing/indexer.d.ts.map +1 -0
- package/dist/indexing/indexer.js +352 -0
- package/dist/indexing/indexer.js.map +1 -0
- package/dist/indexing/recent-edits-cache.d.ts +77 -0
- package/dist/indexing/recent-edits-cache.d.ts.map +1 -0
- package/dist/indexing/recent-edits-cache.js +123 -0
- package/dist/indexing/recent-edits-cache.js.map +1 -0
- package/dist/indexing/types.d.ts +39 -0
- package/dist/indexing/types.d.ts.map +1 -0
- package/dist/indexing/types.js +6 -0
- package/dist/indexing/types.js.map +1 -0
- package/dist/mcp/index.d.ts +33 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +37 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/manager.d.ts +123 -0
- package/dist/mcp/manager.d.ts.map +1 -0
- package/dist/mcp/manager.js +331 -0
- package/dist/mcp/manager.js.map +1 -0
- package/dist/oauth.d.ts +33 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +312 -0
- package/dist/oauth.js.map +1 -0
- package/dist/permissions/index.d.ts +216 -0
- package/dist/permissions/index.d.ts.map +1 -0
- package/dist/permissions/index.js +938 -0
- package/dist/permissions/index.js.map +1 -0
- package/dist/plan/index.d.ts +20 -0
- package/dist/plan/index.d.ts.map +1 -0
- package/dist/plan/index.js +24 -0
- package/dist/plan/index.js.map +1 -0
- package/dist/plan/manager.d.ts +101 -0
- package/dist/plan/manager.d.ts.map +1 -0
- package/dist/plan/manager.js +170 -0
- package/dist/plan/manager.js.map +1 -0
- package/dist/rules/index.d.ts +28 -0
- package/dist/rules/index.d.ts.map +1 -0
- package/dist/rules/index.js +31 -0
- package/dist/rules/index.js.map +1 -0
- package/dist/rules/manager.d.ts +77 -0
- package/dist/rules/manager.d.ts.map +1 -0
- package/dist/rules/manager.js +279 -0
- package/dist/rules/manager.js.map +1 -0
- package/dist/rules/types.d.ts +34 -0
- package/dist/rules/types.d.ts.map +1 -0
- package/dist/rules/types.js +9 -0
- package/dist/rules/types.js.map +1 -0
- package/dist/sandbox/filesystem.d.ts +20 -0
- package/dist/sandbox/filesystem.d.ts.map +1 -0
- package/dist/sandbox/filesystem.js +141 -0
- package/dist/sandbox/filesystem.js.map +1 -0
- package/dist/sandbox/index.d.ts +4 -0
- package/dist/sandbox/index.d.ts.map +1 -0
- package/dist/sandbox/index.js +8 -0
- package/dist/sandbox/index.js.map +1 -0
- package/dist/sandbox/manager.d.ts +47 -0
- package/dist/sandbox/manager.d.ts.map +1 -0
- package/dist/sandbox/manager.js +220 -0
- package/dist/sandbox/manager.js.map +1 -0
- package/dist/sandbox/network.d.ts +14 -0
- package/dist/sandbox/network.d.ts.map +1 -0
- package/dist/sandbox/network.js +87 -0
- package/dist/sandbox/network.js.map +1 -0
- package/dist/sandbox/types.d.ts +42 -0
- package/dist/sandbox/types.d.ts.map +1 -0
- package/dist/sandbox/types.js +25 -0
- package/dist/sandbox/types.js.map +1 -0
- package/dist/tools/ast-edit.d.ts +57 -0
- package/dist/tools/ast-edit.d.ts.map +1 -0
- package/dist/tools/ast-edit.js +443 -0
- package/dist/tools/ast-edit.js.map +1 -0
- package/dist/tools/code-verify.d.ts +8 -0
- package/dist/tools/code-verify.d.ts.map +1 -0
- package/dist/tools/code-verify.js +159 -0
- package/dist/tools/code-verify.js.map +1 -0
- package/dist/tools/codebase-search.d.ts +17 -0
- package/dist/tools/codebase-search.d.ts.map +1 -0
- package/dist/tools/codebase-search.js +104 -0
- package/dist/tools/codebase-search.js.map +1 -0
- package/dist/tools/file-delete.d.ts +26 -0
- package/dist/tools/file-delete.d.ts.map +1 -0
- package/dist/tools/file-delete.js +179 -0
- package/dist/tools/file-delete.js.map +1 -0
- package/dist/tools/file-edit.d.ts +10 -0
- package/dist/tools/file-edit.d.ts.map +1 -0
- package/dist/tools/file-edit.js +138 -0
- package/dist/tools/file-edit.js.map +1 -0
- package/dist/tools/file-read.d.ts +12 -0
- package/dist/tools/file-read.d.ts.map +1 -0
- package/dist/tools/file-read.js +211 -0
- package/dist/tools/file-read.js.map +1 -0
- package/dist/tools/file-run.d.ts +10 -0
- package/dist/tools/file-run.d.ts.map +1 -0
- package/dist/tools/file-run.js +179 -0
- package/dist/tools/file-run.js.map +1 -0
- package/dist/tools/file-write.d.ts +10 -0
- package/dist/tools/file-write.d.ts.map +1 -0
- package/dist/tools/file-write.js +134 -0
- package/dist/tools/file-write.js.map +1 -0
- package/dist/tools/glob-search.d.ts +8 -0
- package/dist/tools/glob-search.d.ts.map +1 -0
- package/dist/tools/glob-search.js +108 -0
- package/dist/tools/glob-search.js.map +1 -0
- package/dist/tools/grep-search.d.ts +8 -0
- package/dist/tools/grep-search.d.ts.map +1 -0
- package/dist/tools/grep-search.js +139 -0
- package/dist/tools/grep-search.js.map +1 -0
- package/dist/tools/list-dir.d.ts +16 -0
- package/dist/tools/list-dir.d.ts.map +1 -0
- package/dist/tools/list-dir.js +183 -0
- package/dist/tools/list-dir.js.map +1 -0
- package/dist/tools/multi-edit.d.ts +16 -0
- package/dist/tools/multi-edit.d.ts.map +1 -0
- package/dist/tools/multi-edit.js +163 -0
- package/dist/tools/multi-edit.js.map +1 -0
- package/dist/tools/notebook-edit.d.ts +31 -0
- package/dist/tools/notebook-edit.d.ts.map +1 -0
- package/dist/tools/notebook-edit.js +321 -0
- package/dist/tools/notebook-edit.js.map +1 -0
- package/dist/tools/registry.d.ts +16 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +41 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/shell-exec.d.ts +12 -0
- package/dist/tools/shell-exec.d.ts.map +1 -0
- package/dist/tools/shell-exec.js +261 -0
- package/dist/tools/shell-exec.js.map +1 -0
- package/dist/tools/sub-agent-manager.d.ts +57 -0
- package/dist/tools/sub-agent-manager.d.ts.map +1 -0
- package/dist/tools/sub-agent-manager.js +153 -0
- package/dist/tools/sub-agent-manager.js.map +1 -0
- package/dist/tools/sub-agent-status.d.ts +12 -0
- package/dist/tools/sub-agent-status.d.ts.map +1 -0
- package/dist/tools/sub-agent-status.js +59 -0
- package/dist/tools/sub-agent-status.js.map +1 -0
- package/dist/tools/sub-agent-terminate.d.ts +12 -0
- package/dist/tools/sub-agent-terminate.d.ts.map +1 -0
- package/dist/tools/sub-agent-terminate.js +55 -0
- package/dist/tools/sub-agent-terminate.js.map +1 -0
- package/dist/tools/sub-agent.d.ts +34 -0
- package/dist/tools/sub-agent.d.ts.map +1 -0
- package/dist/tools/sub-agent.js +140 -0
- package/dist/tools/sub-agent.js.map +1 -0
- package/dist/tools/system-info.d.ts +24 -0
- package/dist/tools/system-info.d.ts.map +1 -0
- package/dist/tools/system-info.js +220 -0
- package/dist/tools/system-info.js.map +1 -0
- package/dist/tools/todo.d.ts +16 -0
- package/dist/tools/todo.d.ts.map +1 -0
- package/dist/tools/todo.js +144 -0
- package/dist/tools/todo.js.map +1 -0
- package/dist/tools/types.d.ts +20 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +3 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/view-diff.d.ts +11 -0
- package/dist/tools/view-diff.d.ts.map +1 -0
- package/dist/tools/view-diff.js +88 -0
- package/dist/tools/view-diff.js.map +1 -0
- package/dist/tools/view-repo-map.d.ts +18 -0
- package/dist/tools/view-repo-map.d.ts.map +1 -0
- package/dist/tools/view-repo-map.js +245 -0
- package/dist/tools/view-repo-map.js.map +1 -0
- package/dist/tools/web-fetch.d.ts +13 -0
- package/dist/tools/web-fetch.d.ts.map +1 -0
- package/dist/tools/web-fetch.js +106 -0
- package/dist/tools/web-fetch.js.map +1 -0
- package/dist/tools/web-search.d.ts +10 -0
- package/dist/tools/web-search.d.ts.map +1 -0
- package/dist/tools/web-search.js +106 -0
- package/dist/tools/web-search.js.map +1 -0
- package/dist/utils/gitignore.d.ts +10 -0
- package/dist/utils/gitignore.d.ts.map +1 -0
- package/dist/utils/gitignore.js +104 -0
- package/dist/utils/gitignore.js.map +1 -0
- package/dist/utils/lazy-apply.d.ts +45 -0
- package/dist/utils/lazy-apply.d.ts.map +1 -0
- package/dist/utils/lazy-apply.js +164 -0
- package/dist/utils/lazy-apply.js.map +1 -0
- package/dist/utils/memory.d.ts +36 -0
- package/dist/utils/memory.d.ts.map +1 -0
- package/dist/utils/memory.js +136 -0
- package/dist/utils/memory.js.map +1 -0
- package/dist/utils/path-matching.d.ts +24 -0
- package/dist/utils/path-matching.d.ts.map +1 -0
- package/dist/utils/path-matching.js +116 -0
- package/dist/utils/path-matching.js.map +1 -0
- package/dist/utils/path-safety.d.ts +13 -0
- package/dist/utils/path-safety.d.ts.map +1 -0
- package/dist/utils/path-safety.js +54 -0
- package/dist/utils/path-safety.js.map +1 -0
- package/dist/utils/project-config.d.ts +18 -0
- package/dist/utils/project-config.d.ts.map +1 -0
- package/dist/utils/project-config.js +76 -0
- package/dist/utils/project-config.js.map +1 -0
- package/dist/utils/search-match.d.ts +63 -0
- package/dist/utils/search-match.d.ts.map +1 -0
- package/dist/utils/search-match.js +426 -0
- package/dist/utils/search-match.js.map +1 -0
- package/dist/utils/shell-paths.d.ts +17 -0
- package/dist/utils/shell-paths.d.ts.map +1 -0
- package/dist/utils/shell-paths.js +107 -0
- package/dist/utils/shell-paths.js.map +1 -0
- package/dist/utils/streaming-diff.d.ts +45 -0
- package/dist/utils/streaming-diff.d.ts.map +1 -0
- package/dist/utils/streaming-diff.js +230 -0
- package/dist/utils/streaming-diff.js.map +1 -0
- package/dist/utils/todo.d.ts +47 -0
- package/dist/utils/todo.d.ts.map +1 -0
- package/dist/utils/todo.js +102 -0
- package/dist/utils/todo.js.map +1 -0
- package/package.json +23 -0
- package/src/agents/coordinator.ts +240 -0
- package/src/context-providers/clipboard.ts +48 -0
- package/src/context-providers/codebase.ts +274 -0
- package/src/context-providers/diff.ts +66 -0
- package/src/context-providers/docs.ts +160 -0
- package/src/context-providers/file-include.ts +54 -0
- package/src/context-providers/folder.ts +106 -0
- package/src/context-providers/git.ts +72 -0
- package/src/context-providers/index.ts +26 -0
- package/src/context-providers/open-files.ts +113 -0
- package/src/context-providers/problems.ts +100 -0
- package/src/context-providers/registry.ts +99 -0
- package/src/context-providers/terminal.ts +58 -0
- package/src/context-providers/tree.ts +161 -0
- package/src/context-providers/types.ts +84 -0
- package/src/context-providers/url.ts +138 -0
- package/src/effort/index.ts +177 -0
- package/src/hooks/index.ts +148 -0
- package/src/index.ts +114 -0
- package/src/indexing/README.md +267 -0
- package/src/indexing/chunker.ts +206 -0
- package/src/indexing/database.ts +299 -0
- package/src/indexing/index.ts +15 -0
- package/src/indexing/indexer.ts +383 -0
- package/src/indexing/recent-edits-cache.ts +150 -0
- package/src/indexing/types.ts +44 -0
- package/src/mcp/index.ts +33 -0
- package/src/mcp/manager.ts +385 -0
- package/src/oauth.ts +330 -0
- package/src/permissions/index.ts +1011 -0
- package/src/plan/index.ts +20 -0
- package/src/plan/manager.ts +233 -0
- package/src/rules/index.ts +28 -0
- package/src/rules/manager.ts +276 -0
- package/src/rules/types.ts +40 -0
- package/src/sandbox/filesystem.ts +135 -0
- package/src/sandbox/index.ts +9 -0
- package/src/sandbox/manager.ts +213 -0
- package/src/sandbox/network.ts +101 -0
- package/src/sandbox/types.ts +63 -0
- package/src/tools/ast-edit.ts +493 -0
- package/src/tools/code-verify.ts +143 -0
- package/src/tools/codebase-search.ts +117 -0
- package/src/tools/file-delete.ts +155 -0
- package/src/tools/file-edit.ts +115 -0
- package/src/tools/file-read.ts +195 -0
- package/src/tools/file-run.ts +158 -0
- package/src/tools/file-write.ts +104 -0
- package/src/tools/glob-search.ts +80 -0
- package/src/tools/grep-search.ts +120 -0
- package/src/tools/list-dir.ts +172 -0
- package/src/tools/multi-edit.ts +138 -0
- package/src/tools/notebook-edit.ts +342 -0
- package/src/tools/registry.ts +43 -0
- package/src/tools/shell-exec.ts +251 -0
- package/src/tools/sub-agent-manager.ts +183 -0
- package/src/tools/sub-agent-status.ts +67 -0
- package/src/tools/sub-agent-terminate.ts +62 -0
- package/src/tools/sub-agent.ts +162 -0
- package/src/tools/system-info.ts +248 -0
- package/src/tools/todo.ts +149 -0
- package/src/tools/types.ts +21 -0
- package/src/tools/view-diff.ts +99 -0
- package/src/tools/view-repo-map.ts +249 -0
- package/src/tools/web-fetch.ts +118 -0
- package/src/tools/web-search.ts +129 -0
- package/src/utils/gitignore.ts +73 -0
- package/src/utils/lazy-apply.ts +189 -0
- package/src/utils/memory.ts +124 -0
- package/src/utils/path-matching.ts +84 -0
- package/src/utils/path-safety.ts +19 -0
- package/src/utils/project-config.ts +41 -0
- package/src/utils/search-match.ts +495 -0
- package/src/utils/shell-paths.ts +79 -0
- package/src/utils/streaming-diff.ts +260 -0
- package/src/utils/todo.ts +115 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* View Repo Map Tool — generate a structural overview of the repository.
|
|
3
|
+
*
|
|
4
|
+
* Shows the project layout: directories, key files, entry points,
|
|
5
|
+
* config files, and a summary of the codebase structure.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import * as fs from "fs";
|
|
9
|
+
import * as path from "path";
|
|
10
|
+
import { exec } from "child_process";
|
|
11
|
+
import type { BaseTool, ToolDefinition, ToolResult } from "./types";
|
|
12
|
+
import { loadIgnorePatterns } from "../utils/gitignore";
|
|
13
|
+
|
|
14
|
+
const ALWAYS_IGNORE = new Set([
|
|
15
|
+
"node_modules", ".git", "dist", "build", "out", ".next", ".nuxt",
|
|
16
|
+
"__pycache__", ".cache", ".turbo", "coverage", "venv", ".venv",
|
|
17
|
+
"target", "vendor", ".idea", ".vscode", ".DS_Store", "*.pyc",
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
const CONFIG_FILES = new Set([
|
|
21
|
+
"package.json", "tsconfig.json", "tsconfig.base.json",
|
|
22
|
+
".eslintrc.js", ".eslintrc.json", ".prettierrc",
|
|
23
|
+
"jest.config.js", "jest.config.ts", "vitest.config.ts",
|
|
24
|
+
"webpack.config.js", "vite.config.ts", "vite.config.js",
|
|
25
|
+
"rollup.config.js", "esbuild.config.js",
|
|
26
|
+
"Dockerfile", "docker-compose.yml", "docker-compose.yaml",
|
|
27
|
+
"Makefile", "CMakeLists.txt",
|
|
28
|
+
".env.example", ".gitignore", ".dockerignore",
|
|
29
|
+
"pyproject.toml", "setup.py", "setup.cfg", "requirements.txt",
|
|
30
|
+
"Cargo.toml", "go.mod", "Gemfile", "composer.json",
|
|
31
|
+
"turbo.json", "lerna.json", "nx.json",
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
const ENTRY_PATTERNS = [
|
|
35
|
+
"index.ts", "index.js", "main.ts", "main.js", "app.ts", "app.js",
|
|
36
|
+
"server.ts", "server.js", "cli.ts", "cli.js",
|
|
37
|
+
"index.py", "main.py", "app.py", "__main__.py",
|
|
38
|
+
"main.go", "main.rs", "lib.rs",
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
interface RepoStats {
|
|
42
|
+
totalFiles: number;
|
|
43
|
+
totalDirs: number;
|
|
44
|
+
languages: Map<string, number>;
|
|
45
|
+
configFiles: string[];
|
|
46
|
+
entryPoints: string[];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export class ViewRepoMapTool implements BaseTool {
|
|
50
|
+
definition: ToolDefinition = {
|
|
51
|
+
name: "view_repo_map",
|
|
52
|
+
description:
|
|
53
|
+
`Generate a structural overview of the repository. Shows:
|
|
54
|
+
- Directory tree (top 2 levels)
|
|
55
|
+
- Detected languages and file counts
|
|
56
|
+
- Config files found
|
|
57
|
+
- Likely entry points
|
|
58
|
+
- Git branch and recent commits
|
|
59
|
+
|
|
60
|
+
Use this to understand a new project before diving into code.`,
|
|
61
|
+
inputSchema: {
|
|
62
|
+
type: "object",
|
|
63
|
+
properties: {
|
|
64
|
+
directory: {
|
|
65
|
+
type: "string",
|
|
66
|
+
description: "Subdirectory to focus on. Defaults to project root.",
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
required: [],
|
|
70
|
+
},
|
|
71
|
+
requiresPermission: false,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
private workingDir: string;
|
|
75
|
+
|
|
76
|
+
constructor(workingDir: string) {
|
|
77
|
+
this.workingDir = workingDir;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async execute(input: Record<string, unknown>): Promise<ToolResult> {
|
|
81
|
+
const subdir = (input.directory as string) || "";
|
|
82
|
+
const rootDir = subdir ? path.resolve(this.workingDir, subdir) : this.workingDir;
|
|
83
|
+
|
|
84
|
+
if (!fs.existsSync(rootDir) || !fs.statSync(rootDir).isDirectory()) {
|
|
85
|
+
return { success: false, output: "", error: `Directory not found: ${rootDir}` };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const sections: string[] = [];
|
|
89
|
+
|
|
90
|
+
// 1. Header
|
|
91
|
+
sections.push(`# Repository Map: ${path.basename(rootDir)}`);
|
|
92
|
+
sections.push(`Path: ${rootDir}`);
|
|
93
|
+
|
|
94
|
+
// 2. Git info
|
|
95
|
+
const gitInfo = await this.getGitInfo(rootDir);
|
|
96
|
+
if (gitInfo) sections.push(gitInfo);
|
|
97
|
+
|
|
98
|
+
// 3. Directory tree (2 levels)
|
|
99
|
+
const tree = this.buildTree(rootDir, 2);
|
|
100
|
+
sections.push("\n## Directory Structure\n```\n" + tree + "\n```");
|
|
101
|
+
|
|
102
|
+
// 4. Stats
|
|
103
|
+
const stats = this.collectStats(rootDir);
|
|
104
|
+
sections.push(this.formatStats(stats));
|
|
105
|
+
|
|
106
|
+
return { success: true, output: sections.join("\n") };
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private buildTree(dir: string, maxDepth: number, prefix = "", depth = 0): string {
|
|
110
|
+
if (depth > maxDepth) return "";
|
|
111
|
+
|
|
112
|
+
let entries: fs.Dirent[];
|
|
113
|
+
try {
|
|
114
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
115
|
+
} catch {
|
|
116
|
+
return "";
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
entries = entries
|
|
120
|
+
.filter((e) => !ALWAYS_IGNORE.has(e.name) && !e.name.startsWith("."))
|
|
121
|
+
.sort((a, b) => {
|
|
122
|
+
if (a.isDirectory() && !b.isDirectory()) return -1;
|
|
123
|
+
if (!a.isDirectory() && b.isDirectory()) return 1;
|
|
124
|
+
return a.name.localeCompare(b.name);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const lines: string[] = [];
|
|
128
|
+
for (let i = 0; i < entries.length; i++) {
|
|
129
|
+
const entry = entries[i];
|
|
130
|
+
const isLast = i === entries.length - 1;
|
|
131
|
+
const connector = isLast ? "└── " : "├── ";
|
|
132
|
+
const childPrefix = isLast ? " " : "│ ";
|
|
133
|
+
|
|
134
|
+
if (entry.isDirectory()) {
|
|
135
|
+
lines.push(`${prefix}${connector}${entry.name}/`);
|
|
136
|
+
const subtree = this.buildTree(
|
|
137
|
+
path.join(dir, entry.name),
|
|
138
|
+
maxDepth,
|
|
139
|
+
prefix + childPrefix,
|
|
140
|
+
depth + 1,
|
|
141
|
+
);
|
|
142
|
+
if (subtree) lines.push(subtree);
|
|
143
|
+
} else {
|
|
144
|
+
lines.push(`${prefix}${connector}${entry.name}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return lines.join("\n");
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private collectStats(dir: string, stats?: RepoStats, depth = 0): RepoStats {
|
|
152
|
+
if (!stats) {
|
|
153
|
+
stats = { totalFiles: 0, totalDirs: 0, languages: new Map(), configFiles: [], entryPoints: [] };
|
|
154
|
+
}
|
|
155
|
+
if (depth > 10 || stats.totalFiles > 5000) return stats;
|
|
156
|
+
|
|
157
|
+
let entries: fs.Dirent[];
|
|
158
|
+
try {
|
|
159
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
160
|
+
} catch {
|
|
161
|
+
return stats;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
for (const entry of entries) {
|
|
165
|
+
if (ALWAYS_IGNORE.has(entry.name)) continue;
|
|
166
|
+
|
|
167
|
+
if (entry.isDirectory()) {
|
|
168
|
+
stats.totalDirs++;
|
|
169
|
+
this.collectStats(path.join(dir, entry.name), stats, depth + 1);
|
|
170
|
+
} else {
|
|
171
|
+
stats.totalFiles++;
|
|
172
|
+
|
|
173
|
+
// Track language
|
|
174
|
+
const ext = path.extname(entry.name).toLowerCase();
|
|
175
|
+
if (ext) {
|
|
176
|
+
stats.languages.set(ext, (stats.languages.get(ext) || 0) + 1);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Config files
|
|
180
|
+
if (CONFIG_FILES.has(entry.name) && depth <= 2) {
|
|
181
|
+
const rel = path.relative(this.workingDir, path.join(dir, entry.name));
|
|
182
|
+
stats.configFiles.push(rel);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Entry points
|
|
186
|
+
if (ENTRY_PATTERNS.includes(entry.name) && depth <= 3) {
|
|
187
|
+
const rel = path.relative(this.workingDir, path.join(dir, entry.name));
|
|
188
|
+
stats.entryPoints.push(rel);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return stats;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
private formatStats(stats: RepoStats): string {
|
|
197
|
+
const lines: string[] = ["\n## Summary"];
|
|
198
|
+
lines.push(`- **${stats.totalFiles}** files in **${stats.totalDirs}** directories`);
|
|
199
|
+
|
|
200
|
+
// Languages (top 10)
|
|
201
|
+
if (stats.languages.size > 0) {
|
|
202
|
+
const sorted = [...stats.languages.entries()]
|
|
203
|
+
.sort((a, b) => b[1] - a[1])
|
|
204
|
+
.slice(0, 10);
|
|
205
|
+
const langStr = sorted.map(([ext, count]) => `${ext} (${count})`).join(", ");
|
|
206
|
+
lines.push(`- **Languages:** ${langStr}`);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Config files
|
|
210
|
+
if (stats.configFiles.length > 0) {
|
|
211
|
+
lines.push(`\n### Config Files`);
|
|
212
|
+
for (const f of stats.configFiles.slice(0, 20)) lines.push(`- ${f}`);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Entry points
|
|
216
|
+
if (stats.entryPoints.length > 0) {
|
|
217
|
+
lines.push(`\n### Entry Points`);
|
|
218
|
+
for (const f of stats.entryPoints.slice(0, 20)) lines.push(`- ${f}`);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return lines.join("\n");
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
private getGitInfo(dir: string): Promise<string | null> {
|
|
225
|
+
return new Promise((resolve) => {
|
|
226
|
+
exec(
|
|
227
|
+
'git branch --show-current && echo "---" && git log --oneline -5 2>/dev/null',
|
|
228
|
+
{ cwd: dir, timeout: 5000 },
|
|
229
|
+
(error, stdout) => {
|
|
230
|
+
if (error || !stdout.trim()) {
|
|
231
|
+
resolve(null);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const parts = stdout.split("---");
|
|
235
|
+
const branch = parts[0]?.trim();
|
|
236
|
+
const commits = parts[1]?.trim();
|
|
237
|
+
const lines = [`Branch: **${branch}**`];
|
|
238
|
+
if (commits) {
|
|
239
|
+
lines.push("\nRecent commits:");
|
|
240
|
+
for (const c of commits.split("\n").slice(0, 5)) {
|
|
241
|
+
lines.push(` ${c.trim()}`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
resolve(lines.join("\n"));
|
|
245
|
+
},
|
|
246
|
+
);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web Fetch Tool — fetch content from URLs.
|
|
3
|
+
* Supports HTML pages (extracts text), JSON APIs, and plain text.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { BaseTool, ToolDefinition, ToolResult } from "./types";
|
|
7
|
+
import type { SandboxManager } from "../sandbox";
|
|
8
|
+
|
|
9
|
+
export class WebFetchTool implements BaseTool {
|
|
10
|
+
definition: ToolDefinition = {
|
|
11
|
+
name: "web_fetch",
|
|
12
|
+
description:
|
|
13
|
+
"Fetch content from a URL. Returns the text content of the page. Useful for reading documentation, APIs, or web pages. Requires user permission. Network access is controlled by sandbox domain rules — requests to non-allowed domains may be blocked.",
|
|
14
|
+
inputSchema: {
|
|
15
|
+
type: "object",
|
|
16
|
+
properties: {
|
|
17
|
+
url: {
|
|
18
|
+
type: "string",
|
|
19
|
+
description: "The URL to fetch",
|
|
20
|
+
},
|
|
21
|
+
max_length: {
|
|
22
|
+
type: "number",
|
|
23
|
+
description: "Maximum characters to return. Default: 10000.",
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
required: ["url"],
|
|
27
|
+
},
|
|
28
|
+
requiresPermission: true,
|
|
29
|
+
permissionMessage: (input) => `Fetch URL: ${input.url}`,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
private sandboxManager?: SandboxManager;
|
|
33
|
+
|
|
34
|
+
constructor(sandboxManager?: SandboxManager) {
|
|
35
|
+
this.sandboxManager = sandboxManager;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async execute(input: Record<string, unknown>): Promise<ToolResult> {
|
|
39
|
+
const url = input.url as string;
|
|
40
|
+
const maxLength = (input.max_length as number) || 10000;
|
|
41
|
+
|
|
42
|
+
// Validate URL
|
|
43
|
+
try {
|
|
44
|
+
new URL(url);
|
|
45
|
+
} catch {
|
|
46
|
+
return { success: false, output: "", error: `Invalid URL: ${url}` };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Sandbox network check
|
|
50
|
+
if (this.sandboxManager) {
|
|
51
|
+
const check = await this.sandboxManager.checkNetworkAccess(url);
|
|
52
|
+
if (!check.allowed) {
|
|
53
|
+
return { success: false, output: "", error: check.reason || "Sandbox: network access denied" };
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
const controller = new AbortController();
|
|
59
|
+
const timeout = setTimeout(() => controller.abort(), 30000);
|
|
60
|
+
|
|
61
|
+
const response = await fetch(url, {
|
|
62
|
+
signal: controller.signal,
|
|
63
|
+
headers: {
|
|
64
|
+
"User-Agent": "Cdoing-Agent/0.1.0",
|
|
65
|
+
"Accept": "text/html,application/json,text/plain,*/*",
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
clearTimeout(timeout);
|
|
70
|
+
|
|
71
|
+
if (!response.ok) {
|
|
72
|
+
return {
|
|
73
|
+
success: false,
|
|
74
|
+
output: "",
|
|
75
|
+
error: `HTTP ${response.status}: ${response.statusText}`,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const contentType = response.headers.get("content-type") || "";
|
|
80
|
+
let text = await response.text();
|
|
81
|
+
|
|
82
|
+
// If HTML, strip tags and extract text content
|
|
83
|
+
if (contentType.includes("text/html")) {
|
|
84
|
+
text = stripHtml(text);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Truncate if too long
|
|
88
|
+
if (text.length > maxLength) {
|
|
89
|
+
text = text.substring(0, maxLength) + `\n\n... [truncated at ${maxLength} characters]`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return { success: true, output: text || "(empty response)" };
|
|
93
|
+
} catch (err) {
|
|
94
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
95
|
+
return { success: false, output: "", error: `Fetch failed: ${message}` };
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Simple HTML-to-text: remove tags, decode common entities, collapse whitespace */
|
|
101
|
+
function stripHtml(html: string): string {
|
|
102
|
+
return html
|
|
103
|
+
// Remove script and style blocks
|
|
104
|
+
.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, "")
|
|
105
|
+
.replace(/<style[^>]*>[\s\S]*?<\/style>/gi, "")
|
|
106
|
+
// Remove HTML tags
|
|
107
|
+
.replace(/<[^>]+>/g, " ")
|
|
108
|
+
// Decode common entities
|
|
109
|
+
.replace(/&/g, "&")
|
|
110
|
+
.replace(/</g, "<")
|
|
111
|
+
.replace(/>/g, ">")
|
|
112
|
+
.replace(/"/g, '"')
|
|
113
|
+
.replace(/'/g, "'")
|
|
114
|
+
.replace(/ /g, " ")
|
|
115
|
+
// Collapse whitespace
|
|
116
|
+
.replace(/\s+/g, " ")
|
|
117
|
+
.trim();
|
|
118
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Web Search Tool — search the web using DuckDuckGo's HTML page.
|
|
3
|
+
* No API key required — uses DDG's lite HTML interface.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { BaseTool, ToolDefinition, ToolResult } from "./types";
|
|
7
|
+
|
|
8
|
+
export class WebSearchTool implements BaseTool {
|
|
9
|
+
definition: ToolDefinition = {
|
|
10
|
+
name: "web_search",
|
|
11
|
+
description:
|
|
12
|
+
"Search the web for information. Returns search results with titles, URLs, and snippets. Useful for finding documentation, solutions, or current information.",
|
|
13
|
+
inputSchema: {
|
|
14
|
+
type: "object",
|
|
15
|
+
properties: {
|
|
16
|
+
query: {
|
|
17
|
+
type: "string",
|
|
18
|
+
description: "The search query",
|
|
19
|
+
},
|
|
20
|
+
max_results: {
|
|
21
|
+
type: "number",
|
|
22
|
+
description: "Maximum number of results. Default: 5.",
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
required: ["query"],
|
|
26
|
+
},
|
|
27
|
+
requiresPermission: true,
|
|
28
|
+
permissionMessage: (input) => `Web search: ${input.query}`,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
async execute(input: Record<string, unknown>): Promise<ToolResult> {
|
|
32
|
+
const query = input.query as string;
|
|
33
|
+
const maxResults = (input.max_results as number) || 5;
|
|
34
|
+
|
|
35
|
+
try {
|
|
36
|
+
const encodedQuery = encodeURIComponent(query);
|
|
37
|
+
const url = `https://lite.duckduckgo.com/lite/?q=${encodedQuery}`;
|
|
38
|
+
|
|
39
|
+
const controller = new AbortController();
|
|
40
|
+
const timeout = setTimeout(() => controller.abort(), 15000);
|
|
41
|
+
|
|
42
|
+
const response = await fetch(url, {
|
|
43
|
+
signal: controller.signal,
|
|
44
|
+
headers: {
|
|
45
|
+
"User-Agent": "Cdoing-Agent/0.1.0",
|
|
46
|
+
"Accept": "text/html",
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
clearTimeout(timeout);
|
|
51
|
+
|
|
52
|
+
if (!response.ok) {
|
|
53
|
+
return {
|
|
54
|
+
success: false,
|
|
55
|
+
output: "",
|
|
56
|
+
error: `Search failed: HTTP ${response.status}`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const html = await response.text();
|
|
61
|
+
const results = parseSearchResults(html, maxResults);
|
|
62
|
+
|
|
63
|
+
if (results.length === 0) {
|
|
64
|
+
return { success: true, output: "No results found." };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const formatted = results
|
|
68
|
+
.map((r, i) => `${i + 1}. **${r.title}**\n ${r.url}\n ${r.snippet}`)
|
|
69
|
+
.join("\n\n");
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
success: true,
|
|
73
|
+
output: `Search results for "${query}":\n\n${formatted}`,
|
|
74
|
+
};
|
|
75
|
+
} catch (err) {
|
|
76
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
77
|
+
return { success: false, output: "", error: `Search failed: ${message}` };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
interface SearchResult {
|
|
83
|
+
title: string;
|
|
84
|
+
url: string;
|
|
85
|
+
snippet: string;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Parse DDG lite HTML for search results */
|
|
89
|
+
function parseSearchResults(html: string, maxResults: number): SearchResult[] {
|
|
90
|
+
const results: SearchResult[] = [];
|
|
91
|
+
|
|
92
|
+
// DDG lite puts results in table rows with class "result-link" for titles
|
|
93
|
+
// and "result-snippet" for descriptions
|
|
94
|
+
const linkRegex = /<a[^>]+class="result-link"[^>]*href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/gi;
|
|
95
|
+
const snippetRegex = /<td[^>]+class="result-snippet"[^>]*>([\s\S]*?)<\/td>/gi;
|
|
96
|
+
|
|
97
|
+
const links: { url: string; title: string }[] = [];
|
|
98
|
+
const snippets: string[] = [];
|
|
99
|
+
|
|
100
|
+
let match;
|
|
101
|
+
while ((match = linkRegex.exec(html)) !== null) {
|
|
102
|
+
links.push({
|
|
103
|
+
url: match[1].replace(/&/g, "&"),
|
|
104
|
+
title: match[2].replace(/<[^>]+>/g, "").trim(),
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
while ((match = snippetRegex.exec(html)) !== null) {
|
|
109
|
+
snippets.push(
|
|
110
|
+
match[1]
|
|
111
|
+
.replace(/<[^>]+>/g, "")
|
|
112
|
+
.replace(/&/g, "&")
|
|
113
|
+
.replace(/</g, "<")
|
|
114
|
+
.replace(/>/g, ">")
|
|
115
|
+
.replace(/"/g, '"')
|
|
116
|
+
.trim()
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
for (let i = 0; i < Math.min(links.length, maxResults); i++) {
|
|
121
|
+
results.push({
|
|
122
|
+
title: links[i].title || "(untitled)",
|
|
123
|
+
url: links[i].url,
|
|
124
|
+
snippet: snippets[i] || "",
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return results;
|
|
129
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gitignore-aware file filtering.
|
|
3
|
+
* Reads .gitignore and applies patterns to glob/grep searches.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as fs from "fs";
|
|
7
|
+
import * as path from "path";
|
|
8
|
+
|
|
9
|
+
/** Default patterns to always ignore */
|
|
10
|
+
const DEFAULT_IGNORE = [
|
|
11
|
+
"**/node_modules/**",
|
|
12
|
+
"**/dist/**",
|
|
13
|
+
"**/.git/**",
|
|
14
|
+
"**/*.lock",
|
|
15
|
+
"**/build/**",
|
|
16
|
+
"**/.next/**",
|
|
17
|
+
"**/.nuxt/**",
|
|
18
|
+
"**/coverage/**",
|
|
19
|
+
"**/__pycache__/**",
|
|
20
|
+
"**/.venv/**",
|
|
21
|
+
"**/venv/**",
|
|
22
|
+
"**/.env",
|
|
23
|
+
"**/.DS_Store",
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Load ignore patterns from .gitignore + defaults.
|
|
28
|
+
* Converts .gitignore patterns to glob-compatible patterns.
|
|
29
|
+
*/
|
|
30
|
+
export function loadIgnorePatterns(workingDir: string): string[] {
|
|
31
|
+
const patterns = [...DEFAULT_IGNORE];
|
|
32
|
+
const gitignorePath = path.join(workingDir, ".gitignore");
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
if (fs.existsSync(gitignorePath)) {
|
|
36
|
+
const content = fs.readFileSync(gitignorePath, "utf-8");
|
|
37
|
+
const lines = content.split("\n");
|
|
38
|
+
|
|
39
|
+
for (let line of lines) {
|
|
40
|
+
line = line.trim();
|
|
41
|
+
// Skip empty lines and comments
|
|
42
|
+
if (!line || line.startsWith("#")) continue;
|
|
43
|
+
// Skip negation patterns (complex to handle)
|
|
44
|
+
if (line.startsWith("!")) continue;
|
|
45
|
+
|
|
46
|
+
// Convert to glob pattern
|
|
47
|
+
let pattern = line;
|
|
48
|
+
|
|
49
|
+
// If it ends with /, it's a directory — add **
|
|
50
|
+
if (pattern.endsWith("/")) {
|
|
51
|
+
pattern = `**/${pattern}**`;
|
|
52
|
+
}
|
|
53
|
+
// If it doesn't contain a slash, it can match anywhere
|
|
54
|
+
else if (!pattern.includes("/")) {
|
|
55
|
+
pattern = `**/${pattern}`;
|
|
56
|
+
}
|
|
57
|
+
// If it starts with /, it's relative to root
|
|
58
|
+
else if (pattern.startsWith("/")) {
|
|
59
|
+
pattern = pattern.substring(1);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Avoid duplicates
|
|
63
|
+
if (!patterns.includes(pattern)) {
|
|
64
|
+
patterns.push(pattern);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
} catch {
|
|
69
|
+
// Silently ignore read errors
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return patterns;
|
|
73
|
+
}
|