btca-server 1.0.962 → 2.0.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/package.json +3 -3
- package/src/agent/agent.test.ts +31 -24
- package/src/agent/index.ts +8 -2
- package/src/agent/loop.ts +303 -346
- package/src/agent/service.ts +252 -233
- package/src/agent/types.ts +2 -2
- package/src/collections/index.ts +2 -1
- package/src/collections/service.ts +352 -345
- package/src/config/config.test.ts +3 -1
- package/src/config/index.ts +615 -727
- package/src/config/remote.ts +214 -369
- package/src/context/index.ts +6 -12
- package/src/context/transaction.ts +23 -30
- package/src/effect/errors.ts +45 -0
- package/src/effect/layers.ts +26 -0
- package/src/effect/runtime.ts +19 -0
- package/src/effect/services.ts +154 -0
- package/src/index.ts +291 -369
- package/src/metrics/index.ts +46 -46
- package/src/pricing/models-dev.ts +104 -106
- package/src/providers/auth.ts +159 -200
- package/src/providers/index.ts +19 -2
- package/src/providers/model.ts +115 -135
- package/src/providers/openai.ts +3 -3
- package/src/resources/impls/git.ts +123 -146
- package/src/resources/impls/npm.test.ts +16 -5
- package/src/resources/impls/npm.ts +66 -75
- package/src/resources/index.ts +6 -1
- package/src/resources/schema.ts +7 -6
- package/src/resources/service.test.ts +13 -12
- package/src/resources/service.ts +153 -112
- package/src/stream/index.ts +1 -1
- package/src/stream/service.test.ts +5 -5
- package/src/stream/service.ts +282 -293
- package/src/tools/glob.ts +126 -141
- package/src/tools/grep.ts +205 -210
- package/src/tools/index.ts +8 -4
- package/src/tools/list.ts +118 -140
- package/src/tools/read.ts +209 -235
- package/src/tools/virtual-sandbox.ts +91 -83
- package/src/validation/index.ts +18 -22
- package/src/vfs/virtual-fs.test.ts +37 -25
- package/src/vfs/virtual-fs.ts +218 -216
package/src/tools/list.ts
CHANGED
|
@@ -4,160 +4,138 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import * as path from 'node:path';
|
|
6
6
|
import { z } from 'zod';
|
|
7
|
-
import { Result } from 'better-result';
|
|
8
7
|
|
|
9
8
|
import type { ToolContext } from './context.ts';
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
export
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
9
|
+
import { resolveSandboxPath } from './virtual-sandbox.ts';
|
|
10
|
+
import { readdirVirtualFs, statVirtualFs } from '../vfs/virtual-fs.ts';
|
|
11
|
+
|
|
12
|
+
export const ListToolParameters = z.object({
|
|
13
|
+
path: z.string().describe('The directory path to list')
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export type ListToolParametersType = z.infer<typeof ListToolParameters>;
|
|
17
|
+
|
|
18
|
+
export type ListToolEntry = {
|
|
19
|
+
name: string;
|
|
20
|
+
type: 'file' | 'directory' | 'other';
|
|
21
|
+
size?: number;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export type ListToolResult = {
|
|
25
|
+
title: string;
|
|
26
|
+
output: string;
|
|
27
|
+
metadata: {
|
|
28
|
+
entries: ListToolEntry[];
|
|
29
|
+
fileCount: number;
|
|
30
|
+
directoryCount: number;
|
|
26
31
|
};
|
|
32
|
+
};
|
|
27
33
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
const safeStat = async (filePath: string, vfsId?: string) => {
|
|
35
|
+
try {
|
|
36
|
+
return await statVirtualFs(filePath, vfsId);
|
|
37
|
+
} catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export const executeListTool = async (
|
|
43
|
+
params: ListToolParametersType,
|
|
44
|
+
context: ToolContext
|
|
45
|
+
): Promise<ListToolResult> => {
|
|
46
|
+
const { basePath, vfsId } = context;
|
|
47
|
+
const resolvedPath = resolveSandboxPath(basePath, params.path);
|
|
48
|
+
const stats = await safeStat(resolvedPath, vfsId);
|
|
49
|
+
if (!stats) {
|
|
50
|
+
return {
|
|
51
|
+
title: params.path,
|
|
52
|
+
output: `Directory not found: ${params.path}`,
|
|
53
|
+
metadata: {
|
|
54
|
+
entries: [],
|
|
55
|
+
fileCount: 0,
|
|
56
|
+
directoryCount: 0
|
|
57
|
+
}
|
|
36
58
|
};
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Execute the list tool
|
|
49
|
-
*/
|
|
50
|
-
export async function execute(params: ParametersType, context: ToolContext): Promise<Result> {
|
|
51
|
-
const { basePath, vfsId } = context;
|
|
52
|
-
|
|
53
|
-
// Resolve path within sandbox
|
|
54
|
-
const resolvedPath = VirtualSandbox.resolvePath(basePath, params.path);
|
|
55
|
-
|
|
56
|
-
// Check if path exists
|
|
57
|
-
const stats = await safeStat(resolvedPath, vfsId);
|
|
58
|
-
if (!stats) {
|
|
59
|
-
return {
|
|
60
|
-
title: params.path,
|
|
61
|
-
output: `Directory not found: ${params.path}`,
|
|
62
|
-
metadata: {
|
|
63
|
-
entries: [],
|
|
64
|
-
fileCount: 0,
|
|
65
|
-
directoryCount: 0
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
if (!stats.isDirectory) {
|
|
70
|
-
return {
|
|
71
|
-
title: params.path,
|
|
72
|
-
output: `Path is not a directory: ${params.path}`,
|
|
73
|
-
metadata: {
|
|
74
|
-
entries: [],
|
|
75
|
-
fileCount: 0,
|
|
76
|
-
directoryCount: 0
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Read directory contents
|
|
82
|
-
const entries: Entry[] = [];
|
|
83
|
-
|
|
84
|
-
const dirents = await VirtualFs.readdir(resolvedPath, vfsId);
|
|
85
|
-
for (const dirent of dirents) {
|
|
86
|
-
let type: Entry['type'] = 'other';
|
|
87
|
-
let size: number | undefined;
|
|
88
|
-
if (dirent.isDirectory) {
|
|
89
|
-
type = 'directory';
|
|
90
|
-
} else if (dirent.isFile) {
|
|
91
|
-
type = 'file';
|
|
92
|
-
const stats = await safeStat(path.posix.join(resolvedPath, dirent.name), vfsId);
|
|
93
|
-
size = stats?.size;
|
|
59
|
+
}
|
|
60
|
+
if (!stats.isDirectory) {
|
|
61
|
+
return {
|
|
62
|
+
title: params.path,
|
|
63
|
+
output: `Path is not a directory: ${params.path}`,
|
|
64
|
+
metadata: {
|
|
65
|
+
entries: [],
|
|
66
|
+
fileCount: 0,
|
|
67
|
+
directoryCount: 0
|
|
94
68
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
type,
|
|
98
|
-
size
|
|
99
|
-
});
|
|
100
|
-
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
101
71
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
72
|
+
const entries: ListToolEntry[] = [];
|
|
73
|
+
const dirents = await readdirVirtualFs(resolvedPath, vfsId);
|
|
74
|
+
for (const dirent of dirents) {
|
|
75
|
+
let type: ListToolEntry['type'] = 'other';
|
|
76
|
+
let size: number | undefined;
|
|
77
|
+
if (dirent.isDirectory) {
|
|
78
|
+
type = 'directory';
|
|
79
|
+
} else if (dirent.isFile) {
|
|
80
|
+
type = 'file';
|
|
81
|
+
const stats = await safeStat(path.posix.join(resolvedPath, dirent.name), vfsId);
|
|
82
|
+
size = stats?.size;
|
|
83
|
+
}
|
|
84
|
+
entries.push({
|
|
85
|
+
name: dirent.name,
|
|
86
|
+
type,
|
|
87
|
+
size
|
|
107
88
|
});
|
|
89
|
+
}
|
|
108
90
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const outputLines: string[] = [];
|
|
91
|
+
entries.sort((a, b) => {
|
|
92
|
+
if (a.type === 'directory' && b.type !== 'directory') return -1;
|
|
93
|
+
if (a.type !== 'directory' && b.type === 'directory') return 1;
|
|
94
|
+
return a.name.localeCompare(b.name);
|
|
95
|
+
});
|
|
115
96
|
|
|
116
|
-
|
|
117
|
-
|
|
97
|
+
const fileCount = entries.filter((e) => e.type === 'file').length;
|
|
98
|
+
const directoryCount = entries.filter((e) => e.type === 'directory').length;
|
|
99
|
+
const outputLines: string[] = [];
|
|
100
|
+
|
|
101
|
+
for (const entry of entries) {
|
|
102
|
+
let line: string;
|
|
103
|
+
if (entry.type === 'directory') {
|
|
104
|
+
line = `[DIR] ${entry.name}/`;
|
|
105
|
+
} else if (entry.type === 'file') {
|
|
106
|
+
const sizeStr = entry.size !== undefined ? formatSize(entry.size) : '';
|
|
107
|
+
line = `[FILE] ${entry.name}${sizeStr ? ` (${sizeStr})` : ''}`;
|
|
108
|
+
} else {
|
|
109
|
+
line = `[???] ${entry.name}`;
|
|
110
|
+
}
|
|
111
|
+
outputLines.push(line);
|
|
112
|
+
}
|
|
118
113
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
line = `[FILE] ${entry.name}${sizeStr ? ` (${sizeStr})` : ''}`;
|
|
124
|
-
} else {
|
|
125
|
-
line = `[???] ${entry.name}`;
|
|
126
|
-
}
|
|
114
|
+
outputLines.push('');
|
|
115
|
+
outputLines.push(
|
|
116
|
+
`Total: ${entries.length} items (${directoryCount} directories, ${fileCount} files)`
|
|
117
|
+
);
|
|
127
118
|
|
|
128
|
-
|
|
119
|
+
return {
|
|
120
|
+
title: params.path,
|
|
121
|
+
output: outputLines.join('\n'),
|
|
122
|
+
metadata: {
|
|
123
|
+
entries,
|
|
124
|
+
fileCount,
|
|
125
|
+
directoryCount
|
|
129
126
|
}
|
|
127
|
+
};
|
|
128
|
+
};
|
|
130
129
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
);
|
|
130
|
+
const formatSize = (bytes: number): string => {
|
|
131
|
+
const units = ['B', 'KB', 'MB', 'GB'];
|
|
132
|
+
let size = bytes;
|
|
133
|
+
let unitIndex = 0;
|
|
136
134
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
metadata: {
|
|
141
|
-
entries,
|
|
142
|
-
fileCount,
|
|
143
|
-
directoryCount
|
|
144
|
-
}
|
|
145
|
-
};
|
|
135
|
+
while (size >= 1024 && unitIndex < units.length - 1) {
|
|
136
|
+
size /= 1024;
|
|
137
|
+
unitIndex++;
|
|
146
138
|
}
|
|
147
139
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
*/
|
|
151
|
-
function formatSize(bytes: number): string {
|
|
152
|
-
const units = ['B', 'KB', 'MB', 'GB'];
|
|
153
|
-
let size = bytes;
|
|
154
|
-
let unitIndex = 0;
|
|
155
|
-
|
|
156
|
-
while (size >= 1024 && unitIndex < units.length - 1) {
|
|
157
|
-
size /= 1024;
|
|
158
|
-
unitIndex++;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
return `${size.toFixed(unitIndex === 0 ? 0 : 1)} ${units[unitIndex]}`;
|
|
162
|
-
}
|
|
163
|
-
}
|
|
140
|
+
return `${size.toFixed(unitIndex === 0 ? 0 : 1)} ${units[unitIndex]}`;
|
|
141
|
+
};
|