{"record":{"id":"fec6bfdd7c1938dd","repo":"affaan-m/ECC","slug":"this-install-would-enable-ecc-s-automatic-hook-runtime-which","errorCode":null,"errorMessage":"This install would enable ECC's automatic hook runtime, which can:\n${formatHookCapabilityDisclosure()}\nConfirm with --enable-hooks to install it, or --no-hooks to install everything else without the hook runtime. The guided installer (ecc install --guided) collects this choice interactively.","messagePattern":"This install would enable ECC's automatic hook runtime, which can:\n(.+?)\nConfirm with --enable-hooks to install it, or --no-hooks to install everything else without the hook runtime\\. The guided installer \\(ecc install --guided\\) collects this choice interactively\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"scripts/lib/install/hook-consent.js","lineNumber":184,"sourceCode":"  }\n  if (hookConsent === 'declined') {\n    return { ...stripHookRuntimeFromPlan(plan), hookConsent };\n  }\n  return {\n    ...plan,\n    hookConsent,\n    statePreview: setStatePreviewHookConsent(plan.statePreview, hookConsent),\n  };\n}\n\nfunction assertHookConsentReady(plan = {}) {\n  if (!planMaterializesHookRuntime(plan)) {\n    return;\n  }\n  if (plan.hookConsent === 'enabled') {\n    return;\n  }\n  throw new Error(\n    'This install would enable ECC\\'s automatic hook runtime, which can:\\n'\n      + `${formatHookCapabilityDisclosure()}\\n`\n      + 'Confirm with --enable-hooks to install it, or --no-hooks to install '\n      + 'everything else without the hook runtime. The guided installer '\n      + '(ecc install --guided) collects this choice interactively.'\n  );\n}\n\nmodule.exports = {\n  HOOK_CAPABILITY_GROUPS,\n  assertHookConsentReady,\n  formatHookCapabilityDisclosure,\n  getRecordedHookConsent,\n  isHookRuntimeOperation,\n  planMaterializesHookRuntime,\n  resolveHookConsentFlags,\n  withHookConsent,\n};","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/install/hook-consent.js#L166-L202","documentation":"assertHookConsentReady() is a safety gate called before applying an install plan. If the plan materializes the ECC hook runtime but hookConsent is not 'enabled', it throws this explicit consent-required error listing what hooks can do and how to opt in or out. Installing hooks without an affirmative decision is deliberately blocked.","triggerScenarios":"Calling applyInstallPlan(plan) with a plan whose modules include the hook runtime while plan.hookConsent is null (no decision recorded); building a plan without running the guided consent flow; clearing/replacing hookConsent with a default that is not 'enabled'.","commonSituations":"Non-interactive CI installs that skip the guided prompt; custom scripts calling applyInstallPlan directly on hand-built plans; upgrading where hook modules newly joined the selected module set.","solutions":["Re-run with explicit consent: append --enable-hooks (install hooks) or --no-hooks (install everything else) to the install command.","Use the interactive flow (ecc install --guided) to record the consent decision properly.","If applying plans programmatically, call withHookConsent(plan, 'enabled') or 'declined' before applyInstallPlan.","Review formatHookCapabilityDisclosure output in the message to make an informed decision before enabling."],"exampleFix":"// before\napplyInstallPlan(plan) // plan.hookConsent === null\n// after\napplyInstallPlan(withHookConsent(plan, 'enabled'))","handlingStrategy":"validation","validationCode":"function planNeedsConsent(plan) {\n  const materializesHooks = plan.operations?.some(op =>\n    /hooks?\\//.test(op.destinationPath || '')) ?? false;\n  if (materializesHooks && plan.hookConsent !== 'enabled' && plan.hookConsent !== 'declined') {\n    throw new Error('Hook runtime in plan but no consent recorded; pass --enable-hooks or --no-hooks');\n  }\n}","typeGuard":"function hasHookConsent(plan) {\n  return plan.hookConsent === 'enabled' || plan.hookConsent === 'declined';\n}","tryCatchPattern":"try {\n  assertHookConsentReady(plan);\n  applyInstallPlan(plan);\n} catch (err) {\n  if (err.message.includes('automatic hook runtime')) {\n    console.error(err.message); // shows disclosure and both flag options\n    process.exitCode = 1;\n  } else throw err;\n}","preventionTips":["Always record a consent decision on plans before applyInstallPlan (via withHookConsent or the guided installer).","In CI, pass --enable-hooks or --no-hooks explicitly since there is no interactive prompt.","Run assertHookConsentReady yourself in pre-flight checks to fail early with a clear message.","Review the hook capability disclosure once and standardize your team's default flag."],"tags":["hooks","consent","installer"],"backgroundTag":"missing-required-flag","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}