import { AiConfigurationService, ToolProvider, ToolRequest } from '@theia/ai-core'; import { FileReadTracker } from '@theia/ai-chat'; import { CancellationToken, PreferenceService, URI, ILogger } from '@theia/core'; import { ContributionProvider } from '@theia/core/lib/common/contribution-provider'; import { EnvVariablesServer } from '@theia/core/lib/common/env-variables'; import { FileService } from '@theia/filesystem/lib/browser/file-service'; import { FileStat } from '@theia/filesystem/lib/common/files'; import { FileSearchService } from '@theia/file-search/lib/common/file-search-service'; import { WorkspaceService } from '@theia/workspace/lib/browser'; import ignore from 'ignore'; import { MonacoWorkspace } from '@theia/monaco/lib/browser/monaco-workspace'; import { MonacoTextModelService } from '@theia/monaco/lib/browser/monaco-text-model-service'; import { ProblemManager } from '@theia/markers/lib/browser'; import { Range } from '@theia/core/shared/vscode-languageserver-protocol'; export declare const AccessibleRootContribution: unique symbol; /** * Contributes directories outside the workspace roots that the AI workspace tools may access, in * addition to the user-configured `ai-features.workspaceFunctions.allowedExternalPaths`. This is meant * for locations Theia owns and resolves itself, such as the memory store of the current workspace, * whose path is generated and can therefore not be named in a preference by the user. */ export interface AccessibleRootContribution { /** * The currently accessible roots. Queried on every check rather than once, so that a root which * moves with the workspace is picked up without invalidation. */ getRoots(): Promise; } export declare class WorkspaceFunctionScope { protected readonly GITIGNORE_FILE_NAME = ".gitignore"; protected readonly workspaceService: WorkspaceService; protected readonly fileService: FileService; protected readonly preferences: PreferenceService; protected readonly aiConfiguration: AiConfigurationService; protected readonly envVariablesServer: EnvVariablesServer; protected readonly logger: ILogger; protected readonly accessibleRootContributions: ContributionProvider | undefined; private gitignoreMatchers; private gitignoreWatchersInitialized; private _rootMapping; private _allRootUris; private homeDirUri; protected init(): void; /** * Returns all workspace root URIs (synchronous, cached). */ private getAllRootUris; /** * Returns a mapping of root names to root URIs. * * Root names are always the directory basename. When multiple roots share the * same basename, only the first (by URI sort order) is addressable by name — * the others are still reachable via the `resolveRelativePath` supra-relative * check (which examines path segments against all roots). * * **Known limitation:** duplicate basenames are not disambiguated with synthetic * suffixes because agents observe real filesystem paths in terminal output, * compiler errors, stack traces, etc. Synthetic names like `app-1` would * conflict with those observations and cause more confusion than they solve. * A future improvement could let users assign display names to roots. */ getRootMapping(): Map; /** * Returns the root name for a given root URI based on the cached mapping. */ getRootName(rootUri: URI): string | undefined; /** * Returns the workspace root that contains the given URI. * If nested roots exist, returns the most specific (deepest) one. */ getContainingRoot(uri: URI): URI | undefined; /** * Converts a URI to a workspace-relative path with root name prefix. * Format: / */ toWorkspaceRelativePath(uri: URI): string | undefined; /** * Resolves a relative path to a URI using a deterministic, synchronous algorithm. * No filesystem I/O is performed — the agent is expected to use `/` * format. If the path cannot be resolved deterministically, an error is thrown. * * Resolution order: * 1. Root+relative: first segment matches a root name → resolve rest relative to that root. * 2. Supra-relative: a root's basename appears as a segment, and any preceding material * matches the preceding path components of the root → resolve the trailing portion. * 3. Single-root fallback: if exactly one workspace root, resolve relative to it. * 4. Error: tell the agent how to format the path. */ resolveRelativePath(relativePath: string): URI; resolveToUri(pathOrUri: string | URI): Promise; /** * Resolves a tool argument and asserts that it may be accessed. This is the single entry point every * tool uses, so that a path is subjected to the same parsing and the same boundary check no matter * which tool received it. * * @throws if the path cannot be resolved or points outside the accessible roots. */ resolveAccessiblePath(pathOrUri: string): Promise; /** * Asserts the target URI is reachable by the AI tools. Allowed when the URI is inside any workspace * root, below a root contributed by an {@link AccessibleRootContribution}, or covered by an entry of * the `ai-features.workspaceFunctions.allowedExternalPaths` preference. Workspace-scoped overrides of * that preference are dropped when the workspace is not trusted. * * The target URI is normalized before the check so that literal `..` * segments and percent-encoded equivalents (e.g. `%2e%2e`) are resolved * away — otherwise the path-prefix comparison would admit traversals. * * Note: symlinks within allow-listed directories are NOT canonicalized * before the check. Only allow-list directories whose contents you trust. */ ensureAccessible(targetUri: URI): Promise; protected isUnderAny(roots: URI[], normalizedTarget: URI): boolean; /** * The roots contributed by {@link AccessibleRootContribution}s, normalized like the allow-list. A * contribution that fails to resolve is skipped rather than allowed to fail every path check. */ protected getContributedRootUris(): Promise; isInWorkspace(uri: URI): boolean; isInPrimaryWorkspace(uri: URI): boolean; /** * Resolves the configured external allow-list to URIs. Reads via the * trust-aware {@link AiConfigurationService} so workspace-scoped overrides are * dropped when the workspace is untrusted. Awaits the service's `ready` promise * so that the trust state is resolved before the first preference read. * Non-string entries, blanks, and entries that don't parse to a `file://` * URI are filtered out; URIs are returned in normalized form. */ getAllowedExternalUris(resourceUri?: string): Promise; /** * Whether path comparisons should be case-sensitive on the current * backend. Windows and macOS default to case-insensitive file systems * (NTFS, HFS+, APFS); Linux is treated as case-sensitive. This is a * heuristic — a case-sensitive APFS volume on macOS or a case-insensitive * volume mounted on Linux will be misclassified, but querying the actual * file system would require a backend round-trip. */ static get pathCaseSensitive(): boolean; /** * Converts a user-supplied allow-list entry (absolute POSIX path, Windows * drive path, `~`-prefixed path, or `file://` URI) into a normalized URI. * Returns undefined for invalid input (relative paths, malformed URIs). */ protected toExternalUri(entry: string): Promise; /** * If the given separator-normalized path is `~` or starts with `~/`, * expands the leading `~` against the user's home directory and returns * the resulting URI. Returns undefined if the path does not start with * `~` or the home directory cannot be resolved. The remainder is * resolved in URI space to avoid Windows drive-letter round-tripping * issues with `URI.fromFilePath`. */ protected resolveTildePath(normalizedPath: string): Promise; /** * Whether an already-separator-normalized path is absolute on either * platform: POSIX `/foo`, UNC `//host/share`, or Windows drive `C:/foo`. */ static isAbsolutePath(normalized: string): boolean; /** * Returns the URI without a trailing path separator (except for a root path). This makes * directory comparisons via {@link URI.isEqualOrParent} insensitive to a trailing slash, so * an allow-list entry such as `/foo/` matches the directory `/foo` itself, not only its * children. */ static withoutTrailingSeparator(uri: URI): URI; protected getHomeDirUri(): Promise; /** * Whether the already-separator-normalized path contains `..` as a path * segment (not merely as a substring of a filename like `my..file.json`). */ static hasParentSegment(normalizedPath: string): boolean; private initializeGitignoreWatcher; shouldExclude(stat: FileStat): Promise; protected isUserExcluded(fileName: string, userExcludePatterns: string[]): boolean; protected isGitIgnored(stat: FileStat, workspaceRoot: URI): Promise; /** * Returns the cached `.gitignore` matcher for the given root, reading the file at most * once per root. A root with no (or unreadable) `.gitignore` is cached as `undefined`. * The cache is invalidated by {@link initializeGitignoreWatcher} when the `.gitignore` is * created, changed, or deleted, so individual exclusion checks need no filesystem RPC. */ protected getGitignoreMatcher(workspaceRoot: URI): Promise | undefined>; } export declare class GetWorkspaceDirectoryStructure implements ToolProvider { static ID: string; getTool(): ToolRequest; protected readonly fileService: FileService; protected workspaceScope: WorkspaceFunctionScope; private getDirectoryStructure; private buildDirectoryStructure; } export declare class FileContentFunction implements ToolProvider { static ID: string; getTool(): ToolRequest; protected readonly fileService: FileService; protected readonly workspaceScope: WorkspaceFunctionScope; protected readonly monacoWorkspace: MonacoWorkspace; protected readonly preferences: PreferenceService; /** Optional: tracking is advisory, so containers without a tracker still get a working tool. */ protected readonly fileReadTracker: FileReadTracker | undefined; private parseArg; private getFileContent; private handleEditorContent; /** * Remembers the content handed to the agent, if it came from a chat session at all. Only full reads are * tracked: a slice says nothing about the rest of the file, so the streaming path is skipped. */ private trackRead; private handleFullDiskRead; private readStreamedSlice; private sizeInKB; private buildFileSizeLimitError; private buildSliceSizeLimitError; } export declare class GetWorkspaceFileList implements ToolProvider { static ID: string; getTool(): ToolRequest; protected readonly fileService: FileService; protected workspaceScope: WorkspaceFunctionScope; getProjectFileList(path?: string, cancellationToken?: CancellationToken): Promise; private listFilesDirectly; } export declare class FileDiagnosticProvider implements ToolProvider { static ID: string; protected readonly workspaceScope: WorkspaceFunctionScope; protected readonly problemManager: ProblemManager; protected readonly modelService: MonacoTextModelService; protected readonly logger: ILogger; getTool(): ToolRequest; protected getDiagnosticsForFile(uri: URI, cancellationToken?: CancellationToken): Promise; /** * Expands the range provided until it contains at least {@link desiredLines} lines or reaches the end of the document * to attempt to provide the agent sufficient context to understand the diagnostic. */ protected atLeastNLines(desiredLines: number, range: Range, documentLineCount: number): Range; } export declare class FindFilesByPattern implements ToolProvider { static ID: string; protected readonly workspaceScope: WorkspaceFunctionScope; protected readonly preferences: PreferenceService; protected readonly fileSearchService: FileSearchService; getTool(): ToolRequest; private findFiles; /** * Renders a search-result URI in the format expected by the caller: an absolute * path for external roots, or a `/` (or bare relative * path when no root name is available) for workspace roots. */ protected toDisplayPath(match: URI, target: { rootUri: URI; rootName?: string; external: boolean; }): string | undefined; } //# sourceMappingURL=workspace-functions.d.ts.map