All files / src/cli/plugin runtime.ts

100% Statements 60/60
93.54% Branches 29/31
100% Functions 6/6
100% Lines 52/52

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 882x 2x 2x 2x                 2x 6x 22x 6x 6x         8x 60x 8x 7x 7x 5x 5x 4x   6x   6x 15x 25x 25x       5x 20x 20x 20x 15x 1x     6x 9x 9x 8x 6x   6x 12x 12x 6x   6x 5x 5x 5x 5x 4x     6x 6x 1x 5x 5x 5x                     5x 2x 4x      
import { createRequire } from 'node:module';
import { existsSync, readFileSync, readdirSync, realpathSync } from 'node:fs';
import { dirname, join, posix } from 'node:path';
import { compareCodeUnits } from './zip';
 
interface RuntimePackage {
  name: string;
  version: string;
  dependencies?: Record<string, string>;
}
 
/** Include installed production dependencies only, preserving conflicting versions at their consumer. */
export function collectRuntime(root: string, files: Map<string, Buffer>): void {
  const metadata = (dir: string): RuntimePackage =>
    JSON.parse(readFileSync(join(dir, 'package.json'), 'utf8')) as RuntimePackage;
  const occupied = new Map<string, string>();
  const dependencyDirectory = (
    requireFrom: ReturnType<typeof createRequire>,
    name: string,
  ): string => {
    // Package exports need not provide a root entry point (the MCP SDK does not).
    const lookup = requireFrom.resolve.paths(name) ?? [];
    const packageJson = lookup.map((dir) => join(dir, name, 'package.json')).find(existsSync);
    if (!packageJson) throw new Error(`Cannot find runtime dependency ${name}`);
    let dependency = dirname(packageJson);
    while (!existsSync(join(dependency, 'package.json')) || metadata(dependency).name !== name) {
      const next = dirname(dependency);
      if (next === dependency) throw new Error(`Cannot find runtime dependency ${name}`);
      dependency = next;
    }
    return realpathSync(dependency);
  };
  const copy = (source: string, target: string): void => {
    for (const entry of readdirSync(source, { withFileTypes: true })) {
      const legal = /^(?:licen[sc]e|notice|copying)(?:[.-]|$)/i.test(entry.name);
      if (
        ['node_modules', '.git', 'test', 'tests', 'coverage', 'docs'].includes(entry.name) ||
        (!legal && /\.(?:map|md|ts|mts|cts)$/i.test(entry.name))
      )
        continue;
      const from = join(source, entry.name);
      const to = posix.join(target, entry.name);
      if (entry.isDirectory()) copy(from, to);
      else if (entry.isFile()) files.set(to, readFileSync(from));
      else throw new Error(`Runtime package contains an unsupported symbolic link: ${entry.name}`);
    }
  };
  const dependencies = (source: string, parent: string): void => {
    const requireFrom = createRequire(join(source, 'package.json'));
    for (const name of Object.keys(metadata(source).dependencies ?? {}).sort(compareCodeUnits)) {
      const dependency = dependencyDirectory(requireFrom, name);
      let ancestor = parent;
      let installed: string | undefined;
      for (;;) {
        installed = occupied.get(posix.join(ancestor, 'node_modules', name));
        if (installed || ancestor === 'runtime') break;
        ancestor = posix.dirname(ancestor);
      }
      if (installed === dependency) continue;
      const shared = posix.join('runtime/node_modules', name);
      const target = occupied.has(shared) ? posix.join(parent, 'node_modules', name) : shared;
      occupied.set(target, dependency);
      copy(dependency, target);
      dependencies(dependency, target);
    }
  };
  const compiled = join(root, 'dist', 'src');
  if (!existsSync(join(compiled, 'plugin', 'main.js')))
    throw new Error('Build the core package before building the local plugin.');
  copy(compiled, 'runtime/src');
  const version = metadata(root).version;
  files.set(
    'runtime/package.json',
    Buffer.from(
      JSON.stringify({
        name: 'gitlab-mcp-plugin-runtime',
        version,
        private: true,
        type: 'commonjs',
      }),
    ),
  );
  dependencies(root, 'runtime');
  for (const name of ['LICENSE', 'NOTICE']) {
    if (existsSync(join(root, name))) files.set(`runtime/${name}`, readFileSync(join(root, name)));
  }
}