{"record":{"id":"3b2ceddbdf23c320","repo":"affaan-m/ECC","slug":"projectroot-or-reporoot-is-required-for-project-in","errorCode":null,"errorMessage":"projectRoot or repoRoot is required for project install targets","messagePattern":"projectRoot or repoRoot is required for project install targets","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/install-targets/helpers.js","lineNumber":48,"sourceCode":"\n  for (const [prefix, ownerTarget] of Object.entries(PLATFORM_SOURCE_PATH_OWNERS)) {\n    if (normalizedPath === prefix || normalizedPath.startsWith(`${prefix}/`)) {\n      return ownerTarget !== adapterTarget;\n    }\n  }\n\n  return false;\n}\n\nfunction resolveBaseRoot(scope, input = {}) {\n  if (scope === 'home') {\n    return input.homeDir || os.homedir();\n  }\n\n  if (scope === 'project') {\n    const projectRoot = input.projectRoot || input.repoRoot;\n    if (!projectRoot) {\n      throw new Error('projectRoot or repoRoot is required for project install targets');\n    }\n    return projectRoot;\n  }\n\n  throw new Error(`Unsupported install target scope: ${scope}`);\n}\n\nfunction buildValidationIssue(severity, code, message, extra = {}) {\n  return {\n    severity,\n    code,\n    message,\n    ...extra,\n  };\n}\n\nfunction listRelativeFiles(dirPath, prefix = '') {\n  if (!fs.existsSync(dirPath)) {","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/install-targets/helpers.js#L30-L66","documentation":"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.","triggerScenarios":"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'.","commonSituations":"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).","solutions":["Pass projectRoot explicitly: adapter.resolveRoot({ projectRoot: process.cwd() }).","If repoRoot is the intended install root, pass that instead — resolveBaseRoot accepts either.","Switch to a home-scoped adapter (adapter.scope === 'home') if you want to install into ~/.claude etc.","Validate the input shape before planning: assert(input.projectRoot || input.repoRoot)."],"exampleFix":"// before\nadapter.resolveRoot({ homeDir: os.homedir() }); // missing projectRoot for project adapter\n// after\nadapter.resolveRoot({ projectRoot: process.cwd(), homeDir: os.homedir() });","handlingStrategy":"validation","validationCode":"const projectRoot = input.projectRoot || input.repoRoot || process.cwd();\nif (!projectRoot) {\n  throw new Error('Cannot resolve project root — pass projectRoot or run from a project directory.');\n}\nadapter.resolveRoot({ ...input, projectRoot });","typeGuard":"/** @param {unknown} v */\nfunction hasProjectRoot(v) {\n  return typeof v === 'object' && v !== null\n    && (typeof v.projectRoot === 'string' || typeof v.repoRoot === 'string');\n}","tryCatchPattern":null,"preventionTips":["Always pass projectRoot explicitly to project-scoped adapters — never assume cwd.","Confirm the adapter's scope before constructing input: home adapters do not need projectRoot."],"tags":["install","target","filesystem","validation","argument"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}