Skip to main content
Glama
codedrop-codes

Refactory

refactory_characterize

Captures behavioral contract by generating characterization tests and golden snapshots before decomposition. Ensures safe refactoring.

Instructions

Generate characterization tests and golden export snapshot BEFORE decomposition. Captures behavioral contract.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
fileYesPath to the module to characterize
outputDirNoWhere to write test + golden files

Implementation Reference

  • The characterize function is the handler for the refactory_characterize tool. It loads the module, captures export types, writes a golden-exports JSON snapshot, and generates a characterization test file.
    function characterize({ file, outputDir }) {
      const absFile = path.resolve(file);
      if (!fs.existsSync(absFile)) {
        throw new Error(`Source file not found: ${absFile}`);
      }
    
      const outDir = path.resolve(outputDir);
      fs.mkdirSync(outDir, { recursive: true });
    
      // Load the module in a child process to avoid side effects (some modules
      // run main() on require or call process.exit). Falls back to empty exports.
      let mod = {};
      try {
        const { execSync } = require("node:child_process");
        const script = `try { const m = require(${JSON.stringify(absFile)}); const e = {}; if (m && typeof m === "object") { for (const [k,v] of Object.entries(m)) e[k] = typeof v; } else if (typeof m === "function") { e["default"] = "function"; } console.log(JSON.stringify(e)); } catch { console.log("{}"); }`;
        const out = execSync(`node -e '${script.replace(/'/g, "'\\''")}'`, { timeout: 10000, encoding: "utf8" }).trim();
        mod = JSON.parse(out || "{}");
      } catch {
        // Module has side effects or can't be loaded — use static analysis fallback
        const source = fs.readFileSync(absFile, "utf8");
        const exportsMatch = source.match(/module\.exports\s*=\s*\{([^}]+)\}/);
        if (exportsMatch) {
          for (const name of exportsMatch[1].match(/\w+/g) || []) {
            mod[name] = "unknown";
          }
        }
      }
      const exports = typeof mod === "object" ? mod : {};
      const exportCount = Object.keys(exports).length;
    
      // Write golden-exports JSON
      const baseName = path.basename(absFile, path.extname(absFile));
      const goldenFile = path.join(outDir, `${baseName}.golden-exports.json`);
      const golden = {
        file: absFile,
        exports,
        exportCount,
        generatedAt: new Date().toISOString(),
      };
      fs.writeFileSync(goldenFile, JSON.stringify(golden, null, 2) + "\n");
    
      // Generate node:test file
      const testFile = path.join(outDir, `${baseName}.characterize.test.js`);
      const testSource = generateTest(absFile, exports, exportCount, goldenFile);
      fs.writeFileSync(testFile, testSource);
    
      return { testFile, goldenFile, exportCount, exports };
    }
  • Input schema definition for refactory_characterize tool: requires 'file' (path to module), optional 'outputDir'.
    {
      name: "refactory_characterize",
      description: "Generate characterization tests and golden export snapshot BEFORE decomposition. Captures behavioral contract.",
      inputSchema: {
        type: "object",
        properties: {
          file: { type: "string", description: "Path to the module to characterize" },
          outputDir: { type: "string", description: "Where to write test + golden files" },
        },
        required: ["file"],
      },
    },
  • src/server.js:129-140 (registration)
    Tool registration entry in the TOOLS array listing refactory_characterize with its name, description, and inputSchema.
    {
      name: "refactory_characterize",
      description: "Generate characterization tests and golden export snapshot BEFORE decomposition. Captures behavioral contract.",
      inputSchema: {
        type: "object",
        properties: {
          file: { type: "string", description: "Path to the module to characterize" },
          outputDir: { type: "string", description: "Where to write test + golden files" },
        },
        required: ["file"],
      },
    },
  • src/server.js:209-209 (registration)
    Switch-case dispatching 'refactory_characterize' to the characterize() handler in the CallToolRequestSchema handler.
    case "refactory_characterize": result = await characterize(args); break;
  • Helper functions: captureExports (maps export keys to typeof), freshRequire (clears require cache), generateTest (generates node:test file), and esc (string escape).
    function captureExports(mod) {
      const result = {};
      if (mod == null) return result;
    
      // If the module is a plain function (module.exports = fn), record as "default"
      if (typeof mod === "function") {
        result["default"] = "function";
        // Also capture any properties attached to the function
        for (const key of Object.keys(mod)) {
          result[key] = typeof mod[key];
        }
        return result;
      }
    
      if (typeof mod !== "object") {
        result["default"] = typeof mod;
        return result;
      }
    
      for (const key of Object.keys(mod)) {
        result[key] = typeof mod[key];
      }
      return result;
    }
    
    /** Require a module without cache (for post-decomposition re-check). */
    function freshRequire(absPath) {
      delete require.cache[require.resolve(absPath)];
      return require(absPath);
    }
    
    /** Generate a node:test characterization test file as a string. */
    function generateTest(absFile, exports, exportCount, goldenFile) {
      const relModule = JSON.stringify(absFile);
      const relGolden = JSON.stringify(goldenFile);
    
      const lines = [
        `"use strict";`,
        `const { describe, it } = require("node:test");`,
        `const assert = require("node:assert/strict");`,
        `const fs = require("node:fs");`,
        ``,
        `describe("Characterization: ${path.basename(absFile)}", () => {`,
        `  const mod = require(${relModule});`,
        `  const golden = JSON.parse(fs.readFileSync(${relGolden}, "utf8"));`,
        ``,
        `  it("export count matches golden snapshot (${exportCount})", () => {`,
        `    const keys = typeof mod === "object" && mod !== null`,
        `      ? Object.keys(mod)`,
        `      : typeof mod === "function" ? ["default", ...Object.keys(mod)] : ["default"];`,
        `    assert.equal(keys.length, golden.exportCount,`,
        `      \`Export count changed: expected \${golden.exportCount}, got \${keys.length}. ` +
          `Missing or added exports after refactoring.\`);`,
        `  });`,
        ``,
      ];
    
      // Per-export type assertions
      for (const [name, type] of Object.entries(exports)) {
        const accessor = name === "default" ? "mod" : `mod[${JSON.stringify(name)}]`;
        lines.push(
          `  it("export ${esc(name)} is ${type}", () => {`,
          `    assert.equal(typeof ${accessor}, ${JSON.stringify(type)});`,
          `  });`,
          ``
        );
      }
    
      // Callable check for function exports
      const fnExports = Object.entries(exports).filter(([, t]) => t === "function");
      if (fnExports.length > 0) {
        lines.push(`  describe("function exports are callable", () => {`);
        for (const [name] of fnExports) {
          const accessor = name === "default" ? "mod" : `mod[${JSON.stringify(name)}]`;
          lines.push(
            `    it("${esc(name)} does not throw on typeof check", () => {`,
            `      assert.equal(typeof ${accessor}, "function");`,
            `      assert.ok(${accessor}.length >= 0, "has an arity");`,
            `    });`,
            ``
          );
        }
        lines.push(`  });`);
      }
    
      lines.push(`});`, ``);
      return lines.join("\n");
    }
    
    /** Escape a string for safe inclusion in a JS string literal. */
    function esc(s) {
      return s.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
    }
    
    module.exports = { characterize, verifyExports };
Behavior2/5

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

No annotations are provided, so the description bears full responsibility for behavioral disclosure. It fails to mention side effects (e.g., file creation), required permissions, or error handling, leaving significant gaps.

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 sentences, no wasted words, front-loaded with action. Highly concise and direct.

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?

With no output schema, the description omits what the tool returns (e.g., success indicator, file paths). While purpose is clear, behavioral details are insufficient for complete understanding.

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?

Input schema coverage is 100%, and both parameters have descriptions. The tool description adds no meaningful detail beyond what the schema already provides, so baseline 3 is appropriate.

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 tool generates characterization tests and golden export snapshots before decomposition, using specific verbs and resources. It distinguishes itself from siblings like refactory_analyze and refactory_decompose.

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

Usage Guidelines4/5

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

The description explicitly says 'BEFORE decomposition', providing clear timing context. However, it does not mention when not to use or list alternative tools, missing some guidance.

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/codedrop-codes/refactory'

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