@perstack/base 0.0.5 → 0.0.7
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.js +584 -1037
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import { Command } from "commander";
|
|
|
8
8
|
// package.json
|
|
9
9
|
var package_default = {
|
|
10
10
|
name: "@perstack/base",
|
|
11
|
-
version: "0.0.
|
|
11
|
+
version: "0.0.7",
|
|
12
12
|
description: "Perstack base skills for agents.",
|
|
13
13
|
author: "Wintermute Technologies, Inc.",
|
|
14
14
|
type: "module",
|
|
@@ -46,56 +46,6 @@ var package_default = {
|
|
|
46
46
|
}
|
|
47
47
|
};
|
|
48
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";
|
|
55
|
-
|
|
56
|
-
// 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
|
-
var workspacePath = realpathSync(expandHome(process.cwd()));
|
|
62
|
-
function expandHome(filepath) {
|
|
63
|
-
if (filepath.startsWith("~/") || filepath === "~") {
|
|
64
|
-
return path.join(os.homedir(), filepath.slice(1));
|
|
65
|
-
}
|
|
66
|
-
return filepath;
|
|
67
|
-
}
|
|
68
|
-
async function validatePath(requestedPath) {
|
|
69
|
-
const expandedPath = expandHome(requestedPath);
|
|
70
|
-
const absolute = path.isAbsolute(expandedPath) ? path.resolve(expandedPath) : path.resolve(process.cwd(), expandedPath);
|
|
71
|
-
if (absolute === `${workspacePath}/perstack`) {
|
|
72
|
-
throw new Error("Access denied - perstack directory is not allowed");
|
|
73
|
-
}
|
|
74
|
-
try {
|
|
75
|
-
const realAbsolute = await fs.realpath(absolute);
|
|
76
|
-
if (!realAbsolute.startsWith(workspacePath)) {
|
|
77
|
-
throw new Error("Access denied - symlink target outside allowed directories");
|
|
78
|
-
}
|
|
79
|
-
return realAbsolute;
|
|
80
|
-
} catch (error) {
|
|
81
|
-
const parentDir = path.dirname(absolute);
|
|
82
|
-
try {
|
|
83
|
-
const realParentPath = await fs.realpath(parentDir);
|
|
84
|
-
if (!realParentPath.startsWith(workspacePath)) {
|
|
85
|
-
throw new Error("Access denied - parent directory outside allowed directories");
|
|
86
|
-
}
|
|
87
|
-
return absolute;
|
|
88
|
-
} catch {
|
|
89
|
-
if (!absolute.startsWith(workspacePath)) {
|
|
90
|
-
throw new Error(
|
|
91
|
-
`Access denied - path outside allowed directories: ${absolute} not in ${workspacePath}`
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
throw new Error(`Parent directory does not exist: ${parentDir}`);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
49
|
// src/lib/workspace-api.ts
|
|
100
50
|
import mime from "mime-types";
|
|
101
51
|
var getWorkspaceApiConfig = () => {
|
|
@@ -250,98 +200,110 @@ var deleteWorkspaceItem = async (workspaceItemId) => {
|
|
|
250
200
|
}
|
|
251
201
|
};
|
|
252
202
|
|
|
253
|
-
// src/
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
203
|
+
// src/lib/register-tool.ts
|
|
204
|
+
function resolveToolByMode(localModeFunction, studioModeFunction) {
|
|
205
|
+
const mode = getWorkspaceMode();
|
|
206
|
+
const func = !studioModeFunction ? localModeFunction : mode === "local" /* LOCAL */ ? localModeFunction : studioModeFunction;
|
|
207
|
+
return async (input) => {
|
|
208
|
+
try {
|
|
209
|
+
const result = await func(input);
|
|
210
|
+
return { content: [{ type: "text", text: JSON.stringify(result) }] };
|
|
211
|
+
} catch (e) {
|
|
212
|
+
if (e instanceof Error) {
|
|
213
|
+
return {
|
|
214
|
+
content: [{ type: "text", text: JSON.stringify({ error: e.name, message: e.message }) }]
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
throw e;
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
}
|
|
257
221
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
222
|
+
// src/tools/append-text-file.ts
|
|
223
|
+
import { existsSync, statSync } from "fs";
|
|
224
|
+
import { appendFile } from "fs/promises";
|
|
225
|
+
import { readFile } from "fs/promises";
|
|
226
|
+
import { dedent } from "ts-dedent";
|
|
227
|
+
import { z } from "zod";
|
|
264
228
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
229
|
+
// src/lib/path.ts
|
|
230
|
+
import { realpathSync } from "fs";
|
|
231
|
+
import fs from "fs/promises";
|
|
232
|
+
import os from "os";
|
|
233
|
+
import path from "path";
|
|
234
|
+
var workspacePath = realpathSync(expandHome(process.cwd()));
|
|
235
|
+
function expandHome(filepath) {
|
|
236
|
+
if (filepath.startsWith("~/") || filepath === "~") {
|
|
237
|
+
return path.join(os.homedir(), filepath.slice(1));
|
|
238
|
+
}
|
|
239
|
+
return filepath;
|
|
240
|
+
}
|
|
241
|
+
async function validatePath(requestedPath) {
|
|
242
|
+
const expandedPath = expandHome(requestedPath);
|
|
243
|
+
const absolute = path.isAbsolute(expandedPath) ? path.resolve(expandedPath) : path.resolve(process.cwd(), expandedPath);
|
|
244
|
+
if (absolute === `${workspacePath}/perstack`) {
|
|
245
|
+
throw new Error("Access denied - perstack directory is not allowed");
|
|
246
|
+
}
|
|
247
|
+
try {
|
|
248
|
+
const realAbsolute = await fs.realpath(absolute);
|
|
249
|
+
if (!realAbsolute.startsWith(workspacePath)) {
|
|
250
|
+
throw new Error("Access denied - symlink target outside allowed directories");
|
|
251
|
+
}
|
|
252
|
+
return realAbsolute;
|
|
253
|
+
} catch (error) {
|
|
254
|
+
const parentDir = path.dirname(absolute);
|
|
255
|
+
try {
|
|
256
|
+
const realParentPath = await fs.realpath(parentDir);
|
|
257
|
+
if (!realParentPath.startsWith(workspacePath)) {
|
|
258
|
+
throw new Error("Access denied - parent directory outside allowed directories");
|
|
259
|
+
}
|
|
260
|
+
return absolute;
|
|
261
|
+
} catch {
|
|
262
|
+
if (!absolute.startsWith(workspacePath)) {
|
|
263
|
+
throw new Error(
|
|
264
|
+
`Access denied - path outside allowed directories: ${absolute} not in ${workspacePath}`
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
throw new Error(`Parent directory does not exist: ${parentDir}`);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
270
271
|
|
|
271
|
-
|
|
272
|
-
|
|
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 = {
|
|
272
|
+
// src/tools/append-text-file.ts
|
|
273
|
+
var inputSchema = z.object({
|
|
278
274
|
path: z.string().describe("Target file path to append to."),
|
|
279
275
|
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}
|
|
276
|
+
});
|
|
277
|
+
function appendTextFileConfig() {
|
|
278
|
+
return {
|
|
279
|
+
title: "Append text file",
|
|
280
|
+
description: dedent`
|
|
281
|
+
Adding content to the end of existing files.
|
|
288
282
|
|
|
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}
|
|
283
|
+
Use cases:
|
|
284
|
+
- Adding entries to log files
|
|
285
|
+
- Appending data to CSV or JSON files
|
|
286
|
+
- Adding new sections to documentation
|
|
287
|
+
- Extending configuration files
|
|
288
|
+
- Building files incrementally
|
|
317
289
|
|
|
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
|
-
}
|
|
290
|
+
How it works:
|
|
291
|
+
- Appends text to the end of an existing file
|
|
292
|
+
- Does not modify existing content
|
|
293
|
+
- Creates a new line before appending if needed
|
|
294
|
+
- Returns the appended file path
|
|
295
|
+
|
|
296
|
+
Rules:
|
|
297
|
+
- FILE MUST EXIST BEFORE APPENDING
|
|
298
|
+
- YOU MUST PROVIDE A VALID UTF-8 STRING FOR THE TEXT
|
|
299
|
+
- THERE IS A LIMIT ON THE NUMBER OF TOKENS THAT CAN BE GENERATED, SO DO NOT APPEND ALL THE CONTENT AT ONCE
|
|
300
|
+
- IF YOU WANT TO APPEND MORE THAN 2000 CHARACTERS, USE THIS TOOL MULTIPLE TIMES
|
|
301
|
+
`,
|
|
302
|
+
inputSchema: inputSchema.shape
|
|
303
|
+
};
|
|
343
304
|
}
|
|
344
|
-
async function appendTextFileLocalMode(
|
|
305
|
+
async function appendTextFileLocalMode(input) {
|
|
306
|
+
const { path: path2, text } = input;
|
|
345
307
|
const validatedPath = await validatePath(path2);
|
|
346
308
|
if (!existsSync(validatedPath)) {
|
|
347
309
|
throw new Error(`File ${path2} does not exist.`);
|
|
@@ -351,12 +313,10 @@ async function appendTextFileLocalMode(path2, text) {
|
|
|
351
313
|
throw new Error(`File ${path2} is not writable`);
|
|
352
314
|
}
|
|
353
315
|
await appendFile(validatedPath, text);
|
|
354
|
-
return {
|
|
355
|
-
path: validatedPath,
|
|
356
|
-
text
|
|
357
|
-
};
|
|
316
|
+
return { path: validatedPath, text };
|
|
358
317
|
}
|
|
359
|
-
async function appendTextFileStudioMode(
|
|
318
|
+
async function appendTextFileStudioMode(input) {
|
|
319
|
+
const { path: path2, text } = input;
|
|
360
320
|
const validatedPath = await validatePath(path2);
|
|
361
321
|
const relativePath = validatedPath.startsWith(workspacePath) ? validatedPath.slice(workspacePath.length + 1) : validatedPath;
|
|
362
322
|
const existingItem = await findWorkspaceItem(relativePath);
|
|
@@ -366,7 +326,7 @@ async function appendTextFileStudioMode(path2, text) {
|
|
|
366
326
|
if (existingItem.type === "workspaceItemDirectory") {
|
|
367
327
|
throw new Error(`Path ${relativePath} is a directory.`);
|
|
368
328
|
}
|
|
369
|
-
await appendTextFileLocalMode(
|
|
329
|
+
await appendTextFileLocalMode(input);
|
|
370
330
|
await deleteWorkspaceItem(existingItem.id);
|
|
371
331
|
const content = await readFile(validatedPath, "utf-8");
|
|
372
332
|
await createWorkspaceItem(
|
|
@@ -379,45 +339,36 @@ async function appendTextFileStudioMode(path2, text) {
|
|
|
379
339
|
},
|
|
380
340
|
content
|
|
381
341
|
);
|
|
382
|
-
return {
|
|
383
|
-
path: relativePath,
|
|
384
|
-
text
|
|
385
|
-
};
|
|
342
|
+
return { path: relativePath, text };
|
|
386
343
|
}
|
|
387
344
|
|
|
388
345
|
// src/tools/attempt-completion.ts
|
|
389
346
|
import { dedent as dedent2 } from "ts-dedent";
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
"
|
|
393
|
-
dedent2`
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
{}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
};
|
|
347
|
+
function attemptCompletionConfig() {
|
|
348
|
+
return {
|
|
349
|
+
title: "Attempt completion",
|
|
350
|
+
description: dedent2`
|
|
351
|
+
Task completion signal that triggers immediate final report generation.
|
|
352
|
+
Use cases:
|
|
353
|
+
- Signaling task completion to Perstack runtime
|
|
354
|
+
- Triggering final report generation
|
|
355
|
+
- Ending the current expert's work cycle
|
|
356
|
+
How it works:
|
|
357
|
+
- Sends completion signal to Perstack runtime
|
|
358
|
+
- Runtime immediately proceeds to final report generation
|
|
359
|
+
- No confirmation or approval step required
|
|
360
|
+
- No parameters needed for this signal
|
|
361
|
+
Notes:
|
|
362
|
+
- Triggers immediate transition to final report
|
|
363
|
+
- Should only be used when task is fully complete
|
|
364
|
+
- Cannot be reverted once called
|
|
365
|
+
`,
|
|
366
|
+
inputSchema: {}
|
|
367
|
+
};
|
|
368
|
+
}
|
|
413
369
|
async function attemptCompletion() {
|
|
414
370
|
return {
|
|
415
|
-
|
|
416
|
-
{
|
|
417
|
-
type: "text",
|
|
418
|
-
text: "End the agent loop and provide a final report"
|
|
419
|
-
}
|
|
420
|
-
]
|
|
371
|
+
message: "End the agent loop and provide a final report"
|
|
421
372
|
};
|
|
422
373
|
}
|
|
423
374
|
|
|
@@ -427,92 +378,35 @@ import { mkdir } from "fs/promises";
|
|
|
427
378
|
import { dirname } from "path";
|
|
428
379
|
import { dedent as dedent3 } from "ts-dedent";
|
|
429
380
|
import { z as z2 } from "zod";
|
|
430
|
-
var
|
|
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 = {
|
|
381
|
+
var inputSchema2 = z2.object({
|
|
450
382
|
path: z2.string()
|
|
451
|
-
};
|
|
452
|
-
function
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
toolName2,
|
|
458
|
-
`${toolDescription2}
|
|
383
|
+
});
|
|
384
|
+
function createDirectoryConfig() {
|
|
385
|
+
return {
|
|
386
|
+
title: "Create directory",
|
|
387
|
+
description: dedent3`
|
|
388
|
+
Directory creator for establishing folder structures in the workspace.
|
|
459
389
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
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}
|
|
390
|
+
Use cases:
|
|
391
|
+
- Setting up project directory structure
|
|
392
|
+
- Creating output folders for generated content
|
|
393
|
+
- Organizing files into logical groups
|
|
394
|
+
- Preparing directory hierarchies
|
|
488
395
|
|
|
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
|
-
}
|
|
396
|
+
How it works:
|
|
397
|
+
- Creates directories recursively
|
|
398
|
+
- Handles existing directories gracefully
|
|
399
|
+
- Creates parent directories as needed
|
|
400
|
+
- Returns creation status
|
|
401
|
+
|
|
402
|
+
Parameters:
|
|
403
|
+
- path: Directory path to create
|
|
404
|
+
`,
|
|
405
|
+
inputSchema: inputSchema2.shape
|
|
406
|
+
};
|
|
514
407
|
}
|
|
515
|
-
async function createDirectoryLocalMode(
|
|
408
|
+
async function createDirectoryLocalMode(input) {
|
|
409
|
+
const { path: path2 } = input;
|
|
516
410
|
const validatedPath = await validatePath(path2);
|
|
517
411
|
const exists = existsSync2(validatedPath);
|
|
518
412
|
if (exists) {
|
|
@@ -530,7 +424,8 @@ async function createDirectoryLocalMode(path2) {
|
|
|
530
424
|
path: validatedPath
|
|
531
425
|
};
|
|
532
426
|
}
|
|
533
|
-
async function createDirectoryStudioMode(
|
|
427
|
+
async function createDirectoryStudioMode(input) {
|
|
428
|
+
const { path: path2 } = input;
|
|
534
429
|
const validatedPath = await validatePath(path2);
|
|
535
430
|
const relativePath = validatedPath.startsWith(workspacePath) ? validatedPath.slice(workspacePath.length + 1) : validatedPath;
|
|
536
431
|
const existingItem = await findWorkspaceItem(relativePath);
|
|
@@ -552,7 +447,7 @@ async function createDirectoryStudioMode(path2) {
|
|
|
552
447
|
});
|
|
553
448
|
}
|
|
554
449
|
}
|
|
555
|
-
await createDirectoryLocalMode(
|
|
450
|
+
await createDirectoryLocalMode(input);
|
|
556
451
|
return {
|
|
557
452
|
path: relativePath
|
|
558
453
|
};
|
|
@@ -563,92 +458,35 @@ import { existsSync as existsSync3, statSync as statSync3 } from "fs";
|
|
|
563
458
|
import { unlink } from "fs/promises";
|
|
564
459
|
import { dedent as dedent4 } from "ts-dedent";
|
|
565
460
|
import { z as z3 } from "zod";
|
|
566
|
-
var
|
|
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 = {
|
|
461
|
+
var inputSchema3 = z3.object({
|
|
586
462
|
path: z3.string()
|
|
587
|
-
};
|
|
588
|
-
function
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
toolName3,
|
|
594
|
-
`${toolDescription3}
|
|
463
|
+
});
|
|
464
|
+
function deleteFileConfig() {
|
|
465
|
+
return {
|
|
466
|
+
title: "Delete file",
|
|
467
|
+
description: dedent4`
|
|
468
|
+
File deleter for removing files from the workspace.
|
|
595
469
|
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
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}
|
|
470
|
+
Use cases:
|
|
471
|
+
- Removing temporary files
|
|
472
|
+
- Cleaning up generated files
|
|
473
|
+
- Deleting outdated configuration files
|
|
474
|
+
- Removing unwanted artifacts
|
|
624
475
|
|
|
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
|
-
}
|
|
476
|
+
How it works:
|
|
477
|
+
- Validates file existence and permissions
|
|
478
|
+
- Performs atomic delete operation
|
|
479
|
+
- Removes file from both filesystem and workspace API
|
|
480
|
+
- Returns deletion status
|
|
481
|
+
|
|
482
|
+
Parameters:
|
|
483
|
+
- path: File path to delete
|
|
484
|
+
`,
|
|
485
|
+
inputSchema: inputSchema3.shape
|
|
486
|
+
};
|
|
650
487
|
}
|
|
651
|
-
async function deleteFileLocalMode(
|
|
488
|
+
async function deleteFileLocalMode(input) {
|
|
489
|
+
const { path: path2 } = input;
|
|
652
490
|
const validatedPath = await validatePath(path2);
|
|
653
491
|
if (!existsSync3(validatedPath)) {
|
|
654
492
|
throw new Error(`File ${path2} does not exist.`);
|
|
@@ -665,7 +503,8 @@ async function deleteFileLocalMode(path2) {
|
|
|
665
503
|
path: validatedPath
|
|
666
504
|
};
|
|
667
505
|
}
|
|
668
|
-
async function deleteFileStudioMode(
|
|
506
|
+
async function deleteFileStudioMode(input) {
|
|
507
|
+
const { path: path2 } = input;
|
|
669
508
|
const validatedPath = await validatePath(path2);
|
|
670
509
|
const relativePath = validatedPath.startsWith(workspacePath) ? validatedPath.slice(workspacePath.length + 1) : validatedPath;
|
|
671
510
|
const existingItem = await findWorkspaceItem(relativePath);
|
|
@@ -675,7 +514,7 @@ async function deleteFileStudioMode(path2) {
|
|
|
675
514
|
if (existingItem.type === "workspaceItemDirectory") {
|
|
676
515
|
throw new Error(`Path ${relativePath} is a directory. Use delete directory tool instead.`);
|
|
677
516
|
}
|
|
678
|
-
await deleteFileLocalMode(
|
|
517
|
+
await deleteFileLocalMode(input);
|
|
679
518
|
await deleteWorkspaceItem(existingItem.id);
|
|
680
519
|
return {
|
|
681
520
|
path: relativePath
|
|
@@ -687,98 +526,41 @@ import { existsSync as existsSync4, statSync as statSync4 } from "fs";
|
|
|
687
526
|
import { readFile as readFile2, writeFile } from "fs/promises";
|
|
688
527
|
import { dedent as dedent5 } from "ts-dedent";
|
|
689
528
|
import { z as z4 } from "zod";
|
|
690
|
-
var
|
|
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 = {
|
|
529
|
+
var inputSchema4 = z4.object({
|
|
714
530
|
path: z4.string().describe("Target file path to edit."),
|
|
715
531
|
newText: z4.string().min(1).max(2e3).describe("Text to append to the file. Max 2000 characters."),
|
|
716
532
|
oldText: z4.string().min(1).max(2e3).describe("Exact text to find and replace. Max 2000 characters.")
|
|
717
|
-
};
|
|
718
|
-
function
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
toolName4,
|
|
724
|
-
`${toolDescription4}
|
|
533
|
+
});
|
|
534
|
+
function editTextFileConfig() {
|
|
535
|
+
return {
|
|
536
|
+
title: "Edit text file",
|
|
537
|
+
description: dedent5`
|
|
538
|
+
Text file editor for modifying existing files with precise text replacement.
|
|
725
539
|
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
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}
|
|
540
|
+
Use cases:
|
|
541
|
+
- Updating configuration values
|
|
542
|
+
- Modifying code snippets
|
|
543
|
+
- Replacing specific text blocks
|
|
544
|
+
- Making targeted edits to files
|
|
754
545
|
|
|
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
|
-
}
|
|
546
|
+
How it works:
|
|
547
|
+
- Reads existing file content
|
|
548
|
+
- Performs exact text replacement of oldText with newText
|
|
549
|
+
- Normalizes line endings for consistent behavior
|
|
550
|
+
- Returns summary of changes made
|
|
551
|
+
- For appending text to files, use the appendTextFile tool instead
|
|
552
|
+
|
|
553
|
+
Rules:
|
|
554
|
+
- YOU MUST PROVIDE A VALID UTF-8 STRING FOR THE TEXT
|
|
555
|
+
- 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)
|
|
556
|
+
- IF YOU WANT TO EDIT MORE THAN 2000 CHARACTERS, USE THIS TOOL MULTIPLE TIMES
|
|
557
|
+
- DO NOT USE THIS TOOL FOR APPENDING TEXT TO FILES - USE appendTextFile TOOL INSTEAD
|
|
558
|
+
`,
|
|
559
|
+
inputSchema: inputSchema4.shape
|
|
560
|
+
};
|
|
780
561
|
}
|
|
781
|
-
async function editTextFileLocalMode(
|
|
562
|
+
async function editTextFileLocalMode(input) {
|
|
563
|
+
const { path: path2, newText, oldText } = input;
|
|
782
564
|
const validatedPath = await validatePath(path2);
|
|
783
565
|
if (!existsSync4(validatedPath)) {
|
|
784
566
|
throw new Error(`File ${path2} does not exist.`);
|
|
@@ -794,7 +576,8 @@ async function editTextFileLocalMode(path2, newText, oldText) {
|
|
|
794
576
|
oldText
|
|
795
577
|
};
|
|
796
578
|
}
|
|
797
|
-
async function editTextFileStudioMode(
|
|
579
|
+
async function editTextFileStudioMode(input) {
|
|
580
|
+
const { path: path2, newText, oldText } = input;
|
|
798
581
|
const validatedPath = await validatePath(path2);
|
|
799
582
|
const relativePath = validatedPath.startsWith(workspacePath) ? validatedPath.slice(workspacePath.length + 1) : validatedPath;
|
|
800
583
|
const existingItem = await findWorkspaceItem(relativePath);
|
|
@@ -804,7 +587,7 @@ async function editTextFileStudioMode(path2, newText, oldText) {
|
|
|
804
587
|
if (existingItem.type === "workspaceItemDirectory") {
|
|
805
588
|
throw new Error(`Path ${relativePath} is a directory.`);
|
|
806
589
|
}
|
|
807
|
-
await editTextFileLocalMode(
|
|
590
|
+
await editTextFileLocalMode(input);
|
|
808
591
|
await deleteWorkspaceItem(existingItem.id);
|
|
809
592
|
const content = await readFile2(validatedPath, "utf-8");
|
|
810
593
|
await createWorkspaceItem(
|
|
@@ -843,92 +626,35 @@ import { basename, dirname as dirname2, extname, resolve } from "path";
|
|
|
843
626
|
import mime2 from "mime-types";
|
|
844
627
|
import { dedent as dedent6 } from "ts-dedent";
|
|
845
628
|
import { z as z5 } from "zod";
|
|
846
|
-
var
|
|
847
|
-
var toolDescription5 = dedent6`
|
|
848
|
-
File information retriever for detailed metadata about files and directories.
|
|
849
|
-
|
|
850
|
-
Use cases:
|
|
851
|
-
- Checking file existence and type
|
|
852
|
-
- Getting file size and timestamps
|
|
853
|
-
- Determining MIME types
|
|
854
|
-
- Validating file accessibility
|
|
855
|
-
|
|
856
|
-
How it works:
|
|
857
|
-
- Retrieves comprehensive file system metadata
|
|
858
|
-
- Detects MIME type from file extension
|
|
859
|
-
- Provides both absolute and relative paths
|
|
860
|
-
- Returns human-readable file sizes
|
|
861
|
-
|
|
862
|
-
Parameters:
|
|
863
|
-
- path: File or directory path to inspect
|
|
864
|
-
`;
|
|
865
|
-
var toolInputSchema5 = {
|
|
629
|
+
var inputSchema5 = z5.object({
|
|
866
630
|
path: z5.string()
|
|
867
|
-
};
|
|
868
|
-
function
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
toolName5,
|
|
874
|
-
`${toolDescription5}
|
|
631
|
+
});
|
|
632
|
+
function getFileInfoConfig() {
|
|
633
|
+
return {
|
|
634
|
+
title: "Get file info",
|
|
635
|
+
description: dedent6`
|
|
636
|
+
File information retriever for detailed metadata about files and directories.
|
|
875
637
|
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
content: [
|
|
882
|
-
{
|
|
883
|
-
type: "text",
|
|
884
|
-
text: JSON.stringify(await getFileInfoLocalMode(path2))
|
|
885
|
-
}
|
|
886
|
-
]
|
|
887
|
-
};
|
|
888
|
-
} catch (e) {
|
|
889
|
-
if (e instanceof Error) {
|
|
890
|
-
return {
|
|
891
|
-
content: [{ type: "text", text: JSON.stringify({ error: e.message }) }]
|
|
892
|
-
};
|
|
893
|
-
}
|
|
894
|
-
throw e;
|
|
895
|
-
}
|
|
896
|
-
}
|
|
897
|
-
);
|
|
898
|
-
break;
|
|
899
|
-
}
|
|
900
|
-
case "studio" /* STUDIO */: {
|
|
901
|
-
server.tool(
|
|
902
|
-
toolName5,
|
|
903
|
-
`${toolDescription5}
|
|
638
|
+
Use cases:
|
|
639
|
+
- Checking file existence and type
|
|
640
|
+
- Getting file size and timestamps
|
|
641
|
+
- Determining MIME types
|
|
642
|
+
- Validating file accessibility
|
|
904
643
|
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
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
|
-
}
|
|
925
|
-
}
|
|
926
|
-
);
|
|
927
|
-
break;
|
|
928
|
-
}
|
|
929
|
-
}
|
|
644
|
+
How it works:
|
|
645
|
+
- Retrieves comprehensive file system metadata
|
|
646
|
+
- Detects MIME type from file extension
|
|
647
|
+
- Provides both absolute and relative paths
|
|
648
|
+
- Returns human-readable file sizes
|
|
649
|
+
|
|
650
|
+
Parameters:
|
|
651
|
+
- path: File or directory path to inspect
|
|
652
|
+
`,
|
|
653
|
+
inputSchema: inputSchema5.shape
|
|
654
|
+
};
|
|
930
655
|
}
|
|
931
|
-
async function getFileInfoLocalMode(
|
|
656
|
+
async function getFileInfoLocalMode(input) {
|
|
657
|
+
const { path: path2 } = input;
|
|
932
658
|
const validatedPath = await validatePath(path2);
|
|
933
659
|
if (!existsSync5(validatedPath)) {
|
|
934
660
|
throw new Error(`File or directory ${path2} does not exist`);
|
|
@@ -963,10 +689,11 @@ async function getFileInfoLocalMode(path2) {
|
|
|
963
689
|
}
|
|
964
690
|
};
|
|
965
691
|
}
|
|
966
|
-
async function getFileInfoStudioMode(
|
|
692
|
+
async function getFileInfoStudioMode(input) {
|
|
693
|
+
const { path: path2 } = input;
|
|
967
694
|
const validatedPath = await validatePath(path2);
|
|
968
695
|
const relativePath = validatedPath.startsWith(workspacePath) ? validatedPath.slice(workspacePath.length + 1) : validatedPath;
|
|
969
|
-
const localInfo = await getFileInfoLocalMode(
|
|
696
|
+
const localInfo = await getFileInfoLocalMode(input);
|
|
970
697
|
const workspaceItem = await findWorkspaceItem(relativePath);
|
|
971
698
|
return {
|
|
972
699
|
...localInfo,
|
|
@@ -994,92 +721,35 @@ import { readdir } from "fs/promises";
|
|
|
994
721
|
import { join } from "path";
|
|
995
722
|
import { dedent as dedent7 } from "ts-dedent";
|
|
996
723
|
import { z as z6 } from "zod";
|
|
997
|
-
var
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
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}
|
|
724
|
+
var inputSchema6 = z6.object({
|
|
725
|
+
path: z6.string()
|
|
726
|
+
});
|
|
727
|
+
function listDirectoryConfig() {
|
|
728
|
+
return {
|
|
729
|
+
title: "List directory",
|
|
730
|
+
description: dedent7`
|
|
731
|
+
Directory content lister with detailed file information.
|
|
1026
732
|
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
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}
|
|
733
|
+
Use cases:
|
|
734
|
+
- Exploring project structure
|
|
735
|
+
- Finding files in a directory
|
|
736
|
+
- Checking directory contents before operations
|
|
737
|
+
- Understanding file organization
|
|
1055
738
|
|
|
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
|
-
}
|
|
739
|
+
How it works:
|
|
740
|
+
- Lists all files and subdirectories in specified directory only
|
|
741
|
+
- Provides file type, size, and modification time
|
|
742
|
+
- Sorts entries alphabetically
|
|
743
|
+
- Handles empty directories
|
|
744
|
+
|
|
745
|
+
Parameters:
|
|
746
|
+
- path: Directory path to list (optional, defaults to workspace root)
|
|
747
|
+
`,
|
|
748
|
+
inputSchema: inputSchema6.shape
|
|
749
|
+
};
|
|
1081
750
|
}
|
|
1082
|
-
async function listDirectoryLocalMode(
|
|
751
|
+
async function listDirectoryLocalMode(input) {
|
|
752
|
+
const { path: path2 } = input;
|
|
1083
753
|
const validatedPath = await validatePath(path2);
|
|
1084
754
|
if (!existsSync6(validatedPath)) {
|
|
1085
755
|
throw new Error(`Directory ${path2} does not exist.`);
|
|
@@ -1114,7 +784,8 @@ async function listDirectoryLocalMode(path2) {
|
|
|
1114
784
|
items
|
|
1115
785
|
};
|
|
1116
786
|
}
|
|
1117
|
-
async function listDirectoryStudioMode(
|
|
787
|
+
async function listDirectoryStudioMode(input) {
|
|
788
|
+
const { path: path2 } = input;
|
|
1118
789
|
const validatedPath = await validatePath(path2);
|
|
1119
790
|
const relativePath = validatedPath.startsWith(workspacePath) ? validatedPath.slice(workspacePath.length + 1) : validatedPath;
|
|
1120
791
|
const workspaceItems = await getWorkspaceItems();
|
|
@@ -1143,94 +814,37 @@ import { mkdir as mkdir2, rename } from "fs/promises";
|
|
|
1143
814
|
import { dirname as dirname3 } from "path";
|
|
1144
815
|
import { dedent as dedent8 } from "ts-dedent";
|
|
1145
816
|
import { z as z7 } from "zod";
|
|
1146
|
-
var
|
|
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 = {
|
|
817
|
+
var inputSchema7 = z7.object({
|
|
1167
818
|
source: z7.string(),
|
|
1168
819
|
destination: z7.string()
|
|
1169
|
-
};
|
|
1170
|
-
function
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
toolName7,
|
|
1176
|
-
`${toolDescription7}
|
|
820
|
+
});
|
|
821
|
+
function moveFileConfig() {
|
|
822
|
+
return {
|
|
823
|
+
title: "Move file",
|
|
824
|
+
description: dedent8`
|
|
825
|
+
File mover for relocating or renaming files within the workspace.
|
|
1177
826
|
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
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}
|
|
827
|
+
Use cases:
|
|
828
|
+
- Renaming files to follow naming conventions
|
|
829
|
+
- Moving files to different directories
|
|
830
|
+
- Organizing project structure
|
|
831
|
+
- Backing up files before modifications
|
|
1206
832
|
|
|
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
|
-
}
|
|
833
|
+
How it works:
|
|
834
|
+
- Validates source file existence
|
|
835
|
+
- Creates destination directory if needed
|
|
836
|
+
- Performs atomic move operation
|
|
837
|
+
- Preserves file permissions and timestamps
|
|
838
|
+
|
|
839
|
+
Parameters:
|
|
840
|
+
- source: Current file path
|
|
841
|
+
- destination: Target file path
|
|
842
|
+
`,
|
|
843
|
+
inputSchema: inputSchema7.shape
|
|
844
|
+
};
|
|
1232
845
|
}
|
|
1233
|
-
async function moveFileLocalMode(
|
|
846
|
+
async function moveFileLocalMode(input) {
|
|
847
|
+
const { source, destination } = input;
|
|
1234
848
|
const validatedSource = await validatePath(source);
|
|
1235
849
|
const validatedDestination = await validatePath(destination);
|
|
1236
850
|
if (!existsSync7(validatedSource)) {
|
|
@@ -1251,7 +865,8 @@ async function moveFileLocalMode(source, destination) {
|
|
|
1251
865
|
destination: validatedDestination
|
|
1252
866
|
};
|
|
1253
867
|
}
|
|
1254
|
-
async function moveFileStudioMode(
|
|
868
|
+
async function moveFileStudioMode(input) {
|
|
869
|
+
const { source, destination } = input;
|
|
1255
870
|
const validatedSource = await validatePath(source);
|
|
1256
871
|
const validatedDestination = await validatePath(destination);
|
|
1257
872
|
const relativeSource = validatedSource.startsWith(workspacePath) ? validatedSource.slice(workspacePath.length + 1) : validatedSource;
|
|
@@ -1280,7 +895,7 @@ async function moveFileStudioMode(source, destination) {
|
|
|
1280
895
|
await updateWorkspaceItem(sourceItem.id, {
|
|
1281
896
|
path: relativeDestination
|
|
1282
897
|
});
|
|
1283
|
-
await moveFileLocalMode(
|
|
898
|
+
await moveFileLocalMode(input);
|
|
1284
899
|
return {
|
|
1285
900
|
source: relativeSource,
|
|
1286
901
|
destination: relativeDestination
|
|
@@ -1294,55 +909,40 @@ import mime3 from "mime-types";
|
|
|
1294
909
|
import { dedent as dedent9 } from "ts-dedent";
|
|
1295
910
|
import { z as z8 } from "zod";
|
|
1296
911
|
var MAX_IMAGE_SIZE = 15 * 1024 * 1024;
|
|
1297
|
-
var
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
912
|
+
var inputSchema8 = z8.object({
|
|
913
|
+
path: z8.string()
|
|
914
|
+
});
|
|
915
|
+
function readImageFileConfig() {
|
|
916
|
+
return {
|
|
917
|
+
title: "Read image file",
|
|
918
|
+
description: dedent9`
|
|
919
|
+
Image file reader that converts images to base64 encoded strings with MIME type validation.
|
|
1305
920
|
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
- Rejects unsupported formats with clear error messages
|
|
921
|
+
Use cases:
|
|
922
|
+
- Loading images for LLM to process
|
|
923
|
+
- Retrieving image data for analysis or display
|
|
924
|
+
- Converting workspace image files to base64 format
|
|
1311
925
|
|
|
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
|
-
});
|
|
926
|
+
How it works:
|
|
927
|
+
- Validates file existence and MIME type before reading
|
|
928
|
+
- Encodes file content as base64 string
|
|
929
|
+
- Returns image data with correct MIME type for proper handling
|
|
930
|
+
- Rejects unsupported formats with clear error messages
|
|
931
|
+
|
|
932
|
+
Supported formats:
|
|
933
|
+
- PNG (image/png)
|
|
934
|
+
- JPEG/JPG (image/jpeg)
|
|
935
|
+
- GIF (image/gif) - static only, animated not supported
|
|
936
|
+
- WebP (image/webp)
|
|
937
|
+
|
|
938
|
+
Notes:
|
|
939
|
+
- Maximum file size: 15MB (larger files will be rejected)
|
|
940
|
+
`,
|
|
941
|
+
inputSchema: inputSchema8.shape
|
|
942
|
+
};
|
|
1344
943
|
}
|
|
1345
|
-
async function readImageFile(
|
|
944
|
+
async function readImageFile(input) {
|
|
945
|
+
const { path: path2 } = input;
|
|
1346
946
|
const validatedPath = await validatePath(path2);
|
|
1347
947
|
const isFile = existsSync8(validatedPath);
|
|
1348
948
|
if (!isFile) {
|
|
@@ -1373,51 +973,36 @@ import mime4 from "mime-types";
|
|
|
1373
973
|
import { dedent as dedent10 } from "ts-dedent";
|
|
1374
974
|
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 = z9.object({
|
|
977
|
+
path: z9.string()
|
|
978
|
+
});
|
|
979
|
+
function readPdfFileConfig() {
|
|
980
|
+
return {
|
|
981
|
+
title: "Read PDF file",
|
|
982
|
+
description: dedent10`
|
|
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
1007
|
const isFile = existsSync9(validatedPath);
|
|
1423
1008
|
if (!isFile) {
|
|
@@ -1443,64 +1028,49 @@ async function readPdfFile(path2) {
|
|
|
1443
1028
|
|
|
1444
1029
|
// src/tools/read-text-file.ts
|
|
1445
1030
|
import { existsSync as existsSync10 } from "fs";
|
|
1446
|
-
import { readFile as
|
|
1031
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
1447
1032
|
import { dedent as dedent11 } from "ts-dedent";
|
|
1448
1033
|
import { z as z10 } from "zod";
|
|
1449
|
-
var
|
|
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
|
|
1464
|
-
|
|
1465
|
-
Common file types:
|
|
1466
|
-
- Source code: .ts, .js, .py, .java, .cpp, etc.
|
|
1467
|
-
- Documentation: .md, .txt, .rst
|
|
1468
|
-
- Configuration: .json, .yaml, .toml, .ini
|
|
1469
|
-
- Data files: .csv, .log, .sql
|
|
1470
|
-
`;
|
|
1471
|
-
var toolInputSchema10 = {
|
|
1034
|
+
var inputSchema10 = z10.object({
|
|
1472
1035
|
path: z10.string(),
|
|
1473
1036
|
from: z10.number().optional().describe("The line number to start reading from."),
|
|
1474
1037
|
to: z10.number().optional().describe("The line number to stop reading at.")
|
|
1475
|
-
};
|
|
1476
|
-
function
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1038
|
+
});
|
|
1039
|
+
function readTextFileConfig() {
|
|
1040
|
+
return {
|
|
1041
|
+
title: "Read text file",
|
|
1042
|
+
description: dedent11`
|
|
1043
|
+
Text file reader with line range support for UTF-8 encoded files.
|
|
1044
|
+
|
|
1045
|
+
Use cases:
|
|
1046
|
+
- Reading source code files for analysis
|
|
1047
|
+
- Extracting specific sections from large text files
|
|
1048
|
+
- Loading configuration or documentation files
|
|
1049
|
+
- Viewing log files or data files
|
|
1050
|
+
|
|
1051
|
+
How it works:
|
|
1052
|
+
- Reads files as UTF-8 encoded text without format validation
|
|
1053
|
+
- Supports partial file reading via line number ranges
|
|
1054
|
+
- Returns content wrapped in JSON with metadata
|
|
1055
|
+
- WARNING: Binary files will cause errors or corrupted output
|
|
1056
|
+
|
|
1057
|
+
Common file types:
|
|
1058
|
+
- Source code: .ts, .js, .py, .java, .cpp, etc.
|
|
1059
|
+
- Documentation: .md, .txt, .rst
|
|
1060
|
+
- Configuration: .json, .yaml, .toml, .ini
|
|
1061
|
+
- Data files: .csv, .log, .sql
|
|
1062
|
+
`,
|
|
1063
|
+
inputSchema: inputSchema10.shape
|
|
1064
|
+
};
|
|
1496
1065
|
}
|
|
1497
|
-
async function readTextFile(
|
|
1066
|
+
async function readTextFile(input) {
|
|
1067
|
+
const { path: path2, from, to } = input;
|
|
1498
1068
|
const validatedPath = await validatePath(path2);
|
|
1499
1069
|
const isFile = existsSync10(validatedPath);
|
|
1500
1070
|
if (!isFile) {
|
|
1501
1071
|
throw new Error(`File ${path2} does not exist.`);
|
|
1502
1072
|
}
|
|
1503
|
-
const fileContent = await
|
|
1073
|
+
const fileContent = await readFile3(validatedPath, "utf-8");
|
|
1504
1074
|
const lines = fileContent.split("\n");
|
|
1505
1075
|
const fromLine = from ?? 0;
|
|
1506
1076
|
const toLine = to ?? lines.length;
|
|
@@ -1517,54 +1087,38 @@ async function readTextFile(path2, from, to) {
|
|
|
1517
1087
|
// src/tools/test-url.ts
|
|
1518
1088
|
import { dedent as dedent12 } from "ts-dedent";
|
|
1519
1089
|
import { z as z11 } from "zod";
|
|
1520
|
-
var
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
- Batch URL validation for link checking
|
|
1090
|
+
var inputSchema11 = z11.object({
|
|
1091
|
+
urls: z11.array(z11.string()).min(1).max(10).describe("Array of URLs to test (max 10 URLs).")
|
|
1092
|
+
});
|
|
1093
|
+
function testUrlConfig() {
|
|
1094
|
+
return {
|
|
1095
|
+
title: "Test URL",
|
|
1096
|
+
description: dedent12`
|
|
1097
|
+
URL tester that validates multiple URLs and extracts metadata.
|
|
1529
1098
|
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1099
|
+
Use cases:
|
|
1100
|
+
- Checking if URLs are accessible before web scraping
|
|
1101
|
+
- Validating URL collections for RAG processes
|
|
1102
|
+
- Extracting page metadata (title, description) for content analysis
|
|
1103
|
+
- Batch URL validation for link checking
|
|
1535
1104
|
|
|
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
|
-
});
|
|
1105
|
+
How it works:
|
|
1106
|
+
- Performs HTTP GET requests to each URL
|
|
1107
|
+
- Returns status code, title, and description for each URL
|
|
1108
|
+
- Handles errors gracefully with timeout protection
|
|
1109
|
+
- Processes URLs in parallel for performance
|
|
1110
|
+
|
|
1111
|
+
Rules:
|
|
1112
|
+
- URLs must be valid HTTP/HTTPS addresses
|
|
1113
|
+
- Maximum 10 URLs per request to prevent abuse
|
|
1114
|
+
- 10 second timeout per URL request
|
|
1115
|
+
- Returns empty title/description if HTML parsing fails
|
|
1116
|
+
`,
|
|
1117
|
+
inputSchema: inputSchema11.shape
|
|
1118
|
+
};
|
|
1566
1119
|
}
|
|
1567
|
-
async function testUrls(
|
|
1120
|
+
async function testUrls(input) {
|
|
1121
|
+
const { urls } = input;
|
|
1568
1122
|
const results = await Promise.allSettled(
|
|
1569
1123
|
urls.map(async (url) => {
|
|
1570
1124
|
try {
|
|
@@ -1641,10 +1195,42 @@ function extractDescription(html) {
|
|
|
1641
1195
|
// src/tools/think.ts
|
|
1642
1196
|
import { dedent as dedent13 } from "ts-dedent";
|
|
1643
1197
|
import { z as z12 } from "zod";
|
|
1644
|
-
var
|
|
1198
|
+
var inputSchema12 = z12.object({
|
|
1645
1199
|
thought: z12.string().describe("Your current thinking step"),
|
|
1646
1200
|
nextThoughtNeeded: z12.boolean().optional().describe("true if you need more thinking, even if at what seemed like the end")
|
|
1647
1201
|
});
|
|
1202
|
+
function thinkConfig() {
|
|
1203
|
+
return {
|
|
1204
|
+
title: "think",
|
|
1205
|
+
description: dedent13`
|
|
1206
|
+
Sequential thinking tool for step-by-step problem analysis and solution development.
|
|
1207
|
+
|
|
1208
|
+
Use cases:
|
|
1209
|
+
- Breaking down complex problems into manageable steps
|
|
1210
|
+
- Developing solutions through iterative reasoning
|
|
1211
|
+
- Analyzing problems that require multiple perspectives
|
|
1212
|
+
- Planning tasks with dependencies and considerations
|
|
1213
|
+
|
|
1214
|
+
How it works:
|
|
1215
|
+
- Records each thinking step sequentially
|
|
1216
|
+
- Maintains thought history for context
|
|
1217
|
+
- Continues until solution is reached
|
|
1218
|
+
- Returns thought count and continuation status
|
|
1219
|
+
|
|
1220
|
+
Parameters:
|
|
1221
|
+
- thought: Current reasoning step or analysis
|
|
1222
|
+
- nextThoughtNeeded: Whether additional thinking is required (optional)
|
|
1223
|
+
|
|
1224
|
+
Best practices:
|
|
1225
|
+
- Use multiple calls for sophisticated reasoning chains
|
|
1226
|
+
- Progress from high-level overview to detailed analysis (drill-down approach)
|
|
1227
|
+
- Capture insights and eureka moments as they emerge
|
|
1228
|
+
- Engage in reflective introspection and constructive self-critique
|
|
1229
|
+
- Set nextThoughtNeeded to false only when fully satisfied with the solution
|
|
1230
|
+
`,
|
|
1231
|
+
inputSchema: inputSchema12.shape
|
|
1232
|
+
};
|
|
1233
|
+
}
|
|
1648
1234
|
var Thought = class {
|
|
1649
1235
|
thoughtHistory = [];
|
|
1650
1236
|
branches = {};
|
|
@@ -1652,65 +1238,19 @@ var Thought = class {
|
|
|
1652
1238
|
const { nextThoughtNeeded } = input;
|
|
1653
1239
|
this.thoughtHistory.push(input);
|
|
1654
1240
|
return {
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
type: "text",
|
|
1658
|
-
text: JSON.stringify({
|
|
1659
|
-
nextThoughtNeeded,
|
|
1660
|
-
thoughtHistoryLength: this.thoughtHistory.length
|
|
1661
|
-
})
|
|
1662
|
-
}
|
|
1663
|
-
]
|
|
1241
|
+
nextThoughtNeeded,
|
|
1242
|
+
thoughtHistoryLength: this.thoughtHistory.length
|
|
1664
1243
|
};
|
|
1665
1244
|
}
|
|
1666
1245
|
};
|
|
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
|
-
);
|
|
1246
|
+
var thought = new Thought();
|
|
1247
|
+
async function think(input) {
|
|
1248
|
+
return thought.processThought(input);
|
|
1705
1249
|
}
|
|
1706
1250
|
|
|
1707
1251
|
// src/tools/todo.ts
|
|
1708
1252
|
import { dedent as dedent14 } from "ts-dedent";
|
|
1709
1253
|
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
1254
|
var Todo = class {
|
|
1715
1255
|
currentTodoId = 0;
|
|
1716
1256
|
todos = [];
|
|
@@ -1722,28 +1262,32 @@ var Todo = class {
|
|
|
1722
1262
|
);
|
|
1723
1263
|
}
|
|
1724
1264
|
if (completedTodos) {
|
|
1725
|
-
this.todos = this.todos.map((
|
|
1726
|
-
...
|
|
1727
|
-
completed:
|
|
1265
|
+
this.todos = this.todos.map((todo2) => ({
|
|
1266
|
+
...todo2,
|
|
1267
|
+
completed: todo2.completed || completedTodos.includes(todo2.id)
|
|
1728
1268
|
}));
|
|
1729
1269
|
}
|
|
1730
1270
|
return {
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1271
|
+
todos: this.todos
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1274
|
+
clearTodo() {
|
|
1275
|
+
this.todos = [];
|
|
1276
|
+
this.currentTodoId = 0;
|
|
1277
|
+
return {
|
|
1278
|
+
todos: this.todos
|
|
1739
1279
|
};
|
|
1740
1280
|
}
|
|
1741
1281
|
};
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1282
|
+
var todoSingleton = new Todo();
|
|
1283
|
+
var todoInputSchema = z13.object({
|
|
1284
|
+
newTodos: z13.array(z13.string()).describe("New todos to add").optional(),
|
|
1285
|
+
completedTodos: z13.array(z13.number()).describe("Todo ids that are completed").optional()
|
|
1286
|
+
});
|
|
1287
|
+
function todoConfig() {
|
|
1288
|
+
return {
|
|
1289
|
+
title: "todo",
|
|
1290
|
+
description: dedent14`
|
|
1747
1291
|
Todo list manager that tracks tasks and their completion status.
|
|
1748
1292
|
|
|
1749
1293
|
Use cases:
|
|
@@ -1760,11 +1304,33 @@ function addTodoTool(server) {
|
|
|
1760
1304
|
- newTodos: Array of task descriptions to add
|
|
1761
1305
|
- completedTodos: Array of todo IDs to mark as completed
|
|
1762
1306
|
`,
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
);
|
|
1307
|
+
inputSchema: todoInputSchema.shape
|
|
1308
|
+
};
|
|
1309
|
+
}
|
|
1310
|
+
async function todo(input) {
|
|
1311
|
+
return todoSingleton.processTodo(input);
|
|
1312
|
+
}
|
|
1313
|
+
var clearTodoInputSchema = z13.object({});
|
|
1314
|
+
function clearTodoConfig() {
|
|
1315
|
+
return {
|
|
1316
|
+
title: "clearTodo",
|
|
1317
|
+
description: dedent14`
|
|
1318
|
+
Clears the todo list.
|
|
1319
|
+
|
|
1320
|
+
Use cases:
|
|
1321
|
+
- Resetting the todo list to an empty state
|
|
1322
|
+
- Starting fresh with a new task list
|
|
1323
|
+
- Clearing all tasks for a new day or project
|
|
1324
|
+
|
|
1325
|
+
How it works:
|
|
1326
|
+
- Resets the todo list to an empty state
|
|
1327
|
+
- Returns an empty todo list
|
|
1328
|
+
`,
|
|
1329
|
+
inputSchema: clearTodoInputSchema.shape
|
|
1330
|
+
};
|
|
1331
|
+
}
|
|
1332
|
+
async function clearTodo(input) {
|
|
1333
|
+
return todoSingleton.clearTodo();
|
|
1768
1334
|
}
|
|
1769
1335
|
|
|
1770
1336
|
// src/tools/write-text-file.ts
|
|
@@ -1774,94 +1340,37 @@ import { mkdir as mkdir3 } from "fs/promises";
|
|
|
1774
1340
|
import { dirname as dirname4 } from "path";
|
|
1775
1341
|
import { dedent as dedent15 } from "ts-dedent";
|
|
1776
1342
|
import { z as z14 } from "zod";
|
|
1777
|
-
var
|
|
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
|
|
1790
|
-
|
|
1791
|
-
Rules:
|
|
1792
|
-
- IF THE FILE ALREADY EXISTS, IT WILL BE OVERWRITTEN
|
|
1793
|
-
- YOU MUST PROVIDE A VALID UTF-8 STRING FOR THE TEXT
|
|
1794
|
-
- 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)
|
|
1795
|
-
- IF YOU WANT TO WRITE MORE THAN 2000 CHARACTERS, USE "appendTextFile" TOOL AFTER THIS ONE
|
|
1796
|
-
`;
|
|
1797
|
-
var toolInputSchema12 = {
|
|
1343
|
+
var toolInputSchema = z14.object({
|
|
1798
1344
|
path: z14.string().describe("Target file path (relative or absolute)."),
|
|
1799
|
-
text: z14.string().min(1).max(
|
|
1800
|
-
};
|
|
1801
|
-
function
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
toolName12,
|
|
1807
|
-
`${toolDescription12}
|
|
1345
|
+
text: z14.string().min(1).max(1e4).describe("Text to write to the file. Max 10000 characters.")
|
|
1346
|
+
});
|
|
1347
|
+
function writeTextFileConfig() {
|
|
1348
|
+
return {
|
|
1349
|
+
title: "writeTextFile",
|
|
1350
|
+
description: dedent15`
|
|
1351
|
+
Text file writer that creates or overwrites files with UTF-8 content.
|
|
1808
1352
|
|
|
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}
|
|
1353
|
+
Use cases:
|
|
1354
|
+
- Creating new configuration files
|
|
1355
|
+
- Writing generated code or documentation
|
|
1356
|
+
- Saving processed data or results
|
|
1357
|
+
- Creating log files or reports
|
|
1837
1358
|
|
|
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
|
-
}
|
|
1359
|
+
How it works:
|
|
1360
|
+
- Writes content as UTF-8 encoded text
|
|
1361
|
+
- Returns success status with file path
|
|
1362
|
+
|
|
1363
|
+
Rules:
|
|
1364
|
+
- IF THE FILE ALREADY EXISTS, IT WILL BE OVERWRITTEN
|
|
1365
|
+
- YOU MUST PROVIDE A VALID UTF-8 STRING FOR THE TEXT
|
|
1366
|
+
- 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)
|
|
1367
|
+
- IF YOU WANT TO WRITE MORE THAN 10,000 CHARACTERS, USE "appendTextFile" TOOL AFTER THIS ONE
|
|
1368
|
+
`,
|
|
1369
|
+
inputSchema: toolInputSchema.shape
|
|
1370
|
+
};
|
|
1863
1371
|
}
|
|
1864
|
-
async function writeTextFileLocalMode(
|
|
1372
|
+
async function writeTextFileLocalMode(input) {
|
|
1373
|
+
const { path: path2, text } = input;
|
|
1865
1374
|
const validatedPath = await validatePath(path2);
|
|
1866
1375
|
if (existsSync11(validatedPath)) {
|
|
1867
1376
|
const stats = statSync8(validatedPath);
|
|
@@ -1877,7 +1386,8 @@ async function writeTextFileLocalMode(path2, text) {
|
|
|
1877
1386
|
text
|
|
1878
1387
|
};
|
|
1879
1388
|
}
|
|
1880
|
-
async function writeTextFileStudioMode(
|
|
1389
|
+
async function writeTextFileStudioMode(input) {
|
|
1390
|
+
const { path: path2, text } = input;
|
|
1881
1391
|
const validatedPath = await validatePath(path2);
|
|
1882
1392
|
const relativePath = validatedPath.startsWith(workspacePath) ? validatedPath.slice(workspacePath.length + 1) : validatedPath;
|
|
1883
1393
|
const existingItem = await findWorkspaceItem(relativePath);
|
|
@@ -1912,7 +1422,7 @@ async function writeTextFileStudioMode(path2, text) {
|
|
|
1912
1422
|
},
|
|
1913
1423
|
text
|
|
1914
1424
|
);
|
|
1915
|
-
await writeTextFileLocalMode(
|
|
1425
|
+
await writeTextFileLocalMode(input);
|
|
1916
1426
|
return {
|
|
1917
1427
|
path: relativePath,
|
|
1918
1428
|
text
|
|
@@ -1934,21 +1444,58 @@ async function main() {
|
|
|
1934
1444
|
}
|
|
1935
1445
|
}
|
|
1936
1446
|
);
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1447
|
+
server.registerTool(
|
|
1448
|
+
"attemptCompletion",
|
|
1449
|
+
attemptCompletionConfig(),
|
|
1450
|
+
resolveToolByMode(attemptCompletion)
|
|
1451
|
+
);
|
|
1452
|
+
server.registerTool("think", thinkConfig(), resolveToolByMode(think));
|
|
1453
|
+
server.registerTool("todo", todoConfig(), resolveToolByMode(todo));
|
|
1454
|
+
server.registerTool("clearTodo", clearTodoConfig(), resolveToolByMode(clearTodo));
|
|
1455
|
+
server.registerTool("testUrl", testUrlConfig(), resolveToolByMode(testUrls));
|
|
1456
|
+
server.registerTool(
|
|
1457
|
+
"getFileInfo",
|
|
1458
|
+
getFileInfoConfig(),
|
|
1459
|
+
resolveToolByMode(getFileInfoLocalMode, getFileInfoStudioMode)
|
|
1460
|
+
);
|
|
1461
|
+
server.registerTool("readTextFile", readTextFileConfig(), resolveToolByMode(readTextFile));
|
|
1462
|
+
server.registerTool("readImageFile", readImageFileConfig(), resolveToolByMode(readImageFile));
|
|
1463
|
+
server.registerTool("readPdfFile", readPdfFileConfig(), resolveToolByMode(readPdfFile));
|
|
1464
|
+
server.registerTool(
|
|
1465
|
+
"writeTextFile",
|
|
1466
|
+
writeTextFileConfig(),
|
|
1467
|
+
resolveToolByMode(writeTextFileLocalMode, writeTextFileStudioMode)
|
|
1468
|
+
);
|
|
1469
|
+
server.registerTool(
|
|
1470
|
+
"appendTextFile",
|
|
1471
|
+
appendTextFileConfig(),
|
|
1472
|
+
resolveToolByMode(appendTextFileLocalMode, appendTextFileStudioMode)
|
|
1473
|
+
);
|
|
1474
|
+
server.registerTool(
|
|
1475
|
+
"editTextFile",
|
|
1476
|
+
editTextFileConfig(),
|
|
1477
|
+
resolveToolByMode(editTextFileLocalMode, editTextFileStudioMode)
|
|
1478
|
+
);
|
|
1479
|
+
server.registerTool(
|
|
1480
|
+
"moveFile",
|
|
1481
|
+
moveFileConfig(),
|
|
1482
|
+
resolveToolByMode(moveFileLocalMode, moveFileStudioMode)
|
|
1483
|
+
);
|
|
1484
|
+
server.registerTool(
|
|
1485
|
+
"deleteFile",
|
|
1486
|
+
deleteFileConfig(),
|
|
1487
|
+
resolveToolByMode(deleteFileLocalMode, deleteFileStudioMode)
|
|
1488
|
+
);
|
|
1489
|
+
server.registerTool(
|
|
1490
|
+
"listDirectory",
|
|
1491
|
+
listDirectoryConfig(),
|
|
1492
|
+
resolveToolByMode(listDirectoryLocalMode, listDirectoryStudioMode)
|
|
1493
|
+
);
|
|
1494
|
+
server.registerTool(
|
|
1495
|
+
"createDirectory",
|
|
1496
|
+
createDirectoryConfig(),
|
|
1497
|
+
resolveToolByMode(createDirectoryLocalMode, createDirectoryStudioMode)
|
|
1498
|
+
);
|
|
1952
1499
|
const transport = new StdioServerTransport();
|
|
1953
1500
|
await server.connect(transport);
|
|
1954
1501
|
});
|