@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.js CHANGED
@@ -1,63 +1,14 @@
1
- #!/usr/bin/env node
2
-
3
- // src/index.ts
4
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
- import { Command } from "commander";
7
-
8
- // package.json
9
- var package_default = {
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
- // src/lib/workspace-api.ts
100
- import mime from "mime-types";
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/tools/append-text-file.ts
254
- var toolName = "appendTextFile";
255
- var toolDescription = dedent`
256
- Text file appender for adding content to the end of existing files.
257
-
258
- Use cases:
259
- - Adding entries to log files
260
- - Appending data to CSV or JSON files
261
- - Adding new sections to documentation
262
- - Extending configuration files
263
- - Building files incrementally
264
-
265
- How it works:
266
- - Appends text to the end of an existing file
267
- - Does not modify existing content
268
- - Creates a new line before appending if needed
269
- - Returns the appended file path
270
-
271
- Rules:
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 addAppendTextFileTool(server) {
282
- const mode = getWorkspaceMode();
283
- switch (mode) {
284
- case "local" /* LOCAL */: {
285
- server.tool(
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
- Mode: Local (Local filesystem)`,
290
- toolInputSchema,
291
- async ({ path: path2, text }) => {
292
- try {
293
- return {
294
- content: [
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
- Mode: Studio (Workspace API)`,
319
- toolInputSchema,
320
- async ({ path: path2, text }) => {
321
- try {
322
- return {
323
- content: [
324
- {
325
- type: "text",
326
- text: JSON.stringify(await appendTextFileStudioMode(path2, text))
327
- }
328
- ]
329
- };
330
- } catch (e) {
331
- if (e instanceof Error) {
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(path2, text) {
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(path2, text) {
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(path2, text);
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
- path: relativePath,
384
- text
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
- content: [
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
- // src/tools/create-directory.ts
425
- import { existsSync as existsSync2, statSync as statSync2 } from "fs";
426
- import { mkdir } from "fs/promises";
427
- import { dirname } from "path";
428
- import { dedent as dedent3 } from "ts-dedent";
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
- Mode: Studio (Workspace API)`,
490
- toolInputSchema2,
491
- async ({ path: path2 }) => {
492
- try {
493
- return {
494
- content: [
495
- {
496
- type: "text",
497
- text: JSON.stringify(await createDirectoryStudioMode(path2))
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(path2) {
357
+ async function createDirectoryLocalMode(input) {
358
+ const { path: path2 } = input;
516
359
  const validatedPath = await validatePath(path2);
517
- const exists = existsSync2(validatedPath);
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 (existsSync2(parentDir)) {
523
- const parentStats = statSync2(parentDir);
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(path2) {
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(path2);
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
- // src/tools/delete-file.ts
562
- import { existsSync as existsSync3, statSync as statSync3 } from "fs";
563
- import { unlink } from "fs/promises";
564
- import { dedent as dedent4 } from "ts-dedent";
565
- import { z as z3 } from "zod";
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
- Mode: Studio (Workspace API)`,
626
- toolInputSchema3,
627
- async ({ path: path2 }) => {
628
- try {
629
- return {
630
- content: [
631
- {
632
- type: "text",
633
- text: JSON.stringify(await deleteFileStudioMode(path2))
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(path2) {
429
+ async function deleteFileLocalMode(input) {
430
+ const { path: path2 } = input;
652
431
  const validatedPath = await validatePath(path2);
653
- if (!existsSync3(validatedPath)) {
432
+ if (!existsSync(validatedPath)) {
654
433
  throw new Error(`File ${path2} does not exist.`);
655
434
  }
656
- const stats = statSync3(validatedPath);
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(path2) {
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(path2);
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
- // src/tools/edit-text-file.ts
686
- import { existsSync as existsSync4, statSync as statSync4 } from "fs";
687
- import { readFile as readFile2, writeFile } from "fs/promises";
688
- import { dedent as dedent5 } from "ts-dedent";
689
- import { z as z4 } from "zod";
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
- Mode: Studio (Workspace API)`,
756
- toolInputSchema4,
757
- async ({ path: path2, oldText, newText }) => {
758
- try {
759
- return {
760
- content: [
761
- {
762
- type: "text",
763
- text: JSON.stringify(await editTextFileStudioMode(path2, newText, oldText))
764
- }
765
- ]
766
- };
767
- } catch (e) {
768
- if (e instanceof Error) {
769
- return {
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(path2, newText, oldText) {
497
+ async function editTextFileLocalMode(input) {
498
+ const { path: path2, newText, oldText } = input;
782
499
  const validatedPath = await validatePath(path2);
783
- if (!existsSync4(validatedPath)) {
500
+ if (!existsSync(validatedPath)) {
784
501
  throw new Error(`File ${path2} does not exist.`);
785
502
  }
786
- const stats = statSync4(validatedPath);
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(path2, newText, oldText) {
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(path2, newText, oldText);
525
+ await editTextFileLocalMode(input);
808
526
  await deleteWorkspaceItem(existingItem.id);
809
- const content = await readFile2(validatedPath, "utf-8");
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 readFile2(filePath, "utf-8"));
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
- // src/tools/get-file-info.ts
841
- import { existsSync as existsSync5, statSync as statSync5 } from "fs";
842
- import { basename, dirname as dirname2, extname, resolve } from "path";
843
- import mime2 from "mime-types";
844
- import { dedent as dedent6 } from "ts-dedent";
845
- import { z as z5 } from "zod";
846
- var toolName5 = "getFileInfo";
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 = {
866
- path: z5.string()
867
- };
868
- function addGetFileInfoTool(server) {
869
- const mode = getWorkspaceMode();
870
- switch (mode) {
871
- case "local" /* LOCAL */: {
872
- server.tool(
873
- toolName5,
874
- `${toolDescription5}
875
-
876
- Mode: Local (Local filesystem)`,
877
- toolInputSchema5,
878
- async ({ path: path2 }) => {
879
- try {
880
- return {
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;
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
- case "studio" /* STUDIO */: {
901
- server.tool(
902
- toolName5,
903
- `${toolDescription5}
904
-
905
- Mode: Studio (Workspace API + Local filesystem)`,
906
- toolInputSchema5,
907
- async ({ path: path2 }) => {
908
- try {
909
- return {
910
- content: [
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
- break;
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
- async function getFileInfoLocalMode(path2) {
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 (!existsSync5(validatedPath)) {
689
+ if (!existsSync(validatedPath)) {
934
690
  throw new Error(`File or directory ${path2} does not exist`);
935
691
  }
936
- const stats = statSync5(validatedPath);
692
+ const stats = statSync(validatedPath);
937
693
  const isDirectory = stats.isDirectory();
938
- const mimeType = isDirectory ? null : mime2.lookup(validatedPath) || "application/octet-stream";
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: dirname2(validatedPath),
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(path2) {
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(path2);
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
- // src/tools/list-directory.ts
992
- import { existsSync as existsSync6, statSync as statSync6 } from "fs";
993
- import { readdir } from "fs/promises";
994
- import { join } from "path";
995
- import { dedent as dedent7 } from "ts-dedent";
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
- Mode: Studio (Workspace API)`,
1057
- toolInputSchema6,
1058
- async ({ path: path2 = "." }) => {
1059
- try {
1060
- return {
1061
- content: [
1062
- {
1063
- type: "text",
1064
- text: JSON.stringify(await listDirectoryStudioMode(path2))
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(path2) {
774
+ async function listDirectoryLocalMode(input) {
775
+ const { path: path2 } = input;
1083
776
  const validatedPath = await validatePath(path2);
1084
- if (!existsSync6(validatedPath)) {
777
+ if (!existsSync(validatedPath)) {
1085
778
  throw new Error(`Directory ${path2} does not exist.`);
1086
779
  }
1087
- const stats = statSync6(validatedPath);
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 = statSync6(fullPath);
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(path2) {
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
- // src/tools/move-file.ts
1141
- import { existsSync as existsSync7, statSync as statSync7 } from "fs";
1142
- import { mkdir as mkdir2, rename } from "fs/promises";
1143
- import { dirname as dirname3 } from "path";
1144
- import { dedent as dedent8 } from "ts-dedent";
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
- Mode: Studio (Workspace API)`,
1208
- toolInputSchema7,
1209
- async ({ source, destination }) => {
1210
- try {
1211
- return {
1212
- content: [
1213
- {
1214
- type: "text",
1215
- text: JSON.stringify(await moveFileStudioMode(source, destination))
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(source, destination) {
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 (!existsSync7(validatedSource)) {
866
+ if (!existsSync(validatedSource)) {
1237
867
  throw new Error(`Source file ${source} does not exist.`);
1238
868
  }
1239
- const sourceStats = statSync7(validatedSource);
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 (existsSync7(validatedDestination)) {
873
+ if (existsSync(validatedDestination)) {
1244
874
  throw new Error(`Destination ${destination} already exists.`);
1245
875
  }
1246
- const destDir = dirname3(validatedDestination);
1247
- await mkdir2(destDir, { recursive: true });
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(source, destination) {
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 = dirname3(relativeDestination);
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(source, destination);
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 toolName8 = "readImageFile";
1298
- var toolDescription8 = dedent9`
1299
- Image file reader that converts images to base64 encoded strings with MIME type validation.
1300
-
1301
- Use cases:
1302
- - Loading images for LLM to process
1303
- - Retrieving image data for analysis or display
1304
- - Converting workspace image files to base64 format
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
- How it works:
1307
- - Validates file existence and MIME type before reading
1308
- - Encodes file content as base64 string
1309
- - Returns image data with correct MIME type for proper handling
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
- Supported formats:
1313
- - PNG (image/png)
1314
- - JPEG/JPG (image/jpeg)
1315
- - GIF (image/gif) - static only, animated not supported
1316
- - WebP (image/webp)
1317
-
1318
- Notes:
1319
- - Maximum file size: 15MB (larger files will be rejected)
1320
- `;
1321
- var toolInputSchema8 = {
1322
- path: z8.string()
1323
- };
1324
- function addReadImageFileTool(server) {
1325
- server.tool(toolName8, toolDescription8, toolInputSchema8, async ({ path: path2 }) => {
1326
- try {
1327
- return {
1328
- content: [
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(path2) {
951
+ async function readImageFile(input) {
952
+ const { path: path2 } = input;
1346
953
  const validatedPath = await validatePath(path2);
1347
- const isFile = existsSync8(validatedPath);
954
+ const isFile = existsSync(validatedPath);
1348
955
  if (!isFile) {
1349
956
  throw new Error(`File ${path2} does not exist.`);
1350
957
  }
1351
- const mimeType = mime3.lookup(validatedPath);
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 toolName9 = "readPdfFile";
1377
- var toolDescription9 = dedent10`
1378
- PDF file reader that converts documents to base64 encoded resources.
1379
-
1380
- Use cases:
1381
- - Extracting content from PDF documents for analysis
1382
- - Loading PDF files for LLM processing
1383
- - Retrieving PDF data for conversion or manipulation
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
- How it works:
1386
- - Validates file existence and MIME type (application/pdf)
1387
- - Encodes PDF content as base64 blob
1388
- - Returns as resource type with proper MIME type and URI
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
- Notes:
1392
- - Returns entire PDF content, no page range support
1393
- - Maximum file size: 10MB (larger files will be rejected)
1394
- - Text extraction not performed, returns raw PDF data
1395
- `;
1396
- var toolInputSchema9 = {
1397
- path: z9.string()
1398
- };
1399
- function addReadPdfFileTool(server) {
1400
- server.tool(toolName9, toolDescription9, toolInputSchema9, async ({ path: path2 }) => {
1401
- try {
1402
- return {
1403
- content: [
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(path2) {
1004
+ async function readPdfFile(input) {
1005
+ const { path: path2 } = input;
1421
1006
  const validatedPath = await validatePath(path2);
1422
- const isFile = existsSync9(validatedPath);
1007
+ const isFile = existsSync(validatedPath);
1423
1008
  if (!isFile) {
1424
1009
  throw new Error(`File ${path2} does not exist.`);
1425
1010
  }
1426
- const mimeType = mime4.lookup(validatedPath);
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 stat2(validatedPath);
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
- // src/tools/read-text-file.ts
1445
- import { existsSync as existsSync10 } from "fs";
1446
- import { readFile as readFile4 } from "fs/promises";
1447
- import { dedent as dedent11 } from "ts-dedent";
1448
- import { z as z10 } from "zod";
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
- 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 = {
1472
- path: z10.string(),
1473
- from: z10.number().optional().describe("The line number to start reading from."),
1474
- to: z10.number().optional().describe("The line number to stop reading at.")
1475
- };
1476
- function addReadTextFileTool(server) {
1477
- server.tool(toolName10, toolDescription10, toolInputSchema10, async ({ path: path2, from, to }) => {
1478
- try {
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(path2, from, to) {
1060
+ async function readTextFile(input) {
1061
+ const { path: path2, from, to } = input;
1498
1062
  const validatedPath = await validatePath(path2);
1499
- const isFile = existsSync10(validatedPath);
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 readFile4(validatedPath, "utf-8");
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
- // src/tools/test-url.ts
1518
- import { dedent as dedent12 } from "ts-dedent";
1519
- import { z as z11 } from "zod";
1520
- var toolName11 = "testUrl";
1521
- var toolDescription11 = dedent12`
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
- Rules:
1537
- - URLs must be valid HTTP/HTTPS addresses
1538
- - Maximum 10 URLs per request to prevent abuse
1539
- - 10 second timeout per URL request
1540
- - Returns empty title/description if HTML parsing fails
1541
- `;
1542
- var toolInputSchema11 = {
1543
- urls: z11.array(z11.string()).min(1).max(10).describe("Array of URLs to test (max 10 URLs).")
1544
- };
1545
- function addTestUrlTool(server) {
1546
- server.tool(toolName11, toolDescription11, toolInputSchema11, async ({ urls }) => {
1547
- try {
1548
- const results = await testUrls(urls);
1549
- return {
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(urls) {
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
- // src/tools/think.ts
1642
- import { dedent as dedent13 } from "ts-dedent";
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
- content: [
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
- function addThinkTool(server) {
1668
- const thought = new Thought();
1669
- server.registerTool(
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((todo) => ({
1726
- ...todo,
1727
- completed: todo.completed || completedTodos.includes(todo.id)
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
- content: [
1732
- {
1733
- type: "text",
1734
- text: JSON.stringify({
1735
- todos: this.todos
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
- function addTodoTool(server) {
1743
- const todo = new Todo();
1744
- server.tool(
1745
- "todo",
1746
- dedent14`
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
- TodoInputSchema.shape,
1764
- async (input) => {
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
- // src/tools/write-text-file.ts
1771
- import { existsSync as existsSync11, statSync as statSync8 } from "fs";
1772
- import { writeFile as writeFile2 } from "fs/promises";
1773
- import { mkdir as mkdir3 } from "fs/promises";
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
- 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 = {
1798
- path: z14.string().describe("Target file path (relative or absolute)."),
1799
- text: z14.string().min(1).max(2e3).describe("Text to write to the file. Max 2000 characters.")
1800
- };
1801
- function addWriteTextFileTool(server) {
1802
- const mode = getWorkspaceMode();
1803
- switch (mode) {
1804
- case "local" /* LOCAL */: {
1805
- server.tool(
1806
- toolName12,
1807
- `${toolDescription12}
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
- Mode: Local (Local filesystem)`,
1810
- toolInputSchema12,
1811
- async ({ path: path2, text }) => {
1812
- try {
1813
- return {
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
- Mode: Studio (Workspace API)`,
1839
- toolInputSchema12,
1840
- async ({ path: path2, text }) => {
1841
- try {
1842
- return {
1843
- content: [
1844
- {
1845
- type: "text",
1846
- text: JSON.stringify(await writeTextFileStudioMode(path2, text))
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(path2, text) {
1346
+ async function writeTextFileLocalMode(input) {
1347
+ const { path: path2, text } = input;
1865
1348
  const validatedPath = await validatePath(path2);
1866
- if (existsSync11(validatedPath)) {
1867
- const stats = statSync8(validatedPath);
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 = dirname4(validatedPath);
1873
- await mkdir3(dir, { recursive: true });
1874
- await writeFile2(validatedPath, text, "utf-8");
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(path2, text) {
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(path2, text);
1395
+ await writeTextFileLocalMode(input);
1916
1396
  return {
1917
1397
  path: relativePath,
1918
1398
  text
1919
1399
  };
1920
1400
  }
1921
1401
 
1922
- // src/index.ts
1923
- async function main() {
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