@perstack/base 0.0.6 → 0.0.8
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/index.d.ts +532 -1
- package/dist/index.js +650 -1204
- package/dist/index.js.map +1 -1
- package/package.json +16 -11
package/dist/index.js
CHANGED
|
@@ -1,63 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
name: "@perstack/base",
|
|
11
|
-
version: "0.0.6",
|
|
12
|
-
description: "Perstack base skills for agents.",
|
|
13
|
-
author: "Wintermute Technologies, Inc.",
|
|
14
|
-
type: "module",
|
|
15
|
-
bin: {
|
|
16
|
-
base: "dist/index.js"
|
|
17
|
-
},
|
|
18
|
-
exports: {
|
|
19
|
-
".": "./dist/index.js"
|
|
20
|
-
},
|
|
21
|
-
files: [
|
|
22
|
-
"dist"
|
|
23
|
-
],
|
|
24
|
-
scripts: {
|
|
25
|
-
clean: "rm -rf dist",
|
|
26
|
-
dev: "tsup --watch --config ../../tsup.config.ts",
|
|
27
|
-
build: "npm run clean && tsup --config ../../tsup.config.ts",
|
|
28
|
-
prepublishOnly: "npm run clean && npm run build"
|
|
29
|
-
},
|
|
30
|
-
dependencies: {
|
|
31
|
-
"@modelcontextprotocol/sdk": "^1.17.1",
|
|
32
|
-
commander: "^14.0.0",
|
|
33
|
-
"mime-types": "^3.0.1",
|
|
34
|
-
"ts-dedent": "^2.2.0",
|
|
35
|
-
zod: "^3.23.8"
|
|
36
|
-
},
|
|
37
|
-
devDependencies: {
|
|
38
|
-
"@tsconfig/node22": "^22.0.2",
|
|
39
|
-
"@types/mime-types": "^3.0.1",
|
|
40
|
-
"@types/node": "^24.2.0",
|
|
41
|
-
tsup: "^8.5.0",
|
|
42
|
-
typescript: "^5.9.2"
|
|
43
|
-
},
|
|
44
|
-
engines: {
|
|
45
|
-
node: ">=22.0.0"
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
// src/tools/append-text-file.ts
|
|
50
|
-
import { existsSync, statSync } from "fs";
|
|
51
|
-
import { appendFile } from "fs/promises";
|
|
52
|
-
import { readFile } from "fs/promises";
|
|
53
|
-
import { dedent } from "ts-dedent";
|
|
54
|
-
import { z } from "zod";
|
|
1
|
+
import { realpathSync, existsSync, statSync } from 'fs';
|
|
2
|
+
import fs, { appendFile, readFile, mkdir, unlink, writeFile, readdir, rename, stat } from 'fs/promises';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import path, { dirname, extname, basename, resolve, join } from 'path';
|
|
5
|
+
import mime from 'mime-types';
|
|
6
|
+
import { dedent } from 'ts-dedent';
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { execFile } from 'child_process';
|
|
9
|
+
import { promisify } from 'util';
|
|
55
10
|
|
|
56
11
|
// src/lib/path.ts
|
|
57
|
-
import { realpathSync } from "fs";
|
|
58
|
-
import fs from "fs/promises";
|
|
59
|
-
import os from "os";
|
|
60
|
-
import path from "path";
|
|
61
12
|
var workspacePath = realpathSync(expandHome(process.cwd()));
|
|
62
13
|
function expandHome(filepath) {
|
|
63
14
|
if (filepath.startsWith("~/") || filepath === "~") {
|
|
@@ -95,9 +46,11 @@ async function validatePath(requestedPath) {
|
|
|
95
46
|
}
|
|
96
47
|
}
|
|
97
48
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
49
|
+
var WorkspaceMode = /* @__PURE__ */ ((WorkspaceMode2) => {
|
|
50
|
+
WorkspaceMode2["LOCAL"] = "local";
|
|
51
|
+
WorkspaceMode2["STUDIO"] = "studio";
|
|
52
|
+
return WorkspaceMode2;
|
|
53
|
+
})(WorkspaceMode || {});
|
|
101
54
|
var getWorkspaceApiConfig = () => {
|
|
102
55
|
const baseUrl = process.env.PERSTACK_API_BASE_URL;
|
|
103
56
|
const apiKey = process.env.PERSTACK_API_KEY;
|
|
@@ -249,99 +202,69 @@ var deleteWorkspaceItem = async (workspaceItemId) => {
|
|
|
249
202
|
throw new Error(`Failed to delete workspace item: ${response.status} ${errorText}`);
|
|
250
203
|
}
|
|
251
204
|
};
|
|
205
|
+
var getWorkspaceItemContent = async (workspaceItem) => {
|
|
206
|
+
const config = getWorkspaceApiConfig();
|
|
207
|
+
if (!config) {
|
|
208
|
+
throw new Error("Workspace API not configured");
|
|
209
|
+
}
|
|
210
|
+
if (workspaceItem.type !== "workspaceItemFile") {
|
|
211
|
+
throw new Error("Can only get content for files");
|
|
212
|
+
}
|
|
213
|
+
throw new Error("Getting file content is not implemented yet");
|
|
214
|
+
};
|
|
252
215
|
|
|
253
|
-
// src/
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
- FILE MUST EXIST BEFORE APPENDING
|
|
273
|
-
- YOU MUST PROVIDE A VALID UTF-8 STRING FOR THE TEXT
|
|
274
|
-
- THERE IS A LIMIT ON THE NUMBER OF TOKENS THAT CAN BE GENERATED, SO DO NOT APPEND ALL THE CONTENT AT ONCE
|
|
275
|
-
- IF YOU WANT TO APPEND MORE THAN 2000 CHARACTERS, USE THIS TOOL MULTIPLE TIMES
|
|
276
|
-
`;
|
|
277
|
-
var toolInputSchema = {
|
|
216
|
+
// src/lib/register-tool.ts
|
|
217
|
+
function resolveToolByMode(localModeFunction, studioModeFunction) {
|
|
218
|
+
const mode = getWorkspaceMode();
|
|
219
|
+
const func = !studioModeFunction ? localModeFunction : mode === "local" /* LOCAL */ ? localModeFunction : studioModeFunction;
|
|
220
|
+
return async (input) => {
|
|
221
|
+
try {
|
|
222
|
+
const result = await func(input);
|
|
223
|
+
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
|
224
|
+
} catch (e) {
|
|
225
|
+
if (e instanceof Error) {
|
|
226
|
+
return {
|
|
227
|
+
content: [{ type: "text", text: JSON.stringify({ error: e.name, message: e.message }) }]
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
throw e;
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
var inputSchema = z.object({
|
|
278
235
|
path: z.string().describe("Target file path to append to."),
|
|
279
236
|
text: z.string().min(1).max(2e3).describe("Text to append to the file. Max 2000 characters.")
|
|
280
|
-
};
|
|
281
|
-
function
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
toolName,
|
|
287
|
-
`${toolDescription}
|
|
237
|
+
});
|
|
238
|
+
function appendTextFileConfig() {
|
|
239
|
+
return {
|
|
240
|
+
title: "Append text file",
|
|
241
|
+
description: dedent`
|
|
242
|
+
Adding content to the end of existing files.
|
|
288
243
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
{
|
|
296
|
-
type: "text",
|
|
297
|
-
text: JSON.stringify(await appendTextFileLocalMode(path2, text))
|
|
298
|
-
}
|
|
299
|
-
]
|
|
300
|
-
};
|
|
301
|
-
} catch (e) {
|
|
302
|
-
if (e instanceof Error) {
|
|
303
|
-
return {
|
|
304
|
-
content: [{ type: "text", text: JSON.stringify({ error: e.message }) }]
|
|
305
|
-
};
|
|
306
|
-
}
|
|
307
|
-
throw e;
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
);
|
|
311
|
-
break;
|
|
312
|
-
}
|
|
313
|
-
case "studio" /* STUDIO */: {
|
|
314
|
-
server.tool(
|
|
315
|
-
toolName,
|
|
316
|
-
`${toolDescription}
|
|
244
|
+
Use cases:
|
|
245
|
+
- Adding entries to log files
|
|
246
|
+
- Appending data to CSV or JSON files
|
|
247
|
+
- Adding new sections to documentation
|
|
248
|
+
- Extending configuration files
|
|
249
|
+
- Building files incrementally
|
|
317
250
|
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
return {
|
|
333
|
-
content: [{ type: "text", text: JSON.stringify({ error: e.message }) }]
|
|
334
|
-
};
|
|
335
|
-
}
|
|
336
|
-
throw e;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
);
|
|
340
|
-
break;
|
|
341
|
-
}
|
|
342
|
-
}
|
|
251
|
+
How it works:
|
|
252
|
+
- Appends text to the end of an existing file
|
|
253
|
+
- Does not modify existing content
|
|
254
|
+
- Creates a new line before appending if needed
|
|
255
|
+
- Returns the appended file path
|
|
256
|
+
|
|
257
|
+
Rules:
|
|
258
|
+
- FILE MUST EXIST BEFORE APPENDING
|
|
259
|
+
- YOU MUST PROVIDE A VALID UTF-8 STRING FOR THE TEXT
|
|
260
|
+
- THERE IS A LIMIT ON THE NUMBER OF TOKENS THAT CAN BE GENERATED, SO DO NOT APPEND ALL THE CONTENT AT ONCE
|
|
261
|
+
- IF YOU WANT TO APPEND MORE THAN 2000 CHARACTERS, USE THIS TOOL MULTIPLE TIMES
|
|
262
|
+
`,
|
|
263
|
+
inputSchema: inputSchema.shape
|
|
264
|
+
};
|
|
343
265
|
}
|
|
344
|
-
async function appendTextFileLocalMode(
|
|
266
|
+
async function appendTextFileLocalMode(input) {
|
|
267
|
+
const { path: path2, text } = input;
|
|
345
268
|
const validatedPath = await validatePath(path2);
|
|
346
269
|
if (!existsSync(validatedPath)) {
|
|
347
270
|
throw new Error(`File ${path2} does not exist.`);
|
|
@@ -351,12 +274,10 @@ async function appendTextFileLocalMode(path2, text) {
|
|
|
351
274
|
throw new Error(`File ${path2} is not writable`);
|
|
352
275
|
}
|
|
353
276
|
await appendFile(validatedPath, text);
|
|
354
|
-
return {
|
|
355
|
-
path: validatedPath,
|
|
356
|
-
text
|
|
357
|
-
};
|
|
277
|
+
return { path: validatedPath, text };
|
|
358
278
|
}
|
|
359
|
-
async function appendTextFileStudioMode(
|
|
279
|
+
async function appendTextFileStudioMode(input) {
|
|
280
|
+
const { path: path2, text } = input;
|
|
360
281
|
const validatedPath = await validatePath(path2);
|
|
361
282
|
const relativePath = validatedPath.startsWith(workspacePath) ? validatedPath.slice(workspacePath.length + 1) : validatedPath;
|
|
362
283
|
const existingItem = await findWorkspaceItem(relativePath);
|
|
@@ -366,161 +287,83 @@ async function appendTextFileStudioMode(path2, text) {
|
|
|
366
287
|
if (existingItem.type === "workspaceItemDirectory") {
|
|
367
288
|
throw new Error(`Path ${relativePath} is a directory.`);
|
|
368
289
|
}
|
|
369
|
-
await appendTextFileLocalMode(
|
|
290
|
+
await appendTextFileLocalMode(input);
|
|
370
291
|
await deleteWorkspaceItem(existingItem.id);
|
|
371
292
|
const content = await readFile(validatedPath, "utf-8");
|
|
372
293
|
await createWorkspaceItem(
|
|
373
294
|
{
|
|
374
295
|
type: "workspaceItemFile",
|
|
375
296
|
path: relativePath,
|
|
376
|
-
owner: "expert",
|
|
377
|
-
lifecycle: "expertJob",
|
|
378
297
|
permission: "readWrite"
|
|
379
298
|
},
|
|
380
299
|
content
|
|
381
300
|
);
|
|
301
|
+
return { path: relativePath, text };
|
|
302
|
+
}
|
|
303
|
+
function attemptCompletionConfig() {
|
|
382
304
|
return {
|
|
383
|
-
|
|
384
|
-
|
|
305
|
+
title: "Attempt completion",
|
|
306
|
+
description: dedent`
|
|
307
|
+
Task completion signal that triggers immediate final report generation.
|
|
308
|
+
Use cases:
|
|
309
|
+
- Signaling task completion to Perstack runtime
|
|
310
|
+
- Triggering final report generation
|
|
311
|
+
- Ending the current expert's work cycle
|
|
312
|
+
How it works:
|
|
313
|
+
- Sends completion signal to Perstack runtime
|
|
314
|
+
- Runtime immediately proceeds to final report generation
|
|
315
|
+
- No confirmation or approval step required
|
|
316
|
+
- No parameters needed for this signal
|
|
317
|
+
Notes:
|
|
318
|
+
- Triggers immediate transition to final report
|
|
319
|
+
- Should only be used when task is fully complete
|
|
320
|
+
- Cannot be reverted once called
|
|
321
|
+
`,
|
|
322
|
+
inputSchema: {}
|
|
385
323
|
};
|
|
386
324
|
}
|
|
387
|
-
|
|
388
|
-
// src/tools/attempt-completion.ts
|
|
389
|
-
import { dedent as dedent2 } from "ts-dedent";
|
|
390
|
-
var addAttemptCompletionTool = (server) => {
|
|
391
|
-
server.tool(
|
|
392
|
-
"attemptCompletion",
|
|
393
|
-
dedent2`
|
|
394
|
-
Task completion signal that triggers immediate final report generation.
|
|
395
|
-
Use cases:
|
|
396
|
-
- Signaling task completion to Perstack runtime
|
|
397
|
-
- Triggering final report generation
|
|
398
|
-
- Ending the current expert's work cycle
|
|
399
|
-
How it works:
|
|
400
|
-
- Sends completion signal to Perstack runtime
|
|
401
|
-
- Runtime immediately proceeds to final report generation
|
|
402
|
-
- No confirmation or approval step required
|
|
403
|
-
- No parameters needed for this signal
|
|
404
|
-
Notes:
|
|
405
|
-
- Triggers immediate transition to final report
|
|
406
|
-
- Should only be used when task is fully complete
|
|
407
|
-
- Cannot be reverted once called
|
|
408
|
-
`,
|
|
409
|
-
{},
|
|
410
|
-
attemptCompletion
|
|
411
|
-
);
|
|
412
|
-
};
|
|
413
325
|
async function attemptCompletion() {
|
|
414
326
|
return {
|
|
415
|
-
|
|
416
|
-
{
|
|
417
|
-
type: "text",
|
|
418
|
-
text: "End the agent loop and provide a final report"
|
|
419
|
-
}
|
|
420
|
-
]
|
|
327
|
+
message: "End the agent loop and provide a final report"
|
|
421
328
|
};
|
|
422
329
|
}
|
|
330
|
+
var inputSchema2 = z.object({
|
|
331
|
+
path: z.string()
|
|
332
|
+
});
|
|
333
|
+
function createDirectoryConfig() {
|
|
334
|
+
return {
|
|
335
|
+
title: "Create directory",
|
|
336
|
+
description: dedent`
|
|
337
|
+
Directory creator for establishing folder structures in the workspace.
|
|
423
338
|
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
import { z as z2 } from "zod";
|
|
430
|
-
var toolName2 = "createDirectory";
|
|
431
|
-
var toolDescription2 = dedent3`
|
|
432
|
-
Directory creator for establishing folder structures in the workspace.
|
|
433
|
-
|
|
434
|
-
Use cases:
|
|
435
|
-
- Setting up project directory structure
|
|
436
|
-
- Creating output folders for generated content
|
|
437
|
-
- Organizing files into logical groups
|
|
438
|
-
- Preparing directory hierarchies
|
|
439
|
-
|
|
440
|
-
How it works:
|
|
441
|
-
- Creates directories recursively
|
|
442
|
-
- Handles existing directories gracefully
|
|
443
|
-
- Creates parent directories as needed
|
|
444
|
-
- Returns creation status
|
|
445
|
-
|
|
446
|
-
Parameters:
|
|
447
|
-
- path: Directory path to create
|
|
448
|
-
`;
|
|
449
|
-
var toolInputSchema2 = {
|
|
450
|
-
path: z2.string()
|
|
451
|
-
};
|
|
452
|
-
function addCreateDirectoryTool(server) {
|
|
453
|
-
const mode = getWorkspaceMode();
|
|
454
|
-
switch (mode) {
|
|
455
|
-
case "local" /* LOCAL */: {
|
|
456
|
-
server.tool(
|
|
457
|
-
toolName2,
|
|
458
|
-
`${toolDescription2}
|
|
459
|
-
|
|
460
|
-
Mode: Local (Local filesystem)`,
|
|
461
|
-
toolInputSchema2,
|
|
462
|
-
async ({ path: path2 }) => {
|
|
463
|
-
try {
|
|
464
|
-
return {
|
|
465
|
-
content: [
|
|
466
|
-
{
|
|
467
|
-
type: "text",
|
|
468
|
-
text: JSON.stringify(await createDirectoryLocalMode(path2))
|
|
469
|
-
}
|
|
470
|
-
]
|
|
471
|
-
};
|
|
472
|
-
} catch (e) {
|
|
473
|
-
if (e instanceof Error) {
|
|
474
|
-
return {
|
|
475
|
-
content: [{ type: "text", text: JSON.stringify({ error: e.message }) }]
|
|
476
|
-
};
|
|
477
|
-
}
|
|
478
|
-
throw e;
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
);
|
|
482
|
-
break;
|
|
483
|
-
}
|
|
484
|
-
case "studio" /* STUDIO */: {
|
|
485
|
-
server.tool(
|
|
486
|
-
toolName2,
|
|
487
|
-
`${toolDescription2}
|
|
339
|
+
Use cases:
|
|
340
|
+
- Setting up project directory structure
|
|
341
|
+
- Creating output folders for generated content
|
|
342
|
+
- Organizing files into logical groups
|
|
343
|
+
- Preparing directory hierarchies
|
|
488
344
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
};
|
|
501
|
-
} catch (e) {
|
|
502
|
-
if (e instanceof Error) {
|
|
503
|
-
return {
|
|
504
|
-
content: [{ type: "text", text: JSON.stringify({ error: e.message }) }]
|
|
505
|
-
};
|
|
506
|
-
}
|
|
507
|
-
throw e;
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
);
|
|
511
|
-
break;
|
|
512
|
-
}
|
|
513
|
-
}
|
|
345
|
+
How it works:
|
|
346
|
+
- Creates directories recursively
|
|
347
|
+
- Handles existing directories gracefully
|
|
348
|
+
- Creates parent directories as needed
|
|
349
|
+
- Returns creation status
|
|
350
|
+
|
|
351
|
+
Parameters:
|
|
352
|
+
- path: Directory path to create
|
|
353
|
+
`,
|
|
354
|
+
inputSchema: inputSchema2.shape
|
|
355
|
+
};
|
|
514
356
|
}
|
|
515
|
-
async function createDirectoryLocalMode(
|
|
357
|
+
async function createDirectoryLocalMode(input) {
|
|
358
|
+
const { path: path2 } = input;
|
|
516
359
|
const validatedPath = await validatePath(path2);
|
|
517
|
-
const exists =
|
|
360
|
+
const exists = existsSync(validatedPath);
|
|
518
361
|
if (exists) {
|
|
519
362
|
throw new Error(`Directory ${path2} already exists`);
|
|
520
363
|
}
|
|
521
364
|
const parentDir = dirname(validatedPath);
|
|
522
|
-
if (
|
|
523
|
-
const parentStats =
|
|
365
|
+
if (existsSync(parentDir)) {
|
|
366
|
+
const parentStats = statSync(parentDir);
|
|
524
367
|
if (!(parentStats.mode & 128)) {
|
|
525
368
|
throw new Error(`Parent directory ${parentDir} is not writable`);
|
|
526
369
|
}
|
|
@@ -530,7 +373,8 @@ async function createDirectoryLocalMode(path2) {
|
|
|
530
373
|
path: validatedPath
|
|
531
374
|
};
|
|
532
375
|
}
|
|
533
|
-
async function createDirectoryStudioMode(
|
|
376
|
+
async function createDirectoryStudioMode(input) {
|
|
377
|
+
const { path: path2 } = input;
|
|
534
378
|
const validatedPath = await validatePath(path2);
|
|
535
379
|
const relativePath = validatedPath.startsWith(workspacePath) ? validatedPath.slice(workspacePath.length + 1) : validatedPath;
|
|
536
380
|
const existingItem = await findWorkspaceItem(relativePath);
|
|
@@ -546,114 +390,49 @@ async function createDirectoryStudioMode(path2) {
|
|
|
546
390
|
await createWorkspaceItem({
|
|
547
391
|
type: "workspaceItemDirectory",
|
|
548
392
|
path: currentPath,
|
|
549
|
-
owner: "expert",
|
|
550
|
-
lifecycle: "expertJob",
|
|
551
393
|
permission: "readWrite"
|
|
552
394
|
});
|
|
553
395
|
}
|
|
554
396
|
}
|
|
555
|
-
await createDirectoryLocalMode(
|
|
397
|
+
await createDirectoryLocalMode(input);
|
|
556
398
|
return {
|
|
557
399
|
path: relativePath
|
|
558
400
|
};
|
|
559
401
|
}
|
|
402
|
+
var inputSchema3 = z.object({
|
|
403
|
+
path: z.string()
|
|
404
|
+
});
|
|
405
|
+
function deleteFileConfig() {
|
|
406
|
+
return {
|
|
407
|
+
title: "Delete file",
|
|
408
|
+
description: dedent`
|
|
409
|
+
File deleter for removing files from the workspace.
|
|
560
410
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
var toolName3 = "deleteFile";
|
|
567
|
-
var toolDescription3 = dedent4`
|
|
568
|
-
File deleter for removing files from the workspace.
|
|
569
|
-
|
|
570
|
-
Use cases:
|
|
571
|
-
- Removing temporary files
|
|
572
|
-
- Cleaning up generated files
|
|
573
|
-
- Deleting outdated configuration files
|
|
574
|
-
- Removing unwanted artifacts
|
|
575
|
-
|
|
576
|
-
How it works:
|
|
577
|
-
- Validates file existence and permissions
|
|
578
|
-
- Performs atomic delete operation
|
|
579
|
-
- Removes file from both filesystem and workspace API
|
|
580
|
-
- Returns deletion status
|
|
581
|
-
|
|
582
|
-
Parameters:
|
|
583
|
-
- path: File path to delete
|
|
584
|
-
`;
|
|
585
|
-
var toolInputSchema3 = {
|
|
586
|
-
path: z3.string()
|
|
587
|
-
};
|
|
588
|
-
function addDeleteFileTool(server) {
|
|
589
|
-
const mode = getWorkspaceMode();
|
|
590
|
-
switch (mode) {
|
|
591
|
-
case "local" /* LOCAL */: {
|
|
592
|
-
server.tool(
|
|
593
|
-
toolName3,
|
|
594
|
-
`${toolDescription3}
|
|
595
|
-
|
|
596
|
-
Mode: Local (Local filesystem)`,
|
|
597
|
-
toolInputSchema3,
|
|
598
|
-
async ({ path: path2 }) => {
|
|
599
|
-
try {
|
|
600
|
-
return {
|
|
601
|
-
content: [
|
|
602
|
-
{
|
|
603
|
-
type: "text",
|
|
604
|
-
text: JSON.stringify(await deleteFileLocalMode(path2))
|
|
605
|
-
}
|
|
606
|
-
]
|
|
607
|
-
};
|
|
608
|
-
} catch (e) {
|
|
609
|
-
if (e instanceof Error) {
|
|
610
|
-
return {
|
|
611
|
-
content: [{ type: "text", text: JSON.stringify({ error: e.message }) }]
|
|
612
|
-
};
|
|
613
|
-
}
|
|
614
|
-
throw e;
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
);
|
|
618
|
-
break;
|
|
619
|
-
}
|
|
620
|
-
case "studio" /* STUDIO */: {
|
|
621
|
-
server.tool(
|
|
622
|
-
toolName3,
|
|
623
|
-
`${toolDescription3}
|
|
411
|
+
Use cases:
|
|
412
|
+
- Removing temporary files
|
|
413
|
+
- Cleaning up generated files
|
|
414
|
+
- Deleting outdated configuration files
|
|
415
|
+
- Removing unwanted artifacts
|
|
624
416
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
};
|
|
637
|
-
} catch (e) {
|
|
638
|
-
if (e instanceof Error) {
|
|
639
|
-
return {
|
|
640
|
-
content: [{ type: "text", text: JSON.stringify({ error: e.message }) }]
|
|
641
|
-
};
|
|
642
|
-
}
|
|
643
|
-
throw e;
|
|
644
|
-
}
|
|
645
|
-
}
|
|
646
|
-
);
|
|
647
|
-
break;
|
|
648
|
-
}
|
|
649
|
-
}
|
|
417
|
+
How it works:
|
|
418
|
+
- Validates file existence and permissions
|
|
419
|
+
- Performs atomic delete operation
|
|
420
|
+
- Removes file from both filesystem and workspace API
|
|
421
|
+
- Returns deletion status
|
|
422
|
+
|
|
423
|
+
Parameters:
|
|
424
|
+
- path: File path to delete
|
|
425
|
+
`,
|
|
426
|
+
inputSchema: inputSchema3.shape
|
|
427
|
+
};
|
|
650
428
|
}
|
|
651
|
-
async function deleteFileLocalMode(
|
|
429
|
+
async function deleteFileLocalMode(input) {
|
|
430
|
+
const { path: path2 } = input;
|
|
652
431
|
const validatedPath = await validatePath(path2);
|
|
653
|
-
if (!
|
|
432
|
+
if (!existsSync(validatedPath)) {
|
|
654
433
|
throw new Error(`File ${path2} does not exist.`);
|
|
655
434
|
}
|
|
656
|
-
const stats =
|
|
435
|
+
const stats = statSync(validatedPath);
|
|
657
436
|
if (stats.isDirectory()) {
|
|
658
437
|
throw new Error(`Path ${path2} is a directory. Use delete directory tool instead.`);
|
|
659
438
|
}
|
|
@@ -665,7 +444,8 @@ async function deleteFileLocalMode(path2) {
|
|
|
665
444
|
path: validatedPath
|
|
666
445
|
};
|
|
667
446
|
}
|
|
668
|
-
async function deleteFileStudioMode(
|
|
447
|
+
async function deleteFileStudioMode(input) {
|
|
448
|
+
const { path: path2 } = input;
|
|
669
449
|
const validatedPath = await validatePath(path2);
|
|
670
450
|
const relativePath = validatedPath.startsWith(workspacePath) ? validatedPath.slice(workspacePath.length + 1) : validatedPath;
|
|
671
451
|
const existingItem = await findWorkspaceItem(relativePath);
|
|
@@ -675,115 +455,52 @@ async function deleteFileStudioMode(path2) {
|
|
|
675
455
|
if (existingItem.type === "workspaceItemDirectory") {
|
|
676
456
|
throw new Error(`Path ${relativePath} is a directory. Use delete directory tool instead.`);
|
|
677
457
|
}
|
|
678
|
-
await deleteFileLocalMode(
|
|
458
|
+
await deleteFileLocalMode(input);
|
|
679
459
|
await deleteWorkspaceItem(existingItem.id);
|
|
680
460
|
return {
|
|
681
461
|
path: relativePath
|
|
682
462
|
};
|
|
683
463
|
}
|
|
464
|
+
var inputSchema4 = z.object({
|
|
465
|
+
path: z.string().describe("Target file path to edit."),
|
|
466
|
+
newText: z.string().min(1).max(2e3).describe("Text to append to the file. Max 2000 characters."),
|
|
467
|
+
oldText: z.string().min(1).max(2e3).describe("Exact text to find and replace. Max 2000 characters.")
|
|
468
|
+
});
|
|
469
|
+
function editTextFileConfig() {
|
|
470
|
+
return {
|
|
471
|
+
title: "Edit text file",
|
|
472
|
+
description: dedent`
|
|
473
|
+
Text file editor for modifying existing files with precise text replacement.
|
|
684
474
|
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
var toolName4 = "editTextFile";
|
|
691
|
-
var toolDescription4 = dedent5`
|
|
692
|
-
Text file editor for modifying existing files with precise text replacement.
|
|
693
|
-
|
|
694
|
-
Use cases:
|
|
695
|
-
- Updating configuration values
|
|
696
|
-
- Modifying code snippets
|
|
697
|
-
- Replacing specific text blocks
|
|
698
|
-
- Making targeted edits to files
|
|
699
|
-
|
|
700
|
-
How it works:
|
|
701
|
-
- Reads existing file content
|
|
702
|
-
- Performs exact text replacement of oldText with newText
|
|
703
|
-
- Normalizes line endings for consistent behavior
|
|
704
|
-
- Returns summary of changes made
|
|
705
|
-
- For appending text to files, use the appendTextFile tool instead
|
|
706
|
-
|
|
707
|
-
Rules:
|
|
708
|
-
- YOU MUST PROVIDE A VALID UTF-8 STRING FOR THE TEXT
|
|
709
|
-
- THERE IS A LIMIT ON THE NUMBER OF TOKENS THAT CAN BE GENERATED, SO DO NOT WRITE ALL THE CONTENT AT ONCE (IT WILL CAUSE AN ERROR)
|
|
710
|
-
- IF YOU WANT TO EDIT MORE THAN 2000 CHARACTERS, USE THIS TOOL MULTIPLE TIMES
|
|
711
|
-
- DO NOT USE THIS TOOL FOR APPENDING TEXT TO FILES - USE appendTextFile TOOL INSTEAD
|
|
712
|
-
`;
|
|
713
|
-
var toolInputSchema4 = {
|
|
714
|
-
path: z4.string().describe("Target file path to edit."),
|
|
715
|
-
newText: z4.string().min(1).max(2e3).describe("Text to append to the file. Max 2000 characters."),
|
|
716
|
-
oldText: z4.string().min(1).max(2e3).describe("Exact text to find and replace. Max 2000 characters.")
|
|
717
|
-
};
|
|
718
|
-
function addEditTextFileTool(server) {
|
|
719
|
-
const mode = getWorkspaceMode();
|
|
720
|
-
switch (mode) {
|
|
721
|
-
case "local" /* LOCAL */: {
|
|
722
|
-
server.tool(
|
|
723
|
-
toolName4,
|
|
724
|
-
`${toolDescription4}
|
|
725
|
-
|
|
726
|
-
Mode: Local (Local filesystem)`,
|
|
727
|
-
toolInputSchema4,
|
|
728
|
-
async ({ path: path2, newText, oldText }) => {
|
|
729
|
-
try {
|
|
730
|
-
return {
|
|
731
|
-
content: [
|
|
732
|
-
{
|
|
733
|
-
type: "text",
|
|
734
|
-
text: JSON.stringify(await editTextFileLocalMode(path2, newText, oldText))
|
|
735
|
-
}
|
|
736
|
-
]
|
|
737
|
-
};
|
|
738
|
-
} catch (e) {
|
|
739
|
-
if (e instanceof Error) {
|
|
740
|
-
return {
|
|
741
|
-
content: [{ type: "text", text: JSON.stringify({ error: e.message }) }]
|
|
742
|
-
};
|
|
743
|
-
}
|
|
744
|
-
throw e;
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
|
-
);
|
|
748
|
-
break;
|
|
749
|
-
}
|
|
750
|
-
case "studio" /* STUDIO */: {
|
|
751
|
-
server.tool(
|
|
752
|
-
toolName4,
|
|
753
|
-
`${toolDescription4}
|
|
475
|
+
Use cases:
|
|
476
|
+
- Updating configuration values
|
|
477
|
+
- Modifying code snippets
|
|
478
|
+
- Replacing specific text blocks
|
|
479
|
+
- Making targeted edits to files
|
|
754
480
|
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
content: [{ type: "text", text: JSON.stringify({ error: e.message }) }]
|
|
771
|
-
};
|
|
772
|
-
}
|
|
773
|
-
throw e;
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
);
|
|
777
|
-
break;
|
|
778
|
-
}
|
|
779
|
-
}
|
|
481
|
+
How it works:
|
|
482
|
+
- Reads existing file content
|
|
483
|
+
- Performs exact text replacement of oldText with newText
|
|
484
|
+
- Normalizes line endings for consistent behavior
|
|
485
|
+
- Returns summary of changes made
|
|
486
|
+
- For appending text to files, use the appendTextFile tool instead
|
|
487
|
+
|
|
488
|
+
Rules:
|
|
489
|
+
- YOU MUST PROVIDE A VALID UTF-8 STRING FOR THE TEXT
|
|
490
|
+
- THERE IS A LIMIT ON THE NUMBER OF TOKENS THAT CAN BE GENERATED, SO DO NOT WRITE ALL THE CONTENT AT ONCE (IT WILL CAUSE AN ERROR)
|
|
491
|
+
- IF YOU WANT TO EDIT MORE THAN 2000 CHARACTERS, USE THIS TOOL MULTIPLE TIMES
|
|
492
|
+
- DO NOT USE THIS TOOL FOR APPENDING TEXT TO FILES - USE appendTextFile TOOL INSTEAD
|
|
493
|
+
`,
|
|
494
|
+
inputSchema: inputSchema4.shape
|
|
495
|
+
};
|
|
780
496
|
}
|
|
781
|
-
async function editTextFileLocalMode(
|
|
497
|
+
async function editTextFileLocalMode(input) {
|
|
498
|
+
const { path: path2, newText, oldText } = input;
|
|
782
499
|
const validatedPath = await validatePath(path2);
|
|
783
|
-
if (!
|
|
500
|
+
if (!existsSync(validatedPath)) {
|
|
784
501
|
throw new Error(`File ${path2} does not exist.`);
|
|
785
502
|
}
|
|
786
|
-
const stats =
|
|
503
|
+
const stats = statSync(validatedPath);
|
|
787
504
|
if (!(stats.mode & 128)) {
|
|
788
505
|
throw new Error(`File ${path2} is not writable`);
|
|
789
506
|
}
|
|
@@ -794,7 +511,8 @@ async function editTextFileLocalMode(path2, newText, oldText) {
|
|
|
794
511
|
oldText
|
|
795
512
|
};
|
|
796
513
|
}
|
|
797
|
-
async function editTextFileStudioMode(
|
|
514
|
+
async function editTextFileStudioMode(input) {
|
|
515
|
+
const { path: path2, newText, oldText } = input;
|
|
798
516
|
const validatedPath = await validatePath(path2);
|
|
799
517
|
const relativePath = validatedPath.startsWith(workspacePath) ? validatedPath.slice(workspacePath.length + 1) : validatedPath;
|
|
800
518
|
const existingItem = await findWorkspaceItem(relativePath);
|
|
@@ -804,15 +522,13 @@ async function editTextFileStudioMode(path2, newText, oldText) {
|
|
|
804
522
|
if (existingItem.type === "workspaceItemDirectory") {
|
|
805
523
|
throw new Error(`Path ${relativePath} is a directory.`);
|
|
806
524
|
}
|
|
807
|
-
await editTextFileLocalMode(
|
|
525
|
+
await editTextFileLocalMode(input);
|
|
808
526
|
await deleteWorkspaceItem(existingItem.id);
|
|
809
|
-
const content = await
|
|
527
|
+
const content = await readFile(validatedPath, "utf-8");
|
|
810
528
|
await createWorkspaceItem(
|
|
811
529
|
{
|
|
812
530
|
type: "workspaceItemFile",
|
|
813
531
|
path: relativePath,
|
|
814
|
-
owner: "expert",
|
|
815
|
-
lifecycle: "expertJob",
|
|
816
532
|
permission: "readWrite"
|
|
817
533
|
},
|
|
818
534
|
content
|
|
@@ -827,7 +543,7 @@ function normalizeLineEndings(text) {
|
|
|
827
543
|
return text.replace(/\r\n/g, "\n");
|
|
828
544
|
}
|
|
829
545
|
async function applyFileEdit(filePath, newText, oldText) {
|
|
830
|
-
const content = normalizeLineEndings(await
|
|
546
|
+
const content = normalizeLineEndings(await readFile(filePath, "utf-8"));
|
|
831
547
|
const normalizedOld = normalizeLineEndings(oldText);
|
|
832
548
|
const normalizedNew = normalizeLineEndings(newText);
|
|
833
549
|
if (!content.includes(normalizedOld)) {
|
|
@@ -836,106 +552,146 @@ async function applyFileEdit(filePath, newText, oldText) {
|
|
|
836
552
|
const modifiedContent = content.replace(normalizedOld, normalizedNew);
|
|
837
553
|
await writeFile(filePath, modifiedContent, "utf-8");
|
|
838
554
|
}
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
throw e;
|
|
895
|
-
}
|
|
896
|
-
}
|
|
897
|
-
);
|
|
898
|
-
break;
|
|
555
|
+
var execFileAsync = promisify(execFile);
|
|
556
|
+
var execInputSchema = z.object({
|
|
557
|
+
command: z.string().describe("The command to execute"),
|
|
558
|
+
args: z.array(z.string()).describe("The arguments to pass to the command"),
|
|
559
|
+
env: z.record(z.string(), z.string()).describe("The environment variables to set"),
|
|
560
|
+
cwd: z.string().describe("The working directory to execute the command in"),
|
|
561
|
+
stdout: z.boolean().describe("Whether to capture the standard output"),
|
|
562
|
+
stderr: z.boolean().describe("Whether to capture the standard error"),
|
|
563
|
+
timeout: z.number().optional().describe("Timeout in milliseconds")
|
|
564
|
+
});
|
|
565
|
+
function execConfig() {
|
|
566
|
+
return {
|
|
567
|
+
title: "Execute Command",
|
|
568
|
+
description: dedent`
|
|
569
|
+
A tool for executing a command.
|
|
570
|
+
This tool helps execute a command with the given parameters.
|
|
571
|
+
|
|
572
|
+
When to use this tool:
|
|
573
|
+
- When you need to run system tasks or scripts.
|
|
574
|
+
- When automating the use of command-line tools or utilities.
|
|
575
|
+
|
|
576
|
+
Key features:
|
|
577
|
+
- Flexible Execution Environment: Specify environment variables, working directory, and arguments to tailor the command execution.
|
|
578
|
+
- Output Capture: Control whether to capture the standard output and standard error from the executed command.
|
|
579
|
+
- Simple Interface: A unified input schema consolidates all parameters needed for command execution.
|
|
580
|
+
|
|
581
|
+
Parameters explained:
|
|
582
|
+
- command: The command to execute (e.g., \`ls\`, \`python\`).
|
|
583
|
+
- args: A list of arguments to pass to the command, functioning similarly to command-line input.
|
|
584
|
+
- env: A record of key-value pairs representing environment variables for the command's execution environment.
|
|
585
|
+
- cwd: The working directory in which the command will run; both relative and absolute paths are supported.
|
|
586
|
+
- stdout: A boolean flag indicating whether to capture the standard output (set to \`true\` to capture).
|
|
587
|
+
- stderr: A boolean flag indicating whether to capture the standard error (set to \`true\` to capture).
|
|
588
|
+
- timeout: The timeout in milliseconds for the command execution.
|
|
589
|
+
|
|
590
|
+
Rules:
|
|
591
|
+
- Safety: Only execute commands from trusted sources to avoid executing malicious code.
|
|
592
|
+
- Command Termination: Do not execute commands that remain running in the foreground (e.g., \`tail -f\`), as the tool requires commands to complete.
|
|
593
|
+
- Resource Management: Be cautious when running commands that may consume significant system resources or produce large amounts of output.
|
|
594
|
+
- Error Handling: Implement proper error handling to catch and manage any issues that arise during command execution.
|
|
595
|
+
- Parameter Validation: Ensure that all provided parameters adhere to the expected format to prevent unexpected behavior.
|
|
596
|
+
`,
|
|
597
|
+
inputSchema: execInputSchema.shape
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
async function exec(input) {
|
|
601
|
+
try {
|
|
602
|
+
const { stdout, stderr } = await execFileAsync(input.command, input.args, {
|
|
603
|
+
cwd: input.cwd,
|
|
604
|
+
env: { ...process.env, ...input.env },
|
|
605
|
+
timeout: input.timeout
|
|
606
|
+
});
|
|
607
|
+
let output = "";
|
|
608
|
+
if (input.stdout) {
|
|
609
|
+
output += stdout;
|
|
899
610
|
}
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
{
|
|
912
|
-
type: "text",
|
|
913
|
-
text: JSON.stringify(await getFileInfoStudioMode(path2))
|
|
914
|
-
}
|
|
915
|
-
]
|
|
916
|
-
};
|
|
917
|
-
} catch (e) {
|
|
918
|
-
if (e instanceof Error) {
|
|
919
|
-
return {
|
|
920
|
-
content: [{ type: "text", text: JSON.stringify({ error: e.message }) }]
|
|
921
|
-
};
|
|
922
|
-
}
|
|
923
|
-
throw e;
|
|
924
|
-
}
|
|
611
|
+
if (input.stderr) {
|
|
612
|
+
output += stderr;
|
|
613
|
+
}
|
|
614
|
+
if (!output.trim()) {
|
|
615
|
+
output = "Command executed successfully, but produced no output.";
|
|
616
|
+
}
|
|
617
|
+
return {
|
|
618
|
+
content: [
|
|
619
|
+
{
|
|
620
|
+
type: "text",
|
|
621
|
+
text: output
|
|
925
622
|
}
|
|
926
|
-
|
|
927
|
-
|
|
623
|
+
]
|
|
624
|
+
};
|
|
625
|
+
} catch (error) {
|
|
626
|
+
let errMsg = "";
|
|
627
|
+
const execError = error;
|
|
628
|
+
if (execError && (execError.killed || execError.signal === "SIGTERM") && typeof input.timeout === "number") {
|
|
629
|
+
errMsg = `Error: Command timed out after ${input.timeout}ms.
|
|
630
|
+
`;
|
|
631
|
+
} else if (error instanceof Error) {
|
|
632
|
+
if (error.message.includes("timeout")) {
|
|
633
|
+
errMsg = `Error: Command timed out after ${input.timeout}ms.
|
|
634
|
+
`;
|
|
635
|
+
} else {
|
|
636
|
+
errMsg = `Error: ${error.message}
|
|
637
|
+
`;
|
|
638
|
+
}
|
|
639
|
+
} else {
|
|
640
|
+
errMsg = "An unknown error occurred.\n";
|
|
641
|
+
}
|
|
642
|
+
if (execError.stdout && input.stdout) {
|
|
643
|
+
errMsg += `Standard Output: ${execError.stdout}`;
|
|
928
644
|
}
|
|
645
|
+
if (execError.stderr && input.stderr) {
|
|
646
|
+
errMsg += `
|
|
647
|
+
Standard Error: ${execError.stderr}`;
|
|
648
|
+
}
|
|
649
|
+
return {
|
|
650
|
+
content: [
|
|
651
|
+
{
|
|
652
|
+
type: "text",
|
|
653
|
+
text: errMsg
|
|
654
|
+
}
|
|
655
|
+
]
|
|
656
|
+
};
|
|
929
657
|
}
|
|
930
658
|
}
|
|
931
|
-
|
|
659
|
+
var inputSchema5 = z.object({
|
|
660
|
+
path: z.string()
|
|
661
|
+
});
|
|
662
|
+
function getFileInfoConfig() {
|
|
663
|
+
return {
|
|
664
|
+
title: "Get file info",
|
|
665
|
+
description: dedent`
|
|
666
|
+
File information retriever for detailed metadata about files and directories.
|
|
667
|
+
|
|
668
|
+
Use cases:
|
|
669
|
+
- Checking file existence and type
|
|
670
|
+
- Getting file size and timestamps
|
|
671
|
+
- Determining MIME types
|
|
672
|
+
- Validating file accessibility
|
|
673
|
+
|
|
674
|
+
How it works:
|
|
675
|
+
- Retrieves comprehensive file system metadata
|
|
676
|
+
- Detects MIME type from file extension
|
|
677
|
+
- Provides both absolute and relative paths
|
|
678
|
+
- Returns human-readable file sizes
|
|
679
|
+
|
|
680
|
+
Parameters:
|
|
681
|
+
- path: File or directory path to inspect
|
|
682
|
+
`,
|
|
683
|
+
inputSchema: inputSchema5.shape
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
async function getFileInfoLocalMode(input) {
|
|
687
|
+
const { path: path2 } = input;
|
|
932
688
|
const validatedPath = await validatePath(path2);
|
|
933
|
-
if (!
|
|
689
|
+
if (!existsSync(validatedPath)) {
|
|
934
690
|
throw new Error(`File or directory ${path2} does not exist`);
|
|
935
691
|
}
|
|
936
|
-
const stats =
|
|
692
|
+
const stats = statSync(validatedPath);
|
|
937
693
|
const isDirectory = stats.isDirectory();
|
|
938
|
-
const mimeType = isDirectory ? null :
|
|
694
|
+
const mimeType = isDirectory ? null : mime.lookup(validatedPath) || "application/octet-stream";
|
|
939
695
|
const formatSize = (bytes) => {
|
|
940
696
|
if (bytes === 0) return "0 B";
|
|
941
697
|
const units = ["B", "KB", "MB", "GB", "TB"];
|
|
@@ -947,7 +703,7 @@ async function getFileInfoLocalMode(path2) {
|
|
|
947
703
|
path: validatedPath,
|
|
948
704
|
absolutePath: resolve(validatedPath),
|
|
949
705
|
name: basename(validatedPath),
|
|
950
|
-
directory:
|
|
706
|
+
directory: dirname(validatedPath),
|
|
951
707
|
extension: isDirectory ? null : extname(validatedPath),
|
|
952
708
|
type: isDirectory ? "directory" : "file",
|
|
953
709
|
mimeType,
|
|
@@ -963,10 +719,11 @@ async function getFileInfoLocalMode(path2) {
|
|
|
963
719
|
}
|
|
964
720
|
};
|
|
965
721
|
}
|
|
966
|
-
async function getFileInfoStudioMode(
|
|
722
|
+
async function getFileInfoStudioMode(input) {
|
|
723
|
+
const { path: path2 } = input;
|
|
967
724
|
const validatedPath = await validatePath(path2);
|
|
968
725
|
const relativePath = validatedPath.startsWith(workspacePath) ? validatedPath.slice(workspacePath.length + 1) : validatedPath;
|
|
969
|
-
const localInfo = await getFileInfoLocalMode(
|
|
726
|
+
const localInfo = await getFileInfoLocalMode(input);
|
|
970
727
|
const workspaceItem = await findWorkspaceItem(relativePath);
|
|
971
728
|
return {
|
|
972
729
|
...localInfo,
|
|
@@ -987,104 +744,40 @@ async function getFileInfoStudioMode(path2) {
|
|
|
987
744
|
} : null
|
|
988
745
|
};
|
|
989
746
|
}
|
|
747
|
+
var inputSchema6 = z.object({
|
|
748
|
+
path: z.string()
|
|
749
|
+
});
|
|
750
|
+
function listDirectoryConfig() {
|
|
751
|
+
return {
|
|
752
|
+
title: "List directory",
|
|
753
|
+
description: dedent`
|
|
754
|
+
Directory content lister with detailed file information.
|
|
990
755
|
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
import { z as z6 } from "zod";
|
|
997
|
-
var toolName6 = "listDirectory";
|
|
998
|
-
var toolDescription6 = dedent7`
|
|
999
|
-
Directory content lister with detailed file information.
|
|
1000
|
-
|
|
1001
|
-
Use cases:
|
|
1002
|
-
- Exploring project structure
|
|
1003
|
-
- Finding files in a directory
|
|
1004
|
-
- Checking directory contents before operations
|
|
1005
|
-
- Understanding file organization
|
|
1006
|
-
|
|
1007
|
-
How it works:
|
|
1008
|
-
- Lists all files and subdirectories in specified directory only
|
|
1009
|
-
- Provides file type, size, and modification time
|
|
1010
|
-
- Sorts entries alphabetically
|
|
1011
|
-
- Handles empty directories
|
|
1012
|
-
|
|
1013
|
-
Parameters:
|
|
1014
|
-
- path: Directory path to list (optional, defaults to workspace root)
|
|
1015
|
-
`;
|
|
1016
|
-
var toolInputSchema6 = {
|
|
1017
|
-
path: z6.string().optional()
|
|
1018
|
-
};
|
|
1019
|
-
function addListDirectoryTool(server) {
|
|
1020
|
-
const mode = getWorkspaceMode();
|
|
1021
|
-
switch (mode) {
|
|
1022
|
-
case "local" /* LOCAL */: {
|
|
1023
|
-
server.tool(
|
|
1024
|
-
toolName6,
|
|
1025
|
-
`${toolDescription6}
|
|
1026
|
-
|
|
1027
|
-
Mode: Local (Local filesystem)`,
|
|
1028
|
-
toolInputSchema6,
|
|
1029
|
-
async ({ path: path2 = "." }) => {
|
|
1030
|
-
try {
|
|
1031
|
-
return {
|
|
1032
|
-
content: [
|
|
1033
|
-
{
|
|
1034
|
-
type: "text",
|
|
1035
|
-
text: JSON.stringify(await listDirectoryLocalMode(path2))
|
|
1036
|
-
}
|
|
1037
|
-
]
|
|
1038
|
-
};
|
|
1039
|
-
} catch (e) {
|
|
1040
|
-
if (e instanceof Error) {
|
|
1041
|
-
return {
|
|
1042
|
-
content: [{ type: "text", text: JSON.stringify({ error: e.message }) }]
|
|
1043
|
-
};
|
|
1044
|
-
}
|
|
1045
|
-
throw e;
|
|
1046
|
-
}
|
|
1047
|
-
}
|
|
1048
|
-
);
|
|
1049
|
-
break;
|
|
1050
|
-
}
|
|
1051
|
-
case "studio" /* STUDIO */: {
|
|
1052
|
-
server.tool(
|
|
1053
|
-
toolName6,
|
|
1054
|
-
`${toolDescription6}
|
|
756
|
+
Use cases:
|
|
757
|
+
- Exploring project structure
|
|
758
|
+
- Finding files in a directory
|
|
759
|
+
- Checking directory contents before operations
|
|
760
|
+
- Understanding file organization
|
|
1055
761
|
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
};
|
|
1068
|
-
} catch (e) {
|
|
1069
|
-
if (e instanceof Error) {
|
|
1070
|
-
return {
|
|
1071
|
-
content: [{ type: "text", text: JSON.stringify({ error: e.message }) }]
|
|
1072
|
-
};
|
|
1073
|
-
}
|
|
1074
|
-
throw e;
|
|
1075
|
-
}
|
|
1076
|
-
}
|
|
1077
|
-
);
|
|
1078
|
-
break;
|
|
1079
|
-
}
|
|
1080
|
-
}
|
|
762
|
+
How it works:
|
|
763
|
+
- Lists all files and subdirectories in specified directory only
|
|
764
|
+
- Provides file type, size, and modification time
|
|
765
|
+
- Sorts entries alphabetically
|
|
766
|
+
- Handles empty directories
|
|
767
|
+
|
|
768
|
+
Parameters:
|
|
769
|
+
- path: Directory path to list (optional, defaults to workspace root)
|
|
770
|
+
`,
|
|
771
|
+
inputSchema: inputSchema6.shape
|
|
772
|
+
};
|
|
1081
773
|
}
|
|
1082
|
-
async function listDirectoryLocalMode(
|
|
774
|
+
async function listDirectoryLocalMode(input) {
|
|
775
|
+
const { path: path2 } = input;
|
|
1083
776
|
const validatedPath = await validatePath(path2);
|
|
1084
|
-
if (!
|
|
777
|
+
if (!existsSync(validatedPath)) {
|
|
1085
778
|
throw new Error(`Directory ${path2} does not exist.`);
|
|
1086
779
|
}
|
|
1087
|
-
const stats =
|
|
780
|
+
const stats = statSync(validatedPath);
|
|
1088
781
|
if (!stats.isDirectory()) {
|
|
1089
782
|
throw new Error(`Path ${path2} is not a directory.`);
|
|
1090
783
|
}
|
|
@@ -1093,7 +786,7 @@ async function listDirectoryLocalMode(path2) {
|
|
|
1093
786
|
for (const entry of entries.sort()) {
|
|
1094
787
|
try {
|
|
1095
788
|
const fullPath = await validatePath(join(validatedPath, entry));
|
|
1096
|
-
const entryStats =
|
|
789
|
+
const entryStats = statSync(fullPath);
|
|
1097
790
|
const item = {
|
|
1098
791
|
name: entry,
|
|
1099
792
|
path: entry,
|
|
@@ -1114,7 +807,8 @@ async function listDirectoryLocalMode(path2) {
|
|
|
1114
807
|
items
|
|
1115
808
|
};
|
|
1116
809
|
}
|
|
1117
|
-
async function listDirectoryStudioMode(
|
|
810
|
+
async function listDirectoryStudioMode(input) {
|
|
811
|
+
const { path: path2 } = input;
|
|
1118
812
|
const validatedPath = await validatePath(path2);
|
|
1119
813
|
const relativePath = validatedPath.startsWith(workspacePath) ? validatedPath.slice(workspacePath.length + 1) : validatedPath;
|
|
1120
814
|
const workspaceItems = await getWorkspaceItems();
|
|
@@ -1136,122 +830,59 @@ async function listDirectoryStudioMode(path2) {
|
|
|
1136
830
|
}))
|
|
1137
831
|
};
|
|
1138
832
|
}
|
|
833
|
+
var inputSchema7 = z.object({
|
|
834
|
+
source: z.string(),
|
|
835
|
+
destination: z.string()
|
|
836
|
+
});
|
|
837
|
+
function moveFileConfig() {
|
|
838
|
+
return {
|
|
839
|
+
title: "Move file",
|
|
840
|
+
description: dedent`
|
|
841
|
+
File mover for relocating or renaming files within the workspace.
|
|
1139
842
|
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
import { z as z7 } from "zod";
|
|
1146
|
-
var toolName7 = "moveFile";
|
|
1147
|
-
var toolDescription7 = dedent8`
|
|
1148
|
-
File mover for relocating or renaming files within the workspace.
|
|
1149
|
-
|
|
1150
|
-
Use cases:
|
|
1151
|
-
- Renaming files to follow naming conventions
|
|
1152
|
-
- Moving files to different directories
|
|
1153
|
-
- Organizing project structure
|
|
1154
|
-
- Backing up files before modifications
|
|
1155
|
-
|
|
1156
|
-
How it works:
|
|
1157
|
-
- Validates source file existence
|
|
1158
|
-
- Creates destination directory if needed
|
|
1159
|
-
- Performs atomic move operation
|
|
1160
|
-
- Preserves file permissions and timestamps
|
|
1161
|
-
|
|
1162
|
-
Parameters:
|
|
1163
|
-
- source: Current file path
|
|
1164
|
-
- destination: Target file path
|
|
1165
|
-
`;
|
|
1166
|
-
var toolInputSchema7 = {
|
|
1167
|
-
source: z7.string(),
|
|
1168
|
-
destination: z7.string()
|
|
1169
|
-
};
|
|
1170
|
-
function addMoveFileTool(server) {
|
|
1171
|
-
const mode = getWorkspaceMode();
|
|
1172
|
-
switch (mode) {
|
|
1173
|
-
case "local" /* LOCAL */: {
|
|
1174
|
-
server.tool(
|
|
1175
|
-
toolName7,
|
|
1176
|
-
`${toolDescription7}
|
|
1177
|
-
|
|
1178
|
-
Mode: Local (Local filesystem)`,
|
|
1179
|
-
toolInputSchema7,
|
|
1180
|
-
async ({ source, destination }) => {
|
|
1181
|
-
try {
|
|
1182
|
-
return {
|
|
1183
|
-
content: [
|
|
1184
|
-
{
|
|
1185
|
-
type: "text",
|
|
1186
|
-
text: JSON.stringify(await moveFileLocalMode(source, destination))
|
|
1187
|
-
}
|
|
1188
|
-
]
|
|
1189
|
-
};
|
|
1190
|
-
} catch (e) {
|
|
1191
|
-
if (e instanceof Error) {
|
|
1192
|
-
return {
|
|
1193
|
-
content: [{ type: "text", text: JSON.stringify({ error: e.message }) }]
|
|
1194
|
-
};
|
|
1195
|
-
}
|
|
1196
|
-
throw e;
|
|
1197
|
-
}
|
|
1198
|
-
}
|
|
1199
|
-
);
|
|
1200
|
-
break;
|
|
1201
|
-
}
|
|
1202
|
-
case "studio" /* STUDIO */: {
|
|
1203
|
-
server.tool(
|
|
1204
|
-
toolName7,
|
|
1205
|
-
`${toolDescription7}
|
|
843
|
+
Use cases:
|
|
844
|
+
- Renaming files to follow naming conventions
|
|
845
|
+
- Moving files to different directories
|
|
846
|
+
- Organizing project structure
|
|
847
|
+
- Backing up files before modifications
|
|
1206
848
|
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
} catch (e) {
|
|
1220
|
-
if (e instanceof Error) {
|
|
1221
|
-
return {
|
|
1222
|
-
content: [{ type: "text", text: JSON.stringify({ error: e.message }) }]
|
|
1223
|
-
};
|
|
1224
|
-
}
|
|
1225
|
-
throw e;
|
|
1226
|
-
}
|
|
1227
|
-
}
|
|
1228
|
-
);
|
|
1229
|
-
break;
|
|
1230
|
-
}
|
|
1231
|
-
}
|
|
849
|
+
How it works:
|
|
850
|
+
- Validates source file existence
|
|
851
|
+
- Creates destination directory if needed
|
|
852
|
+
- Performs atomic move operation
|
|
853
|
+
- Preserves file permissions and timestamps
|
|
854
|
+
|
|
855
|
+
Parameters:
|
|
856
|
+
- source: Current file path
|
|
857
|
+
- destination: Target file path
|
|
858
|
+
`,
|
|
859
|
+
inputSchema: inputSchema7.shape
|
|
860
|
+
};
|
|
1232
861
|
}
|
|
1233
|
-
async function moveFileLocalMode(
|
|
862
|
+
async function moveFileLocalMode(input) {
|
|
863
|
+
const { source, destination } = input;
|
|
1234
864
|
const validatedSource = await validatePath(source);
|
|
1235
865
|
const validatedDestination = await validatePath(destination);
|
|
1236
|
-
if (!
|
|
866
|
+
if (!existsSync(validatedSource)) {
|
|
1237
867
|
throw new Error(`Source file ${source} does not exist.`);
|
|
1238
868
|
}
|
|
1239
|
-
const sourceStats =
|
|
869
|
+
const sourceStats = statSync(validatedSource);
|
|
1240
870
|
if (!(sourceStats.mode & 128)) {
|
|
1241
871
|
throw new Error(`Source file ${source} is not writable`);
|
|
1242
872
|
}
|
|
1243
|
-
if (
|
|
873
|
+
if (existsSync(validatedDestination)) {
|
|
1244
874
|
throw new Error(`Destination ${destination} already exists.`);
|
|
1245
875
|
}
|
|
1246
|
-
const destDir =
|
|
1247
|
-
await
|
|
876
|
+
const destDir = dirname(validatedDestination);
|
|
877
|
+
await mkdir(destDir, { recursive: true });
|
|
1248
878
|
await rename(validatedSource, validatedDestination);
|
|
1249
879
|
return {
|
|
1250
880
|
source: validatedSource,
|
|
1251
881
|
destination: validatedDestination
|
|
1252
882
|
};
|
|
1253
883
|
}
|
|
1254
|
-
async function moveFileStudioMode(
|
|
884
|
+
async function moveFileStudioMode(input) {
|
|
885
|
+
const { source, destination } = input;
|
|
1255
886
|
const validatedSource = await validatePath(source);
|
|
1256
887
|
const validatedDestination = await validatePath(destination);
|
|
1257
888
|
const relativeSource = validatedSource.startsWith(workspacePath) ? validatedSource.slice(workspacePath.length + 1) : validatedSource;
|
|
@@ -1264,15 +895,13 @@ async function moveFileStudioMode(source, destination) {
|
|
|
1264
895
|
if (destItem) {
|
|
1265
896
|
throw new Error(`Destination ${relativeDestination} already exists.`);
|
|
1266
897
|
}
|
|
1267
|
-
const destDir =
|
|
898
|
+
const destDir = dirname(relativeDestination);
|
|
1268
899
|
if (destDir !== "." && destDir !== "/") {
|
|
1269
900
|
const destDirItem = await findWorkspaceItem(destDir);
|
|
1270
901
|
if (!destDirItem) {
|
|
1271
902
|
await createWorkspaceItem({
|
|
1272
903
|
type: "workspaceItemDirectory",
|
|
1273
904
|
path: destDir,
|
|
1274
|
-
owner: "expert",
|
|
1275
|
-
lifecycle: "expertJob",
|
|
1276
905
|
permission: "readWrite"
|
|
1277
906
|
});
|
|
1278
907
|
}
|
|
@@ -1280,75 +909,53 @@ async function moveFileStudioMode(source, destination) {
|
|
|
1280
909
|
await updateWorkspaceItem(sourceItem.id, {
|
|
1281
910
|
path: relativeDestination
|
|
1282
911
|
});
|
|
1283
|
-
await moveFileLocalMode(
|
|
912
|
+
await moveFileLocalMode(input);
|
|
1284
913
|
return {
|
|
1285
914
|
source: relativeSource,
|
|
1286
915
|
destination: relativeDestination
|
|
1287
916
|
};
|
|
1288
917
|
}
|
|
1289
|
-
|
|
1290
|
-
// src/tools/read-image-file.ts
|
|
1291
|
-
import { existsSync as existsSync8 } from "fs";
|
|
1292
|
-
import { stat } from "fs/promises";
|
|
1293
|
-
import mime3 from "mime-types";
|
|
1294
|
-
import { dedent as dedent9 } from "ts-dedent";
|
|
1295
|
-
import { z as z8 } from "zod";
|
|
1296
918
|
var MAX_IMAGE_SIZE = 15 * 1024 * 1024;
|
|
1297
|
-
var
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
919
|
+
var inputSchema8 = z.object({
|
|
920
|
+
path: z.string()
|
|
921
|
+
});
|
|
922
|
+
function readImageFileConfig() {
|
|
923
|
+
return {
|
|
924
|
+
title: "Read image file",
|
|
925
|
+
description: dedent`
|
|
926
|
+
Image file reader that converts images to base64 encoded strings with MIME type validation.
|
|
1305
927
|
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
- Rejects unsupported formats with clear error messages
|
|
928
|
+
Use cases:
|
|
929
|
+
- Loading images for LLM to process
|
|
930
|
+
- Retrieving image data for analysis or display
|
|
931
|
+
- Converting workspace image files to base64 format
|
|
1311
932
|
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
{
|
|
1330
|
-
type: "text",
|
|
1331
|
-
text: JSON.stringify(await readImageFile(path2))
|
|
1332
|
-
}
|
|
1333
|
-
]
|
|
1334
|
-
};
|
|
1335
|
-
} catch (e) {
|
|
1336
|
-
if (e instanceof Error) {
|
|
1337
|
-
return {
|
|
1338
|
-
content: [{ type: "text", text: JSON.stringify({ error: e.message }) }]
|
|
1339
|
-
};
|
|
1340
|
-
}
|
|
1341
|
-
throw e;
|
|
1342
|
-
}
|
|
1343
|
-
});
|
|
933
|
+
How it works:
|
|
934
|
+
- Validates file existence and MIME type before reading
|
|
935
|
+
- Encodes file content as base64 string
|
|
936
|
+
- Returns image data with correct MIME type for proper handling
|
|
937
|
+
- Rejects unsupported formats with clear error messages
|
|
938
|
+
|
|
939
|
+
Supported formats:
|
|
940
|
+
- PNG (image/png)
|
|
941
|
+
- JPEG/JPG (image/jpeg)
|
|
942
|
+
- GIF (image/gif) - static only, animated not supported
|
|
943
|
+
- WebP (image/webp)
|
|
944
|
+
|
|
945
|
+
Notes:
|
|
946
|
+
- Maximum file size: 15MB (larger files will be rejected)
|
|
947
|
+
`,
|
|
948
|
+
inputSchema: inputSchema8.shape
|
|
949
|
+
};
|
|
1344
950
|
}
|
|
1345
|
-
async function readImageFile(
|
|
951
|
+
async function readImageFile(input) {
|
|
952
|
+
const { path: path2 } = input;
|
|
1346
953
|
const validatedPath = await validatePath(path2);
|
|
1347
|
-
const isFile =
|
|
954
|
+
const isFile = existsSync(validatedPath);
|
|
1348
955
|
if (!isFile) {
|
|
1349
956
|
throw new Error(`File ${path2} does not exist.`);
|
|
1350
957
|
}
|
|
1351
|
-
const mimeType =
|
|
958
|
+
const mimeType = mime.lookup(validatedPath);
|
|
1352
959
|
if (!mimeType || !["image/png", "image/jpeg", "image/gif", "image/webp"].includes(mimeType)) {
|
|
1353
960
|
throw new Error(`File ${path2} is not supported.`);
|
|
1354
961
|
}
|
|
@@ -1365,69 +972,47 @@ async function readImageFile(path2) {
|
|
|
1365
972
|
size: fileStats.size
|
|
1366
973
|
};
|
|
1367
974
|
}
|
|
1368
|
-
|
|
1369
|
-
// src/tools/read-pdf-file.ts
|
|
1370
|
-
import { existsSync as existsSync9 } from "fs";
|
|
1371
|
-
import { stat as stat2 } from "fs/promises";
|
|
1372
|
-
import mime4 from "mime-types";
|
|
1373
|
-
import { dedent as dedent10 } from "ts-dedent";
|
|
1374
|
-
import { z as z9 } from "zod";
|
|
1375
975
|
var MAX_PDF_SIZE = 30 * 1024 * 1024;
|
|
1376
|
-
var
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
976
|
+
var inputSchema9 = z.object({
|
|
977
|
+
path: z.string()
|
|
978
|
+
});
|
|
979
|
+
function readPdfFileConfig() {
|
|
980
|
+
return {
|
|
981
|
+
title: "Read PDF file",
|
|
982
|
+
description: dedent`
|
|
983
|
+
PDF file reader that converts documents to base64 encoded resources.
|
|
1384
984
|
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
- Rejects non-PDF files with clear error messages
|
|
985
|
+
Use cases:
|
|
986
|
+
- Extracting content from PDF documents for analysis
|
|
987
|
+
- Loading PDF files for LLM processing
|
|
988
|
+
- Retrieving PDF data for conversion or manipulation
|
|
1390
989
|
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
{
|
|
1405
|
-
type: "text",
|
|
1406
|
-
text: JSON.stringify(await readPdfFile(path2))
|
|
1407
|
-
}
|
|
1408
|
-
]
|
|
1409
|
-
};
|
|
1410
|
-
} catch (e) {
|
|
1411
|
-
if (e instanceof Error) {
|
|
1412
|
-
return {
|
|
1413
|
-
content: [{ type: "text", text: JSON.stringify({ error: e.message }) }]
|
|
1414
|
-
};
|
|
1415
|
-
}
|
|
1416
|
-
throw e;
|
|
1417
|
-
}
|
|
1418
|
-
});
|
|
990
|
+
How it works:
|
|
991
|
+
- Validates file existence and MIME type (application/pdf)
|
|
992
|
+
- Encodes PDF content as base64 blob
|
|
993
|
+
- Returns as resource type with proper MIME type and URI
|
|
994
|
+
- Rejects non-PDF files with clear error messages
|
|
995
|
+
|
|
996
|
+
Notes:
|
|
997
|
+
- Returns entire PDF content, no page range support
|
|
998
|
+
- Maximum file size: 10MB (larger files will be rejected)
|
|
999
|
+
- Text extraction not performed, returns raw PDF data
|
|
1000
|
+
`,
|
|
1001
|
+
inputSchema: inputSchema9.shape
|
|
1002
|
+
};
|
|
1419
1003
|
}
|
|
1420
|
-
async function readPdfFile(
|
|
1004
|
+
async function readPdfFile(input) {
|
|
1005
|
+
const { path: path2 } = input;
|
|
1421
1006
|
const validatedPath = await validatePath(path2);
|
|
1422
|
-
const isFile =
|
|
1007
|
+
const isFile = existsSync(validatedPath);
|
|
1423
1008
|
if (!isFile) {
|
|
1424
1009
|
throw new Error(`File ${path2} does not exist.`);
|
|
1425
1010
|
}
|
|
1426
|
-
const mimeType =
|
|
1011
|
+
const mimeType = mime.lookup(validatedPath);
|
|
1427
1012
|
if (mimeType !== "application/pdf") {
|
|
1428
1013
|
throw new Error(`File ${path2} is not a PDF file.`);
|
|
1429
1014
|
}
|
|
1430
|
-
const fileStats = await
|
|
1015
|
+
const fileStats = await stat(validatedPath);
|
|
1431
1016
|
const fileSizeMB = fileStats.size / (1024 * 1024);
|
|
1432
1017
|
if (fileStats.size > MAX_PDF_SIZE) {
|
|
1433
1018
|
throw new Error(
|
|
@@ -1440,67 +1025,46 @@ async function readPdfFile(path2) {
|
|
|
1440
1025
|
size: fileStats.size
|
|
1441
1026
|
};
|
|
1442
1027
|
}
|
|
1028
|
+
var inputSchema10 = z.object({
|
|
1029
|
+
path: z.string(),
|
|
1030
|
+
from: z.number().optional().describe("The line number to start reading from."),
|
|
1031
|
+
to: z.number().optional().describe("The line number to stop reading at.")
|
|
1032
|
+
});
|
|
1033
|
+
function readTextFileConfig() {
|
|
1034
|
+
return {
|
|
1035
|
+
title: "Read text file",
|
|
1036
|
+
description: dedent`
|
|
1037
|
+
Text file reader with line range support for UTF-8 encoded files.
|
|
1443
1038
|
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
var toolName10 = "readTextFile";
|
|
1450
|
-
var toolDescription10 = dedent11`
|
|
1451
|
-
Text file reader with line range support for UTF-8 encoded files.
|
|
1452
|
-
|
|
1453
|
-
Use cases:
|
|
1454
|
-
- Reading source code files for analysis
|
|
1455
|
-
- Extracting specific sections from large text files
|
|
1456
|
-
- Loading configuration or documentation files
|
|
1457
|
-
- Viewing log files or data files
|
|
1458
|
-
|
|
1459
|
-
How it works:
|
|
1460
|
-
- Reads files as UTF-8 encoded text without format validation
|
|
1461
|
-
- Supports partial file reading via line number ranges
|
|
1462
|
-
- Returns content wrapped in JSON with metadata
|
|
1463
|
-
- WARNING: Binary files will cause errors or corrupted output
|
|
1039
|
+
Use cases:
|
|
1040
|
+
- Reading source code files for analysis
|
|
1041
|
+
- Extracting specific sections from large text files
|
|
1042
|
+
- Loading configuration or documentation files
|
|
1043
|
+
- Viewing log files or data files
|
|
1464
1044
|
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
return {
|
|
1480
|
-
content: [
|
|
1481
|
-
{
|
|
1482
|
-
type: "text",
|
|
1483
|
-
text: JSON.stringify(await readTextFile(path2, from, to))
|
|
1484
|
-
}
|
|
1485
|
-
]
|
|
1486
|
-
};
|
|
1487
|
-
} catch (e) {
|
|
1488
|
-
if (e instanceof Error) {
|
|
1489
|
-
return {
|
|
1490
|
-
content: [{ type: "text", text: JSON.stringify({ error: e.message }) }]
|
|
1491
|
-
};
|
|
1492
|
-
}
|
|
1493
|
-
throw e;
|
|
1494
|
-
}
|
|
1495
|
-
});
|
|
1045
|
+
How it works:
|
|
1046
|
+
- Reads files as UTF-8 encoded text without format validation
|
|
1047
|
+
- Supports partial file reading via line number ranges
|
|
1048
|
+
- Returns content wrapped in JSON with metadata
|
|
1049
|
+
- WARNING: Binary files will cause errors or corrupted output
|
|
1050
|
+
|
|
1051
|
+
Common file types:
|
|
1052
|
+
- Source code: .ts, .js, .py, .java, .cpp, etc.
|
|
1053
|
+
- Documentation: .md, .txt, .rst
|
|
1054
|
+
- Configuration: .json, .yaml, .toml, .ini
|
|
1055
|
+
- Data files: .csv, .log, .sql
|
|
1056
|
+
`,
|
|
1057
|
+
inputSchema: inputSchema10.shape
|
|
1058
|
+
};
|
|
1496
1059
|
}
|
|
1497
|
-
async function readTextFile(
|
|
1060
|
+
async function readTextFile(input) {
|
|
1061
|
+
const { path: path2, from, to } = input;
|
|
1498
1062
|
const validatedPath = await validatePath(path2);
|
|
1499
|
-
const isFile =
|
|
1063
|
+
const isFile = existsSync(validatedPath);
|
|
1500
1064
|
if (!isFile) {
|
|
1501
1065
|
throw new Error(`File ${path2} does not exist.`);
|
|
1502
1066
|
}
|
|
1503
|
-
const fileContent = await
|
|
1067
|
+
const fileContent = await readFile(validatedPath, "utf-8");
|
|
1504
1068
|
const lines = fileContent.split("\n");
|
|
1505
1069
|
const fromLine = from ?? 0;
|
|
1506
1070
|
const toLine = to ?? lines.length;
|
|
@@ -1513,58 +1077,38 @@ async function readTextFile(path2, from, to) {
|
|
|
1513
1077
|
to: toLine
|
|
1514
1078
|
};
|
|
1515
1079
|
}
|
|
1080
|
+
var inputSchema11 = z.object({
|
|
1081
|
+
urls: z.array(z.string()).min(1).max(10).describe("Array of URLs to test (max 10 URLs).")
|
|
1082
|
+
});
|
|
1083
|
+
function testUrlConfig() {
|
|
1084
|
+
return {
|
|
1085
|
+
title: "Test URL",
|
|
1086
|
+
description: dedent`
|
|
1087
|
+
URL tester that validates multiple URLs and extracts metadata.
|
|
1516
1088
|
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
URL tester that validates multiple URLs and extracts metadata.
|
|
1523
|
-
|
|
1524
|
-
Use cases:
|
|
1525
|
-
- Checking if URLs are accessible before web scraping
|
|
1526
|
-
- Validating URL collections for RAG processes
|
|
1527
|
-
- Extracting page metadata (title, description) for content analysis
|
|
1528
|
-
- Batch URL validation for link checking
|
|
1529
|
-
|
|
1530
|
-
How it works:
|
|
1531
|
-
- Performs HTTP GET requests to each URL
|
|
1532
|
-
- Returns status code, title, and description for each URL
|
|
1533
|
-
- Handles errors gracefully with timeout protection
|
|
1534
|
-
- Processes URLs in parallel for performance
|
|
1089
|
+
Use cases:
|
|
1090
|
+
- Checking if URLs are accessible before web scraping
|
|
1091
|
+
- Validating URL collections for RAG processes
|
|
1092
|
+
- Extracting page metadata (title, description) for content analysis
|
|
1093
|
+
- Batch URL validation for link checking
|
|
1535
1094
|
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
content: [
|
|
1551
|
-
{
|
|
1552
|
-
type: "text",
|
|
1553
|
-
text: JSON.stringify(results, null, 2)
|
|
1554
|
-
}
|
|
1555
|
-
]
|
|
1556
|
-
};
|
|
1557
|
-
} catch (e) {
|
|
1558
|
-
if (e instanceof Error) {
|
|
1559
|
-
return {
|
|
1560
|
-
content: [{ type: "text", text: JSON.stringify({ error: e.message }) }]
|
|
1561
|
-
};
|
|
1562
|
-
}
|
|
1563
|
-
throw e;
|
|
1564
|
-
}
|
|
1565
|
-
});
|
|
1095
|
+
How it works:
|
|
1096
|
+
- Performs HTTP GET requests to each URL
|
|
1097
|
+
- Returns status code, title, and description for each URL
|
|
1098
|
+
- Handles errors gracefully with timeout protection
|
|
1099
|
+
- Processes URLs in parallel for performance
|
|
1100
|
+
|
|
1101
|
+
Rules:
|
|
1102
|
+
- URLs must be valid HTTP/HTTPS addresses
|
|
1103
|
+
- Maximum 10 URLs per request to prevent abuse
|
|
1104
|
+
- 10 second timeout per URL request
|
|
1105
|
+
- Returns empty title/description if HTML parsing fails
|
|
1106
|
+
`,
|
|
1107
|
+
inputSchema: inputSchema11.shape
|
|
1108
|
+
};
|
|
1566
1109
|
}
|
|
1567
|
-
async function testUrls(
|
|
1110
|
+
async function testUrls(input) {
|
|
1111
|
+
const { urls } = input;
|
|
1568
1112
|
const results = await Promise.allSettled(
|
|
1569
1113
|
urls.map(async (url) => {
|
|
1570
1114
|
try {
|
|
@@ -1637,14 +1181,42 @@ function extractDescription(html) {
|
|
|
1637
1181
|
}
|
|
1638
1182
|
return "";
|
|
1639
1183
|
}
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
import { z as z12 } from "zod";
|
|
1644
|
-
var thoughtInputSchema = z12.object({
|
|
1645
|
-
thought: z12.string().describe("Your current thinking step"),
|
|
1646
|
-
nextThoughtNeeded: z12.boolean().optional().describe("true if you need more thinking, even if at what seemed like the end")
|
|
1184
|
+
var inputSchema12 = z.object({
|
|
1185
|
+
thought: z.string().describe("Your current thinking step"),
|
|
1186
|
+
nextThoughtNeeded: z.boolean().optional().describe("true if you need more thinking, even if at what seemed like the end")
|
|
1647
1187
|
});
|
|
1188
|
+
function thinkConfig() {
|
|
1189
|
+
return {
|
|
1190
|
+
title: "think",
|
|
1191
|
+
description: dedent`
|
|
1192
|
+
Sequential thinking tool for step-by-step problem analysis and solution development.
|
|
1193
|
+
|
|
1194
|
+
Use cases:
|
|
1195
|
+
- Breaking down complex problems into manageable steps
|
|
1196
|
+
- Developing solutions through iterative reasoning
|
|
1197
|
+
- Analyzing problems that require multiple perspectives
|
|
1198
|
+
- Planning tasks with dependencies and considerations
|
|
1199
|
+
|
|
1200
|
+
How it works:
|
|
1201
|
+
- Records each thinking step sequentially
|
|
1202
|
+
- Maintains thought history for context
|
|
1203
|
+
- Continues until solution is reached
|
|
1204
|
+
- Returns thought count and continuation status
|
|
1205
|
+
|
|
1206
|
+
Parameters:
|
|
1207
|
+
- thought: Current reasoning step or analysis
|
|
1208
|
+
- nextThoughtNeeded: Whether additional thinking is required (optional)
|
|
1209
|
+
|
|
1210
|
+
Best practices:
|
|
1211
|
+
- Use multiple calls for sophisticated reasoning chains
|
|
1212
|
+
- Progress from high-level overview to detailed analysis (drill-down approach)
|
|
1213
|
+
- Capture insights and eureka moments as they emerge
|
|
1214
|
+
- Engage in reflective introspection and constructive self-critique
|
|
1215
|
+
- Set nextThoughtNeeded to false only when fully satisfied with the solution
|
|
1216
|
+
`,
|
|
1217
|
+
inputSchema: inputSchema12.shape
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1648
1220
|
var Thought = class {
|
|
1649
1221
|
thoughtHistory = [];
|
|
1650
1222
|
branches = {};
|
|
@@ -1652,65 +1224,15 @@ var Thought = class {
|
|
|
1652
1224
|
const { nextThoughtNeeded } = input;
|
|
1653
1225
|
this.thoughtHistory.push(input);
|
|
1654
1226
|
return {
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
type: "text",
|
|
1658
|
-
text: JSON.stringify({
|
|
1659
|
-
nextThoughtNeeded,
|
|
1660
|
-
thoughtHistoryLength: this.thoughtHistory.length
|
|
1661
|
-
})
|
|
1662
|
-
}
|
|
1663
|
-
]
|
|
1227
|
+
nextThoughtNeeded,
|
|
1228
|
+
thoughtHistoryLength: this.thoughtHistory.length
|
|
1664
1229
|
};
|
|
1665
1230
|
}
|
|
1666
1231
|
};
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
"think",
|
|
1671
|
-
{
|
|
1672
|
-
title: "think",
|
|
1673
|
-
description: dedent13`
|
|
1674
|
-
Sequential thinking tool for step-by-step problem analysis and solution development.
|
|
1675
|
-
|
|
1676
|
-
Use cases:
|
|
1677
|
-
- Breaking down complex problems into manageable steps
|
|
1678
|
-
- Developing solutions through iterative reasoning
|
|
1679
|
-
- Analyzing problems that require multiple perspectives
|
|
1680
|
-
- Planning tasks with dependencies and considerations
|
|
1681
|
-
|
|
1682
|
-
How it works:
|
|
1683
|
-
- Records each thinking step sequentially
|
|
1684
|
-
- Maintains thought history for context
|
|
1685
|
-
- Continues until solution is reached
|
|
1686
|
-
- Returns thought count and continuation status
|
|
1687
|
-
|
|
1688
|
-
Parameters:
|
|
1689
|
-
- thought: Current reasoning step or analysis
|
|
1690
|
-
- nextThoughtNeeded: Whether additional thinking is required (optional)
|
|
1691
|
-
|
|
1692
|
-
Best practices:
|
|
1693
|
-
- Use multiple calls for sophisticated reasoning chains
|
|
1694
|
-
- Progress from high-level overview to detailed analysis (drill-down approach)
|
|
1695
|
-
- Capture insights and eureka moments as they emerge
|
|
1696
|
-
- Engage in reflective introspection and constructive self-critique
|
|
1697
|
-
- Set nextThoughtNeeded to false only when fully satisfied with the solution
|
|
1698
|
-
`,
|
|
1699
|
-
inputSchema: thoughtInputSchema.shape
|
|
1700
|
-
},
|
|
1701
|
-
async (input) => {
|
|
1702
|
-
return thought.processThought(input);
|
|
1703
|
-
}
|
|
1704
|
-
);
|
|
1232
|
+
var thought = new Thought();
|
|
1233
|
+
async function think(input) {
|
|
1234
|
+
return thought.processThought(input);
|
|
1705
1235
|
}
|
|
1706
|
-
|
|
1707
|
-
// src/tools/todo.ts
|
|
1708
|
-
import { dedent as dedent14 } from "ts-dedent";
|
|
1709
|
-
import { z as z13 } from "zod";
|
|
1710
|
-
var TodoInputSchema = z13.object({
|
|
1711
|
-
newTodos: z13.array(z13.string()).describe("New todos to add").optional(),
|
|
1712
|
-
completedTodos: z13.array(z13.number()).describe("Todo ids that are completed").optional()
|
|
1713
|
-
});
|
|
1714
1236
|
var Todo = class {
|
|
1715
1237
|
currentTodoId = 0;
|
|
1716
1238
|
todos = [];
|
|
@@ -1722,28 +1244,32 @@ var Todo = class {
|
|
|
1722
1244
|
);
|
|
1723
1245
|
}
|
|
1724
1246
|
if (completedTodos) {
|
|
1725
|
-
this.todos = this.todos.map((
|
|
1726
|
-
...
|
|
1727
|
-
completed:
|
|
1247
|
+
this.todos = this.todos.map((todo2) => ({
|
|
1248
|
+
...todo2,
|
|
1249
|
+
completed: todo2.completed || completedTodos.includes(todo2.id)
|
|
1728
1250
|
}));
|
|
1729
1251
|
}
|
|
1730
1252
|
return {
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1253
|
+
todos: this.todos
|
|
1254
|
+
};
|
|
1255
|
+
}
|
|
1256
|
+
clearTodo() {
|
|
1257
|
+
this.todos = [];
|
|
1258
|
+
this.currentTodoId = 0;
|
|
1259
|
+
return {
|
|
1260
|
+
todos: this.todos
|
|
1739
1261
|
};
|
|
1740
1262
|
}
|
|
1741
1263
|
};
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1264
|
+
var todoSingleton = new Todo();
|
|
1265
|
+
var todoInputSchema = z.object({
|
|
1266
|
+
newTodos: z.array(z.string()).describe("New todos to add").optional(),
|
|
1267
|
+
completedTodos: z.array(z.number()).describe("Todo ids that are completed").optional()
|
|
1268
|
+
});
|
|
1269
|
+
function todoConfig() {
|
|
1270
|
+
return {
|
|
1271
|
+
title: "todo",
|
|
1272
|
+
description: dedent`
|
|
1747
1273
|
Todo list manager that tracks tasks and their completion status.
|
|
1748
1274
|
|
|
1749
1275
|
Use cases:
|
|
@@ -1760,124 +1286,82 @@ function addTodoTool(server) {
|
|
|
1760
1286
|
- newTodos: Array of task descriptions to add
|
|
1761
1287
|
- completedTodos: Array of todo IDs to mark as completed
|
|
1762
1288
|
`,
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
return todo.processTodo(input);
|
|
1766
|
-
}
|
|
1767
|
-
);
|
|
1289
|
+
inputSchema: todoInputSchema.shape
|
|
1290
|
+
};
|
|
1768
1291
|
}
|
|
1292
|
+
async function todo(input) {
|
|
1293
|
+
return todoSingleton.processTodo(input);
|
|
1294
|
+
}
|
|
1295
|
+
var clearTodoInputSchema = z.object({});
|
|
1296
|
+
function clearTodoConfig() {
|
|
1297
|
+
return {
|
|
1298
|
+
title: "clearTodo",
|
|
1299
|
+
description: dedent`
|
|
1300
|
+
Clears the todo list.
|
|
1769
1301
|
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
import { dirname as dirname4 } from "path";
|
|
1775
|
-
import { dedent as dedent15 } from "ts-dedent";
|
|
1776
|
-
import { z as z14 } from "zod";
|
|
1777
|
-
var toolName12 = "writeTextFile";
|
|
1778
|
-
var toolDescription12 = dedent15`
|
|
1779
|
-
Text file writer that creates or overwrites files with UTF-8 content.
|
|
1780
|
-
|
|
1781
|
-
Use cases:
|
|
1782
|
-
- Creating new configuration files
|
|
1783
|
-
- Writing generated code or documentation
|
|
1784
|
-
- Saving processed data or results
|
|
1785
|
-
- Creating log files or reports
|
|
1786
|
-
|
|
1787
|
-
How it works:
|
|
1788
|
-
- Writes content as UTF-8 encoded text
|
|
1789
|
-
- Returns success status with file path
|
|
1302
|
+
Use cases:
|
|
1303
|
+
- Resetting the todo list to an empty state
|
|
1304
|
+
- Starting fresh with a new task list
|
|
1305
|
+
- Clearing all tasks for a new day or project
|
|
1790
1306
|
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
}
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1307
|
+
How it works:
|
|
1308
|
+
- Resets the todo list to an empty state
|
|
1309
|
+
- Returns an empty todo list
|
|
1310
|
+
`,
|
|
1311
|
+
inputSchema: clearTodoInputSchema.shape
|
|
1312
|
+
};
|
|
1313
|
+
}
|
|
1314
|
+
async function clearTodo(input) {
|
|
1315
|
+
return todoSingleton.clearTodo();
|
|
1316
|
+
}
|
|
1317
|
+
var toolInputSchema = z.object({
|
|
1318
|
+
path: z.string().describe("Target file path (relative or absolute)."),
|
|
1319
|
+
text: z.string().min(1).max(1e4).describe("Text to write to the file. Max 10000 characters.")
|
|
1320
|
+
});
|
|
1321
|
+
function writeTextFileConfig() {
|
|
1322
|
+
return {
|
|
1323
|
+
title: "writeTextFile",
|
|
1324
|
+
description: dedent`
|
|
1325
|
+
Text file writer that creates or overwrites files with UTF-8 content.
|
|
1808
1326
|
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
content: [
|
|
1815
|
-
{
|
|
1816
|
-
type: "text",
|
|
1817
|
-
text: JSON.stringify(await writeTextFileLocalMode(path2, text))
|
|
1818
|
-
}
|
|
1819
|
-
]
|
|
1820
|
-
};
|
|
1821
|
-
} catch (e) {
|
|
1822
|
-
if (e instanceof Error) {
|
|
1823
|
-
return {
|
|
1824
|
-
content: [{ type: "text", text: JSON.stringify({ error: e.message }) }]
|
|
1825
|
-
};
|
|
1826
|
-
}
|
|
1827
|
-
throw e;
|
|
1828
|
-
}
|
|
1829
|
-
}
|
|
1830
|
-
);
|
|
1831
|
-
break;
|
|
1832
|
-
}
|
|
1833
|
-
case "studio" /* STUDIO */: {
|
|
1834
|
-
server.tool(
|
|
1835
|
-
toolName12,
|
|
1836
|
-
`${toolDescription12}
|
|
1327
|
+
Use cases:
|
|
1328
|
+
- Creating new configuration files
|
|
1329
|
+
- Writing generated code or documentation
|
|
1330
|
+
- Saving processed data or results
|
|
1331
|
+
- Creating log files or reports
|
|
1837
1332
|
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
} catch (e) {
|
|
1851
|
-
if (e instanceof Error) {
|
|
1852
|
-
return {
|
|
1853
|
-
content: [{ type: "text", text: JSON.stringify({ error: e.message }) }]
|
|
1854
|
-
};
|
|
1855
|
-
}
|
|
1856
|
-
throw e;
|
|
1857
|
-
}
|
|
1858
|
-
}
|
|
1859
|
-
);
|
|
1860
|
-
break;
|
|
1861
|
-
}
|
|
1862
|
-
}
|
|
1333
|
+
How it works:
|
|
1334
|
+
- Writes content as UTF-8 encoded text
|
|
1335
|
+
- Returns success status with file path
|
|
1336
|
+
|
|
1337
|
+
Rules:
|
|
1338
|
+
- IF THE FILE ALREADY EXISTS, IT WILL BE OVERWRITTEN
|
|
1339
|
+
- YOU MUST PROVIDE A VALID UTF-8 STRING FOR THE TEXT
|
|
1340
|
+
- THERE IS A LIMIT ON THE NUMBER OF TOKENS THAT CAN BE GENERATED, SO DO NOT WRITE ALL THE CONTENT AT ONCE (IT WILL CAUSE AN ERROR)
|
|
1341
|
+
- IF YOU WANT TO WRITE MORE THAN 10,000 CHARACTERS, USE "appendTextFile" TOOL AFTER THIS ONE
|
|
1342
|
+
`,
|
|
1343
|
+
inputSchema: toolInputSchema.shape
|
|
1344
|
+
};
|
|
1863
1345
|
}
|
|
1864
|
-
async function writeTextFileLocalMode(
|
|
1346
|
+
async function writeTextFileLocalMode(input) {
|
|
1347
|
+
const { path: path2, text } = input;
|
|
1865
1348
|
const validatedPath = await validatePath(path2);
|
|
1866
|
-
if (
|
|
1867
|
-
const stats =
|
|
1349
|
+
if (existsSync(validatedPath)) {
|
|
1350
|
+
const stats = statSync(validatedPath);
|
|
1868
1351
|
if (!(stats.mode & 128)) {
|
|
1869
1352
|
throw new Error(`File ${path2} is not writable`);
|
|
1870
1353
|
}
|
|
1871
1354
|
}
|
|
1872
|
-
const dir =
|
|
1873
|
-
await
|
|
1874
|
-
await
|
|
1355
|
+
const dir = dirname(validatedPath);
|
|
1356
|
+
await mkdir(dir, { recursive: true });
|
|
1357
|
+
await writeFile(validatedPath, text, "utf-8");
|
|
1875
1358
|
return {
|
|
1876
1359
|
path: validatedPath,
|
|
1877
1360
|
text
|
|
1878
1361
|
};
|
|
1879
1362
|
}
|
|
1880
|
-
async function writeTextFileStudioMode(
|
|
1363
|
+
async function writeTextFileStudioMode(input) {
|
|
1364
|
+
const { path: path2, text } = input;
|
|
1881
1365
|
const validatedPath = await validatePath(path2);
|
|
1882
1366
|
const relativePath = validatedPath.startsWith(workspacePath) ? validatedPath.slice(workspacePath.length + 1) : validatedPath;
|
|
1883
1367
|
const existingItem = await findWorkspaceItem(relativePath);
|
|
@@ -1896,8 +1380,6 @@ async function writeTextFileStudioMode(path2, text) {
|
|
|
1896
1380
|
await createWorkspaceItem({
|
|
1897
1381
|
type: "workspaceItemDirectory",
|
|
1898
1382
|
path: currentPath,
|
|
1899
|
-
owner: "expert",
|
|
1900
|
-
lifecycle: "expertJob",
|
|
1901
1383
|
permission: "readWrite"
|
|
1902
1384
|
});
|
|
1903
1385
|
}
|
|
@@ -1906,53 +1388,17 @@ async function writeTextFileStudioMode(path2, text) {
|
|
|
1906
1388
|
{
|
|
1907
1389
|
type: "workspaceItemFile",
|
|
1908
1390
|
path: relativePath,
|
|
1909
|
-
owner: "expert",
|
|
1910
|
-
lifecycle: "expertJob",
|
|
1911
1391
|
permission: "readWrite"
|
|
1912
1392
|
},
|
|
1913
1393
|
text
|
|
1914
1394
|
);
|
|
1915
|
-
await writeTextFileLocalMode(
|
|
1395
|
+
await writeTextFileLocalMode(input);
|
|
1916
1396
|
return {
|
|
1917
1397
|
path: relativePath,
|
|
1918
1398
|
text
|
|
1919
1399
|
};
|
|
1920
1400
|
}
|
|
1921
1401
|
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
const program = new Command();
|
|
1925
|
-
program.name(package_default.name).description(package_default.description).version(package_default.version, "-v, --version", "display the version number").action(async () => {
|
|
1926
|
-
const server = new McpServer(
|
|
1927
|
-
{
|
|
1928
|
-
name: package_default.name,
|
|
1929
|
-
version: package_default.version
|
|
1930
|
-
},
|
|
1931
|
-
{
|
|
1932
|
-
capabilities: {
|
|
1933
|
-
tools: {}
|
|
1934
|
-
}
|
|
1935
|
-
}
|
|
1936
|
-
);
|
|
1937
|
-
addAttemptCompletionTool(server);
|
|
1938
|
-
addThinkTool(server);
|
|
1939
|
-
addTodoTool(server);
|
|
1940
|
-
addReadImageFileTool(server);
|
|
1941
|
-
addReadPdfFileTool(server);
|
|
1942
|
-
addReadTextFileTool(server);
|
|
1943
|
-
addEditTextFileTool(server);
|
|
1944
|
-
addAppendTextFileTool(server);
|
|
1945
|
-
addDeleteFileTool(server);
|
|
1946
|
-
addMoveFileTool(server);
|
|
1947
|
-
addGetFileInfoTool(server);
|
|
1948
|
-
addWriteTextFileTool(server);
|
|
1949
|
-
addCreateDirectoryTool(server);
|
|
1950
|
-
addListDirectoryTool(server);
|
|
1951
|
-
addTestUrlTool(server);
|
|
1952
|
-
const transport = new StdioServerTransport();
|
|
1953
|
-
await server.connect(transport);
|
|
1954
|
-
});
|
|
1955
|
-
program.parse();
|
|
1956
|
-
}
|
|
1957
|
-
main();
|
|
1402
|
+
export { WorkspaceMode, appendTextFileConfig, appendTextFileLocalMode, appendTextFileStudioMode, attemptCompletion, attemptCompletionConfig, clearTodo, clearTodoConfig, createDirectoryConfig, createDirectoryLocalMode, createDirectoryStudioMode, createWorkspaceItem, deleteFileConfig, deleteFileLocalMode, deleteFileStudioMode, deleteWorkspaceItem, editTextFileConfig, editTextFileLocalMode, editTextFileStudioMode, exec, execConfig, findWorkspaceItem, getFileInfoConfig, getFileInfoLocalMode, getFileInfoStudioMode, getWorkspaceApiConfig, getWorkspaceItemContent, getWorkspaceItems, getWorkspaceMode, listDirectoryConfig, listDirectoryLocalMode, listDirectoryStudioMode, moveFileConfig, moveFileLocalMode, moveFileStudioMode, readImageFile, readImageFileConfig, readPdfFile, readPdfFileConfig, readTextFile, readTextFileConfig, resolveToolByMode, testUrlConfig, testUrls, think, thinkConfig, todo, todoConfig, updateWorkspaceItem, validatePath, workspacePath, writeTextFileConfig, writeTextFileLocalMode, writeTextFileStudioMode };
|
|
1403
|
+
//# sourceMappingURL=index.js.map
|
|
1958
1404
|
//# sourceMappingURL=index.js.map
|