{"record":{"id":"bce964a1bad8f6ef","repo":"affaan-m/ECC","slug":"choose-at-least-one-guided-harness-claude-codex","errorCode":null,"errorMessage":"Choose at least one guided harness: Claude, Codex, or Kimi.","messagePattern":"Choose at least one guided harness: Claude, Codex, or Kimi\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/multi-harness-setup.js","lineNumber":23,"sourceCode":"const os = require('os');\nconst path = require('path');\n\nconst { assertSafeInstallOperation } = require('./install/apply');\nconst { assertWithinTrustedRoot, realpathNearestExisting } = require('./path-safety');\n\nconst VALID_CLAUDE_SCOPES = new Set(['user', 'project', 'local']);\nconst VALID_CLAUDE_HOOKS = new Set(['off', 'minimal', 'standard', 'strict']);\nconst VALID_PROFILES = new Set(['minimal', 'core', 'developer', 'security', 'research', 'full']);\n\nfunction catalogHelpers() {\n  return require('./harness-capabilities');\n}\n\nfunction normalizeGuidedInstallRequest(input = {}) {\n  const { normalizeHarnessSelection } = catalogHelpers();\n  const harnesses = normalizeHarnessSelection(input.harnesses || []);\n  if (harnesses.length === 0) {\n    throw new Error('Choose at least one guided harness: Claude, Codex, or Kimi.');\n  }\n\n  const includesClaude = harnesses.includes('claude');\n  const includesKimi = harnesses.includes('kimi');\n  if (!includesClaude && (input.claudeScope !== undefined || input.claudeHooks !== undefined)) {\n    throw new Error('Claude scope and hook options require Claude to be selected.');\n  }\n  if (!includesKimi && input.profile !== undefined) {\n    throw new Error('The managed install profile requires Kimi to be selected.');\n  }\n\n  const claudeScope = includesClaude ? (input.claudeScope || 'user') : undefined;\n  const claudeHooks = includesClaude ? (input.claudeHooks || 'standard') : undefined;\n  const profile = includesKimi ? (input.profile || 'core') : undefined;\n  if (claudeScope && !VALID_CLAUDE_SCOPES.has(claudeScope)) {\n    throw new Error(`Invalid Claude scope: ${claudeScope}`);\n  }\n  if (claudeHooks && !VALID_CLAUDE_HOOKS.has(claudeHooks)) {","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/multi-harness-setup.js#L5-L41","documentation":"normalizeGuidedInstallRequest requires at least one harness to install for. It runs the raw input.harnesses through normalizeHarnessSelection (which dedupes, lowercases, and validates against the supported set); if the result is empty — either because nothing was passed or because every entry was unrecognized and filtered out — it throws. This is the top-level guard for the multi-harness installer; without a selected harness there is nothing to do.","triggerScenarios":"Calling normalizeGuidedInstallRequest (or the guided install CLI that wraps it) with no harnesses argument, an empty array, or an array of values none of which normalize to 'claude', 'codex', or 'kimi'.","commonSituations":"CLI invocation without a --harness flag; passing harnesses under the wrong key (e.g. harness instead of harnesses); typos like 'claudecode' or 'Kimi' with case-sensitivity issues in a custom wrapper; a UI defaulting to an empty selection.","solutions":["Pass at least one valid harness: harnesses: ['claude'], ['codex'], ['kimi'], or any combination.","Check the spelling and casing expected by normalizeHarnessSelection (typically lowercase identifiers, not display names).","If driving the CLI, supply the harness flag explicitly (e.g. --harness claude).","Confirm the input object shape — the function reads input.harnesses, not input.harness or input.target."],"exampleFix":"// before\nnormalizeGuidedInstallRequest({}); // throws\n// after\nnormalizeGuidedInstallRequest({ harnesses: ['claude'] });\n// or multiple\nnormalizeGuidedInstallRequest({ harnesses: ['claude', 'kimi'] });","handlingStrategy":"validation","validationCode":"const { normalizeHarnessSelection } = require('./scripts/lib/harness-capabilities');\nfunction assertHasHarness(input = {}) {\n  const harnesses = normalizeHarnessSelection(input.harnesses || []);\n  if (harnesses.length === 0) {\n    throw new Error('Choose at least one guided harness: Claude, Codex, or Kimi.');\n  }\n  return harnesses;\n}\n// before normalizeGuidedInstallRequest:\nassertHasHarness(input);","typeGuard":"function hasHarnessSelection(input = {}) {\n  return Array.isArray(input.harnesses) && input.harnesses.length > 0;\n}","tryCatchPattern":"try { normalizeGuidedInstallRequest(input); }\ncatch (error) {\n  if (/at least one guided harness/i.test(error.message)) {\n    console.error('Pass harnesses: [\\'claude\\'], [\\'codex\\'], [\\'kimi\\'], or a combination.');\n    return;\n  }\n  throw error;\n}","preventionTips":["Always pass at least one harness in the harnesses array.","Use the exact lowercase identifiers: claude, codex, kimi.","Validate the request shape before calling normalize.","Default the harnesses field in the UI to a non-empty selection."],"tags":["multi-harness-setup","validation","configuration","installer"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}