affaan-m/ECC · error

This install would enable ECC's automatic hook runtime…

Error message

This install would enable ECC's automatic hook runtime, which can:
${formatHookCapabilityDisclosure()}
Confirm 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.

What it means

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.

Solutions

  1. Re-run with explicit consent: append --enable-hooks (install hooks) or --no-hooks (install everything else) to the install command.
  2. Use the interactive flow (ecc install --guided) to record the consent decision properly.
  3. If applying plans programmatically, call withHookConsent(plan, 'enabled') or 'declined' before applyInstallPlan.
  4. Review formatHookCapabilityDisclosure output in the message to make an informed decision before enabling.

Example fix

// before
applyInstallPlan(plan) // plan.hookConsent === null
// after
applyInstallPlan(withHookConsent(plan, 'enabled'))
Defensive patterns

Strategy: validation

Validate before calling

function planNeedsConsent(plan) {
  const materializesHooks = plan.operations?.some(op =>
    /hooks?\//.test(op.destinationPath || '')) ?? false;
  if (materializesHooks && plan.hookConsent !== 'enabled' && plan.hookConsent !== 'declined') {
    throw new Error('Hook runtime in plan but no consent recorded; pass --enable-hooks or --no-hooks');
  }
}

Type guard

function hasHookConsent(plan) {
  return plan.hookConsent === 'enabled' || plan.hookConsent === 'declined';
}

Try / catch

try {
  assertHookConsentReady(plan);
  applyInstallPlan(plan);
} catch (err) {
  if (err.message.includes('automatic hook runtime')) {
    console.error(err.message); // shows disclosure and both flag options
    process.exitCode = 1;
  } else throw err;
}

Prevention

When it happens

Trigger: 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'.

Common situations: 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.

Understand the failure class

Background: "--flag is required" and "must specify" CLI errors: how missing-required-flag validation works and how to fix it — this error's family across 20 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/fec6bfdd7c1938dd. Report an issue: GitHub.

Appendix: source

Thrown at scripts/lib/install/hook-consent.js:184

  }
  if (hookConsent === 'declined') {
    return { ...stripHookRuntimeFromPlan(plan), hookConsent };
  }
  return {
    ...plan,
    hookConsent,
    statePreview: setStatePreviewHookConsent(plan.statePreview, hookConsent),
  };
}

function assertHookConsentReady(plan = {}) {
  if (!planMaterializesHookRuntime(plan)) {
    return;
  }
  if (plan.hookConsent === 'enabled') {
    return;
  }
  throw new Error(
    'This install would enable ECC\'s automatic hook runtime, which can:\n'
      + `${formatHookCapabilityDisclosure()}\n`
      + 'Confirm 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.'
  );
}

module.exports = {
  HOOK_CAPABILITY_GROUPS,
  assertHookConsentReady,
  formatHookCapabilityDisclosure,
  getRecordedHookConsent,
  isHookRuntimeOperation,
  planMaterializesHookRuntime,
  resolveHookConsentFlags,
  withHookConsent,
};

View on GitHub (pinned to 8321021c54)