jackwener/OpenCLI · error

Could not find opencli entrypoint under ${projectRoot}. Expe

Error message

Could not find opencli entrypoint under ${projectRoot}. Expected built entry from package.json or src/main.ts.

What it means

opencli failed to locate its own entrypoint script when resolving how to launch the CLI for a project. It looks for a built entry declared in package.json (bin/main) and falls back to src/main.ts; if neither exists under the resolved projectRoot, it throws. This is a project-structure/setup error, not a runtime logic bug.

Source

Thrown at src/cli.ts:3737

} = {}): BrowserVerifyInvocation {
  const platform = opts.platform ?? process.platform;
  const fileExists = opts.fileExists ?? fs.existsSync;
  const readFile = opts.readFile ?? ((filePath: string) => fs.readFileSync(filePath, 'utf-8'));
  const projectRoot = opts.projectRoot ?? findPackageRoot(CLI_FILE, fileExists);

  for (const builtEntry of getBuiltEntryCandidates(projectRoot, readFile)) {
    if (fileExists(builtEntry)) {
      return {
        binary: process.execPath,
        args: [builtEntry],
        cwd: projectRoot,
      };
    }
  }

  const sourceEntry = path.join(projectRoot, 'src', 'main.ts');
  if (!fileExists(sourceEntry)) {
    throw new Error(`Could not find opencli entrypoint under ${projectRoot}. Expected built entry from package.json or src/main.ts.`);
  }

  const localTsxBin = path.join(projectRoot, 'node_modules', '.bin', platform === 'win32' ? 'tsx.cmd' : 'tsx');
  if (fileExists(localTsxBin)) {
    return {
      binary: localTsxBin,
      args: [sourceEntry],
      cwd: projectRoot,
      ...(platform === 'win32' ? { shell: true } : {}),
    };
  }

  return {
    binary: platform === 'win32' ? 'npx.cmd' : 'npx',
    args: ['tsx', sourceEntry],
    cwd: projectRoot,
    ...(platform === 'win32' ? { shell: true } : {}),
  };

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Run the command from the project root that actually contains src/main.ts (or the built entry).
  2. Build the project so the entrypoint declared in package.json exists.
  3. Verify package.json declares the correct main/bin entrypoint path.
  4. Create or restore src/main.ts if it was renamed or deleted.

Example fix

// before (package.json, no entry declared)
{
  "name": "my-cli"
}
// after
{
  "name": "my-cli",
  "main": "dist/main.js",
  "bin": { "opencli": "dist/main.js" }
}
Defensive patterns

Strategy: validation

Validate before calling

import fs from 'node:fs';
import path from 'node:path';
const projectRoot = process.cwd();
const hasBuiltEntry = (() => {
  const pkg = JSON.parse(fs.readFileSync(path.join(projectRoot, 'package.json'), 'utf8'));
  return Boolean(pkg.main || pkg.bin);
})();
if (!hasBuiltEntry && !fs.existsSync(path.join(projectRoot, 'src', 'main.ts'))) {
  throw new Error(`No opencli entrypoint under ${projectRoot}; build the project or add src/main.ts`);
}

Type guard

function hasEntrypoint(root: string): boolean {
  return fs.existsSync(path.join(root, 'src', 'main.ts')) || fs.existsSync(path.join(root, 'package.json'));
}

Try / catch

try {
  await opencli.run(args);
} catch (e) {
  if (e.message.includes('Could not find opencli entrypoint')) {
    console.error('Run from the project root and build first: npm run build');
    process.exitCode = 1;
  } else throw e;
}

Prevention

When it happens

Trigger: Running an opencli command in a directory (or against a projectRoot) that has no src/main.ts and no package.json entry pointing at a built entrypoint; running from a parent/child directory so projectRoot resolves to the wrong folder; a monorepo where main.ts lives in a package subdirectory.

Common situations: Cloning a repo and running the CLI before building; invoking opencli from the wrong working directory; renaming or moving main.ts without updating package.json; fresh checkout missing generated/built files.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/dc338f637ea6377b. Report an issue: GitHub.