Skip to main content
Glama
t09tanaka

TypeScript Rename Helper

by t09tanaka

planDirectoryMove

Plan a directory move with automatic, recursive import path updates across all files. Returns actionable edit plans and move suggestions without altering the filesystem.

Instructions

Plan directory move with recursive import updates for all contained files. Returns edit plans and file move suggestions without modifying the filesystem.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
projectRootNoOptional base directory for resolving relative paths and limiting tsconfig discovery
workspaceRootNoOptional monorepo root used to search multiple tsconfig.json files
tsconfigPathNoOptional explicit tsconfig.json path for the primary project
oldDirYesAbsolute path or path relative to projectRoot/workspaceRoot of the directory to move
newDirYesAbsolute path or path relative to projectRoot/workspaceRoot of the destination

Implementation Reference

  • Main handler function for planDirectoryMove. It resolves paths, collects TypeScript files under the old directory, uses TypeScript language service to compute import-rename edits for each file, and returns both the text edits and file move suggestions.
    export function planDirectoryMove(
      params: PlanDirectoryMoveParams
    ): PlanDirectoryMoveResult {
      const baseDir = path.resolve(
        params.workspaceRoot ?? params.projectRoot ?? process.cwd()
      );
    
      // 1. パスを絶対パスに正規化
      const oldDirAbs = resolveInputPath(params.oldDir, baseDir);
      const newDirAbs = resolveInputPath(params.newDir, baseDir);
      const targetFiles = collectMoveTargetFiles(oldDirAbs);
      const primaryFilePath = targetFiles[0];
      const candidateContexts = collectWorkspaceTsServices([oldDirAbs, newDirAbs], {
        projectRoot: params.projectRoot,
        workspaceRoot: params.workspaceRoot,
        tsconfigPath: params.tsconfigPath,
        primaryFilePath,
      });
      const editBucket = createEditBucket();
      const fsMoves: PlanDirectoryMoveResult["fsMoves"] = [];
    
      // 2. 各ファイルについて移動先を計算し、各 TS プロジェクトの編集をマージ
      for (const oldFile of targetFiles) {
        const rel = path.relative(oldDirAbs, oldFile);
        const newFile = path.join(newDirAbs, rel);
    
        for (const context of candidateContexts) {
          const fileTextChanges = context.service.getEditsForFileRename(
            oldFile,
            newFile,
            {},
            {}
          );
          addFileTextChanges(editBucket, context.tsModule, fileTextChanges);
        }
    
        fsMoves.push({
          from: oldFile,
          to: newFile,
        });
      }
    
      const edits = toFileTextEdits(editBucket);
    
      return {
        edits,
        fsMoves,
      };
    }
  • Type definitions for PlanDirectoryMoveParams (input) and PlanDirectoryMoveResult (output). Input accepts optional projectRoot/workspaceRoot/tsconfigPath, required oldDir and newDir. Output contains edits (FileTextEdits[]) and fsMoves (FsMove[]).
     * planDirectoryMove の入力パラメータ
     */
    export type PlanDirectoryMoveParams = {
      projectRoot?: string; // 旧互換: 相対パスの解決基準 / ワークスペース境界
      workspaceRoot?: string; // monorepo 全体を探索するためのルート
      tsconfigPath?: string; // 移動元ディレクトリ配下の主 tsconfig を明示したい場合
      oldDir: string; // 元ディレクトリパス
      newDir: string; // 移動先ディレクトリパス
    };
  • src/index.ts:113-147 (registration)
    Tool registration in the TOOLS array with name 'planDirectoryMove', description, and inputSchema with JSON Schema properties for projectRoot, workspaceRoot, tsconfigPath, oldDir, newDir.
      {
        name: "planDirectoryMove",
        description:
          "Plan directory move with recursive import updates for all contained files. Returns edit plans and file move suggestions without modifying the filesystem.",
        inputSchema: {
          type: "object",
          properties: {
            projectRoot: {
              type: "string",
              description:
                "Optional base directory for resolving relative paths and limiting tsconfig discovery",
            },
            workspaceRoot: {
              type: "string",
              description:
                "Optional monorepo root used to search multiple tsconfig.json files",
            },
            tsconfigPath: {
              type: "string",
              description:
                "Optional explicit tsconfig.json path for the primary project",
            },
            oldDir: {
              type: "string",
              description: "Absolute path or path relative to projectRoot/workspaceRoot of the directory to move",
            },
            newDir: {
              type: "string",
              description: "Absolute path or path relative to projectRoot/workspaceRoot of the destination",
            },
          },
          required: ["oldDir", "newDir"],
        },
      },
    ];
  • src/index.ts:205-216 (registration)
    Dispatch logic in the CallToolRequestSchema handler: case 'planDirectoryMove' casts args to PlanDirectoryMoveParams, calls planDirectoryMove(params), and returns JSON-stringified result.
    case "planDirectoryMove": {
      const params = args as unknown as PlanDirectoryMoveParams;
      const result = planDirectoryMove(params);
      return {
        content: [
          {
            type: "text",
            text: JSON.stringify(result, null, 2),
          },
        ],
      };
    }
  • Helper constant MOVE_TARGET_EXTENSIONS (Set of .ts/.tsx/.mts/.cts) and collectMoveTargetFiles function that recursively collects all TypeScript files under a directory, sorted alphabetically.
    const MOVE_TARGET_EXTENSIONS = new Set([".ts", ".tsx", ".mts", ".cts"]);
    
    function collectMoveTargetFiles(directoryPath: string): string[] {
      if (!fs.existsSync(directoryPath) || !fs.statSync(directoryPath).isDirectory()) {
        return [];
      }
    
      const collected: string[] = [];
    
      function visit(currentDirectoryPath: string): void {
        const entries = fs.readdirSync(currentDirectoryPath, { withFileTypes: true });
    
        for (const entry of entries) {
          const entryPath = path.join(currentDirectoryPath, entry.name);
    
          if (entry.isDirectory()) {
            visit(entryPath);
            continue;
          }
    
          if (entry.isFile() && MOVE_TARGET_EXTENSIONS.has(path.extname(entry.name))) {
            collected.push(entryPath);
          }
        }
      }
    
      visit(directoryPath);
      return collected.sort((left, right) => left.localeCompare(right));
    }
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description discloses that the tool plans without modifying the filesystem and returns edit plans and file move suggestions. However, it does not explain how optional parameters (projectRoot, workspaceRoot, tsconfigPath) affect behavior or what happens in edge cases.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two concise sentences: first describes action and key behavior, second clarifies output and effect. No wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema and 5 parameters, the description is moderately complete. It covers purpose and non-destructive nature but omits details about return format (e.g., structure of edit plans) and when optional parameters are needed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 100% schema description coverage, the baseline is 3. The description does not add additional meaning to the parameters beyond what the schema already provides; it only states the overall behavior.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'plan directory move' and the resource (directory) with key behavior: recursive import updates for contained files. It distinguishes itself from siblings (planFileMove moves a single file, planRenameSymbol renames a symbol).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit usage guidance is provided. The description does not mention when to use this tool over planFileMove or planRenameSymbol, nor any prerequisites or context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/t09tanaka/ts-rename-helper-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server