diff --git a/package.json b/package.json index 53eb98d..b939999 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,8 @@ "@push.rocks/smartdeno": "^1.2.0", "@push.rocks/smartfs": "^1.2.0", "@push.rocks/smartrequest": "^5.0.1", - "@push.rocks/smartshell": "^3.3.0" + "@push.rocks/smartshell": "^3.3.0", + "minimatch": "^10.1.1" }, "packageManager": "pnpm@10.18.1+sha512.77a884a165cbba2d8d1c19e3b4880eee6d2fcabd0d879121e282196b80042351d5eb3ca0935fa599da1dc51265cc68816ad2bddd2a2de5ea9fdf92adbec7cd34", "repository": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f430629..48584b0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,6 +26,9 @@ importers: '@push.rocks/smartshell': specifier: ^3.3.0 version: 3.3.0 + minimatch: + specifier: ^10.1.1 + version: 10.1.1 devDependencies: '@git.zone/tsbuild': specifier: ^4.0.2 diff --git a/readme.md b/readme.md index 9349b8a..9539a39 100644 --- a/readme.md +++ b/readme.md @@ -483,7 +483,7 @@ Use of these trademarks must comply with Task Venture Capital GmbH's Trademark G ### Company Information -Task Venture Capital GmbH +Task Venture Capital GmbH Registered at District Court Bremen HRB 35230 HB, Germany For any legal inquiries or further information, please contact us via email at hello@task.vc. diff --git a/ts/plugins.ts b/ts/plugins.ts index e428b09..e42752b 100644 --- a/ts/plugins.ts +++ b/ts/plugins.ts @@ -3,6 +3,11 @@ import * as path from 'path'; export { path }; +// third party +import { minimatch } from 'minimatch'; + +export { minimatch }; + // @push.rocks scope import * as smartai from '@push.rocks/smartai'; import * as smartdeno from '@push.rocks/smartdeno'; diff --git a/ts/smartagent.classes.dualagent.ts b/ts/smartagent.classes.dualagent.ts index b610a21..bda743c 100644 --- a/ts/smartagent.classes.dualagent.ts +++ b/ts/smartagent.classes.dualagent.ts @@ -158,9 +158,10 @@ export class DualAgentOrchestrator { /** * Register a scoped filesystem tool that can only access files within the specified directory * @param basePath The directory to scope filesystem operations to + * @param excludePatterns Optional glob patterns to exclude from listings (e.g., ['.nogit/**', 'node_modules/**']) */ - public registerScopedFilesystemTool(basePath: string): void { - const scopedTool = new FilesystemTool({ basePath }); + public registerScopedFilesystemTool(basePath: string, excludePatterns?: string[]): void { + const scopedTool = new FilesystemTool({ basePath, excludePatterns }); this.registerTool(scopedTool); } diff --git a/ts/smartagent.tools.filesystem.ts b/ts/smartagent.tools.filesystem.ts index 0a1d193..5284a16 100644 --- a/ts/smartagent.tools.filesystem.ts +++ b/ts/smartagent.tools.filesystem.ts @@ -8,6 +8,8 @@ import { BaseToolWrapper } from './smartagent.tools.base.js'; export interface IFilesystemToolOptions { /** Base path to scope all operations to. If set, all paths must be within this directory. */ basePath?: string; + /** Glob patterns to exclude from listings (e.g., ['.nogit/**', 'node_modules/**']) */ + excludePatterns?: string[]; } /** @@ -20,12 +22,25 @@ export class FilesystemTool extends BaseToolWrapper { /** Base path to scope all operations to */ private basePath?: string; + /** Glob patterns to exclude from listings */ + private excludePatterns: string[]; constructor(options?: IFilesystemToolOptions) { super(); if (options?.basePath) { this.basePath = plugins.path.resolve(options.basePath); } + this.excludePatterns = options?.excludePatterns || []; + } + + /** + * Check if a relative path should be excluded based on exclude patterns + */ + private isExcluded(relativePath: string): boolean { + if (this.excludePatterns.length === 0) return false; + return this.excludePatterns.some(pattern => + plugins.minimatch(relativePath, pattern, { dot: true }) + ); } /** @@ -361,7 +376,16 @@ export class FilesystemTool extends BaseToolWrapper { if (params.filter) { dir = dir.filter(params.filter as string); } - const entries = await dir.list(); + let entries = await dir.list(); + + // Filter out excluded paths + if (this.excludePatterns.length > 0) { + entries = entries.filter(entry => { + const relativePath = plugins.path.relative(validatedPath, entry.path); + return !this.isExcluded(relativePath) && !this.isExcluded(entry.name); + }); + } + return { success: true, result: { @@ -499,6 +523,11 @@ export class FilesystemTool extends BaseToolWrapper { const itemRelPath = relativePath ? `${relativePath}/${item.name}` : item.name; const isDir = item.isDirectory; + // Skip excluded paths + if (this.isExcluded(itemRelPath) || this.isExcluded(item.name)) { + continue; + } + const entry: ITreeEntry = { path: itemPath, relativePath: itemRelPath, @@ -603,11 +632,14 @@ export class FilesystemTool extends BaseToolWrapper { const matches = await dir.list(); // Return file paths relative to base path for readability - const files = matches.map((entry) => ({ - path: entry.path, - relativePath: plugins.path.relative(basePath, entry.path), - isDirectory: entry.isDirectory, - })); + // Filter out excluded paths + const files = matches + .map((entry) => ({ + path: entry.path, + relativePath: plugins.path.relative(basePath, entry.path), + isDirectory: entry.isDirectory, + })) + .filter((file) => !this.isExcluded(file.relativePath)); return { success: true,