affaan-m/ECC · error · Error

projectRoot or repoRoot is required for project install targ

Error message

projectRoot or repoRoot is required for project install targets

What it means

Thrown by resolveBaseRoot() in install-targets/helpers.js when scope is 'project' but neither input.projectRoot nor input.repoRoot is provided. Project-scoped adapters (cursor-project, claude-project, opencode project mode, etc.) need a concrete directory to write into — they cannot infer one. The guard exists so the failure surfaces at planning time rather than at file-write time.

Source

Thrown at scripts/lib/install-targets/helpers.js:48

  for (const [prefix, ownerTarget] of Object.entries(PLATFORM_SOURCE_PATH_OWNERS)) {
    if (normalizedPath === prefix || normalizedPath.startsWith(`${prefix}/`)) {
      return ownerTarget !== adapterTarget;
    }
  }

  return false;
}

function resolveBaseRoot(scope, input = {}) {
  if (scope === 'home') {
    return input.homeDir || os.homedir();
  }

  if (scope === 'project') {
    const projectRoot = input.projectRoot || input.repoRoot;
    if (!projectRoot) {
      throw new Error('projectRoot or repoRoot is required for project install targets');
    }
    return projectRoot;
  }

  throw new Error(`Unsupported install target scope: ${scope}`);
}

function buildValidationIssue(severity, code, message, extra = {}) {
  return {
    severity,
    code,
    message,
    ...extra,
  };
}

function listRelativeFiles(dirPath, prefix = '') {
  if (!fs.existsSync(dirPath)) {

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Pass projectRoot explicitly: adapter.resolveRoot({ projectRoot: process.cwd() }).
  2. If repoRoot is the intended install root, pass that instead — resolveBaseRoot accepts either.
  3. Switch to a home-scoped adapter (adapter.scope === 'home') if you want to install into ~/.claude etc.
  4. Validate the input shape before planning: assert(input.projectRoot || input.repoRoot).

Example fix

// before
adapter.resolveRoot({ homeDir: os.homedir() }); // missing projectRoot for project adapter
// after
adapter.resolveRoot({ projectRoot: process.cwd(), homeDir: os.homedir() });
Defensive patterns

Strategy: validation

Validate before calling

const projectRoot = input.projectRoot || input.repoRoot || process.cwd();
if (!projectRoot) {
  throw new Error('Cannot resolve project root — pass projectRoot or run from a project directory.');
}
adapter.resolveRoot({ ...input, projectRoot });

Type guard

/** @param {unknown} v */
function hasProjectRoot(v) {
  return typeof v === 'object' && v !== null
    && (typeof v.projectRoot === 'string' || typeof v.repoRoot === 'string');
}

Prevention

When it happens

Trigger: Calling an adapter's planOperations / resolveRoot with an input object missing both projectRoot and repoRoot. Typically happens when a wrapper forwards only homeDir (intending a home install) but the adapter kind is 'project'.

Common situations: User ran the installer from a context with no cwd (some CI runners); a wrapper script destructured the wrong fields; adapter.kind and the supplied roots disagree (project adapter + home-only input).

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/3b2ceddbdf23c320. Report an issue: GitHub.