@animus-labs/cortex 0.2.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/LICENSE +21 -0
- package/README.md +73 -0
- package/dist/budget-guard.d.ts +75 -0
- package/dist/budget-guard.d.ts.map +1 -0
- package/dist/budget-guard.js +142 -0
- package/dist/budget-guard.js.map +1 -0
- package/dist/compaction/compaction.d.ts +99 -0
- package/dist/compaction/compaction.d.ts.map +1 -0
- package/dist/compaction/compaction.js +302 -0
- package/dist/compaction/compaction.js.map +1 -0
- package/dist/compaction/failsafe.d.ts +57 -0
- package/dist/compaction/failsafe.d.ts.map +1 -0
- package/dist/compaction/failsafe.js +135 -0
- package/dist/compaction/failsafe.js.map +1 -0
- package/dist/compaction/index.d.ts +381 -0
- package/dist/compaction/index.d.ts.map +1 -0
- package/dist/compaction/index.js +979 -0
- package/dist/compaction/index.js.map +1 -0
- package/dist/compaction/microcompaction.d.ts +219 -0
- package/dist/compaction/microcompaction.d.ts.map +1 -0
- package/dist/compaction/microcompaction.js +536 -0
- package/dist/compaction/microcompaction.js.map +1 -0
- package/dist/compaction/observational/buffering.d.ts +225 -0
- package/dist/compaction/observational/buffering.d.ts.map +1 -0
- package/dist/compaction/observational/buffering.js +354 -0
- package/dist/compaction/observational/buffering.js.map +1 -0
- package/dist/compaction/observational/constants.d.ts +70 -0
- package/dist/compaction/observational/constants.d.ts.map +1 -0
- package/dist/compaction/observational/constants.js +507 -0
- package/dist/compaction/observational/constants.js.map +1 -0
- package/dist/compaction/observational/index.d.ts +219 -0
- package/dist/compaction/observational/index.d.ts.map +1 -0
- package/dist/compaction/observational/index.js +641 -0
- package/dist/compaction/observational/index.js.map +1 -0
- package/dist/compaction/observational/observer.d.ts +97 -0
- package/dist/compaction/observational/observer.d.ts.map +1 -0
- package/dist/compaction/observational/observer.js +424 -0
- package/dist/compaction/observational/observer.js.map +1 -0
- package/dist/compaction/observational/recall-tool.d.ts +27 -0
- package/dist/compaction/observational/recall-tool.d.ts.map +1 -0
- package/dist/compaction/observational/recall-tool.js +93 -0
- package/dist/compaction/observational/recall-tool.js.map +1 -0
- package/dist/compaction/observational/reflector.d.ts +94 -0
- package/dist/compaction/observational/reflector.d.ts.map +1 -0
- package/dist/compaction/observational/reflector.js +167 -0
- package/dist/compaction/observational/reflector.js.map +1 -0
- package/dist/compaction/observational/types.d.ts +271 -0
- package/dist/compaction/observational/types.d.ts.map +1 -0
- package/dist/compaction/observational/types.js +15 -0
- package/dist/compaction/observational/types.js.map +1 -0
- package/dist/context-manager.d.ts +134 -0
- package/dist/context-manager.d.ts.map +1 -0
- package/dist/context-manager.js +170 -0
- package/dist/context-manager.js.map +1 -0
- package/dist/cortex-agent.d.ts +1020 -0
- package/dist/cortex-agent.d.ts.map +1 -0
- package/dist/cortex-agent.js +3589 -0
- package/dist/cortex-agent.js.map +1 -0
- package/dist/error-classifier.d.ts +48 -0
- package/dist/error-classifier.d.ts.map +1 -0
- package/dist/error-classifier.js +152 -0
- package/dist/error-classifier.js.map +1 -0
- package/dist/event-bridge.d.ts +166 -0
- package/dist/event-bridge.d.ts.map +1 -0
- package/dist/event-bridge.js +381 -0
- package/dist/event-bridge.js.map +1 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +57 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-client.d.ts +119 -0
- package/dist/mcp-client.d.ts.map +1 -0
- package/dist/mcp-client.js +474 -0
- package/dist/mcp-client.js.map +1 -0
- package/dist/model-wrapper.d.ts +58 -0
- package/dist/model-wrapper.d.ts.map +1 -0
- package/dist/model-wrapper.js +86 -0
- package/dist/model-wrapper.js.map +1 -0
- package/dist/noop-logger.d.ts +4 -0
- package/dist/noop-logger.d.ts.map +1 -0
- package/dist/noop-logger.js +8 -0
- package/dist/noop-logger.js.map +1 -0
- package/dist/prompt-diagnostics.d.ts +47 -0
- package/dist/prompt-diagnostics.d.ts.map +1 -0
- package/dist/prompt-diagnostics.js +230 -0
- package/dist/prompt-diagnostics.js.map +1 -0
- package/dist/provider-manager.d.ts +224 -0
- package/dist/provider-manager.d.ts.map +1 -0
- package/dist/provider-manager.js +563 -0
- package/dist/provider-manager.js.map +1 -0
- package/dist/provider-registry.d.ts +115 -0
- package/dist/provider-registry.d.ts.map +1 -0
- package/dist/provider-registry.js +305 -0
- package/dist/provider-registry.js.map +1 -0
- package/dist/schema-converter.d.ts +20 -0
- package/dist/schema-converter.d.ts.map +1 -0
- package/dist/schema-converter.js +48 -0
- package/dist/schema-converter.js.map +1 -0
- package/dist/skill-preprocessor.d.ts +46 -0
- package/dist/skill-preprocessor.d.ts.map +1 -0
- package/dist/skill-preprocessor.js +237 -0
- package/dist/skill-preprocessor.js.map +1 -0
- package/dist/skill-registry.d.ts +107 -0
- package/dist/skill-registry.d.ts.map +1 -0
- package/dist/skill-registry.js +330 -0
- package/dist/skill-registry.js.map +1 -0
- package/dist/skill-tool.d.ts +54 -0
- package/dist/skill-tool.d.ts.map +1 -0
- package/dist/skill-tool.js +88 -0
- package/dist/skill-tool.js.map +1 -0
- package/dist/sub-agent-manager.d.ts +90 -0
- package/dist/sub-agent-manager.d.ts.map +1 -0
- package/dist/sub-agent-manager.js +192 -0
- package/dist/sub-agent-manager.js.map +1 -0
- package/dist/token-estimator.d.ts +23 -0
- package/dist/token-estimator.d.ts.map +1 -0
- package/dist/token-estimator.js +27 -0
- package/dist/token-estimator.js.map +1 -0
- package/dist/tool-contract.d.ts +68 -0
- package/dist/tool-contract.d.ts.map +1 -0
- package/dist/tool-contract.js +35 -0
- package/dist/tool-contract.js.map +1 -0
- package/dist/tool-result-persistence.d.ts +89 -0
- package/dist/tool-result-persistence.d.ts.map +1 -0
- package/dist/tool-result-persistence.js +152 -0
- package/dist/tool-result-persistence.js.map +1 -0
- package/dist/tools/bash/index.d.ts +71 -0
- package/dist/tools/bash/index.d.ts.map +1 -0
- package/dist/tools/bash/index.js +485 -0
- package/dist/tools/bash/index.js.map +1 -0
- package/dist/tools/bash/interactive.d.ts +47 -0
- package/dist/tools/bash/interactive.d.ts.map +1 -0
- package/dist/tools/bash/interactive.js +262 -0
- package/dist/tools/bash/interactive.js.map +1 -0
- package/dist/tools/bash/safety.d.ts +149 -0
- package/dist/tools/bash/safety.d.ts.map +1 -0
- package/dist/tools/bash/safety.js +1116 -0
- package/dist/tools/bash/safety.js.map +1 -0
- package/dist/tools/edit.d.ts +57 -0
- package/dist/tools/edit.d.ts.map +1 -0
- package/dist/tools/edit.js +310 -0
- package/dist/tools/edit.js.map +1 -0
- package/dist/tools/glob.d.ts +34 -0
- package/dist/tools/glob.d.ts.map +1 -0
- package/dist/tools/glob.js +268 -0
- package/dist/tools/glob.js.map +1 -0
- package/dist/tools/grep.d.ts +53 -0
- package/dist/tools/grep.d.ts.map +1 -0
- package/dist/tools/grep.js +673 -0
- package/dist/tools/grep.js.map +1 -0
- package/dist/tools/index.d.ts +62 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +52 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/read.d.ts +43 -0
- package/dist/tools/read.d.ts.map +1 -0
- package/dist/tools/read.js +459 -0
- package/dist/tools/read.js.map +1 -0
- package/dist/tools/runtime.d.ts +62 -0
- package/dist/tools/runtime.d.ts.map +1 -0
- package/dist/tools/runtime.js +116 -0
- package/dist/tools/runtime.js.map +1 -0
- package/dist/tools/shared/cwd-tracker.d.ts +32 -0
- package/dist/tools/shared/cwd-tracker.d.ts.map +1 -0
- package/dist/tools/shared/cwd-tracker.js +44 -0
- package/dist/tools/shared/cwd-tracker.js.map +1 -0
- package/dist/tools/shared/edit-history.d.ts +55 -0
- package/dist/tools/shared/edit-history.d.ts.map +1 -0
- package/dist/tools/shared/edit-history.js +72 -0
- package/dist/tools/shared/edit-history.js.map +1 -0
- package/dist/tools/shared/edit-matcher.d.ts +83 -0
- package/dist/tools/shared/edit-matcher.d.ts.map +1 -0
- package/dist/tools/shared/edit-matcher.js +359 -0
- package/dist/tools/shared/edit-matcher.js.map +1 -0
- package/dist/tools/shared/file-mutation-lock.d.ts +22 -0
- package/dist/tools/shared/file-mutation-lock.d.ts.map +1 -0
- package/dist/tools/shared/file-mutation-lock.js +35 -0
- package/dist/tools/shared/file-mutation-lock.js.map +1 -0
- package/dist/tools/shared/gitignore.d.ts +17 -0
- package/dist/tools/shared/gitignore.d.ts.map +1 -0
- package/dist/tools/shared/gitignore.js +59 -0
- package/dist/tools/shared/gitignore.js.map +1 -0
- package/dist/tools/shared/pdf-extractor.d.ts +96 -0
- package/dist/tools/shared/pdf-extractor.d.ts.map +1 -0
- package/dist/tools/shared/pdf-extractor.js +196 -0
- package/dist/tools/shared/pdf-extractor.js.map +1 -0
- package/dist/tools/shared/read-registry.d.ts +66 -0
- package/dist/tools/shared/read-registry.d.ts.map +1 -0
- package/dist/tools/shared/read-registry.js +65 -0
- package/dist/tools/shared/read-registry.js.map +1 -0
- package/dist/tools/shared/safe-env.d.ts +18 -0
- package/dist/tools/shared/safe-env.d.ts.map +1 -0
- package/dist/tools/shared/safe-env.js +70 -0
- package/dist/tools/shared/safe-env.js.map +1 -0
- package/dist/tools/sub-agent.d.ts +91 -0
- package/dist/tools/sub-agent.d.ts.map +1 -0
- package/dist/tools/sub-agent.js +89 -0
- package/dist/tools/sub-agent.js.map +1 -0
- package/dist/tools/task-output.d.ts +38 -0
- package/dist/tools/task-output.d.ts.map +1 -0
- package/dist/tools/task-output.js +186 -0
- package/dist/tools/task-output.js.map +1 -0
- package/dist/tools/tool-search/index.d.ts +40 -0
- package/dist/tools/tool-search/index.d.ts.map +1 -0
- package/dist/tools/tool-search/index.js +110 -0
- package/dist/tools/tool-search/index.js.map +1 -0
- package/dist/tools/tool-search/registry.d.ts +82 -0
- package/dist/tools/tool-search/registry.d.ts.map +1 -0
- package/dist/tools/tool-search/registry.js +238 -0
- package/dist/tools/tool-search/registry.js.map +1 -0
- package/dist/tools/undo-edit.d.ts +51 -0
- package/dist/tools/undo-edit.d.ts.map +1 -0
- package/dist/tools/undo-edit.js +231 -0
- package/dist/tools/undo-edit.js.map +1 -0
- package/dist/tools/web-fetch/cache.d.ts +49 -0
- package/dist/tools/web-fetch/cache.d.ts.map +1 -0
- package/dist/tools/web-fetch/cache.js +89 -0
- package/dist/tools/web-fetch/cache.js.map +1 -0
- package/dist/tools/web-fetch/index.d.ts +53 -0
- package/dist/tools/web-fetch/index.d.ts.map +1 -0
- package/dist/tools/web-fetch/index.js +513 -0
- package/dist/tools/web-fetch/index.js.map +1 -0
- package/dist/tools/write.d.ts +59 -0
- package/dist/tools/write.d.ts.map +1 -0
- package/dist/tools/write.js +316 -0
- package/dist/tools/write.js.map +1 -0
- package/dist/types.d.ts +881 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +16 -0
- package/dist/types.js.map +1 -0
- package/dist/working-tags.d.ts +44 -0
- package/dist/working-tags.d.ts.map +1 -0
- package/dist/working-tags.js +103 -0
- package/dist/working-tags.js.map +1 -0
- package/package.json +87 -0
- package/src/budget-guard.ts +170 -0
- package/src/compaction/compaction.ts +386 -0
- package/src/compaction/failsafe.ts +185 -0
- package/src/compaction/index.ts +1199 -0
- package/src/compaction/microcompaction.ts +709 -0
- package/src/compaction/observational/buffering.ts +430 -0
- package/src/compaction/observational/constants.ts +532 -0
- package/src/compaction/observational/index.ts +837 -0
- package/src/compaction/observational/observer.ts +510 -0
- package/src/compaction/observational/recall-tool.ts +130 -0
- package/src/compaction/observational/reflector.ts +221 -0
- package/src/compaction/observational/types.ts +343 -0
- package/src/context-manager.ts +237 -0
- package/src/cortex-agent.ts +4297 -0
- package/src/error-classifier.ts +199 -0
- package/src/event-bridge.ts +508 -0
- package/src/index.ts +292 -0
- package/src/mcp-client.ts +582 -0
- package/src/model-wrapper.ts +128 -0
- package/src/noop-logger.ts +9 -0
- package/src/prompt-diagnostics.ts +296 -0
- package/src/provider-manager.ts +823 -0
- package/src/provider-registry.ts +386 -0
- package/src/schema-converter.ts +51 -0
- package/src/skill-preprocessor.ts +314 -0
- package/src/skill-registry.ts +378 -0
- package/src/skill-tool.ts +130 -0
- package/src/sub-agent-manager.ts +236 -0
- package/src/token-estimator.ts +26 -0
- package/src/tool-contract.ts +113 -0
- package/src/tool-result-persistence.ts +197 -0
- package/src/tools/bash/index.ts +633 -0
- package/src/tools/bash/interactive.ts +302 -0
- package/src/tools/bash/safety.ts +1297 -0
- package/src/tools/edit.ts +422 -0
- package/src/tools/glob.ts +330 -0
- package/src/tools/grep.ts +819 -0
- package/src/tools/index.ts +110 -0
- package/src/tools/read.ts +580 -0
- package/src/tools/runtime.ts +173 -0
- package/src/tools/shared/cwd-tracker.ts +50 -0
- package/src/tools/shared/edit-history.ts +96 -0
- package/src/tools/shared/edit-matcher.ts +457 -0
- package/src/tools/shared/file-mutation-lock.ts +40 -0
- package/src/tools/shared/gitignore.ts +61 -0
- package/src/tools/shared/pdf-extractor.ts +290 -0
- package/src/tools/shared/read-registry.ts +93 -0
- package/src/tools/shared/safe-env.ts +82 -0
- package/src/tools/sub-agent.ts +171 -0
- package/src/tools/task-output.ts +236 -0
- package/src/tools/tool-search/index.ts +167 -0
- package/src/tools/tool-search/registry.ts +278 -0
- package/src/tools/undo-edit.ts +314 -0
- package/src/tools/web-fetch/cache.ts +112 -0
- package/src/tools/web-fetch/index.ts +604 -0
- package/src/tools/write.ts +385 -0
- package/src/types.ts +1057 -0
- package/src/working-tags.ts +118 -0
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Glob tool: find files by name pattern matching.
|
|
3
|
+
*
|
|
4
|
+
* Uses fast-glob for pattern matching and sorts results by
|
|
5
|
+
* modification time (newest first). Respects .gitignore rules.
|
|
6
|
+
*
|
|
7
|
+
* Reference: docs/cortex/tools/glob.md
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import * as fs from 'node:fs';
|
|
11
|
+
import * as path from 'node:path';
|
|
12
|
+
import { Type, type Static } from 'typebox';
|
|
13
|
+
import type { ToolContentDetails } from '../types.js';
|
|
14
|
+
import {
|
|
15
|
+
readGitignorePatterns,
|
|
16
|
+
DEFAULT_IGNORE_PATTERNS,
|
|
17
|
+
} from './shared/gitignore.js';
|
|
18
|
+
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Schema
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
export const GlobParams = Type.Object({
|
|
24
|
+
pattern: Type.String({ description: 'Glob pattern to match files against (e.g., "**/*.ts", "src/**/*.test.js")' }),
|
|
25
|
+
path: Type.Optional(
|
|
26
|
+
Type.String({ description: 'Directory to search in. Default: current working directory.' }),
|
|
27
|
+
),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
export type GlobParamsType = Static<typeof GlobParams>;
|
|
31
|
+
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// Details type
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
export interface GlobDetails {
|
|
37
|
+
totalCount: number;
|
|
38
|
+
truncated: boolean;
|
|
39
|
+
durationMs: number;
|
|
40
|
+
searchPath: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ---------------------------------------------------------------------------
|
|
44
|
+
// Constants
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
|
|
47
|
+
const MAX_RESULTS = 100;
|
|
48
|
+
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
// Config
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
export interface GlobToolConfig {
|
|
54
|
+
/** Default search directory when no path param is given. */
|
|
55
|
+
defaultCwd: string;
|
|
56
|
+
/** Whether to respect .gitignore. Default: true. */
|
|
57
|
+
respectGitignore?: boolean | undefined;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
// Helpers
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Recursively walk a directory and collect files matching a glob pattern.
|
|
66
|
+
* Uses Node.js built-in fs for simplicity (fast-glob would be used in production).
|
|
67
|
+
*
|
|
68
|
+
* This implementation is a simplified glob matcher. It supports:
|
|
69
|
+
* - `*` (match any characters except /)
|
|
70
|
+
* - `**` (match any path segment)
|
|
71
|
+
* - `?` (match single character)
|
|
72
|
+
* - `{a,b}` (alternation)
|
|
73
|
+
* - `[abc]` (character class)
|
|
74
|
+
*/
|
|
75
|
+
function globPatternToRegex(pattern: string): RegExp {
|
|
76
|
+
let regex = '';
|
|
77
|
+
let i = 0;
|
|
78
|
+
|
|
79
|
+
while (i < pattern.length) {
|
|
80
|
+
const char = pattern[i]!;
|
|
81
|
+
|
|
82
|
+
if (char === '*') {
|
|
83
|
+
if (pattern[i + 1] === '*') {
|
|
84
|
+
// ** matches any path segment
|
|
85
|
+
if (pattern[i + 2] === '/' || pattern[i + 2] === undefined) {
|
|
86
|
+
regex += '(?:.+/)?';
|
|
87
|
+
i += pattern[i + 2] === '/' ? 3 : 2;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// * matches anything except /
|
|
92
|
+
regex += '[^/]*';
|
|
93
|
+
i++;
|
|
94
|
+
} else if (char === '?') {
|
|
95
|
+
regex += '[^/]';
|
|
96
|
+
i++;
|
|
97
|
+
} else if (char === '{') {
|
|
98
|
+
// Find the closing brace
|
|
99
|
+
const closeIdx = pattern.indexOf('}', i);
|
|
100
|
+
if (closeIdx === -1) {
|
|
101
|
+
regex += '\\{';
|
|
102
|
+
i++;
|
|
103
|
+
} else {
|
|
104
|
+
const alternatives = pattern.slice(i + 1, closeIdx).split(',');
|
|
105
|
+
regex += '(?:' + alternatives.map(escapeRegexPart).join('|') + ')';
|
|
106
|
+
i = closeIdx + 1;
|
|
107
|
+
}
|
|
108
|
+
} else if (char === '[') {
|
|
109
|
+
const closeIdx = pattern.indexOf(']', i);
|
|
110
|
+
if (closeIdx === -1) {
|
|
111
|
+
regex += '\\[';
|
|
112
|
+
i++;
|
|
113
|
+
} else {
|
|
114
|
+
regex += pattern.slice(i, closeIdx + 1);
|
|
115
|
+
i = closeIdx + 1;
|
|
116
|
+
}
|
|
117
|
+
} else if (char === '.') {
|
|
118
|
+
regex += '\\.';
|
|
119
|
+
i++;
|
|
120
|
+
} else {
|
|
121
|
+
regex += char;
|
|
122
|
+
i++;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return new RegExp(`^${regex}$`);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function escapeRegexPart(s: string): string {
|
|
130
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Check if a path matches any of the ignore patterns.
|
|
135
|
+
*/
|
|
136
|
+
function isIgnored(relativePath: string, ignorePatterns: string[]): boolean {
|
|
137
|
+
const parts = relativePath.split('/');
|
|
138
|
+
|
|
139
|
+
for (const pattern of ignorePatterns) {
|
|
140
|
+
// Direct directory/file name match
|
|
141
|
+
const cleanPattern = pattern.endsWith('/') ? pattern.slice(0, -1) : pattern;
|
|
142
|
+
|
|
143
|
+
// Check if any path component matches
|
|
144
|
+
if (!cleanPattern.includes('/')) {
|
|
145
|
+
if (parts.some((part) => {
|
|
146
|
+
if (cleanPattern.includes('*') || cleanPattern.includes('?')) {
|
|
147
|
+
return globPatternToRegex(cleanPattern).test(part);
|
|
148
|
+
}
|
|
149
|
+
return part === cleanPattern;
|
|
150
|
+
})) {
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
} else {
|
|
154
|
+
// Full path pattern match
|
|
155
|
+
if (globPatternToRegex(cleanPattern).test(relativePath)) {
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Walk a directory tree and collect file paths.
|
|
166
|
+
*/
|
|
167
|
+
async function walkDirectory(
|
|
168
|
+
dir: string,
|
|
169
|
+
baseDir: string,
|
|
170
|
+
ignorePatterns: string[],
|
|
171
|
+
): Promise<string[]> {
|
|
172
|
+
const results: string[] = [];
|
|
173
|
+
|
|
174
|
+
let entries: fs.Dirent[];
|
|
175
|
+
try {
|
|
176
|
+
entries = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
177
|
+
} catch {
|
|
178
|
+
// Skip directories we can't read
|
|
179
|
+
return results;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
for (const entry of entries) {
|
|
183
|
+
const fullPath = path.join(dir, entry.name);
|
|
184
|
+
const relativePath = path.relative(baseDir, fullPath).split(path.sep).join('/');
|
|
185
|
+
|
|
186
|
+
// Check ignore patterns
|
|
187
|
+
if (isIgnored(relativePath, ignorePatterns)) {
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (entry.isDirectory()) {
|
|
192
|
+
const subResults = await walkDirectory(fullPath, baseDir, ignorePatterns);
|
|
193
|
+
results.push(...subResults);
|
|
194
|
+
} else if (entry.isFile()) {
|
|
195
|
+
results.push(fullPath);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return results;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// ---------------------------------------------------------------------------
|
|
203
|
+
// Tool factory
|
|
204
|
+
// ---------------------------------------------------------------------------
|
|
205
|
+
|
|
206
|
+
export function createGlobTool(config: GlobToolConfig): {
|
|
207
|
+
name: string;
|
|
208
|
+
description: string;
|
|
209
|
+
parameters: typeof GlobParams;
|
|
210
|
+
execute: (params: GlobParamsType) => Promise<ToolContentDetails<GlobDetails>>;
|
|
211
|
+
} {
|
|
212
|
+
const respectGitignore = config.respectGitignore ?? true;
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
name: 'Glob',
|
|
216
|
+
description: 'Find files by name pattern. Returns paths sorted by modification time (newest first).',
|
|
217
|
+
parameters: GlobParams,
|
|
218
|
+
|
|
219
|
+
async execute(params: GlobParamsType): Promise<ToolContentDetails<GlobDetails>> {
|
|
220
|
+
const searchPath = params.path ? path.resolve(params.path) : path.resolve(config.defaultCwd);
|
|
221
|
+
const startTime = Date.now();
|
|
222
|
+
|
|
223
|
+
// Verify search path exists
|
|
224
|
+
try {
|
|
225
|
+
const stat = await fs.promises.stat(searchPath);
|
|
226
|
+
if (!stat.isDirectory()) {
|
|
227
|
+
return {
|
|
228
|
+
content: [{ type: 'text', text: `Directory does not exist: ${searchPath}` }],
|
|
229
|
+
details: {
|
|
230
|
+
totalCount: 0,
|
|
231
|
+
truncated: false,
|
|
232
|
+
durationMs: Date.now() - startTime,
|
|
233
|
+
searchPath,
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
} catch {
|
|
238
|
+
return {
|
|
239
|
+
content: [{ type: 'text', text: `Directory does not exist: ${searchPath}` }],
|
|
240
|
+
details: {
|
|
241
|
+
totalCount: 0,
|
|
242
|
+
truncated: false,
|
|
243
|
+
durationMs: Date.now() - startTime,
|
|
244
|
+
searchPath,
|
|
245
|
+
},
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Collect ignore patterns
|
|
250
|
+
let ignorePatterns: string[];
|
|
251
|
+
if (respectGitignore) {
|
|
252
|
+
const gitignorePatterns = await readGitignorePatterns(searchPath);
|
|
253
|
+
ignorePatterns = gitignorePatterns.length > 0
|
|
254
|
+
? [...DEFAULT_IGNORE_PATTERNS, ...gitignorePatterns]
|
|
255
|
+
: DEFAULT_IGNORE_PATTERNS;
|
|
256
|
+
} else {
|
|
257
|
+
ignorePatterns = [];
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Walk directory tree
|
|
261
|
+
const allFiles = await walkDirectory(searchPath, searchPath, ignorePatterns);
|
|
262
|
+
|
|
263
|
+
// Convert glob pattern to regex for filtering
|
|
264
|
+
const pattern = params.pattern;
|
|
265
|
+
let regex: RegExp;
|
|
266
|
+
try {
|
|
267
|
+
regex = globPatternToRegex(pattern);
|
|
268
|
+
} catch {
|
|
269
|
+
return {
|
|
270
|
+
content: [{ type: 'text', text: `Invalid glob pattern: ${pattern}` }],
|
|
271
|
+
details: {
|
|
272
|
+
totalCount: 0,
|
|
273
|
+
truncated: false,
|
|
274
|
+
durationMs: Date.now() - startTime,
|
|
275
|
+
searchPath,
|
|
276
|
+
},
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Filter files by pattern
|
|
281
|
+
const matchingFiles = allFiles.filter((filePath) => {
|
|
282
|
+
const relativePath = path.relative(searchPath, filePath).split(path.sep).join('/');
|
|
283
|
+
return regex.test(relativePath);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
// Sort by modification time (newest first)
|
|
287
|
+
const filesWithMtime = await Promise.all(
|
|
288
|
+
matchingFiles.map(async (filePath) => {
|
|
289
|
+
try {
|
|
290
|
+
const stat = await fs.promises.stat(filePath);
|
|
291
|
+
return { filePath, mtime: stat.mtimeMs };
|
|
292
|
+
} catch {
|
|
293
|
+
return { filePath, mtime: 0 };
|
|
294
|
+
}
|
|
295
|
+
}),
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
filesWithMtime.sort((a, b) => b.mtime - a.mtime);
|
|
299
|
+
|
|
300
|
+
const totalCount = filesWithMtime.length;
|
|
301
|
+
const truncated = totalCount > MAX_RESULTS;
|
|
302
|
+
const resultFiles = filesWithMtime.slice(0, MAX_RESULTS);
|
|
303
|
+
|
|
304
|
+
// Normalize paths to forward slashes in output
|
|
305
|
+
const outputPaths = resultFiles.map((f) => f.filePath.split(path.sep).join('/'));
|
|
306
|
+
|
|
307
|
+
const durationMs = Date.now() - startTime;
|
|
308
|
+
|
|
309
|
+
let text: string;
|
|
310
|
+
if (outputPaths.length === 0) {
|
|
311
|
+
text = 'No files matched the pattern.';
|
|
312
|
+
} else {
|
|
313
|
+
text = outputPaths.join('\n');
|
|
314
|
+
if (truncated) {
|
|
315
|
+
text += `\n\n[Showing ${MAX_RESULTS} of ${totalCount} matches. Use a more specific pattern to narrow results.]`;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
return {
|
|
320
|
+
content: [{ type: 'text', text }],
|
|
321
|
+
details: {
|
|
322
|
+
totalCount,
|
|
323
|
+
truncated,
|
|
324
|
+
durationMs,
|
|
325
|
+
searchPath,
|
|
326
|
+
},
|
|
327
|
+
};
|
|
328
|
+
},
|
|
329
|
+
};
|
|
330
|
+
}
|