@uzysjung/agent-harness 26.130.0 → 26.131.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/dist/index.js +100 -70
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../node_modules/sisteransi/src/index.js","../src/index.ts","../src/cli.ts","../node_modules/cac/dist/index.js","../package.json","../src/commands/install.ts","../src/cli-targets.ts","../src/design.ts","../src/installer.ts","../src/antigravity/transform.ts","../src/codex/agents-md.ts","../src/codex/skills.ts","../src/fs-ops.ts","../src/project-claude-merge.ts","../src/ci-scaffold.ts","../src/codex/opt-in.ts","../src/codex/trust-entry.ts","../src/codex/transform.ts","../src/codex/config-toml.ts","../src/env-files.ts","../src/external-installer.ts","../src/install-log.ts","../src/mcp-merge.ts","../src/opencode/transform.ts","../src/opencode/agents-md.ts","../src/opencode/commands.ts","../src/opencode/opencode-json.ts","../src/settings-merge.ts","../src/update-mode.ts","../src/commands/install-render.ts","../src/preset-recommend.ts","../src/commands/list.ts","../src/commands/uninstall.ts","../src/uninstall-interactive.ts","../node_modules/fast-wrap-ansi/src/main.ts","../node_modules/fast-string-width/dist/index.js","../node_modules/fast-string-truncated-width/dist/index.js","../node_modules/fast-string-truncated-width/dist/utils.js","../node_modules/@clack/core/src/utils/cursor.ts","../node_modules/@clack/core/src/utils/settings.ts","../node_modules/@clack/core/src/utils/string.ts","../node_modules/@clack/core/src/utils/index.ts","../node_modules/@clack/core/src/prompts/prompt.ts","../node_modules/@clack/core/src/prompts/autocomplete.ts","../node_modules/@clack/core/src/prompts/confirm.ts","../node_modules/@clack/core/src/prompts/date.ts","../node_modules/@clack/core/src/prompts/group-multiselect.ts","../node_modules/@clack/core/src/prompts/multi-line.ts","../node_modules/@clack/core/src/prompts/multi-select.ts","../node_modules/@clack/core/src/prompts/password.ts","../node_modules/@clack/core/src/prompts/select.ts","../node_modules/@clack/core/src/prompts/select-key.ts","../node_modules/@clack/core/src/prompts/text.ts","../node_modules/node_modules/.pnpm/is-unicode-supported@1.3.0/node_modules/is-unicode-supported/index.js","../node_modules/@clack/prompts/src/common.ts","../node_modules/@clack/prompts/src/limit-options.ts","../node_modules/@clack/prompts/src/autocomplete.ts","../node_modules/@clack/prompts/src/box.ts","../node_modules/@clack/prompts/src/confirm.ts","../node_modules/@clack/prompts/src/date.ts","../node_modules/@clack/prompts/src/group.ts","../node_modules/@clack/prompts/src/group-multi-select.ts","../node_modules/@clack/prompts/src/log.ts","../node_modules/@clack/prompts/src/messages.ts","../node_modules/@clack/prompts/src/multi-line.ts","../node_modules/@clack/prompts/src/multi-select.ts","../node_modules/@clack/prompts/src/note.ts","../node_modules/@clack/prompts/src/password.ts","../node_modules/@clack/prompts/src/path.ts","../node_modules/@clack/prompts/src/spinner.ts","../node_modules/@clack/prompts/src/progress-bar.ts","../node_modules/@clack/prompts/src/select.ts","../node_modules/@clack/prompts/src/select-key.ts","../node_modules/@clack/prompts/src/stream.ts","../node_modules/@clack/prompts/src/task.ts","../node_modules/@clack/prompts/src/task-log.ts","../node_modules/@clack/prompts/src/text.ts","../src/interactive.ts","../src/prompts.ts","../src/router.ts","../src/wizard-steps.ts","../src/state.ts"],"sourcesContent":["'use strict';\n\nconst ESC = '\\x1B';\nconst CSI = `${ESC}[`;\nconst beep = '\\u0007';\n\nconst cursor = {\n to(x, y) {\n if (!y) return `${CSI}${x + 1}G`;\n return `${CSI}${y + 1};${x + 1}H`;\n },\n move(x, y) {\n let ret = '';\n\n if (x < 0) ret += `${CSI}${-x}D`;\n else if (x > 0) ret += `${CSI}${x}C`;\n\n if (y < 0) ret += `${CSI}${-y}A`;\n else if (y > 0) ret += `${CSI}${y}B`;\n\n return ret;\n },\n up: (count = 1) => `${CSI}${count}A`,\n down: (count = 1) => `${CSI}${count}B`,\n forward: (count = 1) => `${CSI}${count}C`,\n backward: (count = 1) => `${CSI}${count}D`,\n nextLine: (count = 1) => `${CSI}E`.repeat(count),\n prevLine: (count = 1) => `${CSI}F`.repeat(count),\n left: `${CSI}G`,\n hide: `${CSI}?25l`,\n show: `${CSI}?25h`,\n save: `${ESC}7`,\n restore: `${ESC}8`\n}\n\nconst scroll = {\n up: (count = 1) => `${CSI}S`.repeat(count),\n down: (count = 1) => `${CSI}T`.repeat(count)\n}\n\nconst erase = {\n screen: `${CSI}2J`,\n up: (count = 1) => `${CSI}1J`.repeat(count),\n down: (count = 1) => `${CSI}J`.repeat(count),\n line: `${CSI}2K`,\n lineEnd: `${CSI}K`,\n lineStart: `${CSI}1K`,\n lines(count) {\n let clear = '';\n for (let i = 0; i < count; i++)\n clear += this.line + (i < count - 1 ? cursor.up() : '');\n if (count)\n clear += cursor.left;\n return clear;\n }\n}\n\nmodule.exports = { cursor, scroll, erase, beep };\n","import { buildCli } from \"./cli.js\";\n\nconst cli = buildCli();\ncli.parse(process.argv);\n","import { cac } from \"cac\";\nimport packageJson from \"../package.json\";\nimport { type ExecuteSpecDeps, executeSpec, registerInstallCommand } from \"./commands/install.js\";\nimport { registerListCommand } from \"./commands/list.js\";\nimport { registerUninstallCommand } from \"./commands/uninstall.js\";\nimport { type InteractiveResult, runInteractive } from \"./interactive.js\";\n\n// v26.72.1 — CalVer 정합 (cli --version / package.json / git tag 단일 버전).\n// v26.82.1 — 하드코딩 → package.json derive. v26.82.0 ship 때 package.json 만 bump 되고\n// 본 상수(26.81.0)가 남아 npm 게시 패키지가 --version 을 거짓 보고 (수동 동기화 주석은\n// 못 막는다는 본 repo 3번째 증명) → 빌드 시 esbuild 가 값 인라인, 동기화 자체를 소멸.\nexport const VERSION: string = packageJson.version;\n\nexport type Cli = ReturnType<typeof cac>;\n\nexport interface DefaultActionDeps {\n log?: (msg: string) => void;\n err?: (msg: string) => void;\n exit?: (code: number) => never;\n run?: (cwd: string) => Promise<InteractiveResult>;\n /** Override the install pipeline + report renderer (used by tests). */\n execute?: (spec: NonNullable<InteractiveResult[\"spec\"]>, deps: ExecuteSpecDeps) => void;\n}\n\n/**\n * Default action — runs the interactive flow, then executes the install\n * pipeline with the captured spec. Mirrors the `install` flag-mode command's\n * post-install report.\n */\nexport async function defaultAction(deps: DefaultActionDeps = {}): Promise<void> {\n const log = deps.log ?? console.log;\n const err = deps.err ?? console.error;\n /* v8 ignore next — process.exit default. tests 는 exit 주입. */\n const exit = deps.exit ?? ((code: number) => process.exit(code) as never);\n const run = deps.run ?? ((cwd: string) => runInteractive(cwd));\n const execute = deps.execute ?? executeSpec;\n\n const result = await run(process.cwd());\n if (!result.ok) {\n if (result.message) {\n err(result.message);\n }\n // exit-code mapping: no-tty=2; cancelled/exit/disabled/declined=0\n exit(result.reason === \"no-tty\" ? 2 : 0);\n return;\n }\n if (!result.spec) {\n err(\"Internal error: interactive returned ok=true without a spec.\");\n exit(1);\n return;\n }\n // v26.63.0 — wizard 모드 표시. install header (TARGET 등) 출력 skip → Step 5 sub-section 으로 자연 흐름.\n const execDeps: import(\"./commands/install.js\").ExecuteSpecDeps = {\n log,\n err,\n exit,\n fromWizard: true,\n };\n if (result.mode) execDeps.mode = result.mode;\n execute(result.spec, execDeps);\n}\n\nexport function buildCli(): Cli {\n const cli = cac(\"agent-harness\");\n\n cli.help();\n cli.version(VERSION);\n\n registerInstallCommand(cli);\n registerListCommand(cli);\n registerUninstallCommand(cli);\n\n cli\n .command(\"\", \"Interactive installer (state detection + prompts)\")\n /* v8 ignore next — cac action callback. defaultAction 자체는 별도 tests 로 검증. */\n .action(() => defaultAction());\n\n return cli;\n}\n","//#region node_modules/.pnpm/mri@1.2.0/node_modules/mri/lib/index.mjs\nfunction toArr(any) {\n\treturn any == null ? [] : Array.isArray(any) ? any : [any];\n}\nfunction toVal(out, key, val, opts) {\n\tvar x, old = out[key], nxt = !!~opts.string.indexOf(key) ? val == null || val === true ? \"\" : String(val) : typeof val === \"boolean\" ? val : !!~opts.boolean.indexOf(key) ? val === \"false\" ? false : val === \"true\" || (out._.push((x = +val, x * 0 === 0) ? x : val), !!val) : (x = +val, x * 0 === 0) ? x : val;\n\tout[key] = old == null ? nxt : Array.isArray(old) ? old.concat(nxt) : [old, nxt];\n}\nfunction lib_default(args, opts) {\n\targs = args || [];\n\topts = opts || {};\n\tvar k, arr, arg, name, val, out = { _: [] };\n\tvar i = 0, j = 0, idx = 0, len = args.length;\n\tconst alibi = opts.alias !== void 0;\n\tconst strict = opts.unknown !== void 0;\n\tconst defaults = opts.default !== void 0;\n\topts.alias = opts.alias || {};\n\topts.string = toArr(opts.string);\n\topts.boolean = toArr(opts.boolean);\n\tif (alibi) for (k in opts.alias) {\n\t\tarr = opts.alias[k] = toArr(opts.alias[k]);\n\t\tfor (i = 0; i < arr.length; i++) (opts.alias[arr[i]] = arr.concat(k)).splice(i, 1);\n\t}\n\tfor (i = opts.boolean.length; i-- > 0;) {\n\t\tarr = opts.alias[opts.boolean[i]] || [];\n\t\tfor (j = arr.length; j-- > 0;) opts.boolean.push(arr[j]);\n\t}\n\tfor (i = opts.string.length; i-- > 0;) {\n\t\tarr = opts.alias[opts.string[i]] || [];\n\t\tfor (j = arr.length; j-- > 0;) opts.string.push(arr[j]);\n\t}\n\tif (defaults) for (k in opts.default) {\n\t\tname = typeof opts.default[k];\n\t\tarr = opts.alias[k] = opts.alias[k] || [];\n\t\tif (opts[name] !== void 0) {\n\t\t\topts[name].push(k);\n\t\t\tfor (i = 0; i < arr.length; i++) opts[name].push(arr[i]);\n\t\t}\n\t}\n\tconst keys = strict ? Object.keys(opts.alias) : [];\n\tfor (i = 0; i < len; i++) {\n\t\targ = args[i];\n\t\tif (arg === \"--\") {\n\t\t\tout._ = out._.concat(args.slice(++i));\n\t\t\tbreak;\n\t\t}\n\t\tfor (j = 0; j < arg.length; j++) if (arg.charCodeAt(j) !== 45) break;\n\t\tif (j === 0) out._.push(arg);\n\t\telse if (arg.substring(j, j + 3) === \"no-\") {\n\t\t\tname = arg.substring(j + 3);\n\t\t\tif (strict && !~keys.indexOf(name)) return opts.unknown(arg);\n\t\t\tout[name] = false;\n\t\t} else {\n\t\t\tfor (idx = j + 1; idx < arg.length; idx++) if (arg.charCodeAt(idx) === 61) break;\n\t\t\tname = arg.substring(j, idx);\n\t\t\tval = arg.substring(++idx) || i + 1 === len || (\"\" + args[i + 1]).charCodeAt(0) === 45 || args[++i];\n\t\t\tarr = j === 2 ? [name] : name;\n\t\t\tfor (idx = 0; idx < arr.length; idx++) {\n\t\t\t\tname = arr[idx];\n\t\t\t\tif (strict && !~keys.indexOf(name)) return opts.unknown(\"-\".repeat(j) + name);\n\t\t\t\ttoVal(out, name, idx + 1 < arr.length || val, opts);\n\t\t\t}\n\t\t}\n\t}\n\tif (defaults) {\n\t\tfor (k in opts.default) if (out[k] === void 0) out[k] = opts.default[k];\n\t}\n\tif (alibi) for (k in out) {\n\t\tarr = opts.alias[k] || [];\n\t\twhile (arr.length > 0) out[arr.shift()] = out[k];\n\t}\n\treturn out;\n}\n\n//#endregion\n//#region src/utils.ts\nfunction removeBrackets(v) {\n\treturn v.replace(/[<[].+/, \"\").trim();\n}\nfunction findAllBrackets(v) {\n\tconst ANGLED_BRACKET_RE_GLOBAL = /<([^>]+)>/g;\n\tconst SQUARE_BRACKET_RE_GLOBAL = /\\[([^\\]]+)\\]/g;\n\tconst res = [];\n\tconst parse = (match) => {\n\t\tlet variadic = false;\n\t\tlet value = match[1];\n\t\tif (value.startsWith(\"...\")) {\n\t\t\tvalue = value.slice(3);\n\t\t\tvariadic = true;\n\t\t}\n\t\treturn {\n\t\t\trequired: match[0].startsWith(\"<\"),\n\t\t\tvalue,\n\t\t\tvariadic\n\t\t};\n\t};\n\tlet angledMatch;\n\twhile (angledMatch = ANGLED_BRACKET_RE_GLOBAL.exec(v)) res.push(parse(angledMatch));\n\tlet squareMatch;\n\twhile (squareMatch = SQUARE_BRACKET_RE_GLOBAL.exec(v)) res.push(parse(squareMatch));\n\treturn res;\n}\nfunction getMriOptions(options) {\n\tconst result = {\n\t\talias: {},\n\t\tboolean: []\n\t};\n\tfor (const [index, option] of options.entries()) {\n\t\tif (option.names.length > 1) result.alias[option.names[0]] = option.names.slice(1);\n\t\tif (option.isBoolean) if (option.negated) {\n\t\t\tif (!options.some((o, i) => {\n\t\t\t\treturn i !== index && o.names.some((name) => option.names.includes(name)) && typeof o.required === \"boolean\";\n\t\t\t})) result.boolean.push(option.names[0]);\n\t\t} else result.boolean.push(option.names[0]);\n\t}\n\treturn result;\n}\nfunction findLongest(arr) {\n\treturn arr.sort((a, b) => {\n\t\treturn a.length > b.length ? -1 : 1;\n\t})[0];\n}\nfunction padRight(str, length) {\n\treturn str.length >= length ? str : `${str}${\" \".repeat(length - str.length)}`;\n}\nfunction camelcase(input) {\n\treturn input.replaceAll(/([a-z])-([a-z])/g, (_, p1, p2) => {\n\t\treturn p1 + p2.toUpperCase();\n\t});\n}\nfunction setDotProp(obj, keys, val) {\n\tlet current = obj;\n\tfor (let i = 0; i < keys.length; i++) {\n\t\tconst key = keys[i];\n\t\tif (i === keys.length - 1) {\n\t\t\tcurrent[key] = val;\n\t\t\treturn;\n\t\t}\n\t\tif (current[key] == null) {\n\t\t\tconst nextKeyIsArrayIndex = +keys[i + 1] > -1;\n\t\t\tcurrent[key] = nextKeyIsArrayIndex ? [] : {};\n\t\t}\n\t\tcurrent = current[key];\n\t}\n}\nfunction setByType(obj, transforms) {\n\tfor (const key of Object.keys(transforms)) {\n\t\tconst transform = transforms[key];\n\t\tif (transform.shouldTransform) {\n\t\t\tobj[key] = [obj[key]].flat();\n\t\t\tif (typeof transform.transformFunction === \"function\") obj[key] = obj[key].map(transform.transformFunction);\n\t\t}\n\t}\n}\nfunction getFileName(input) {\n\tconst m = /([^\\\\/]+)$/.exec(input);\n\treturn m ? m[1] : \"\";\n}\nfunction camelcaseOptionName(name) {\n\treturn name.split(\".\").map((v, i) => {\n\t\treturn i === 0 ? camelcase(v) : v;\n\t}).join(\".\");\n}\nvar CACError = class extends Error {\n\tconstructor(message) {\n\t\tsuper(message);\n\t\tthis.name = \"CACError\";\n\t\tif (typeof Error.captureStackTrace !== \"function\") this.stack = new Error(message).stack;\n\t}\n};\n\n//#endregion\n//#region src/option.ts\nvar Option = class {\n\trawName;\n\tdescription;\n\t/** Option name */\n\tname;\n\t/** Option name and aliases */\n\tnames;\n\tisBoolean;\n\trequired;\n\tconfig;\n\tnegated;\n\tconstructor(rawName, description, config) {\n\t\tthis.rawName = rawName;\n\t\tthis.description = description;\n\t\tthis.config = Object.assign({}, config);\n\t\trawName = rawName.replaceAll(\".*\", \"\");\n\t\tthis.negated = false;\n\t\tthis.names = removeBrackets(rawName).split(\",\").map((v) => {\n\t\t\tlet name = v.trim().replace(/^-{1,2}/, \"\");\n\t\t\tif (name.startsWith(\"no-\")) {\n\t\t\t\tthis.negated = true;\n\t\t\t\tname = name.replace(/^no-/, \"\");\n\t\t\t}\n\t\t\treturn camelcaseOptionName(name);\n\t\t}).sort((a, b) => a.length > b.length ? 1 : -1);\n\t\tthis.name = this.names.at(-1);\n\t\tif (this.negated && this.config.default == null) this.config.default = true;\n\t\tif (rawName.includes(\"<\")) this.required = true;\n\t\telse if (rawName.includes(\"[\")) this.required = false;\n\t\telse this.isBoolean = true;\n\t}\n};\n\n//#endregion\n//#region src/runtime.ts\nlet runtimeProcessArgs;\nlet runtimeInfo;\nif (typeof process !== \"undefined\") {\n\tlet runtimeName;\n\tif (typeof Deno !== \"undefined\" && typeof Deno.version?.deno === \"string\") runtimeName = \"deno\";\n\telse if (typeof Bun !== \"undefined\" && typeof Bun.version === \"string\") runtimeName = \"bun\";\n\telse runtimeName = \"node\";\n\truntimeInfo = `${process.platform}-${process.arch} ${runtimeName}-${process.version}`;\n\truntimeProcessArgs = process.argv;\n} else if (typeof navigator === \"undefined\") runtimeInfo = `unknown`;\nelse runtimeInfo = `${navigator.platform} ${navigator.userAgent}`;\n\n//#endregion\n//#region src/command.ts\nvar Command = class {\n\trawName;\n\tdescription;\n\tconfig;\n\tcli;\n\toptions;\n\taliasNames;\n\tname;\n\targs;\n\tcommandAction;\n\tusageText;\n\tversionNumber;\n\texamples;\n\thelpCallback;\n\tglobalCommand;\n\tconstructor(rawName, description, config = {}, cli) {\n\t\tthis.rawName = rawName;\n\t\tthis.description = description;\n\t\tthis.config = config;\n\t\tthis.cli = cli;\n\t\tthis.options = [];\n\t\tthis.aliasNames = [];\n\t\tthis.name = removeBrackets(rawName);\n\t\tthis.args = findAllBrackets(rawName);\n\t\tthis.examples = [];\n\t}\n\tusage(text) {\n\t\tthis.usageText = text;\n\t\treturn this;\n\t}\n\tallowUnknownOptions() {\n\t\tthis.config.allowUnknownOptions = true;\n\t\treturn this;\n\t}\n\tignoreOptionDefaultValue() {\n\t\tthis.config.ignoreOptionDefaultValue = true;\n\t\treturn this;\n\t}\n\tversion(version, customFlags = \"-v, --version\") {\n\t\tthis.versionNumber = version;\n\t\tthis.option(customFlags, \"Display version number\");\n\t\treturn this;\n\t}\n\texample(example) {\n\t\tthis.examples.push(example);\n\t\treturn this;\n\t}\n\t/**\n\t* Add a option for this command\n\t* @param rawName Raw option name(s)\n\t* @param description Option description\n\t* @param config Option config\n\t*/\n\toption(rawName, description, config) {\n\t\tconst option = new Option(rawName, description, config);\n\t\tthis.options.push(option);\n\t\treturn this;\n\t}\n\talias(name) {\n\t\tthis.aliasNames.push(name);\n\t\treturn this;\n\t}\n\taction(callback) {\n\t\tthis.commandAction = callback;\n\t\treturn this;\n\t}\n\t/**\n\t* Check if a command name is matched by this command\n\t* @param name Command name\n\t*/\n\tisMatched(name) {\n\t\treturn this.name === name || this.aliasNames.includes(name);\n\t}\n\tget isDefaultCommand() {\n\t\treturn this.name === \"\" || this.aliasNames.includes(\"!\");\n\t}\n\tget isGlobalCommand() {\n\t\treturn this instanceof GlobalCommand;\n\t}\n\t/**\n\t* Check if an option is registered in this command\n\t* @param name Option name\n\t*/\n\thasOption(name) {\n\t\tname = name.split(\".\")[0];\n\t\treturn this.options.find((option) => {\n\t\t\treturn option.names.includes(name);\n\t\t});\n\t}\n\toutputHelp() {\n\t\tconst { name, commands } = this.cli;\n\t\tconst { versionNumber, options: globalOptions, helpCallback } = this.cli.globalCommand;\n\t\tlet sections = [{ body: `${name}${versionNumber ? `/${versionNumber}` : \"\"}` }];\n\t\tsections.push({\n\t\t\ttitle: \"Usage\",\n\t\t\tbody: ` $ ${name} ${this.usageText || this.rawName}`\n\t\t});\n\t\tif ((this.isGlobalCommand || this.isDefaultCommand) && commands.length > 0) {\n\t\t\tconst longestCommandName = findLongest(commands.map((command) => command.rawName));\n\t\t\tsections.push({\n\t\t\t\ttitle: \"Commands\",\n\t\t\t\tbody: commands.map((command) => {\n\t\t\t\t\treturn ` ${padRight(command.rawName, longestCommandName.length)} ${command.description}`;\n\t\t\t\t}).join(\"\\n\")\n\t\t\t}, {\n\t\t\t\ttitle: `For more info, run any command with the \\`--help\\` flag`,\n\t\t\t\tbody: commands.map((command) => ` $ ${name}${command.name === \"\" ? \"\" : ` ${command.name}`} --help`).join(\"\\n\")\n\t\t\t});\n\t\t}\n\t\tlet options = this.isGlobalCommand ? globalOptions : [...this.options, ...globalOptions || []];\n\t\tif (!this.isGlobalCommand && !this.isDefaultCommand) options = options.filter((option) => option.name !== \"version\");\n\t\tif (options.length > 0) {\n\t\t\tconst longestOptionName = findLongest(options.map((option) => option.rawName));\n\t\t\tsections.push({\n\t\t\t\ttitle: \"Options\",\n\t\t\t\tbody: options.map((option) => {\n\t\t\t\t\treturn ` ${padRight(option.rawName, longestOptionName.length)} ${option.description} ${option.config.default === void 0 ? \"\" : `(default: ${option.config.default})`}`;\n\t\t\t\t}).join(\"\\n\")\n\t\t\t});\n\t\t}\n\t\tif (this.examples.length > 0) sections.push({\n\t\t\ttitle: \"Examples\",\n\t\t\tbody: this.examples.map((example) => {\n\t\t\t\tif (typeof example === \"function\") return example(name);\n\t\t\t\treturn example;\n\t\t\t}).join(\"\\n\")\n\t\t});\n\t\tif (helpCallback) sections = helpCallback(sections) || sections;\n\t\tconsole.info(sections.map((section) => {\n\t\t\treturn section.title ? `${section.title}:\\n${section.body}` : section.body;\n\t\t}).join(\"\\n\\n\"));\n\t}\n\toutputVersion() {\n\t\tconst { name } = this.cli;\n\t\tconst { versionNumber } = this.cli.globalCommand;\n\t\tif (versionNumber) console.info(`${name}/${versionNumber} ${runtimeInfo}`);\n\t}\n\tcheckRequiredArgs() {\n\t\tconst minimalArgsCount = this.args.filter((arg) => arg.required).length;\n\t\tif (this.cli.args.length < minimalArgsCount) throw new CACError(`missing required args for command \\`${this.rawName}\\``);\n\t}\n\t/**\n\t* Check if the parsed options contain any unknown options\n\t*\n\t* Exit and output error when true\n\t*/\n\tcheckUnknownOptions() {\n\t\tconst { options, globalCommand } = this.cli;\n\t\tif (!this.config.allowUnknownOptions) {\n\t\t\tfor (const name of Object.keys(options)) if (name !== \"--\" && !this.hasOption(name) && !globalCommand.hasOption(name)) throw new CACError(`Unknown option \\`${name.length > 1 ? `--${name}` : `-${name}`}\\``);\n\t\t}\n\t}\n\t/**\n\t* Check if the required string-type options exist\n\t*/\n\tcheckOptionValue() {\n\t\tconst { options: parsedOptions, globalCommand } = this.cli;\n\t\tconst options = [...globalCommand.options, ...this.options];\n\t\tfor (const option of options) {\n\t\t\tconst value = parsedOptions[option.name.split(\".\")[0]];\n\t\t\tif (option.required) {\n\t\t\t\tconst hasNegated = options.some((o) => o.negated && o.names.includes(option.name));\n\t\t\t\tif (value === true || value === false && !hasNegated) throw new CACError(`option \\`${option.rawName}\\` value is missing`);\n\t\t\t}\n\t\t}\n\t}\n\t/**\n\t* Check if the number of args is more than expected\n\t*/\n\tcheckUnusedArgs() {\n\t\tconst maximumArgsCount = this.args.some((arg) => arg.variadic) ? Infinity : this.args.length;\n\t\tif (maximumArgsCount < this.cli.args.length) throw new CACError(`Unused args: ${this.cli.args.slice(maximumArgsCount).map((arg) => `\\`${arg}\\``).join(\", \")}`);\n\t}\n};\nvar GlobalCommand = class extends Command {\n\tconstructor(cli) {\n\t\tsuper(\"@@global@@\", \"\", {}, cli);\n\t}\n};\n\n//#endregion\n//#region src/cac.ts\nvar CAC = class extends EventTarget {\n\t/** The program name to display in help and version message */\n\tname;\n\tcommands;\n\tglobalCommand;\n\tmatchedCommand;\n\tmatchedCommandName;\n\t/**\n\t* Raw CLI arguments\n\t*/\n\trawArgs;\n\t/**\n\t* Parsed CLI arguments\n\t*/\n\targs;\n\t/**\n\t* Parsed CLI options, camelCased\n\t*/\n\toptions;\n\tshowHelpOnExit;\n\tshowVersionOnExit;\n\t/**\n\t* @param name The program name to display in help and version message\n\t*/\n\tconstructor(name = \"\") {\n\t\tsuper();\n\t\tthis.name = name;\n\t\tthis.commands = [];\n\t\tthis.rawArgs = [];\n\t\tthis.args = [];\n\t\tthis.options = {};\n\t\tthis.globalCommand = new GlobalCommand(this);\n\t\tthis.globalCommand.usage(\"<command> [options]\");\n\t}\n\t/**\n\t* Add a global usage text.\n\t*\n\t* This is not used by sub-commands.\n\t*/\n\tusage(text) {\n\t\tthis.globalCommand.usage(text);\n\t\treturn this;\n\t}\n\t/**\n\t* Add a sub-command\n\t*/\n\tcommand(rawName, description, config) {\n\t\tconst command = new Command(rawName, description || \"\", config, this);\n\t\tcommand.globalCommand = this.globalCommand;\n\t\tthis.commands.push(command);\n\t\treturn command;\n\t}\n\t/**\n\t* Add a global CLI option.\n\t*\n\t* Which is also applied to sub-commands.\n\t*/\n\toption(rawName, description, config) {\n\t\tthis.globalCommand.option(rawName, description, config);\n\t\treturn this;\n\t}\n\t/**\n\t* Show help message when `-h, --help` flags appear.\n\t*\n\t*/\n\thelp(callback) {\n\t\tthis.globalCommand.option(\"-h, --help\", \"Display this message\");\n\t\tthis.globalCommand.helpCallback = callback;\n\t\tthis.showHelpOnExit = true;\n\t\treturn this;\n\t}\n\t/**\n\t* Show version number when `-v, --version` flags appear.\n\t*\n\t*/\n\tversion(version, customFlags = \"-v, --version\") {\n\t\tthis.globalCommand.version(version, customFlags);\n\t\tthis.showVersionOnExit = true;\n\t\treturn this;\n\t}\n\t/**\n\t* Add a global example.\n\t*\n\t* This example added here will not be used by sub-commands.\n\t*/\n\texample(example) {\n\t\tthis.globalCommand.example(example);\n\t\treturn this;\n\t}\n\t/**\n\t* Output the corresponding help message\n\t* When a sub-command is matched, output the help message for the command\n\t* Otherwise output the global one.\n\t*\n\t*/\n\toutputHelp() {\n\t\tif (this.matchedCommand) this.matchedCommand.outputHelp();\n\t\telse this.globalCommand.outputHelp();\n\t}\n\t/**\n\t* Output the version number.\n\t*\n\t*/\n\toutputVersion() {\n\t\tthis.globalCommand.outputVersion();\n\t}\n\tsetParsedInfo({ args, options }, matchedCommand, matchedCommandName) {\n\t\tthis.args = args;\n\t\tthis.options = options;\n\t\tif (matchedCommand) this.matchedCommand = matchedCommand;\n\t\tif (matchedCommandName) this.matchedCommandName = matchedCommandName;\n\t\treturn this;\n\t}\n\tunsetMatchedCommand() {\n\t\tthis.matchedCommand = void 0;\n\t\tthis.matchedCommandName = void 0;\n\t}\n\t/**\n\t* Parse argv\n\t*/\n\tparse(argv, { run = true } = {}) {\n\t\tif (!argv) {\n\t\t\tif (!runtimeProcessArgs) throw new Error(\"No argv provided and runtime process argv is not available.\");\n\t\t\targv = runtimeProcessArgs;\n\t\t}\n\t\tthis.rawArgs = argv;\n\t\tif (!this.name) this.name = argv[1] ? getFileName(argv[1]) : \"cli\";\n\t\tlet shouldParse = true;\n\t\tfor (const command of this.commands) {\n\t\t\tconst parsed = this.mri(argv.slice(2), command);\n\t\t\tconst commandName = parsed.args[0];\n\t\t\tif (command.isMatched(commandName)) {\n\t\t\t\tshouldParse = false;\n\t\t\t\tconst parsedInfo = {\n\t\t\t\t\t...parsed,\n\t\t\t\t\targs: parsed.args.slice(1)\n\t\t\t\t};\n\t\t\t\tthis.setParsedInfo(parsedInfo, command, commandName);\n\t\t\t\tthis.dispatchEvent(new CustomEvent(`command:${commandName}`, { detail: command }));\n\t\t\t}\n\t\t}\n\t\tif (shouldParse) {\n\t\t\tfor (const command of this.commands) if (command.isDefaultCommand) {\n\t\t\t\tshouldParse = false;\n\t\t\t\tconst parsed = this.mri(argv.slice(2), command);\n\t\t\t\tthis.setParsedInfo(parsed, command);\n\t\t\t\tthis.dispatchEvent(new CustomEvent(\"command:!\", { detail: command }));\n\t\t\t}\n\t\t}\n\t\tif (shouldParse) {\n\t\t\tconst parsed = this.mri(argv.slice(2));\n\t\t\tthis.setParsedInfo(parsed);\n\t\t}\n\t\tif (this.options.help && this.showHelpOnExit) {\n\t\t\tthis.outputHelp();\n\t\t\trun = false;\n\t\t\tthis.unsetMatchedCommand();\n\t\t}\n\t\tif (this.options.version && this.showVersionOnExit && this.matchedCommandName == null) {\n\t\t\tthis.outputVersion();\n\t\t\trun = false;\n\t\t\tthis.unsetMatchedCommand();\n\t\t}\n\t\tconst parsedArgv = {\n\t\t\targs: this.args,\n\t\t\toptions: this.options\n\t\t};\n\t\tif (run) this.runMatchedCommand();\n\t\tif (!this.matchedCommand && this.args[0]) this.dispatchEvent(new CustomEvent(\"command:*\", { detail: this.args[0] }));\n\t\treturn parsedArgv;\n\t}\n\tmri(argv, command) {\n\t\tconst cliOptions = [...this.globalCommand.options, ...command ? command.options : []];\n\t\tconst mriOptions = getMriOptions(cliOptions);\n\t\tlet argsAfterDoubleDashes = [];\n\t\tconst doubleDashesIndex = argv.indexOf(\"--\");\n\t\tif (doubleDashesIndex !== -1) {\n\t\t\targsAfterDoubleDashes = argv.slice(doubleDashesIndex + 1);\n\t\t\targv = argv.slice(0, doubleDashesIndex);\n\t\t}\n\t\tlet parsed = lib_default(argv, mriOptions);\n\t\tparsed = Object.keys(parsed).reduce((res, name) => {\n\t\t\treturn {\n\t\t\t\t...res,\n\t\t\t\t[camelcaseOptionName(name)]: parsed[name]\n\t\t\t};\n\t\t}, { _: [] });\n\t\tconst args = parsed._;\n\t\tconst options = { \"--\": argsAfterDoubleDashes };\n\t\tconst ignoreDefault = command && command.config.ignoreOptionDefaultValue ? command.config.ignoreOptionDefaultValue : this.globalCommand.config.ignoreOptionDefaultValue;\n\t\tconst transforms = Object.create(null);\n\t\tfor (const cliOption of cliOptions) {\n\t\t\tif (!ignoreDefault && cliOption.config.default !== void 0) for (const name of cliOption.names) options[name] = cliOption.config.default;\n\t\t\tif (Array.isArray(cliOption.config.type) && transforms[cliOption.name] === void 0) {\n\t\t\t\ttransforms[cliOption.name] = Object.create(null);\n\t\t\t\ttransforms[cliOption.name].shouldTransform = true;\n\t\t\t\ttransforms[cliOption.name].transformFunction = cliOption.config.type[0];\n\t\t\t}\n\t\t}\n\t\tfor (const key of Object.keys(parsed)) if (key !== \"_\") {\n\t\t\tsetDotProp(options, key.split(\".\"), parsed[key]);\n\t\t\tsetByType(options, transforms);\n\t\t}\n\t\treturn {\n\t\t\targs,\n\t\t\toptions\n\t\t};\n\t}\n\trunMatchedCommand() {\n\t\tconst { args, options, matchedCommand: command } = this;\n\t\tif (!command || !command.commandAction) return;\n\t\tcommand.checkUnknownOptions();\n\t\tcommand.checkOptionValue();\n\t\tcommand.checkRequiredArgs();\n\t\tcommand.checkUnusedArgs();\n\t\tconst actionArgs = [];\n\t\tcommand.args.forEach((arg, index) => {\n\t\t\tif (arg.variadic) actionArgs.push(args.slice(index));\n\t\t\telse actionArgs.push(args[index]);\n\t\t});\n\t\tactionArgs.push(options);\n\t\treturn command.commandAction.apply(this, actionArgs);\n\t}\n};\n\n//#endregion\n//#region src/index.ts\n/**\n* @param name The program name to display in help and version message\n*/\nconst cac = (name = \"\") => new CAC(name);\n\n//#endregion\nexport { CAC, Command, cac, cac as default };","{\n \"name\": \"@uzysjung/agent-harness\",\n \"version\": \"26.130.0\",\n \"description\": \"Curate vetted AI-coding skills & plugins by your tech stack — install only what you need, across Claude Code, Codex, OpenCode & Antigravity\",\n \"type\": \"module\",\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"engines\": {\n \"node\": \">=20.0.0\"\n },\n \"bin\": {\n \"agent-harness\": \"./dist/index.js\"\n },\n \"files\": [\n \"dist\",\n \"templates\",\n \"scripts/prune-ecc.sh\",\n \"README.md\",\n \"LICENSE\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"gen:compat\": \"npm run build && node scripts/gen-compatibility.mjs\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"test:coverage\": \"vitest run --coverage\",\n \"typecheck\": \"tsc --noEmit\",\n \"lint\": \"biome check src tests\",\n \"lint:fix\": \"biome check --write src tests\",\n \"format\": \"biome format --write src tests\",\n \"ci\": \"npm run typecheck && npm run lint && npm run test:coverage && npm run build\",\n \"prepare\": \"[ -d dist ] || npm run build\",\n \"cost:report\": \"npm run build && node scripts/context-cost-report.mjs\"\n },\n \"dependencies\": {\n \"@clack/prompts\": \"^1.3.0\",\n \"cac\": \"^7.0.0\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"^2.4.13\",\n \"@types/node\": \"^25.6.0\",\n \"@vitest/coverage-v8\": \"^2.1.0\",\n \"tsup\": \"^8.3.0\",\n \"typescript\": \"^5.6.0\",\n \"vitest\": \"^2.1.0\"\n },\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/uzysjung/uzys-agent-harness.git\"\n }\n}\n","/**\n * `install` subcommand — spec 검증 + 파이프라인 오케스트레이션 (v26.82.0, Phase R).\n * 화면 출력(헤더/Phase rows/산출물/Summary)은 `install-render.ts` 로 분리.\n */\n\nimport { resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { Cli } from \"../cli.js\";\nimport { parseCliTargets } from \"../cli-targets.js\";\nimport { c, status, unifiedSection } from \"../design.js\";\nimport { EXTERNAL_ASSETS } from \"../external-assets.js\";\nimport { type InstallReport, runInstall as runInstallPipeline } from \"../installer.js\";\nimport {\n type CliTargets,\n type InstallScope,\n type InstallSpec,\n isInstallScope,\n isTrack,\n type Track,\n} from \"../types.js\";\nimport {\n createInstallRenderer,\n type PipelineCallbacks,\n renderCliArtifacts,\n renderFinalSummary,\n renderInstallHeader,\n renderUpdateSummary,\n} from \"./install-render.js\";\n\nexport interface InstallOptions {\n track?: string[];\n /** v0.7.0 — repeatable. cac type: [String]. v0.8.0 — legacy alias 'both'/'all' 제거됨. */\n cli?: string | string[];\n /** v26.63.0 — Phase 1 templates 의 files 라인 표시 (default: counts only). */\n verbose?: boolean;\n projectDir?: string;\n // v26.81.0 (ADR-022, BREAKING) — 자산 1:1 플래그 13종(withTauri/withGsd/withEcc/withTob/\n // withAddyAgentSkills/withUzysHarness/withSuperpowers/withWshobsonAgents/withOpenspec/\n // withBmad/withClaudeVideo/withUnderstandAnything/withAgentmemory) 완전 삭제.\n // 자산 선택 = generic `--with <id>` / `--without <id>` 만. 아래는 동작 옵션.\n withPrune?: boolean;\n withCodexTrust?: boolean;\n withKarpathyHook?: boolean;\n /**\n * v26.47.0 (Phase C full) — External Asset 직접 추가 (preset condition 무관 강제 포함).\n * cac repeatable. 예: `--with railway-skills --with impeccable`.\n * 옵션-키 동작 flag (예: `--with-prune`) 와 별개 — External Asset id 만.\n */\n with?: string | string[];\n /**\n * v26.47.0 (Phase C full) — External Asset 직접 제외 (preset 추천에서 unchecked).\n * cac repeatable. 예: `--without netlify-cli`.\n */\n without?: string | string[];\n /**\n * v26.64.0 (ADR-020) — Installation scope. `project` (default) | `global`.\n * 명시 안 하면 wizard 의 scope prompt → 비대화형은 \"project\".\n */\n scope?: string;\n}\n\nexport interface RunInstallResult {\n ok: boolean;\n cli: CliTargets;\n /** Deprecation warnings (alias 사용 시 emit). caller가 stderr로 출력. */\n warnings: ReadonlyArray<string>;\n message: string;\n report?: InstallReport;\n}\n\n/**\n * Lift raw flag options to a typed InstallSpec.\n * Returns a Result-shaped value so callers can render errors uniformly.\n */\nexport function specFromOptions(options: InstallOptions): RunInstallResult {\n const parsed = parseCliTargets(options.cli);\n if (!parsed.ok) {\n return {\n ok: false,\n cli: [\"claude\"],\n warnings: parsed.warnings,\n message: parsed.error ?? \"Invalid --cli value\",\n };\n }\n const trackInputs = options.track ?? [];\n if (trackInputs.length === 0) {\n return {\n ok: false,\n cli: parsed.targets,\n warnings: parsed.warnings,\n // v26.56.0 (F6) — wizard 진입 안내. `install` subcommand 는 non-interactive.\n message:\n \"At least one --track is required (e.g. --track tooling)\\n Interactive wizard: run without subcommand → `agent-harness` (drop the `install` word)\",\n };\n }\n for (const t of trackInputs) {\n if (!isTrack(t)) {\n return {\n ok: false,\n cli: parsed.targets,\n warnings: parsed.warnings,\n message: `Unknown track: ${t}`,\n };\n }\n }\n return {\n ok: true,\n cli: parsed.targets,\n warnings: parsed.warnings,\n message: \"spec valid\",\n };\n}\n\nexport interface InstallActionDeps {\n log?: (msg: string) => void;\n err?: (msg: string) => void;\n exit?: (code: number) => never;\n /** Override the install pipeline (used by tests to avoid real fs side effects). */\n runPipeline?: (\n spec: InstallSpec,\n harnessRoot: string,\n mode?: import(\"../installer.js\").InstallMode,\n callbacks?: PipelineCallbacks,\n ) => InstallReport;\n /** Override the harness root resolver (defaults to a path relative to this file). */\n resolveHarnessRoot?: () => string;\n}\n\nexport function installAction(options: InstallOptions, deps: InstallActionDeps = {}): void {\n const log = deps.log ?? console.log;\n const err = deps.err ?? console.error;\n const exit = deps.exit ?? ((code: number) => process.exit(code) as never);\n const runPipeline = deps.runPipeline ?? defaultRunPipeline;\n const resolveHarnessRoot = deps.resolveHarnessRoot ?? defaultHarnessRoot;\n\n const validated = specFromOptions(options);\n // Deprecation warnings to stderr (alias 사용 시), regardless of ok/fail.\n for (const w of validated.warnings) {\n err(c.yellow(`[WARN] ${w}`));\n }\n if (!validated.ok) {\n err(status.failure(c.red(`ERROR: ${validated.message}`)));\n exit(1);\n return;\n }\n\n // v26.47.0 — Phase C full: --with/--without repeatable → userOverride.\n const forceInclude = normalizeRepeatable(options.with);\n const forceExclude = normalizeRepeatable(options.without);\n // v26.49.0 — unknown asset id validation (silent ignore 방지).\n const validIds = new Set(EXTERNAL_ASSETS.map((a) => a.id));\n for (const id of [...forceInclude, ...forceExclude]) {\n if (!validIds.has(id)) {\n err(\n c.yellow(\n `[WARN] Unknown asset id '${id}' (--with/--without). Skipping. Use one of: ${[...validIds].sort().join(\", \")}`,\n ),\n );\n }\n }\n const filteredInclude = forceInclude.filter((id) => validIds.has(id));\n const filteredExclude = forceExclude.filter((id) => validIds.has(id));\n const userOverride =\n filteredInclude.length > 0 || filteredExclude.length > 0\n ? { forceInclude: filteredInclude, forceExclude: filteredExclude }\n : undefined;\n\n const spec: InstallSpec = {\n tracks: (options.track as Track[]) ?? [],\n ...(userOverride ? { userOverride } : {}),\n // v26.81.0 (ADR-022, BREAKING) — 자산 1:1 boolean 13종 삭제. 자산 선택은 위\n // userOverride(--with <id>)로 일원화. 잔존 = 설치 동작 옵션만.\n options: {\n withPrune: options.withPrune === true,\n withCodexTrust: options.withCodexTrust === true,\n withKarpathyHook: options.withKarpathyHook === true,\n },\n cli: validated.cli,\n projectDir: resolve(options.projectDir ?? process.cwd()),\n scope: resolveScopeOption(options.scope, err),\n };\n\n executeSpec(spec, {\n log,\n err,\n exit,\n runPipeline,\n resolveHarnessRoot,\n verbose: options.verbose === true,\n });\n}\n\nexport interface ExecuteSpecDeps {\n log?: (msg: string) => void;\n err?: (msg: string) => void;\n exit?: (code: number) => never;\n runPipeline?: (\n spec: InstallSpec,\n harnessRoot: string,\n mode?: import(\"../installer.js\").InstallMode,\n callbacks?: PipelineCallbacks,\n ) => InstallReport;\n resolveHarnessRoot?: () => string;\n /** Router action mode (forwarded to runInstall). Default \"fresh\". */\n mode?: import(\"../installer.js\").InstallMode;\n /**\n * v26.63.0 — wizard 모드 (Step 1~4 통과 후 호출) 식별. true 시:\n * - install header (TARGET / TRACKS / CLI / OPTIONS / ASSETS) 출력 skip\n * (Step 3 review + Step 4 confirm 에서 이미 표시)\n * - \"Step 5/5 — Installing\" 흐름에 자연 연결\n */\n fromWizard?: boolean;\n /**\n * v26.63.0 — verbose 출력 (Phase 1 templates 의 files 라인 표시).\n * Default false — 카운트 + use 만 표시 (cognitive load 감소).\n */\n verbose?: boolean;\n}\n\n/**\n * Run the install pipeline for a fully-validated InstallSpec and render the\n * report. Shared by the `install` flag-mode command and the default\n * (interactive) action so both have identical post-install output.\n */\nexport function executeSpec(spec: InstallSpec, deps: ExecuteSpecDeps = {}): void {\n const log = deps.log ?? console.log;\n const err = deps.err ?? console.error;\n const exit = deps.exit ?? ((code: number) => process.exit(code) as never);\n const runPipeline = deps.runPipeline ?? defaultRunPipeline;\n const resolveHarnessRoot = deps.resolveHarnessRoot ?? defaultHarnessRoot;\n\n // v26.63.0 — wizard 모드는 header (TARGET ~ ASSETS) 출력 skip — Step 3/4 에서 이미 표시.\n // non-interactive (--track ...) 모드는 기존 header 유지 — 사용자 spec 확인 cue 필요.\n if (!deps.fromWizard) {\n renderInstallHeader(log, spec, deps.mode);\n }\n\n // v26.63.0 — phaseHeader → unifiedSection. Phase 카운터 (1/2/3) 제거 — 5-step 통합 시\n // wizard step 5/5 안 sub-section 으로 자연 흐름. Update mode 도 동일.\n log(unifiedSection(deps.mode === \"update\" ? \"Update Mode\" : \"Templates\"));\n log(\"\");\n\n // Streaming progress: baseline 완료 시 즉시 Phase 1 rows 출력, external은 per-asset 스트리밍.\n const renderer = createInstallRenderer(log, spec, deps.verbose === true);\n\n let report: InstallReport;\n try {\n report = runPipeline(spec, resolveHarnessRoot(), deps.mode, renderer.callbacks);\n } catch (e: unknown) {\n const detail = e instanceof Error ? e.message : String(e);\n log(\"\");\n err(status.failure(c.red(`install failed — ${detail}`)));\n exit(1);\n return;\n }\n\n // Update mode 단축 출력 — manifest copy / external 모두 skip\n if (report.updateMode) {\n renderUpdateSummary(log, report);\n return;\n }\n\n // Phase 2 trailing newline (if header was printed)\n if (renderer.phase2HeaderPrinted()) {\n log(\"\");\n }\n\n renderCliArtifacts(log, spec, report);\n renderFinalSummary(log, spec, report, deps.fromWizard === true);\n}\n\n/**\n * v26.64.0 (ADR-020) — `--scope` flag 해석. invalid 값은 warn + \"project\" default.\n * 비대화형 (--track 명시) 진입에서만 호출. wizard 는 별도 prompt.\n */\nfunction resolveScopeOption(value: string | undefined, err: (msg: string) => void): InstallScope {\n if (value === undefined) return \"project\";\n if (isInstallScope(value)) return value;\n err(\n c.yellow(`[WARN] Unknown --scope value '${value}' (expected: project, global). Using project.`),\n );\n return \"project\";\n}\n\n/**\n * v26.47.0 — Normalize cac repeatable flag (string | string[] | undefined) → string[].\n * Trim 빈 문자열 + dedup.\n */\nfunction normalizeRepeatable(value: string | string[] | undefined): string[] {\n if (!value) return [];\n const arr = Array.isArray(value) ? value : [value];\n return [...new Set(arr.map((s) => s.trim()).filter((s) => s.length > 0))];\n}\n\n/* v8 ignore start — thin dep-inject defaults. tests 는 항상 runPipeline / resolveHarnessRoot 주입. */\nfunction defaultRunPipeline(\n spec: InstallSpec,\n harnessRoot: string,\n mode?: import(\"../installer.js\").InstallMode,\n callbacks?: PipelineCallbacks,\n): InstallReport {\n const ctx: import(\"../installer.js\").InstallContext = {\n harnessRoot,\n projectDir: spec.projectDir,\n spec,\n };\n if (mode) ctx.mode = mode;\n if (callbacks?.onProgress) ctx.onProgress = callbacks.onProgress;\n if (callbacks?.externalDeps) ctx.externalDeps = callbacks.externalDeps;\n return runInstallPipeline(ctx);\n}\n\nfunction defaultHarnessRoot(): string {\n // The bundled CLI lives at <root>/dist/index.js. import.meta.url + ../ resolves to <root>.\n // fileURLToPath 필수 — `.pathname` 은 공백/비ASCII 경로를 percent-encoded 로 남겨\n // \"Templates dir not found\" 로 install 이 실패한다 (v26.103.0 SOD 리뷰 2기 독립 수렴).\n return resolve(fileURLToPath(new URL(\".\", import.meta.url)), \"..\");\n}\n\n/* v8 ignore stop */\n\nexport { defaultHarnessRoot };\n\nexport function registerInstallCommand(cli: Cli): void {\n cli\n .command(\"install\", \"Install harness assets into a project\")\n // === Track / CLI / Project ===\n .option(\"--track <name>\", \"[Track] Track to install (repeatable)\", { type: [String] })\n .option(\n \"--cli <target>\",\n \"[CLI] Target CLI (repeatable): claude | codex | opencode | antigravity\",\n {\n type: [String],\n default: \"claude\",\n },\n )\n .option(\"--project-dir <path>\", \"[Project] Target project directory\", {\n default: process.cwd(),\n })\n .option(\"--scope <scope>\", \"[Scope] Installation scope: project (default) | global\", {\n default: \"project\",\n })\n // === Asset selection (Phase C full, v26.47.0+) ===\n .option(\n \"--with <asset-id>\",\n \"[Asset] Force-include External Asset id (regardless of preset). Repeatable. v26.47.0+\",\n )\n .option(\n \"--without <asset-id>\",\n \"[Asset] Force-exclude External Asset id (drop from preset recommendation). Repeatable. v26.47.0+\",\n )\n // === Codex global (v26.46.0+) ===\n .option(\n \"--with-codex-trust\",\n \"[Codex] Codex global opt-in: register trust entry in ~/.codex/config.toml\",\n )\n // v26.81.0 (ADR-022, BREAKING) — 자산 1:1 플래그 13종 삭제. 자산 opt-in 은 전부\n // generic `--with <asset-id>` (위) — 자산 id 목록은 docs/COMPATIBILITY.md 표 참조.\n // 아래는 자산이 아닌 설치 동작 옵션만.\n .option(\n \"--with-prune\",\n \"[Behavior] Prune ECC items beyond curated 89 (use with --with ecc-plugin)\",\n )\n .option(\n \"--with-karpathy-hook\",\n \"[Behavior] karpathy-coder pre-commit hook (.claude/settings.json PreToolUse Write|Edit)\",\n )\n // === Misc ===\n .option(\"--verbose\", \"[Misc] Show installed file lists per category (default: counts only)\")\n // === Examples (v26.50.0+) ===\n .example(\"install --track tooling --with karpathy-coder\")\n .example(\"install --track csr-supabase --cli claude --cli codex\")\n .example(\"install --track csr-supabase --without netlify-cli --with railway-skills\")\n /* v8 ignore next — cac action callback. installAction 자체는 별도 tests 로 검증. */\n .action((options: InstallOptions) => installAction(options));\n}\n","/**\n * CLI targets parser — v0.7.0 multi-select.\n *\n * SPEC: docs/specs/cli-multi-select.md F2 (parseCliTargets).\n *\n * Input shapes:\n * - undefined / null / \"\" / [] → [\"claude\"] (default)\n * - \"claude\" / \"codex\" / \"opencode\" / \"antigravity\" → single-element array\n * - [\"claude\", \"codex\"] (cac repeatable) → sorted array\n * - \"both\" / \"all\" (v0.8.0 제거된 legacy alias) → ok=false + 마이그레이션 안내 (throw 아님)\n * - \"invalid\" → ok=false + error (throw 아님)\n *\n * Output:\n * - ok: 유효하면 true, reject 시 false (+ error 메시지, targets=[\"claude\"] default)\n * - targets: sorted ReadonlyArray<CliBase> (claude → codex → opencode → antigravity 순)\n * - warnings: 메시지 배열 (현재 reject-only 정책이라 비어 있음)\n */\n\nimport { CLI_BASES, type CliBase, type CliTargets, isCliBase } from \"./types.js\";\n\n/** SSOT — claude → codex → opencode → antigravity 정렬 순서. prompts.ts에서 import. */\nexport const CLI_BASE_SORT_ORDER: Record<CliBase, number> = {\n claude: 0,\n codex: 1,\n opencode: 2,\n antigravity: 3,\n};\n\nexport interface ParseCliTargetsResult {\n ok: boolean;\n targets: CliTargets;\n warnings: ReadonlyArray<string>;\n /** ok=false 시 reject 사유. */\n error?: string;\n}\n\n/**\n * `--cli` 입력을 sorted CliTargets로 정규화.\n *\n * Default `[\"claude\"]` (비어있거나 undefined일 때).\n * Invalid 모드는 reject (ok=false).\n *\n * v0.8.0 — `both`/`all` legacy alias 제거 (v0.7.0에서 1 release deprecation 거침).\n * `both`/`all` 입력 시 invalid reject + 마이그레이션 안내.\n */\nexport function parseCliTargets(input: string | string[] | undefined): ParseCliTargetsResult {\n const items = normalizeInput(input);\n if (items.length === 0) {\n return { ok: true, targets: [\"claude\"], warnings: [] };\n }\n\n const collected = new Set<CliBase>();\n const warnings: string[] = [];\n\n for (const item of items) {\n if (!isCliBase(item)) {\n // v0.8.0 — alias 제거 마이그레이션 힌트\n let hint = \"\";\n if (item === \"both\") {\n hint = \"\\n v0.8.0 removed 'both' alias. Use --cli claude --cli codex.\";\n } else if (item === \"all\") {\n hint =\n \"\\n v0.8.0 removed 'all' alias. Use --cli claude --cli codex --cli opencode.\";\n } else if (item.includes(\",\")) {\n // v0.7.1 — comma-separated input hint\n hint = \"\\n Tip: comma-separated not supported. Use --cli A --cli B for multiple.\";\n }\n return {\n ok: false,\n targets: [\"claude\"],\n warnings,\n error: `Invalid --cli value: ${item}. Must be one of: ${CLI_BASES.join(\" | \")}${hint}`,\n };\n }\n collected.add(item);\n }\n\n const targets = [...collected].sort((a, b) => CLI_BASE_SORT_ORDER[a] - CLI_BASE_SORT_ORDER[b]);\n return { ok: true, targets, warnings };\n}\n\nfunction normalizeInput(input: string | string[] | undefined): string[] {\n if (input === undefined || input === null) return [];\n if (typeof input === \"string\") {\n const trimmed = input.trim();\n return trimmed === \"\" ? [] : [trimmed];\n }\n return input.filter((s) => typeof s === \"string\" && s.trim() !== \"\").map((s) => s.trim());\n}\n\n/** Targets에 특정 base 포함 여부. has() 패턴. */\nexport function targetsInclude(targets: CliTargets, base: CliBase): boolean {\n return targets.includes(base);\n}\n","/**\n * design.ts — CLI visual design tokens (color, symbols, layout helpers).\n *\n * Aesthetic direction: **refined ops-report**. Mission control feel without\n * decoration noise. Phase markers + aligned 2-column rows + structured summary.\n *\n * Goals:\n * 1. Make input-wait points visually obvious (handled by @clack/prompts).\n * 2. Make the install pipeline output legible:\n * - phase-segmented progress (━━━ Phase N · Title ━━━)\n * - aligned per-asset rows (✓/⊘/✗ + id + meta)\n * - explicit skipped/failed reporting (no silent skips)\n * - terminal-width responsive (default 78)\n * 3. Zero runtime dependencies — emit raw ANSI escapes.\n *\n * `NO_COLOR` is honored per https://no-color.org.\n */\n\nconst isColorEnabled = (() => {\n if (process.env.NO_COLOR && process.env.NO_COLOR !== \"\") {\n return false;\n }\n // stdout may be missing in some test contexts\n return Boolean(process.stdout?.isTTY);\n})();\n\nfunction wrap(open: number, close: number) {\n return (s: string): string => {\n if (!isColorEnabled) {\n return s;\n }\n return `\\x1b[${open}m${s}\\x1b[${close}m`;\n };\n}\n\nexport const c = {\n bold: wrap(1, 22),\n dim: wrap(2, 22),\n red: wrap(31, 39),\n green: wrap(32, 39),\n yellow: wrap(33, 39),\n cyan: wrap(36, 39),\n gray: wrap(90, 39),\n};\n\nexport const symbol = {\n success: \"✓\",\n failure: \"✗\",\n skip: \"⊘\",\n arrow: \"›\",\n pointer: \"▸\",\n bullet: \"•\",\n warn: \"⚠\",\n /** Heavy horizontal box-drawing — phase dividers. */\n rule: \"━\",\n /** Middle dot — section separator. */\n mid: \"·\",\n};\n\n/** Default width for phase headers / dividers. Terminal default ≥ 78. */\nexport const DEFAULT_WIDTH = 78;\n\n/** Render a legacy section header. Bold cyan with a leading arrow. (kept for backward compat) */\nexport function header(title: string): string {\n return c.bold(c.cyan(`${symbol.arrow} ${title}`));\n}\n\n/**\n * Render a phase header — `━━━ Phase N · Title ━━━━━━━...` (full-width).\n * v26.63.0 (deprecated): kept for non-interactive mode + backward compat.\n * wizard 모드는 unifiedSection() 사용 (5-step 통합 — phase 카운터 무관).\n */\nexport function phaseHeader(n: number | string, title: string, width = DEFAULT_WIDTH): string {\n const label = `${symbol.rule}${symbol.rule}${symbol.rule} Phase ${n} ${symbol.mid} ${title} `;\n const fill = symbol.rule.repeat(Math.max(0, width - visibleLength(label)));\n return c.bold(c.cyan(`${label}${fill}`));\n}\n\n/**\n * v26.63.0 — Step 5 (Installing) 안의 sub-section 헤더.\n * `━━ Templates ━━` / `━━ External assets (n) ━━` / `━━ Codex artifacts ━━`.\n * phaseHeader (3 rule + Phase N + ·) 대비 단순 — 2 rule + title.\n */\nexport function unifiedSection(title: string, width = DEFAULT_WIDTH): string {\n const label = `${symbol.rule}${symbol.rule} ${title} `;\n const fill = symbol.rule.repeat(Math.max(0, width - visibleLength(label)));\n return c.bold(c.cyan(`${label}${fill}`));\n}\n\n/**\n * Render a section header (non-phase) — `━━━ Title ━━━━━━━...`.\n * Used for TARGET / SUMMARY / NEXT etc.\n */\nexport function sectionHeader(title: string, width = DEFAULT_WIDTH): string {\n const label = `${symbol.rule}${symbol.rule}${symbol.rule} ${title} `;\n const fill = symbol.rule.repeat(Math.max(0, width - visibleLength(label)));\n return c.bold(c.cyan(`${label}${fill}`));\n}\n\n/** Plain horizontal divider — `━━━...━━━` (no label). */\nexport function divider(width = DEFAULT_WIDTH): string {\n return c.dim(symbol.rule.repeat(width));\n}\n\n/**\n * Render a `key: value` row with a fixed-width left column for alignment.\n * Used in pre-flight / summary blocks (▸ TRACKS executive, tooling).\n */\nexport function infoRow(key: string, value: string, width = 12): string {\n const label = `${symbol.pointer} ${key}`.padEnd(width + 2, \" \");\n return ` ${c.dim(label)} ${value}`;\n}\n\n/** Backward-compat — `keyValue` (used by older install report). */\nexport function keyValue(key: string, value: string, width = 16): string {\n const padded = `${key}:`.padEnd(width, \" \");\n return ` ${c.dim(padded)} ${value}`;\n}\n\n/**\n * Render an asset row — ` ✓ asset-id meta`.\n * symbol = success/skip/failure. label = stable id (left-pad). meta = dim right column.\n */\nexport function assetRow(\n kind: \"success\" | \"skip\" | \"failure\",\n label: string,\n meta = \"\",\n labelWidth = 40,\n): string {\n const sym = renderSymbol(kind);\n const labelPadded = label.padEnd(labelWidth, \" \");\n const metaText = meta ? c.dim(meta) : \"\";\n return ` ${sym} ${labelPadded} ${metaText}`.trimEnd();\n}\n\nfunction renderSymbol(kind: \"success\" | \"skip\" | \"failure\"): string {\n switch (kind) {\n case \"success\":\n return c.green(symbol.success);\n case \"skip\":\n return c.yellow(symbol.skip);\n case \"failure\":\n return c.red(symbol.failure);\n }\n}\n\nexport const status = {\n success: (msg: string): string => `${c.green(symbol.success)} ${msg}`,\n failure: (msg: string): string => `${c.red(symbol.failure)} ${msg}`,\n warn: (msg: string): string => `${c.yellow(symbol.warn)} ${msg}`,\n info: (msg: string): string => `${c.cyan(symbol.bullet)} ${msg}`,\n};\n\n/**\n * Strip ANSI escape sequences so visible width can be measured (for header padding).\n */\nfunction visibleLength(s: string): number {\n // biome-ignore lint/suspicious/noControlCharactersInRegex: ANSI escape stripping requires \\x1b\n return s.replace(/\\x1b\\[[0-9;]*m/g, \"\").length;\n}\n\n/**\n * v26.63.2 — Pad to fixed display width (ANSI-aware). spacing scale 정렬 용.\n */\nexport function padDisplay(s: string, width: number): string {\n const visible = visibleLength(s);\n return visible >= width ? s : s + \" \".repeat(width - visible);\n}\n","import {\n chmodSync,\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n writeFileSync,\n} from \"node:fs\";\nimport { basename, dirname, join, resolve } from \"node:path\";\nimport {\n type AntigravityTransformReport,\n runAntigravityTransform,\n} from \"./antigravity/transform.js\";\nimport { type CiScaffoldReport, installCiScaffold } from \"./ci-scaffold.js\";\nimport { type CodexOptInReport, runCodexOptIn } from \"./codex/opt-in.js\";\nimport { type CodexTransformReport, runCodexTransform } from \"./codex/transform.js\";\nimport {\n addGitignoreEnv,\n addGitignoreNpxSkillsAgents,\n writeEnvExample,\n writeMcpAllowlist,\n} from \"./env-files.js\";\nimport { EXTERNAL_ASSETS, INTERNAL_BUNDLED_SKILL_IDS, isAssetSelected } from \"./external-assets.js\";\nimport {\n type ExternalInstallerDeps,\n type ExternalInstallReport,\n runExternalInstall,\n selectExternalTargets,\n} from \"./external-installer.js\";\nimport {\n backupDir,\n backupFileIfChanged,\n copyBackupDir,\n copyDir,\n copyFile,\n ensureProjectSkeleton,\n} from \"./fs-ops.js\";\nimport {\n buildInstallLog,\n collectSkillHashes,\n hashContent,\n type InstallLog,\n type InstallLogRootFile,\n readInstallLog,\n writeInstallLog,\n} from \"./install-log.js\";\nimport { type AssetSpec, buildManifest } from \"./manifest.js\";\nimport { composeMcpJson, writeMcpJson } from \"./mcp-merge.js\";\nimport { type OpencodeTransformReport, runOpencodeTransform } from \"./opencode/transform.js\";\nimport { mergeProjectClaude } from \"./project-claude-merge.js\";\nimport { addPreToolUseHook, type ClaudeSettings } from \"./settings-merge.js\";\nimport { type InstallSpec, type OptionFlags, resolveScope, type Track } from \"./types.js\";\nimport { runUpdateMode, type UpdateModeReport } from \"./update-mode.js\";\n\n/**\n * karpathy-coder hook 상수 — install 이 쓰고 uninstall 의 수기 안내가 읽는다.\n * v26.123.0 — 두 곳이 같은 값을 봐야 해서 export. 파일명이 바뀌면 안내가 조용히 멈추므로\n * 경로도 여기서 파생시킨다 (`no-false-ship`: 같은 값이 2곳에 하드코딩되면 derive 로 단일화).\n */\nexport const KARPATHY_HOOK_RELPATH = \".claude/hooks/karpathy-gate.sh\";\nexport const KARPATHY_HOOK_COMMAND = `bash \"$CLAUDE_PROJECT_DIR/${KARPATHY_HOOK_RELPATH}\"`;\n\n/**\n * Install mode — Router action 매핑.\n * - \"fresh\" : 첫 설치 (기본값)\n * - \"add\" : 기존 위에 Track union 추가 (backup 없음)\n * - \"update\" : 정책 파일만 templates로 갱신 (backup + orphan prune + stale hook)\n * - \"reinstall\" : 기존 .claude/ backup 후 처음부터 (backup 강제)\n */\nexport type InstallMode = \"fresh\" | \"add\" | \"update\" | \"reinstall\";\n\nexport interface InstallContext {\n /** Path to the harness repo (where `templates/` lives). */\n harnessRoot: string;\n /** Target project directory. */\n projectDir: string;\n spec: InstallSpec;\n /**\n * Router action mode. Defaults to \"fresh\".\n * - \"add\"/\"update\"/\"reinstall\" trigger different install paths.\n * - reinstall + update force backup=true.\n */\n mode?: InstallMode;\n /**\n * When true, an existing .claude/ is renamed to a timestamped backup before install.\n * Auto-true when mode ∈ {update, reinstall}.\n */\n backup?: boolean;\n /**\n * External install (claude plugin / npm -g / npx skills) injection point.\n * Default: real `runExternalInstall`. Tests inject mock to avoid real spawn.\n * Pass `null` to disable external install entirely.\n */\n runExternal?:\n | ((\n // v26.77.0 — projectDir: 외부 설치기 spawn cwd (자산 착지 위치). Bug B fix.\n // v26.81.0 (ADR-022) — userOverride: 자산 opt-in(--with <id>) 전파 (flag 13종 대체).\n ctx: {\n tracks: ReadonlyArray<Track>;\n options: OptionFlags;\n projectDir?: string;\n userOverride?: {\n forceInclude: ReadonlyArray<string>;\n forceExclude: ReadonlyArray<string>;\n };\n },\n deps: ExternalInstallerDeps,\n ) => ExternalInstallReport)\n | null;\n /**\n * Progress callback fired between stages so renderers can stream output\n * (avoids \"Phase 1 header → 5 minutes silence\" UX problem).\n */\n onProgress?: (event: ProgressEvent) => void;\n /** External installer streaming hooks (forwarded to runExternalInstall). */\n externalDeps?: Pick<ExternalInstallerDeps, \"onAssetStart\" | \"onAssetResult\">;\n}\n\n/** Progress event types fired during runInstall. */\nexport type ProgressEvent =\n /** Baseline (manifest copy + mcp + envFiles + Codex/OpenCode transforms) finished. External not yet started. */\n | { type: \"baseline-complete\"; baseline: BaselineReport }\n /** External install phase about to begin. */\n | { type: \"external-start\"; assetCount: number }\n /** External install phase finished (with report). */\n | { type: \"external-complete\"; report: ExternalInstallReport }\n /** v26.64.0 — install log write 실패 (non-fatal). */\n | { type: \"install-log-error\"; message: string };\n\n/** karpathy-coder hook auto-wire 결과 (v0.6.0). */\nexport interface KarpathyHookReport {\n /** withKarpathyHook=true && karpathy-coder install 성공 시 true. */\n wired: boolean;\n /** wired=false 시 사유. */\n reason?:\n | \"opt-out\"\n | \"plugin-install-failed\"\n | \"external-skipped\"\n | \"settings-parse-error\"\n | \"claude-not-selected\";\n /** wired=true 시 settings.json 갱신 여부 (idempotent skip 시 false). */\n settingsUpdated?: boolean;\n /** wired=true 시 hook script 복사 여부. */\n hookScriptCopied?: boolean;\n}\n\n/** karpathy-coder asset ID — SSOT (external-assets.ts entry id와 일치 강제). */\nexport const KARPATHY_ASSET_ID = \"karpathy-coder\";\n\n/**\n * v0.6.1 — Phase 1 output 카테고리별 분류. install renderer가 각 카테고리별로 row를 출력한다.\n * Names는 description용 (display only); 빈 배열이면 row 출력 skip.\n */\nexport interface BaselineCategoryCounts {\n /** rule 파일 names (확장자 제외) — git-policy, change-management 등 */\n rules: string[];\n /** agent 파일 names */\n agents: string[];\n /** hook 파일 names (확장자 제외) */\n hooks: string[];\n /** commands 디렉토리 카운트 (uzys + ecc) — names는 디렉토리라 무의미 */\n commands: number;\n /** skill 디렉토리 names */\n skills: string[];\n}\n\n/** Baseline phase result (everything except external assets). */\nexport interface BaselineReport {\n filesCopied: number;\n dirsCopied: number;\n skipped: number;\n backup: string | null;\n installedTracks: string[];\n mcpServers: string[];\n codex: CodexTransformReport | null;\n codexOptIn: CodexOptInReport | null;\n opencode: OpencodeTransformReport | null;\n /** v26.66.0 — Present when spec.cli includes \"antigravity\". */\n antigravity: AntigravityTransformReport | null;\n updateMode: UpdateModeReport | null;\n mode: InstallMode;\n envFiles: {\n envExampleCreated: boolean;\n gitignoreEnvAdded: boolean;\n mcpAllowlist: string[] | null;\n /** v0.8.0 — `.gitignore`에 추가된 npx skills agent 디렉토리 패턴 (`.factory/`, `.goose/`). */\n gitignoreNpxSkillsAdded: string[];\n };\n /**\n * v26.108.0 (ADR-037) — CI 스캐폴드 결과. opt-in 미선택 시 null. `.github/workflows/`\n * 는 CLI-agnostic 이라 claude baseline 밖의 전용 단계 (ci-scaffold.ts) 가 설치 주체.\n */\n ciScaffold: CiScaffoldReport | null;\n /** v0.6.1 — Phase 1 카테고리별 카운트 + names. Update mode에서는 빈 객체. */\n categories?: BaselineCategoryCounts;\n /** Root CLAUDE.md fill-in scaffold (project name + active-track note + FILL sections). null when claude baseline disabled. */\n rootClaudeMd: { tracks: ReadonlyArray<Track> } | null;\n /** 덮어쓰기 전 보존한 사용자 파일 백업 경로 (settings.json·CLAUDE.md, fresh/add 모드). audit SEC-1/CODE-2. */\n backups?: string[];\n}\n\nexport interface InstallReport {\n filesCopied: number;\n dirsCopied: number;\n skipped: number;\n backup: string | null;\n installedTracks: string[];\n mcpServers: string[];\n /** Present when spec.cli includes \"codex\". */\n codex: CodexTransformReport | null;\n /** Present when Codex transform ran AND user opted-in to global skills/trust/prompts. null otherwise. */\n codexOptIn: CodexOptInReport | null;\n /** Present when spec.cli includes \"opencode\". */\n opencode: OpencodeTransformReport | null;\n /** v26.66.0 — Present when spec.cli includes \"antigravity\". */\n antigravity: AntigravityTransformReport | null;\n /** v26.108.0 (ADR-037) — CI 스캐폴드 결과 (opt-in 미선택 시 null). */\n ciScaffold: CiScaffoldReport | null;\n /** External install report (claude plugin / npm -g / npx skills). null when disabled or empty. */\n external: ExternalInstallReport | null;\n /** Update-mode report (rules/agents/commands/hooks/skills 갱신 + orphan prune + stale hook). null when not update mode. */\n updateMode: UpdateModeReport | null;\n /** karpathy-coder hook auto-wire 결과 (v0.6.0). null when withKarpathyHook=false. */\n karpathyHook: KarpathyHookReport | null;\n /** Install mode dispatched (echo of ctx.mode, default \"fresh\"). */\n mode: InstallMode;\n /** Environment file generation results (always present). */\n envFiles: {\n /** true if .env.example was created (csr-supabase/full only). */\n envExampleCreated: boolean;\n /** true if .gitignore got `.env` line appended. */\n gitignoreEnvAdded: boolean;\n /** Server names written to .mcp-allowlist; null if skipped. */\n mcpAllowlist: string[] | null;\n /** v0.8.0 — `.gitignore`에 추가된 npx skills agent 디렉토리 패턴 (`.factory/`, `.goose/`). */\n gitignoreNpxSkillsAdded: string[];\n };\n}\n\n/**\n * Run the installation pipeline. Pure function modulo filesystem side effects.\n * v26.82.0 (Phase R) — 276줄 단일 함수를 단계별 블록 함수로 분해 (동작 변경 0):\n * update 단축 / claude baseline / CLI transforms / external / install log.\n */\nexport function runInstall(ctx: InstallContext): InstallReport {\n const { harnessRoot, projectDir, spec } = ctx;\n const mode: InstallMode = ctx.mode ?? \"fresh\";\n const templatesDir = join(harnessRoot, \"templates\");\n\n if (!existsSync(templatesDir)) {\n throw new Error(`Templates dir not found: ${templatesDir}`);\n }\n\n const claudeDir = join(projectDir, \".claude\");\n\n // Update mode pre-flight: existing .claude/ 필수. backup 전에 검증.\n if (mode === \"update\" && !existsSync(claudeDir)) {\n throw new Error(`Update mode requires existing .claude/ at ${claudeDir}`);\n }\n\n // v26.123.0 (F-1a) — 추가 설치가 이전 설치 기록을 지우지 않도록 기존 로그를 먼저 읽는다.\n // reinstall 은 바로 아래에서 `.claude/` 를 통째로 backup 으로 옮기므로 그 뒤엔 읽을 수 없다.\n const previousLog = readInstallLog(projectDir);\n\n const backupPath = resolveBackupPath(ctx, mode, claudeDir);\n\n // Update mode 단축 — 정책 파일만 갱신하고 종료 (manifest copy / external 모두 skip)\n if (mode === \"update\") {\n return runUpdateInstall(ctx, templatesDir, backupPath);\n }\n\n const manifestSpec = buildManifestSpec(spec);\n\n // v0.8.0 — `.claude/` baseline은 spec.cli에 \"claude\" 포함 시에만 생성.\n // Codex/OpenCode 단독 사용자는 dead weight 회피.\n const base = spec.cli.includes(\"claude\")\n ? installClaudeBaseline(manifestSpec, projectDir, templatesDir)\n : emptyClaudeBaseline();\n\n // Compose .mcp.json from template + track-mcp-map.tsv (Codex/OpenCode도 사용 — claude 무관)\n const mcpResult = composeAndWriteMcp(harnessRoot, projectDir, spec);\n\n // v26.108.0 (ADR-037) — CI 스캐폴드 (opt-in 전용). `.github/` 은 CLI-agnostic 이라\n // claude baseline 조건 밖에서 설치. 기존 워크플로 파일은 절대 덮어쓰지 않는다.\n const ciScaffold = isAssetSelected(\"ci-scaffold\", {\n tracks: spec.tracks,\n options: spec.options,\n ...(spec.userOverride ? { userOverride: spec.userOverride } : {}),\n })\n ? installCiScaffold({ harnessRoot, projectDir, tracks: spec.tracks })\n : null;\n\n const baseline: BaselineReport = {\n filesCopied: base.filesCopied,\n dirsCopied: base.dirsCopied,\n skipped: base.skipped,\n backup: backupPath,\n installedTracks: [...spec.tracks].sort(),\n mcpServers: Object.keys(mcpResult.mcpServers).sort(),\n ...runCliTransforms(spec, harnessRoot, projectDir, manifestSpec.selectedInternalSkills),\n ciScaffold,\n updateMode: null,\n mode,\n envFiles: writeEnvironmentFiles(projectDir, spec.tracks),\n categories: base.categories,\n rootClaudeMd: base.rootClaudeMd,\n backups: base.backups,\n };\n\n // ━━━ Baseline complete — emit progress event so renderer can show Phase 1 rows ━━━\n ctx.onProgress?.({ type: \"baseline-complete\", baseline });\n\n // ━━━ External assets (claude plugin / npm -g / npx skills) ━━━\n const external = runExternalPhase(ctx);\n\n // ━━━ karpathy-coder hook auto-wire (v0.6.0) ━━━\n // SPEC: docs/specs/karpathy-hook-autowire.md AC2 — opt-in 강제 + install 성공 후에만.\n // v0.8.0 — `.claude/settings.json` PreToolUse 의존이라 spec.cli에 \"claude\" 포함 시에만 와이어 가능.\n const karpathyHook = wireKarpathyHook(spec, external, harnessRoot, projectDir);\n\n // ━━━ v26.64.0 (ADR-020) — Install log write ━━━\n // backupPath 가 있으면 `.claude/` 를 rename 으로 밀어냈다는 뜻 — 그 안에 살던 이전 자산은\n // 실제로 사라졌으므로 누적에서 빠져야 한다 (fresh/add 는 backupPath=null → 전부 유지).\n writeInstallLogSafe(\n ctx,\n external,\n base.rootClaudeMdLog,\n previousLog,\n backupPath !== null,\n collectRootFiles(baseline.envFiles, ciScaffold, mcpResult.created),\n );\n\n return { ...baseline, external, karpathyHook };\n}\n\n/**\n * Backup auto-on for update + reinstall (sourced from router action).\n * Update: copy backup (preserve original .claude/ for in-place update).\n * Reinstall + others: rename backup (move .claude/ aside, then full install).\n */\nfunction resolveBackupPath(\n ctx: InstallContext,\n mode: InstallMode,\n claudeDir: string,\n): string | null {\n const wantBackup = ctx.backup ?? (mode === \"update\" || mode === \"reinstall\");\n if (!wantBackup) return null;\n return mode === \"update\" ? copyBackupDir(claudeDir) : backupDir(claudeDir);\n}\n\n/** Update mode 단축 경로 — 정책 파일만 갱신 (manifest copy / external 모두 skip). */\nfunction runUpdateInstall(\n ctx: InstallContext,\n templatesDir: string,\n backupPath: string | null,\n): InstallReport {\n const updateReport = runUpdateMode(ctx.projectDir, templatesDir);\n const baseline: BaselineReport = {\n filesCopied: 0,\n dirsCopied: 0,\n skipped: 0,\n backup: backupPath,\n installedTracks: [...ctx.spec.tracks].sort(),\n mcpServers: [],\n codex: null,\n codexOptIn: null,\n opencode: null,\n antigravity: null,\n ciScaffold: null,\n updateMode: updateReport,\n mode: \"update\",\n envFiles: {\n envExampleCreated: false,\n gitignoreEnvAdded: false,\n mcpAllowlist: null,\n gitignoreNpxSkillsAdded: [],\n },\n rootClaudeMd: null,\n };\n ctx.onProgress?.({ type: \"baseline-complete\", baseline });\n return { ...baseline, external: null, karpathyHook: null };\n}\n\n/**\n * v26.81.0 (ADR-022) — manifest 게이팅 입력. 내부 자산 선택 판정 — 이전\n * OptionFlags.withTauri/withUzysHarness/withEcc boolean 자리를 카탈로그 선택\n * (wizard 체크 / --with <id> → forceInclude)으로 대체 (manifest 필드명은 유지).\n */\nfunction buildManifestSpec(spec: InstallSpec): Required<AssetSpec> {\n const selectionCtx = {\n tracks: spec.tracks,\n options: spec.options,\n ...(spec.userOverride ? { userOverride: spec.userOverride } : {}),\n };\n return {\n tracks: spec.tracks,\n withTauri: isAssetSelected(\"tauri-desktop\", selectionCtx),\n // v26.55.0 — withEcc gating (ADR-016). ECC cherry-pick (agents/skills/commands) 항목 토글.\n // withPrune 은 ecc-plugin 사용을 전제 (이전 applyOptionRules `withEcc ||= withPrune` 의미 보존).\n withEcc: isAssetSelected(\"ecc-plugin\", selectionCtx) || spec.options.withPrune,\n // v26.87.0 — internal bundled skills (dev-method + opt-in advisors, v26.95.0). Each id's\n // condition (has-dev-track vs opt-in) is applied by isAssetSelected — manifest copy + the 3\n // non-Claude CLI transforms gate on this filtered list, so opt-in ones install only when\n // wizard-checked / `--with <id>`, and any uncheck / `--without <id>` (forceExclude) drops it.\n selectedInternalSkills: INTERNAL_BUNDLED_SKILL_IDS.filter((id) =>\n isAssetSelected(id, selectionCtx),\n ),\n };\n}\n\n/** `.claude/` baseline (manifest copy) 결과. claude 미선택 시 emptyClaudeBaseline(). */\ninterface ClaudeBaselineResult {\n filesCopied: number;\n dirsCopied: number;\n skipped: number;\n categories: BaselineCategoryCounts;\n rootClaudeMd: { tracks: ReadonlyArray<Track> } | null;\n /** root CLAUDE.md 무결성 기록 — uninstall 시 사용자 수정 여부 판별 (install 원본과 sha 비교). */\n rootClaudeMdLog: { path: string; sha256: string } | null;\n /** 덮어쓰기 전 보존한 사용자 파일 백업 경로 (settings.json·CLAUDE.md). audit SEC-1/CODE-2. */\n backups: string[];\n}\n\nfunction emptyClaudeBaseline(): ClaudeBaselineResult {\n return {\n filesCopied: 0,\n dirsCopied: 0,\n skipped: 0,\n categories: { rules: [], agents: [], hooks: [], commands: 0, skills: [] },\n rootClaudeMd: null,\n rootClaudeMdLog: null,\n backups: [],\n };\n}\n\n/** `.claude/` baseline — manifest copy + hook chmod + .installed-tracks + root CLAUDE.md merge. */\nfunction installClaudeBaseline(\n manifestSpec: Required<AssetSpec>,\n projectDir: string,\n templatesDir: string,\n): ClaudeBaselineResult {\n ensureProjectSkeleton(projectDir);\n\n const result = emptyClaudeBaseline();\n const manifest = buildManifest(manifestSpec);\n\n for (const entry of manifest) {\n if (!entry.applies(manifestSpec)) {\n continue;\n }\n const source = join(templatesDir, entry.source);\n const target = join(projectDir, entry.target);\n if (!existsSync(source)) {\n result.skipped += 1;\n continue;\n }\n if (entry.type === \"file\") {\n // 사용자 편집 가능 파일은 덮어쓰기 전 백업 (audit SEC-1 — settings.json hook/statusLine 소실 방지).\n if (entry.target === \".claude/settings.json\") {\n const backup = backupFileIfChanged(target, readFileSync(source, \"utf-8\"));\n if (backup) {\n result.backups.push(backup);\n }\n }\n copyFile(source, target);\n result.filesCopied += 1;\n } else {\n copyDir(source, target);\n result.dirsCopied += 1;\n }\n accumulateCategory(result.categories, entry);\n }\n\n // chmod +x on hook scripts (cp does not preserve exec bit when source is non-exec)\n const hookDir = join(projectDir, \".claude/hooks\");\n if (existsSync(hookDir)) {\n chmodHooksSync(hookDir);\n }\n\n // Write metadata file used by detect_install_state on next run (.claude/.installed-tracks)\n writeInstalledTracks(projectDir, manifestSpec.tracks);\n\n // Project root CLAUDE.md — an honest fill-in scaffold (project name + active tracks + FILL sections).\n // Note: overwrites any user customization on re-install. Documented behavior.\n const rootClaudeMd = writeRootClaudeMd(projectDir, manifestSpec.tracks);\n result.rootClaudeMd = { tracks: manifestSpec.tracks };\n result.rootClaudeMdLog = { path: \"CLAUDE.md\", sha256: hashContent(rootClaudeMd.content) };\n if (rootClaudeMd.backup) {\n result.backups.push(rootClaudeMd.backup);\n }\n return result;\n}\n\n/** Environment files (F7/F8 — bash setup-harness.sh L880~890 + L954~996 등가). */\nfunction writeEnvironmentFiles(\n projectDir: string,\n tracks: ReadonlyArray<Track>,\n): BaselineReport[\"envFiles\"] {\n return {\n envExampleCreated: writeEnvExample(projectDir, tracks),\n gitignoreEnvAdded: addGitignoreEnv(projectDir),\n mcpAllowlist: writeMcpAllowlist(projectDir),\n // v0.8.0 — `.factory/`, `.goose/` ignore (npx skills universal install 사용자 #3)\n gitignoreNpxSkillsAdded: addGitignoreNpxSkillsAgents(projectDir),\n };\n}\n\n/** Codex / OpenCode / Antigravity per-CLI transforms (+ scope=global opt-in) 결과. */\ninterface CliTransformResults {\n codex: CodexTransformReport | null;\n codexOptIn: CodexOptInReport | null;\n opencode: OpencodeTransformReport | null;\n antigravity: AntigravityTransformReport | null;\n}\n\nfunction runCliTransforms(\n spec: InstallSpec,\n harnessRoot: string,\n projectDir: string,\n selectedInternalSkills: ReadonlyArray<string>,\n): CliTransformResults {\n // Codex transform when spec.cli includes \"codex\"\n let codex: CodexTransformReport | null = null;\n let codexOptIn: CodexOptInReport | null = null;\n if (spec.cli.includes(\"codex\")) {\n // v26.87.0 — dev-method skills 는 selectedInternalSkills 로 게이팅.\n codex = runCodexTransform({\n harnessRoot,\n projectDir,\n selectedInternalSkills,\n });\n // v26.64.0 (ADR-020) — Codex global trust opt-in 은 scope=global 일 때만 의미.\n // scope=project (default) 시 ~/.codex/ write skip (config.toml trust entry 만).\n const installScope = spec.scope ?? \"project\";\n if (installScope === \"global\" && spec.options.withCodexTrust) {\n codexOptIn = runCodexOptIn({ projectDir });\n }\n }\n\n // OpenCode transform when spec.cli includes \"opencode\"\n let opencode: OpencodeTransformReport | null = null;\n if (spec.cli.includes(\"opencode\")) {\n opencode = runOpencodeTransform({ harnessRoot, projectDir, selectedInternalSkills });\n }\n\n // v26.66.0 — Antigravity transform when spec.cli includes \"antigravity\".\n // `.agents/rules/uzys-harness.md` (project context) + dev-method skills.\n let antigravity: AntigravityTransformReport | null = null;\n if (spec.cli.includes(\"antigravity\")) {\n antigravity = runAntigravityTransform({\n harnessRoot,\n projectDir,\n selectedInternalSkills,\n });\n }\n\n return { codex, codexOptIn, opencode, antigravity };\n}\n\n/**\n * External assets (claude plugin / npm -g / npx skills) 설치 단계.\n * Default = real runExternalInstall. Tests inject mock or `null` to skip.\n * log/warn은 silent (renderer가 onAssetStart/Result로 스트리밍).\n */\nfunction runExternalPhase(ctx: InstallContext): ExternalInstallReport | null {\n if (ctx.runExternal === null) {\n return null;\n }\n const { harnessRoot, projectDir, spec } = ctx;\n const runExt = ctx.runExternal ?? runExternalInstall;\n const externalDeps: ExternalInstallerDeps = {\n harnessRoot,\n log: () => {},\n warn: () => {},\n };\n if (ctx.externalDeps?.onAssetStart) {\n externalDeps.onAssetStart = ctx.externalDeps.onAssetStart;\n }\n if (ctx.externalDeps?.onAssetResult) {\n externalDeps.onAssetResult = ctx.externalDeps.onAssetResult;\n }\n const filterCtx = {\n tracks: spec.tracks,\n options: spec.options,\n ...(spec.userOverride ? { userOverride: spec.userOverride } : {}),\n };\n // v26.102.0 (ADR-031) — 헤더 카운트 = 실제 시도될 자산 수. runExternalInstall 과 **같은\n // selector** 를 호출해 \"External assets (N)\" 의 N 이 시도 목록과 구조적으로 일치\n // (이전엔 internal 8종을 포함해 dev 트랙 전부에서 헤더가 과대였다 — SOD 리뷰 F1 실측).\n const applicableCount = selectExternalTargets(EXTERNAL_ASSETS, {\n ...filterCtx,\n cli: spec.cli,\n }).targets.length;\n ctx.onProgress?.({ type: \"external-start\", assetCount: applicableCount });\n const external = runExt(\n { ...filterCtx, cli: spec.cli, projectDir, ...(spec.scope ? { scope: spec.scope } : {}) },\n externalDeps,\n );\n ctx.onProgress?.({ type: \"external-complete\", report: external });\n return external;\n}\n\n/**\n * Install log write — `.claude/.harness-install.json` (자산 list + scope + timestamp,\n * uninstall command 의 source). 실패는 install 자체를 fail 시키지 않음 (D16 — install 성공 우선).\n */\nfunction writeInstallLogSafe(\n ctx: InstallContext,\n external: ExternalInstallReport | null,\n rootClaudeMdLog: { path: string; sha256: string } | null,\n previousLog: InstallLog | null,\n claudeDirMovedAside: boolean,\n rootFiles: ReadonlyArray<InstallLogRootFile>,\n): void {\n try {\n const log = buildInstallLog(\n ctx.spec,\n external,\n resolveScope(ctx.spec.scope),\n rootClaudeMdLog,\n previousLog,\n claudeDirMovedAside,\n rootFiles,\n );\n // v26.126.0 (ADR-046) — 스킬 기준선은 **이력이 아니라 스냅샷**이라 buildInstallLog 의 누적\n // 경로를 타지 않는다. manifest copy 가 끝난 뒤 디스크를 읽어야 값이 맞다.\n const skillFiles = collectSkillHashes(ctx.projectDir);\n writeInstallLog(ctx.projectDir, skillFiles.length > 0 ? { ...log, skillFiles } : log);\n } catch (e) {\n ctx.onProgress?.({\n type: \"install-log-error\",\n message: e instanceof Error ? e.message : String(e),\n });\n }\n}\n\n/**\n * karpathy-coder pre-commit hook auto-wire (v0.6.0).\n *\n * 활성화 조건 (AND):\n * 1. spec.options.withKarpathyHook === true (opt-in 강제)\n * 2. spec.cli 에 \"claude\" 포함 (v0.8.0 — `.claude/settings.json` 미생성 시 와이어 불가)\n * 3. external.attempted에 karpathy-coder ok=true (plugin install 성공)\n *\n * 동작:\n * - templates/hooks/karpathy-gate.sh → <projectDir>/.claude/hooks/karpathy-gate.sh 복사\n * - .claude/settings.json PreToolUse Write|Edit matcher에 hook entry 추가 (idempotent)\n */\nfunction wireKarpathyHook(\n spec: InstallSpec,\n external: ExternalInstallReport | null,\n harnessRoot: string,\n projectDir: string,\n): KarpathyHookReport | null {\n if (!spec.options.withKarpathyHook) {\n return null;\n }\n // v0.8.0 가드 — `.claude/` baseline 미생성 시 hook 와이어 불가 (silent partial state 방지).\n if (!spec.cli.includes(\"claude\")) {\n return { wired: false, reason: \"claude-not-selected\" };\n }\n if (external === null) {\n return { wired: false, reason: \"external-skipped\" };\n }\n const karpathyResult = external.attempted.find((r) => r.asset.id === KARPATHY_ASSET_ID);\n if (!karpathyResult?.ok) {\n return { wired: false, reason: \"plugin-install-failed\" };\n }\n\n // Hook script 복사 (manifest에 없는 v0.6.0 신규 — opt-in 시에만)\n const sourceHook = join(harnessRoot, \"templates/hooks/karpathy-gate.sh\");\n const targetHook = join(projectDir, KARPATHY_HOOK_RELPATH);\n let hookScriptCopied = false;\n if (existsSync(sourceHook)) {\n copyFile(sourceHook, targetHook);\n try {\n chmodSync(targetHook, 0o755);\n } catch {\n // best-effort\n }\n hookScriptCopied = true;\n }\n\n // settings.json PreToolUse Write|Edit entry 추가 (idempotent)\n // HIGH-2 fix: JSON.parse try/catch — add mode에서 사용자 손상 settings.json 시 install 중단 방지\n const settingsPath = join(projectDir, \".claude/settings.json\");\n let settingsUpdated = false;\n if (existsSync(settingsPath)) {\n const raw = readFileSync(settingsPath, \"utf8\");\n let before: ClaudeSettings;\n try {\n before = JSON.parse(raw);\n } catch {\n return { wired: false, reason: \"settings-parse-error\", hookScriptCopied };\n }\n const after = addPreToolUseHook(before, \"Write|Edit\", KARPATHY_HOOK_COMMAND);\n const beforeStr = JSON.stringify(before);\n const afterStr = JSON.stringify(after);\n if (beforeStr !== afterStr) {\n writeFileSync(settingsPath, `${JSON.stringify(after, null, 2)}\\n`);\n settingsUpdated = true;\n }\n }\n\n return { wired: true, settingsUpdated, hookScriptCopied };\n}\n\nfunction composeAndWriteMcp(\n harnessRoot: string,\n projectDir: string,\n spec: InstallSpec,\n): { mcpServers: Record<string, unknown>; created: boolean } {\n const mcpPath = join(projectDir, \".mcp.json\");\n // 쓰기 전에 본다 — 쓰고 나면 \"우리가 만든 것\"과 \"사용자 것에 병합한 것\"을 구분할 수 없다.\n const created = !existsSync(mcpPath);\n const composed = composeMcpJson({\n templateMcpPath: join(harnessRoot, \"templates/mcp.json\"),\n trackMapPath: join(harnessRoot, \"templates/track-mcp-map.tsv\"),\n existingPath: mcpPath,\n tracks: spec.tracks,\n });\n writeMcpJson(mcpPath, composed);\n return { ...composed, created };\n}\n\n/**\n * v26.124.0 (F-1f) — 이번 설치가 `.claude/` **밖**에 만들거나 고친 루트 파일 목록.\n *\n * uninstall 은 이걸 지우지 않고 **안내만** 한다 (사용자 내용이 섞임). 그러려면 무엇을 건드렸는지\n * 기록이 있어야 하는데 v26.123.0 까지 아무 기록이 없어서 안내조차 못 했다.\n *\n * **이번 설치가 실제로 바꾼 것만 넣는다** — idempotent skip(이미 있어서 안 건드림)은 넣지 않는다.\n * 이전 설치분은 install-log 의 누적(mergeRootFiles)이 살려 준다.\n */\nfunction collectRootFiles(\n envFiles: BaselineReport[\"envFiles\"],\n ciScaffold: CiScaffoldReport | null,\n mcpCreated: boolean,\n): InstallLogRootFile[] {\n const files: InstallLogRootFile[] = [\n {\n path: \".mcp.json\",\n change: mcpCreated ? \"created\" : \"modified\",\n notes: [mcpCreated ? \"MCP 서버 정의 생성\" : \"MCP 서버 정의 병합 (기존 항목 보존)\"],\n },\n ];\n if (envFiles.envExampleCreated) {\n files.push({ path: \".env.example\", change: \"created\", notes: [\"Supabase 토큰 가이드\"] });\n }\n // `mcpAllowlist` 는 세 값이 다 다르다: null=skip · []=**서버가 없어 안 씀** · 비어있지 않음=씀.\n // 길이를 안 보면 안 만든 파일을 만들었다고 기록한다 (env-files.ts writeMcpAllowlist).\n if (envFiles.mcpAllowlist && envFiles.mcpAllowlist.length > 0) {\n files.push({\n path: \".mcp-allowlist\",\n change: \"created\",\n notes: [`MCP allowlist (${envFiles.mcpAllowlist.length} server)`],\n });\n }\n const gitignoreAdded = [\n ...(envFiles.gitignoreEnvAdded ? [\".env\"] : []),\n ...envFiles.gitignoreNpxSkillsAdded,\n ];\n if (gitignoreAdded.length > 0) {\n files.push({\n path: \".gitignore\",\n change: \"modified\",\n notes: [`추가된 줄: ${gitignoreAdded.join(\", \")}`],\n });\n }\n for (const workflow of ciScaffold?.written ?? []) {\n files.push({ path: workflow, change: \"created\", notes: [\"CI 워크플로 스캐폴드\"] });\n }\n return files;\n}\n\n/**\n * v0.6.1 — manifest entry를 카테고리별로 누적. install renderer Phase 1 row 출력에 사용.\n * `entry.target` prefix로 분류. file은 basename(.확장자 제거), dir은 dir name.\n */\nfunction accumulateCategory(\n cats: BaselineCategoryCounts,\n entry: import(\"./manifest.js\").AssetEntry,\n): void {\n const target = entry.target;\n if (target.startsWith(\".claude/rules/\") && target.endsWith(\".md\")) {\n const name = target.replace(/^\\.claude\\/rules\\//, \"\").replace(/\\.md$/, \"\");\n cats.rules.push(name);\n } else if (target.startsWith(\".claude/agents/\") && target.endsWith(\".md\")) {\n const name = target.replace(/^\\.claude\\/agents\\//, \"\").replace(/\\.md$/, \"\");\n cats.agents.push(name);\n } else if (target.startsWith(\".claude/hooks/\") && target.endsWith(\".sh\")) {\n const name = target.replace(/^\\.claude\\/hooks\\//, \"\").replace(/\\.sh$/, \"\");\n cats.hooks.push(name);\n } else if (target.startsWith(\".claude/commands/\")) {\n cats.commands += 1;\n } else if (target.startsWith(\".claude/skills/\") && entry.type === \"dir\") {\n const name = target.replace(/^\\.claude\\/skills\\//, \"\").replace(/\\/?$/, \"\");\n cats.skills.push(name);\n }\n}\n\nfunction writeInstalledTracks(projectDir: string, tracks: ReadonlyArray<string>): void {\n const path = join(projectDir, \".claude/.installed-tracks\");\n mkdirSync(dirname(path), { recursive: true });\n const sorted = [...new Set(tracks)].sort().join(\"\\n\");\n writeFileSync(path, `${sorted}\\n`);\n}\n\nfunction writeRootClaudeMd(\n projectDir: string,\n tracks: ReadonlyArray<Track>,\n): { content: string; backup: string | null } {\n const content = mergeProjectClaude(tracks, { projectName: basename(projectDir) });\n const target = join(projectDir, \"CLAUDE.md\");\n // 기존 사용자 CLAUDE.md 는 덮어쓰기 전 백업 (audit CODE-2 — 무백업 덮어쓰기 데이터 손실 방지).\n const backup = backupFileIfChanged(target, content);\n writeFileSync(target, content);\n return { content, backup };\n}\n\nfunction chmodHooksSync(hookDir: string): void {\n for (const file of listHookFiles(hookDir)) {\n try {\n chmodSync(file, 0o755);\n } catch {\n // Best-effort; many platforms (Windows in particular) ignore mode bits.\n }\n }\n}\n\nfunction listHookFiles(hookDir: string): string[] {\n // Hooks are flat shell scripts — avoid pulling glob deps.\n return readdirSync(hookDir, { withFileTypes: true })\n .filter((e) => e.isFile() && e.name.endsWith(\".sh\"))\n .map((e) => resolve(hookDir, e.name));\n}\n","/**\n * Antigravity transform — v26.66.0 (skills/workflows) + v26.69.0 (rules).\n *\n * Google Antigravity 2.0 (I/O 2026-05-19) 공식 spec (codelabs):\n * - Workspace skills: .agents/skills/<name>/SKILL.md (Anthropic skill format — codex 와 공유)\n * - Workspace workflows: .agents/workflows/<name>.md (`/<name>` 슬래시로 호출)\n * - Workspace rules: .agents/rules/<name>.md (디렉토리, plain markdown)\n * - Global rules: ~/.gemini/GEMINI.md (사용자 글로벌 — harness 미터치)\n * - Global skills: ~/.gemini/antigravity/skills/ (Phase C opt-in — antigravity/opt-in.ts)\n *\n * 본 transform 의 책임 (모두 project-scope):\n * 1. `.agents/rules/uzys-harness.md` — project context (CLAUDE.md → Antigravity rule).\n * foundational context (CLAUDE.md/AGENTS.md 처럼 항상 작성).\n * cli=antigravity 단독 선택 시 이게 없으면 Antigravity 가 프로젝트 컨벤션을 모름.\n * 2. `.agents/skills/<id>/SKILL.md` — dev-method skills (frontmatter 보존, codex 와 공유).\n *\n * SAFETY: `~/.gemini/` 글로벌 write 없음.\n */\n\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { basename, join } from \"node:path\";\nimport { renderAgentsMd } from \"../codex/agents-md.js\";\nimport { renderBundledSkill } from \"../codex/skills.js\";\nimport { backupFileIfChanged, ensureDir } from \"../fs-ops.js\";\nimport { renderFillScaffold } from \"../project-claude-merge.js\";\n\nexport interface AntigravityTransformParams {\n /** harness root (templates/CLAUDE.md source 위치). */\n harnessRoot: string;\n /** 사용자 프로젝트 root. `.agents/` 가 만들어질 위치. */\n projectDir: string;\n /**\n * v26.87.0 — dev-method skill ids 선택 목록. 각 id 의 `templates/skills/<id>/SKILL.md` 를\n * Antigravity native `.agents/skills/<id>/SKILL.md` 로 (frontmatter 보존) 출력.\n */\n selectedInternalSkills?: ReadonlyArray<string>;\n}\n\nexport interface AntigravityTransformReport {\n /** v26.69.0 — 작성된 rules 파일 경로 (.agents/rules/uzys-harness.md). null = template 부재. */\n rulesFile: string | null;\n /** 작성된 SKILL.md 경로 list (.agents/skills/<id>/SKILL.md). */\n skillFiles: ReadonlyArray<string>;\n}\n\n/**\n * Antigravity 용 project-scope 자산 생성 (rules + dev-method skills).\n */\nexport function runAntigravityTransform(\n params: AntigravityTransformParams,\n): AntigravityTransformReport {\n const { harnessRoot, projectDir, selectedInternalSkills = [] } = params;\n\n // 1. .agents/rules/uzys-harness.md — project context (CLAUDE.md → Antigravity rule, 항상).\n const rulesFile = writeRules(harnessRoot, projectDir);\n\n const skillFiles: string[] = [];\n\n // 1b. v26.87.0 — dev-method skills → .agents/skills/<id>/SKILL.md (frontmatter 보존).\n // renderBundledSkill 이 source frontmatter(name: <id>)를 보존.\n for (const id of selectedInternalSkills) {\n const src = join(harnessRoot, \"templates/skills\", id, \"SKILL.md\");\n if (!existsSync(src)) {\n continue;\n }\n const skillDir = join(projectDir, \".agents\", \"skills\", id);\n ensureDir(skillDir);\n const target = join(skillDir, \"SKILL.md\");\n writeFileSync(target, renderBundledSkill(readFileSync(src, \"utf8\")));\n skillFiles.push(target);\n }\n\n return { rulesFile, skillFiles };\n}\n\n/**\n * v26.69.0 — `.agents/rules/uzys-harness.md` 작성. CLAUDE.md → Antigravity workspace rule.\n *\n * Source: templates/CLAUDE.md (전문) + templates/antigravity/AGENTS.md.template.\n * v26.70.0 — renderAgentsMd 재사용 (codex/opencode 와 동일 전문 embed). `{PROJECT_RULES}` 에\n * CLAUDE.md 본문 전체 삽입 + `/uzys:` → `/uzys-` rename.\n *\n * template 또는 CLAUDE.md 부재 시 null (graceful — install 진행).\n */\nfunction writeRules(harnessRoot: string, projectDir: string): string | null {\n const claudeMdPath = join(harnessRoot, \"templates/CLAUDE.md\");\n const templatePath = join(harnessRoot, \"templates/antigravity/AGENTS.md.template\");\n if (!existsSync(claudeMdPath) || !existsSync(templatePath)) {\n return null;\n }\n const claudeMd = readFileSync(claudeMdPath, \"utf8\");\n const template = readFileSync(templatePath, \"utf8\");\n const rulesDir = join(projectDir, \".agents\", \"rules\");\n ensureDir(rulesDir);\n const target = join(rulesDir, \"uzys-harness.md\");\n const rulesOut = renderAgentsMd({\n template,\n claudeMd,\n projectName: basename(projectDir),\n projectContext: renderFillScaffold(),\n });\n // 사용자가 채운 rules 파일을 재설치(add 모드) 덮어쓰기 전 보존 — 루트 CLAUDE.md 와 대칭.\n backupFileIfChanged(target, rulesOut);\n writeFileSync(target, rulesOut);\n return target;\n}\n","/**\n * AGENTS.md transform — CLAUDE.md → AGENTS.md.\n *\n * v26.70.0 — section 추출(Identity/Direction/Principles) → CLAUDE.md **전문 embed**.\n * 실 `templates/CLAUDE.md` 가 Rule 1~12 구조라 Identity/Direction/Principles 헤딩이 없어\n * extractSection 이 빈 결과 → AGENTS.md 가 빈 섹션으로 shipping 되던 버그 fix.\n * `{PROJECT_RULES}` placeholder 에 CLAUDE.md 본문 전체를 삽입 (heading 구조 의존 0).\n */\n\n/** Rename Claude slash conventions (`/uzys:foo`) to Codex (`/uzys-foo`). */\nexport function renameSlashes(text: string): string {\n return text.replaceAll(\"/uzys:\", \"/uzys-\");\n}\n\nexport interface AgentsMdParams {\n template: string;\n claudeMd: string;\n projectName: string;\n /** Project-context fill scaffold — the same body shipped to the Claude Code CLAUDE.md. */\n projectContext: string;\n}\n\n/**\n * Render AGENTS.md by embedding the full CLAUDE.md body into the template.\n *\n * Placeholders:\n * - {PROJECT_NAME} — basename of project dir\n * - {PROJECT_RULES} — full CLAUDE.md body (first h1 stripped; template provides its own h1)\n * - {PROJECT_CONTEXT} — project-specific fill scaffold (renderFillScaffold())\n *\n * 마지막에 `/uzys:` → `/uzys-` rename (Codex/Antigravity 는 slash namespace 미지원).\n */\nexport function renderAgentsMd(params: AgentsMdParams): string {\n // CLAUDE.md 의 첫 h1 (# title) 제거 — 템플릿이 자체 h1 보유.\n const body = params.claudeMd.replace(/^#\\s+.*\\r?\\n/, \"\").trim();\n const replaced = params.template\n .replaceAll(\"{PROJECT_NAME}\", params.projectName)\n .replaceAll(\"{PROJECT_RULES}\", body)\n .replaceAll(\"{PROJECT_CONTEXT}\", params.projectContext);\n return renameSlashes(replaced);\n}\n","/**\n * Bundled SKILL.md → non-Claude CLI native skill transform (dev-method skills).\n */\nimport { renameSlashes } from \"./agents-md.js\";\n\n/**\n * v26.87.0 — render a bundled, already-complete SKILL.md (dev-method skills) for a\n * non-Claude CLI (Codex / Antigravity native `.agents/skills/<id>/SKILL.md`).\n *\n * These sources are full Anthropic skills with their OWN frontmatter (`name: <id>`,\n * full description). We MUST preserve that frontmatter verbatim — only the BODY is\n * ported: `/uzys:` → `/uzys-` slash rename + `CLAUDE_PROJECT_DIR` → `CODEX_PROJECT_DIR`\n * env-var rename (Codex/Antigravity share the `.agents/` format + `CODEX_PROJECT_DIR`).\n */\nexport function renderBundledSkill(source: string): string {\n const trimmed = source.trimEnd();\n const lines = trimmed.split(/\\r?\\n/);\n // No frontmatter → emit body as-is (port slashes/env only). Defensive: bundled\n // dev-method skills always have frontmatter, but never silently drop content.\n if (lines[0] !== \"---\") {\n return `${portBody(trimmed)}\\n`;\n }\n let secondDelimAt = -1;\n for (let i = 1; i < lines.length; i++) {\n if (lines[i] === \"---\") {\n secondDelimAt = i;\n break;\n }\n }\n if (secondDelimAt < 0) {\n // Malformed frontmatter (no closing ---) → port whole thing as body.\n return `${portBody(trimmed)}\\n`;\n }\n const frontmatter = lines.slice(0, secondDelimAt + 1).join(\"\\n\");\n const body = lines.slice(secondDelimAt + 1).join(\"\\n\");\n return `${frontmatter}\\n${portBody(body)}\\n`;\n}\n\n/** Port a skill body for Codex/Antigravity: slash + project-dir env-var rename. */\nfunction portBody(body: string): string {\n return renameSlashes(body)\n .replace(/CLAUDE_PROJECT_DIR/g, \"CODEX_PROJECT_DIR\")\n .trimEnd();\n}\n","import {\n copyFileSync,\n cpSync,\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n renameSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\n/** Ensure a directory exists, creating parents as needed. Idempotent. */\nexport function ensureDir(path: string): void {\n mkdirSync(path, { recursive: true });\n}\n\nexport interface CopyResult {\n copied: number;\n skipped: number;\n}\n\n/** Copy a single file, creating parent dirs as needed. Idempotent. */\nexport function copyFile(source: string, target: string): void {\n if (!existsSync(source)) {\n throw new Error(`Source not found: ${source}`);\n }\n mkdirSync(dirname(target), { recursive: true });\n copyFileSync(source, target);\n}\n\n/** Copy a directory recursively. Creates target if missing. */\nexport function copyDir(source: string, target: string): void {\n if (!existsSync(source)) {\n throw new Error(`Source dir not found: ${source}`);\n }\n mkdirSync(target, { recursive: true });\n cpSync(source, target, { recursive: true, force: true });\n}\n\n/**\n * Move an existing directory to a timestamped backup sibling.\n * Returns the backup path, or null when nothing to back up.\n */\nexport function backupDir(target: string, now: Date = new Date()): string | null {\n if (!existsSync(target)) {\n return null;\n }\n const backup = `${target}.backup-${formatStamp(now)}`;\n renameSync(target, backup);\n return backup;\n}\n\n/**\n * Copy backup — original target preserved (for in-place update mode).\n * bash setup-harness.sh L477 `cp -R .claude \"$BACKUP_DIR\"` 등가.\n */\nexport function copyBackupDir(target: string, now: Date = new Date()): string | null {\n if (!existsSync(target)) {\n return null;\n }\n const backup = `${target}.backup-${formatStamp(now)}`;\n cpSync(target, backup, { recursive: true });\n return backup;\n}\n\n/**\n * 사용자 편집 가능 파일(settings.json·CLAUDE.md)을 덮어쓰기 전 보호.\n * 기존 파일이 있고 새 내용과 다르면 timestamp 백업본을 만들고 그 경로를 반환한다.\n * 부재하거나 내용이 동일하면(idempotent 재설치) null — 불필요한 백업을 만들지 않는다.\n * audit SEC-1/CODE-2 — add 모드(.claude/ backup 없음)에서 통째 덮어쓰기로 인한 데이터 손실 방지.\n */\nexport function backupFileIfChanged(\n target: string,\n newContent: string,\n now: Date = new Date(),\n): string | null {\n if (!existsSync(target)) {\n return null;\n }\n if (readFileSync(target, \"utf-8\") === newContent) {\n return null;\n }\n return backupFile(target, now);\n}\n\n/**\n * 기존 파일을 timestamp 백업본으로 복사하고 그 경로를 반환한다. **판정은 호출자 몫.**\n *\n * `backupFileIfChanged` 와 나뉜 이유는 술어가 다르기 때문이다: 저쪽은 \"새 내용과 다른가\",\n * update 의 스킬 갱신(ADR-046)은 \"**설치 시점**과 다른가\"로 판정한다. 하네스가 개선해서\n * 달라진 파일은 사용자가 안 건드렸으므로 백업 없이 덮어써야 하고, 내용 비교만으로는 그\n * 둘을 구분할 수 없다.\n */\nexport function backupFile(target: string, now: Date = new Date()): string {\n const backup = `${target}.backup-${formatStamp(now)}`;\n copyFileSync(target, backup);\n return backup;\n}\n\n/**\n * `dir` 아래 모든 파일의 상대 경로 (디렉터리 자체는 제외). 순서는 readdir 순.\n *\n * `readdirSync(dir, { recursive: true })` 를 안 쓰는 이유: 그 옵션은 Node 20.1.0 에 들어왔는데\n * `engines` 는 `>=20.0.0` 이다. 20.0.x 에서 조용히 `undefined` 를 흘리는 대신 직접 순회한다.\n */\nexport function listFilesRecursive(dir: string, prefix = \"\"): string[] {\n if (!existsSync(dir)) return [];\n const out: string[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const rel = prefix ? `${prefix}/${entry.name}` : entry.name;\n if (entry.isDirectory()) {\n out.push(...listFilesRecursive(join(dir, entry.name), rel));\n } else if (entry.isFile()) {\n out.push(rel);\n }\n }\n return out;\n}\n\nfunction formatStamp(now: Date): string {\n return now\n .toISOString()\n .replace(/[-:]/g, \"\")\n .replace(/\\.\\d+Z$/, \"Z\")\n .slice(0, 15);\n}\n\n/** Create a project skeleton: <project>/.claude/{commands/{uzys,ecc},rules,skills,agents,hooks}. */\nexport function ensureProjectSkeleton(projectDir: string): void {\n const dirs = [\n \".claude/commands/uzys\",\n \".claude/commands/ecc\",\n \".claude/rules\",\n \".claude/skills\",\n \".claude/agents\",\n \".claude/hooks\",\n \"docs/decisions\",\n ];\n for (const d of dirs) {\n mkdirSync(join(projectDir, d), { recursive: true });\n }\n}\n","import { TRACKS, type Track } from \"./types.js\";\n\n/**\n * Project-context scaffold for the delivered CLAUDE.md / AGENTS.md.\n *\n * The installer is a pure Node CLI and CANNOT run an LLM, so it cannot fill a\n * project-specific context file at install time. Shipping generic per-track prose\n * instead produced \"meaningless\" files (a literal `# [Project Name]` title, a Bash\n * stack advertised to every project, phantom rule names). This module ships an\n * honest fill-in SCAFFOLD instead: each section carries an embedded `<!-- FILL: -->`\n * instruction the user runs in their own coding agent post-install (or by hand).\n * The same scaffold body feeds BOTH the Claude Code root CLAUDE.md and the\n * `{PROJECT_CONTEXT}` block of every AGENTS.md — one source, byte-identical across\n * all 4 CLIs, with no disk read-back coupling.\n */\n\nexport const TRACK_DISPLAY_NAMES: Record<Track, string> = {\n tooling: \"Tooling\",\n \"csr-supabase\": \"CSR Supabase\",\n \"csr-fastify\": \"CSR Fastify\",\n \"csr-fastapi\": \"CSR FastAPI\",\n \"ssr-htmx\": \"SSR HTMX\",\n \"ssr-nextjs\": \"SSR Next.js\",\n data: \"Data\",\n executive: \"Executive\",\n full: \"Full\",\n \"project-management\": \"Project Management\",\n \"growth-marketing\": \"Growth Marketing\",\n};\n\n/** Tracks expanded when 'full' is selected — every track except 'full' itself.\n * Derived from TRACKS so a future track can't be silently omitted from a 'full' install. */\nconst FULL_EXPANSION: ReadonlyArray<Track> = TRACKS.filter((t) => t !== \"full\");\n\n/**\n * The MUST-HAVE project-context sections, from a harness perspective: the context\n * an agent needs to work on ANY project with few round-trips. Order is intentional\n * (identity → stack → architecture → assets → boundaries → verify).\n */\nexport const FILL_SECTIONS = [\n \"identity\",\n \"stack\",\n \"architecture\",\n \"installed-assets\",\n \"boundaries\",\n \"verify\",\n] as const;\nexport type FillSection = (typeof FILL_SECTIONS)[number];\n\ninterface FillSpec {\n /** Rendered `## <title>` header. */\n title: string;\n /** Body of the `<!-- FILL:<id> — … -->` comment: what to inspect and write. */\n prompt: string;\n /** Honest `_(not filled yet — …)_` line so an unfilled section never states a false fact. */\n placeholder: string;\n}\n\nconst FILL_SPECS: Record<FillSection, FillSpec> = {\n identity: {\n title: \"Identity & Purpose\",\n prompt:\n 'Replace the H1 title above with this project\\'s real name, then state in 1-2 plain sentences what it does, who uses it, and why it exists. Sources: README.md, the package.json / pyproject.toml \"description\", docs/. Do NOT describe the harness itself. Delete this comment when done.',\n placeholder: \"what this project is, who it is for, and why it exists\",\n },\n stack: {\n title: \"Stack & Commands\",\n prompt:\n \"Replace the list below with this project's REAL stack. Inspect package.json / pyproject.toml / go.mod / Cargo.toml / Gemfile + lockfiles and any Makefile/justfile/package scripts. List the language(s)+versions, framework(s), package manager, and the exact install/build/test/run commands. Verify each command exists before writing it — never guess. Delete lines that do not apply, then delete this comment.\",\n placeholder: \"languages, runtimes, package manager, and the install/build/test/run commands\",\n },\n architecture: {\n title: \"Architecture & Layout\",\n prompt:\n \"Map this repository. List each top-level source directory and what it holds, the entry point(s), the 3-5 files a newcomer reads first, and how data/requests flow between the main layers. View the real tree (e.g. `git ls-files | sed 's#/.*##' | sort -u`) — do not assume a framework's conventional layout. Flag any generated/vendored directories that must never be hand-edited. If this is a single small module, say so in one line. Delete this comment when done.\",\n placeholder: \"where things live, the entry points, and how data flows between layers\",\n },\n \"installed-assets\": {\n title: \"Installed Harness Assets\",\n prompt:\n \"List the harness assets installed in this project (rules / skills / agents / commands) and add one line each on when to reach for it here. Verify against .claude/rules/*.md, .claude/skills/, .claude/agents/, .claude/commands/ (or this CLI's equivalent) and list ONLY assets whose file exists on disk — do not invent any. Do NOT restate the universal Rule 1-12 (they live in the rules layer) — cross-reference them instead. Delete this comment when done.\",\n placeholder: \"the installed rules/skills/agents/commands and when to use each\",\n },\n boundaries: {\n title: \"Boundaries — Always / Ask First / Never\",\n prompt:\n 'Fill the Always / Ask First / Never lists with this repo\\'s real red lines. Read the CI config, CODEOWNERS, .gitignore, and release/deploy scripts. Never must include secrets, generated files, force-push, and direct commits to the default branch, plus any repo-specific \"do not touch\" directories. Every entry must be specific and enforceable here. Delete this comment when done.',\n placeholder: \"what to always do, ask before doing, and never do in this repo\",\n },\n verify: {\n title: \"Verification Gate\",\n prompt:\n 'State the single command (or short sequence) that PROVES a change is safe here — the test/lint/typecheck/build gate you run before committing — plus the coverage/CI threshold and what \"done\" means. Sources: package scripts, CI workflow files, CONTRIBUTING. An agent must be able to self-verify without guessing. Delete this comment when done.',\n placeholder: \"the single command that proves a change is safe, and the done bar\",\n },\n};\n\n/** Visible (rendered-markdown) banner — HTML FILL comments are invisible in a preview, so this\n * blockquote is what stops the scaffold from reading as verified project fact for a human. */\nexport const SCAFFOLD_BANNER = [\n \"> ⚙️ **SCAFFOLD — not filled in yet.** The sections below are a fill-in template for THIS project, not verified facts.\",\n \"> To fill: open this file and paste each `<!-- FILL: … -->` comment's instruction into your coding agent (e.g. Claude Code) — it will inspect the real repo and write the section. You can also fill them by hand; the comments are the instructions.\",\n \"> The universal harness rules (Rule 1–12) live in the separate rules layer. This file is **project-specific context only**.\",\n].join(\"\\n\");\n\n/**\n * Shared project-context scaffold body: the visible banner followed by the six MUST-HAVE\n * sections, each a `## Title` + a self-contained `<!-- FILL:id — … -->` comment + an honest\n * `_(not filled yet — …)_` placeholder. Pure and track-agnostic, so the Claude Code CLAUDE.md\n * and every AGENTS.md `{PROJECT_CONTEXT}` block get byte-identical prompts from one source.\n */\nexport function renderFillScaffold(): string {\n const blocks = FILL_SECTIONS.map((id) => {\n const spec = FILL_SPECS[id];\n return `## ${spec.title}\\n\\n<!-- FILL:${id} — ${spec.prompt} -->\\n\\n_(not filled yet — ${spec.placeholder})_`;\n });\n return `${SCAFFOLD_BANNER}\\n\\n${blocks.join(\"\\n\\n\")}`;\n}\n\nexport interface MergeOptions {\n /** Project directory basename → the H1 title (fixes the shipped `# [Project Name]` literal). */\n projectName: string;\n}\n\n/**\n * Build the project-root CLAUDE.md: a real H1 project name + the active-track note (genuine\n * install metadata) + the shared fill scaffold. The scaffold is track-agnostic — the selected\n * tracks are recorded in the note; the installed-assets section is filled from real files at\n * fill time rather than from static per-track prose.\n */\nexport function mergeProjectClaude(tracks: ReadonlyArray<Track>, opts: MergeOptions): string {\n const expanded = expandTracks(tracks);\n const trackList = expanded.map((t) => TRACK_DISPLAY_NAMES[t]).join(\", \");\n const header = `# ${opts.projectName}\\n\\n> Active track(s): ${trackList}`;\n return `${header}\\n\\n${renderFillScaffold()}\\n`;\n}\n\nfunction expandTracks(tracks: ReadonlyArray<Track>): ReadonlyArray<Track> {\n if (tracks.includes(\"full\")) {\n return FULL_EXPANSION;\n }\n return tracks;\n}\n","/**\n * CI scaffold (v26.108.0, 라이프사이클 자산화 ② — ADR-037) — `.github/workflows/` fill-in\n * 워크플로 템플릿 설치. 실무 CI 패턴(실DB 서비스 컨테이너 · tag-only 트리거 +\n * 로컬 검증 1차 게이트 · Playwright E2E · coverage 게이트)의 도메인 중립 일반화\n * (docs/plans/lifecycle-codification-2026-07-18.md ② — CI 0 인 실프로젝트가 갭의 존재 증명).\n *\n * 본 하네스가 `.claude/` 밖에 쓰는 첫 자산 — 안전 계약 2가지:\n * 1. opt-in 전용 (`--with ci-scaffold` / wizard 체크) — 무인지 설치 없음.\n * 2. **기존 파일 절대 덮어쓰지 않음** — 이미 존재하는 워크플로 파일은 skip 하고\n * `skippedExisting` 으로 정직 보고 (manifest copyFile 의 무조건 overwrite 와 다른 이유).\n * uninstall 도 `.github/` 를 건드리지 않는다 (install-log 미기록 — 설치 후 사용자 소유물).\n */\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { copyFile } from \"./fs-ops.js\";\nimport { anyTrack, hasUiTrack } from \"./track-match.js\";\nimport type { Track } from \"./types.js\";\n\nexport interface CiScaffoldReport {\n /** 새로 쓴 워크플로 파일 (project-relative). */\n written: string[];\n /** 이미 존재해 보존한 파일 (project-relative) — no-clobber 정직 보고용. */\n skippedExisting: string[];\n}\n\ninterface WorkflowVariant {\n /** `templates/github-workflows/` 안의 소스 파일명. */\n source: string;\n /** `.github/workflows/` 안의 타깃 파일명. */\n target: string;\n applies: (tracks: ReadonlyArray<Track>) => boolean;\n}\n\nconst PYTHON_TRACKS = \"data|csr-fastapi|full\";\n\n/**\n * Track → 변형 매핑 (결정론 — Rule 5, 사용자가 받는 파일을 사전에 알 수 있어야 한다):\n * - node CI: node 계열 트랙, 또는 python 계열이 전혀 없을 때의 fallback — 명시 opt-in 이\n * 트랙 매핑 밖(예: PM 단독)이라고 무설치가 되면 silent no-op (no-false-ship 위반).\n * - python CI: python 계열 트랙. csr-fastapi·full 은 polyglot — node 와 양쪽 설치.\n * - e2e(Playwright): UI 트랙만 (playwright-launch 룰과 동일 게이팅).\n */\nconst VARIANTS: ReadonlyArray<WorkflowVariant> = [\n {\n source: \"ci-node.yml\",\n target: \"ci.yml\",\n applies: (tracks) =>\n anyTrack(tracks, \"csr-*|ssr-*|tooling|full\") || !anyTrack(tracks, PYTHON_TRACKS),\n },\n {\n source: \"ci-python.yml\",\n target: \"ci-python.yml\",\n applies: (tracks) => anyTrack(tracks, PYTHON_TRACKS),\n },\n {\n source: \"e2e.yml\",\n target: \"e2e.yml\",\n applies: (tracks) => hasUiTrack(tracks),\n },\n];\n\nexport function installCiScaffold(ctx: {\n harnessRoot: string;\n projectDir: string;\n tracks: ReadonlyArray<Track>;\n}): CiScaffoldReport {\n const report: CiScaffoldReport = { written: [], skippedExisting: [] };\n for (const v of VARIANTS) {\n if (!v.applies(ctx.tracks)) continue;\n const relTarget = `.github/workflows/${v.target}`;\n const target = join(ctx.projectDir, relTarget);\n if (existsSync(target)) {\n report.skippedExisting.push(relTarget);\n continue;\n }\n copyFile(join(ctx.harnessRoot, \"templates/github-workflows\", v.source), target);\n report.written.push(relTarget);\n }\n return report;\n}\n","/**\n * Codex global opt-in — ~/.codex/config.toml trust entry 등록.\n *\n * SPEC: docs/specs/cli-rewrite-completeness.md F11 (Reviewer HIGH-4)\n * Source: bash setup-harness.sh@911c246~1 L1389~1429\n *\n * SAFETY: 사용자 명시 opt-in 없이 ~/.codex/ 글로벌 수정 금지 (D16 / ADR-002 v2 D4).\n * 호출자(installer)는 OptionFlags.withCodexTrust 가 true 일 때만 호출.\n */\n\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { registerTrustEntry } from \"./trust-entry.js\";\n\nexport interface CodexOptInReport {\n /** ~/.codex/config.toml trust entry 등록 결과 */\n trustEntry: {\n enabled: boolean;\n status: \"registered\" | \"already-present\" | \"error\" | \"skipped\";\n message?: string;\n };\n}\n\nexport interface CodexOptInContext {\n /** 사용자 프로젝트 root (trust entry 경로). */\n projectDir: string;\n /** 글로벌 ~/.codex/ 경로 (테스트 override 가능). */\n codexHome?: string;\n}\n\n/** ~/.codex/config.toml 에 프로젝트 trust entry 등록. */\nexport function runCodexOptIn(ctx: CodexOptInContext): CodexOptInReport {\n const codexHome = ctx.codexHome ?? join(homedir(), \".codex\");\n const configPath = join(codexHome, \"config.toml\");\n const result = registerTrustEntry({ configPath, projectDir: ctx.projectDir });\n return {\n trustEntry: {\n enabled: true,\n status: result.status,\n ...(result.message ? { message: result.message } : {}),\n },\n };\n}\n","/**\n * Codex trust entry — `~/.codex/config.toml [projects.\"<dir>\"]` (parity with\n * setup-harness.sh L1404-1422).\n *\n * SAFETY: never modify the global `~/.codex/config.toml` without an explicit\n * opt-in (D16 / ADR-002 v2 D4). Callers must verify user consent first.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\n\nexport interface RegisterTrustResult {\n status: \"registered\" | \"already-present\" | \"error\";\n message?: string;\n}\n\nconst TRUST_BLOCK_REGEX = /\\[projects\\.\"([^\"]+)\"\\]/g;\n\n/** Append a `[projects.\"<projectDir>\"]` block to the user `config.toml` (idempotent). */\nexport function registerTrustEntry(opts: {\n configPath: string;\n projectDir: string;\n}): RegisterTrustResult {\n const { configPath, projectDir } = opts;\n try {\n mkdirSync(dirname(configPath), { recursive: true });\n const existing = existsSync(configPath) ? readFileSync(configPath, \"utf8\") : \"\";\n if (hasTrustEntry(existing, projectDir)) {\n return { status: \"already-present\" };\n }\n const block = `\\n[projects.\"${projectDir}\"]\\ntrust_level = \"trusted\"\\n`;\n writeFileSync(configPath, existing + block);\n return { status: \"registered\" };\n } catch (e: unknown) {\n return {\n status: \"error\",\n message: e instanceof Error ? e.message : String(e),\n };\n }\n}\n\nexport function hasTrustEntry(configContent: string, projectDir: string): boolean {\n const matches = [...configContent.matchAll(TRUST_BLOCK_REGEX)].map((m) => m[1]);\n return matches.includes(projectDir);\n}\n","/**\n * Codex transform orchestrator — wraps the 5-step pipeline.\n *\n * Replaces `scripts/claude-to-codex.sh` (Phase D, OQ4 = TS port).\n *\n * Inputs:\n * - harnessRoot: repository root (templates/ + .mcp.json)\n * - projectDir: target project to receive AGENTS.md + .codex/ + .agents/skills/\n *\n * Outputs (under projectDir):\n * - AGENTS.md\n * - .codex/config.toml\n * - .codex/hooks/*.sh (hooks ported from templates/hooks/)\n * - .agents/skills/<id>/SKILL.md (dev-method skills, frontmatter 보존)\n *\n * v0.6.4 — skill 출력 경로는 Codex 공식 표준 `.agents/skills/<name>/SKILL.md` (repo-level scope).\n * 참조: https://developers.openai.com/codex/skills\n */\n\nimport { chmodSync, existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { basename, join } from \"node:path\";\nimport { backupFileIfChanged, ensureDir } from \"../fs-ops.js\";\nimport type { McpJson } from \"../mcp-merge.js\";\nimport { renderFillScaffold } from \"../project-claude-merge.js\";\nimport { renderAgentsMd } from \"./agents-md.js\";\nimport { renderConfigToml } from \"./config-toml.js\";\nimport { renderBundledSkill } from \"./skills.js\";\n\nexport interface CodexTransformParams {\n harnessRoot: string;\n projectDir: string;\n /**\n * v26.87.0 — dev-method skill ids 선택 목록 (installer 가 `DEV_METHOD_SKILL_IDS` 를\n * `isAssetSelected` 로 필터). 각 id 의 `templates/skills/<id>/SKILL.md` 를 Codex native\n * `.agents/skills/<id>/SKILL.md` 로 (frontmatter 보존) 출력.\n */\n selectedInternalSkills?: ReadonlyArray<string>;\n}\n\nexport interface CodexTransformReport {\n agentsMdPath: string;\n configTomlPath: string;\n hookFiles: string[];\n skillFiles: string[];\n}\n\nconst HOOK_NAMES = [\"session-start\"];\n\nconst ENV_VAR_RENAME = /CLAUDE_PROJECT_DIR/g;\n\nexport function runCodexTransform(params: CodexTransformParams): CodexTransformReport {\n const { harnessRoot, projectDir, selectedInternalSkills = [] } = params;\n\n const claudeMd = readRequired(join(harnessRoot, \"templates/CLAUDE.md\"));\n const agentsTemplate = readRequired(join(harnessRoot, \"templates/codex/AGENTS.md.template\"));\n const configTemplate = readRequired(join(harnessRoot, \"templates/codex/config.toml.template\"));\n const projectName = basename(projectDir);\n const mcp = readOptionalJson(join(harnessRoot, \".mcp.json\"));\n\n // 1. AGENTS.md\n const agentsMdPath = join(projectDir, \"AGENTS.md\");\n ensureDir(projectDir);\n const agentsMdOut = renderAgentsMd({\n template: agentsTemplate,\n claudeMd,\n projectName,\n projectContext: renderFillScaffold(),\n });\n // 사용자가 채운 AGENTS.md 를 재설치(add 모드) 덮어쓰기 전 보존 — 루트 CLAUDE.md 와 대칭.\n backupFileIfChanged(agentsMdPath, agentsMdOut);\n writeFileSync(agentsMdPath, agentsMdOut);\n\n // 2. .codex/config.toml\n const configTomlPath = join(projectDir, \".codex/config.toml\");\n ensureDir(join(projectDir, \".codex\"));\n writeFileSync(\n configTomlPath,\n renderConfigToml({\n template: configTemplate,\n projectName,\n projectDir,\n mcp,\n }),\n );\n\n // 3. .codex/hooks/session-start.sh\n const hookDir = join(projectDir, \".codex/hooks\");\n ensureDir(hookDir);\n const hookFiles: string[] = [];\n for (const hook of HOOK_NAMES) {\n const src = join(harnessRoot, \"templates/hooks\", `${hook}.sh`);\n if (!existsSync(src)) {\n continue;\n }\n const ported = readFileSync(src, \"utf8\").replace(ENV_VAR_RENAME, \"CODEX_PROJECT_DIR\");\n const target = join(hookDir, `${hook}.sh`);\n writeFileSync(target, ported);\n chmodSync(target, 0o755);\n hookFiles.push(target);\n }\n\n // 4. v26.87.0 — dev-method skills → .agents/skills/<id>/SKILL.md (frontmatter 보존).\n // renderBundledSkill 이 source frontmatter(name: <id>)를 그대로 보존하고 body 만 포팅.\n const skillFiles: string[] = [];\n for (const id of selectedInternalSkills) {\n const src = join(harnessRoot, \"templates/skills\", id, \"SKILL.md\");\n if (!existsSync(src)) {\n continue;\n }\n const skillDir = join(projectDir, \".agents\", \"skills\", id);\n ensureDir(skillDir);\n const target = join(skillDir, \"SKILL.md\");\n writeFileSync(target, renderBundledSkill(readFileSync(src, \"utf8\")));\n skillFiles.push(target);\n }\n\n return { agentsMdPath, configTomlPath, hookFiles, skillFiles };\n}\n\nfunction readRequired(path: string): string {\n if (!existsSync(path)) {\n throw new Error(`Codex transform: required source missing: ${path}`);\n }\n return readFileSync(path, \"utf8\");\n}\n\nfunction readOptionalJson(path: string): McpJson | null {\n if (!existsSync(path)) {\n return null;\n }\n try {\n return JSON.parse(readFileSync(path, \"utf8\")) as McpJson;\n } catch {\n return null;\n }\n}\n","/**\n * config.toml transform — fill placeholders + append [mcp_servers.X] from .mcp.json.\n * Mirrors `claude-to-codex.sh` steps 2 + 5.\n */\n\nimport type { McpJson } from \"../mcp-merge.js\";\n\nexport interface RenderConfigTomlParams {\n template: string;\n projectName: string;\n projectDir: string;\n /** Source `.mcp.json` (parsed). When provided, [mcp_servers.X] blocks replace defaults. */\n mcp?: McpJson | null;\n}\n\nconst DEFAULT_MCP_BLOCK_RE = /\\n# =+\\n# MCP Servers — .*?\\n# =+[\\s\\S]*$/;\n\n/**\n * Substitute placeholders + replace the MCP servers section with blocks\n * derived from the supplied `.mcp.json` (or leave the template default).\n */\nexport function renderConfigToml(params: RenderConfigTomlParams): string {\n const substituted = params.template\n .replaceAll(\"{PROJECT_NAME}\", params.projectName)\n .replaceAll(\"{PROJECT_DIR}\", params.projectDir)\n .replaceAll(\"{GITHUB_TOKEN}\", \"${GITHUB_TOKEN}\");\n\n if (!params.mcp) {\n return substituted;\n }\n\n const stripped = stripExistingMcpSection(substituted);\n const fresh = renderMcpServers(params.mcp);\n return `${stripped.trimEnd()}\\n${fresh}\\n`;\n}\n\nfunction stripExistingMcpSection(toml: string): string {\n // Drop default [mcp_servers.X] blocks shipped in the template (we replace from .mcp.json)\n const lines = toml.split(/\\r?\\n/);\n const out: string[] = [];\n let skipping = false;\n for (const line of lines) {\n if (line.startsWith(\"[mcp_servers.\")) {\n skipping = true;\n continue;\n }\n if (skipping && line.startsWith(\"[\") && !line.startsWith(\"[mcp_servers.\")) {\n skipping = false;\n }\n if (skipping) {\n continue;\n }\n if (\n /^# .*MCP Servers/.test(line) ||\n /^# Railway MCP/.test(line) ||\n /^# github MCP/.test(line)\n ) {\n continue;\n }\n out.push(line);\n }\n return out.join(\"\\n\").replace(DEFAULT_MCP_BLOCK_RE, \"\");\n}\n\nfunction renderMcpServers(mcp: McpJson): string {\n const stamp = new Date().toISOString().slice(0, 10);\n const header = [\n \"# ============================================================\",\n `# MCP Servers — generated from .mcp.json (${stamp})`,\n \"# ============================================================\",\n ].join(\"\\n\");\n\n const blocks = Object.entries(mcp.mcpServers).map(([name, cfg]) => {\n const lines = [`[mcp_servers.${quoteIfNeeded(name)}]`];\n lines.push(`command = ${jsonString(cfg.command)}`);\n lines.push(`args = ${JSON.stringify(cfg.args)}`);\n if (cfg.env && Object.keys(cfg.env).length > 0) {\n const envBody = Object.entries(cfg.env)\n .map(([k, v]) => `${k} = ${jsonString(v)}`)\n .join(\", \");\n lines.push(`env = { ${envBody} }`);\n }\n return lines.join(\"\\n\");\n });\n\n return [header, \"\", ...blocks].join(\"\\n\");\n}\n\nfunction jsonString(s: string): string {\n return JSON.stringify(s);\n}\n\nfunction quoteIfNeeded(name: string): string {\n return /^[A-Za-z0-9_-]+$/.test(name) ? name : `\"${name}\"`;\n}\n","/**\n * env-files.ts — 환경 파일 자동 생성.\n *\n * SPEC: docs/specs/cli-rewrite-completeness.md F7, F8\n * Source: bash setup-harness.sh@911c246~1 L880~890 + L954~996.\n *\n * 3 종 산출:\n * 1. .env.example (csr-supabase / full Track) — Supabase 토큰 가이드\n * 2. .gitignore .env 라인 추가 (없을 때만)\n * 3. .mcp-allowlist (모든 dev Track) — D35 opt-in security gate\n *\n * 모두 idempotent — 이미 있으면 skip.\n */\n\nimport { appendFileSync, existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { Track } from \"./types.js\";\n\nconst ENV_EXAMPLE_BODY = `# .env.example — csr-supabase Track\n# Copy to .env (gitignored) and fill in values: cp .env.example .env\n\n# ===== Supabase Management API (MCP server용) =====\n# Personal Access Token — @supabase/mcp-server가 프로젝트 생성/마이그레이션/Edge Functions 배포에 사용\n# 발급: https://supabase.com/dashboard/account/tokens\nSUPABASE_ACCESS_TOKEN=\n\n# 프로젝트 참조 ID (예: \"abcdefghijklmnop\")\n# 위치: Supabase Dashboard → Project Settings → General\nSUPABASE_PROJECT_REF=\n\n# DB 패스워드 (supabase db push 등 직접 DB 접근용)\n# 위치: Supabase Dashboard → Project Settings → Database\nSUPABASE_DB_PASSWORD=\n\n# ===== Frontend (public, 클라이언트 노출 OK) =====\n# 위치: Supabase Dashboard → Project Settings → API\nNEXT_PUBLIC_SUPABASE_URL=\nNEXT_PUBLIC_SUPABASE_ANON_KEY=\n\n# ===== Optional — 앱 측 AI 기능용 =====\n# OPENAI_API_KEY=\n# ANTHROPIC_API_KEY=\n\n# ===== Note =====\n# - Vercel/Netlify는 별도 CLI login 사용 (env 불필요): vercel login / netlify login\n# - Supabase CLI(supabase login)는 OAuth로 ~/.config/supabase/에 토큰 저장 — env 별개\n# - .env는 .gitignore됨 (자동 추가). 절대 commit 금지.\n`;\n\nconst ENV_EXAMPLE_TRACKS: ReadonlyArray<Track> = [\"csr-supabase\", \"full\"];\n\nconst GITIGNORE_ENV_PATTERN = /^\\.env$|^\\.env\\s/m;\n\n/**\n * .env.example 생성 (csr-supabase/full Track 한정, idempotent).\n * @returns true if created, false if skipped (already exists or non-applicable track)\n */\nexport function writeEnvExample(projectDir: string, tracks: ReadonlyArray<Track>): boolean {\n if (!tracks.some((t) => ENV_EXAMPLE_TRACKS.includes(t))) {\n return false;\n }\n const path = join(projectDir, \".env.example\");\n if (existsSync(path)) {\n return false;\n }\n writeFileSync(path, ENV_EXAMPLE_BODY);\n return true;\n}\n\n/**\n * .gitignore에 `.env` 라인 추가. 이미 있으면 skip.\n * @returns true if appended, false if skipped (no .gitignore or .env already listed)\n */\nexport function addGitignoreEnv(projectDir: string): boolean {\n const path = join(projectDir, \".gitignore\");\n if (!existsSync(path)) {\n return false;\n }\n const content = readFileSync(path, \"utf8\");\n if (GITIGNORE_ENV_PATTERN.test(content)) {\n return false;\n }\n // append with separator (avoid double newlines)\n const sep = content.endsWith(\"\\n\") ? \"\" : \"\\n\";\n appendFileSync(path, `${sep}\\n# Secret env (auto-added by agent-harness install)\\n.env\\n`);\n return true;\n}\n\nconst NPX_SKILLS_AGENT_DIRS = [\".factory/\", \".goose/\"];\nconst GITIGNORE_NPX_SKILLS_HEADER =\n \"# npx skills add multi-CLI cache (auto-added by agent-harness)\";\n\n/**\n * v0.8.0 — `.gitignore`에 `.factory/`, `.goose/` 패턴 추가 (사용자 보고 #3).\n *\n * `npx skills add`가 multi-CLI universal install 동작 — Codex 사용자 환경에서\n * `.factory/skills/`, `.goose/skills/` 자동 생성. 사용자 git noise 회피용 ignore.\n *\n * idempotent — 이미 있으면 skip.\n * @returns added pattern list (empty if all already present or no .gitignore)\n */\nexport function addGitignoreNpxSkillsAgents(projectDir: string): string[] {\n const path = join(projectDir, \".gitignore\");\n if (!existsSync(path)) {\n return [];\n }\n const content = readFileSync(path, \"utf8\");\n const missing = NPX_SKILLS_AGENT_DIRS.filter((pattern) => {\n // exact line match (이스케이프 후 줄 단위 비교 — 단순화: 문자열 포함)\n const lineRegex = new RegExp(`^${pattern.replace(/\\./g, \"\\\\.\").replace(/\\//g, \"/\")}\\\\s*$`, \"m\");\n return !lineRegex.test(content);\n });\n if (missing.length === 0) {\n return [];\n }\n const sep = content.endsWith(\"\\n\") ? \"\" : \"\\n\";\n const block = [GITIGNORE_NPX_SKILLS_HEADER, ...missing].join(\"\\n\");\n appendFileSync(path, `${sep}\\n${block}\\n`);\n return [...missing];\n}\n\n/**\n * .mcp-allowlist 생성 from .mcp.json mcpServers keys (D35 opt-in security gate).\n * mcp-pre-exec.sh hook이 참조. 파일 부재 시 gate disabled.\n * @returns server name list written, or null if skipped (already exists or .mcp.json missing)\n */\nexport function writeMcpAllowlist(projectDir: string): string[] | null {\n const allowlistPath = join(projectDir, \".mcp-allowlist\");\n if (existsSync(allowlistPath)) {\n return null;\n }\n const mcpPath = join(projectDir, \".mcp.json\");\n if (!existsSync(mcpPath)) {\n return null;\n }\n let names: string[] = [];\n try {\n const parsed = JSON.parse(readFileSync(mcpPath, \"utf8\")) as {\n mcpServers?: Record<string, unknown>;\n };\n names = Object.keys(parsed.mcpServers ?? {}).sort();\n } catch {\n return null;\n }\n if (names.length === 0) {\n return [];\n }\n const body = [\n \"# MCP Server Allowlist — auto-generated by agent-harness install\",\n \"# Referenced by mcp-pre-exec.sh hook. Remove or '#' comment any server you want to block.\",\n \"# Deleting this file disables the gate (allows all MCP calls).\",\n \"\",\n ...names,\n \"\",\n ].join(\"\\n\");\n writeFileSync(allowlistPath, body);\n return names;\n}\n","/**\n * External installer — `EXTERNAL_ASSETS` 매트릭스를 실제 호출로 변환.\n *\n * SPEC: docs/specs/cli-rewrite-completeness.md F1\n *\n * Decision (OQ1): 실패는 warn-skip. 종료 시 누락 자산 목록 보고.\n * abort는 첫 실행 신뢰성을 깨뜨리므로 채택 안 함 (vibe killer).\n *\n * Spawning은 `child_process.spawnSync` 사용. command/args 분리로 shell injection 차단.\n * stdout/stderr는 captured — 사용자에게 한 줄 요약만 노출 (verbose-log는 별도 옵션 후속).\n */\n\nimport { type SpawnSyncReturns, spawnSync } from \"node:child_process\";\nimport { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { CATEGORIES as CATEGORY_ORDER } from \"./categories.js\";\nimport {\n assetReachesCli,\n EXTERNAL_ASSETS,\n type ExternalAsset,\n type ExternalAssetMethod,\n filterApplicableAssets,\n} from \"./external-assets.js\";\nimport {\n type CliTargets,\n type InstallScope,\n type OptionFlags,\n resolveScope,\n type Track,\n} from \"./types.js\";\n\nexport interface ExternalInstallerDeps {\n /** Override `spawnSync` for tests (mock으로 호출 횟수 + args 검증). */\n spawn?: (cmd: string, args: ReadonlyArray<string>, opts: SpawnOpts) => SpawnSyncReturns<string>;\n /** harness root (prune-ecc.sh script 위치 resolve용). */\n harnessRoot?: string;\n /** asset 매트릭스 override (테스트용, 기본 EXTERNAL_ASSETS 전체). */\n assets?: ReadonlyArray<ExternalAsset>;\n /** 진행 상황 로그 stream (기본 console.log). 일반 로그용. */\n log?: (msg: string) => void;\n /** 경고 메시지 stream (기본 console.error). */\n warn?: (msg: string) => void;\n /**\n * 자산 설치 시작 직전 호출 (streaming UI용).\n * Renderer가 \"→ asset (installing...)\" 라인 출력에 사용.\n */\n onAssetStart?: (asset: ExternalAsset) => void;\n /**\n * 자산 설치 완료 후 호출 (streaming UI용).\n * Renderer가 \"✓/⊘ asset meta\" 라인 출력에 사용.\n */\n onAssetResult?: (result: AssetInstallResult) => void;\n}\n\ninterface SpawnOpts {\n encoding: \"utf8\";\n stdio: (\"ignore\" | \"pipe\")[] | \"ignore\" | \"pipe\";\n timeout?: number;\n /** v26.77.0 — 작업 디렉토리. projectDir 로 고정해 자산이 올바른 프로젝트에 착지. */\n cwd?: string;\n}\n\nexport interface AssetInstallResult {\n asset: ExternalAsset;\n ok: boolean;\n /** ok=false 시 user-facing 메시지 */\n message?: string;\n /**\n * v26.59.0 — 설치된 자산 version. install 후 detectVersion 으로 path 기반 추출.\n * plugin: ~/.claude/plugins/cache/<marketplace>/<plugin>/<VERSION>/ 디렉토리명\n * npm-global: <npm root -g>/<pkg>/package.json 의 version\n * 그 외 method (skill, npx-run, shell-script): 표준 metadata 없음 → undefined.\n */\n version?: string;\n}\n\nexport interface ExternalInstallReport {\n /** 적용 시도된 자산 (조건 통과한 것만) */\n attempted: ReadonlyArray<AssetInstallResult>;\n /** 성공 갯수 */\n succeeded: number;\n /** warn-skip 된 갯수 */\n skipped: number;\n /**\n * v26.102.0 (ADR-031) — 조건은 통과했으나 선택 CLI 와 도달 범위(assetCliSupport)의\n * 교집합이 없어 **시도조차 하지 않은** 자산 (예: codex 단독 설치의 claude 전용 plugin).\n * 침묵 제외 금지 — render 가 이 목록을 사용자에게 고지한다 (no-false-ship).\n */\n excludedByCli: ReadonlyArray<ExternalAsset>;\n}\n\nconst DEFAULT_SPAWN_TIMEOUT_MS = 120_000;\n\n/**\n * v26.102.0 (ADR-031) — external 단계의 대상/배제 판정 **단일 지점**. 규칙 = 조건 통과 ∧\n * non-internal(Phase 1 담당) ∧ 선택 CLI 도달. runExternalInstall(시도 목록)과\n * runExternalPhase(헤더 카운트)가 이 함수만 호출한다 — 같은 규칙을 두 파일에 각각 기술하면\n * 3번째 조건이 생길 때 카운트만 조용히 어긋난다 (SOD 리뷰 Important-6, no-false-ship\n * \"동일 목록 2곳 하드코딩 금지\").\n */\nexport function selectExternalTargets(\n assets: ReadonlyArray<ExternalAsset>,\n ctx: {\n tracks: ReadonlyArray<Track>;\n options: OptionFlags;\n cli: CliTargets;\n userOverride?: { forceInclude: ReadonlyArray<string>; forceExclude: ReadonlyArray<string> };\n },\n): { targets: ExternalAsset[]; excludedByCli: ExternalAsset[] } {\n const conditionPassed = filterApplicableAssets(assets, ctx).filter(\n (a) => a.method.kind !== \"internal\",\n );\n return {\n targets: conditionPassed.filter((a) => assetReachesCli(a, ctx.cli)),\n excludedByCli: conditionPassed.filter((a) => !assetReachesCli(a, ctx.cli)),\n };\n}\n\n/**\n * spec에 적용 가능한 자산을 모두 시도. 실패는 warn-skip (기본).\n */\nexport function runExternalInstall(\n ctx: {\n tracks: ReadonlyArray<Track>;\n options: OptionFlags;\n cli: CliTargets;\n /** v26.47.0 — Phase C full user override (forceInclude/forceExclude). */\n userOverride?: { forceInclude: ReadonlyArray<string>; forceExclude: ReadonlyArray<string> };\n /** v26.64.0 (ADR-020) — Install scope. undefined → default \"project\". */\n scope?: InstallScope;\n /**\n * v26.77.0 — 외부 설치기 spawn 의 작업 디렉토리.\n * 미지정 시 process.cwd(). 핵심: npm(--save-dev)·npx-run(bmad --directory .)·\n * plugin(--scope project, claude 의 cwd 기반 project 탐지)·skill 이 모두 cwd 기준으로\n * 착지하므로, --project-dir 가 cwd 와 다르면 cwd 를 projectDir 로 맞춰야 자산이 올바른\n * 프로젝트에 떨어진다 (이 누락 = 2026-06-07 probe 가 repo 를 오염시킨 근본 원인).\n */\n projectDir?: string;\n },\n deps: ExternalInstallerDeps = {},\n): ExternalInstallReport {\n const log = deps.log ?? console.log;\n const warn = deps.warn ?? console.error;\n const spawn = deps.spawn ?? defaultSpawn;\n const assets = deps.assets ?? EXTERNAL_ASSETS;\n const harnessRoot = deps.harnessRoot ?? process.cwd();\n const projectDir = ctx.projectDir ?? process.cwd();\n\n // v26.81.0 (ADR-022) — internal 자산(tauri-desktop)은 Phase 1 의\n // manifest/transform 이 설치 주체 — external(spawn) 단계에서 제외. Phase 1 의\n // templates 행으로 사용자에게 이미 가시화됨 (중복 보고 방지).\n // v26.102.0 (ADR-031, Batch3) — CLI 도달 범위 필터. 선택 CLI 와 교집합 없는 자산은\n // spawn 자체를 배제한다: codex 단독 설치가 claude 전용 plugin 을 `claude plugin ...` 으로\n // spawn 해 ~/.claude/plugins 를 오염시키던 P0 [4cli-asymmetry-cluster] 의 구조적 fix.\n // 제외분은 excludedByCli 로 보고 — 침묵 제외 금지 (no-false-ship).\n const { targets: applicable, excludedByCli } = selectExternalTargets(assets, ctx);\n // v26.55.0 — Phase 2 grouped progress UX. 카테고리 순서로 정렬 → install.ts 의 onAssetStart\n // callback 이 category 변경 감지로 헤더 출력 가능. ADR-016.\n const sorted = [...applicable].sort((a, b) => {\n const ai = CATEGORY_ORDER.indexOf(a.category);\n const bi = CATEGORY_ORDER.indexOf(b.category);\n return ai - bi;\n });\n const attempted: AssetInstallResult[] = [];\n const cli = ctx.cli;\n const scope = resolveScope(ctx.scope);\n\n for (const asset of sorted) {\n deps.onAssetStart?.(asset);\n log(` → ${asset.description}`);\n const baseResult = installOne(asset, { spawn, harnessRoot, cli, scope, projectDir });\n let result: AssetInstallResult = baseResult;\n if (baseResult.ok) {\n const v = detectVersion(asset.method, spawn);\n if (v) result = { ...baseResult, version: v };\n }\n deps.onAssetResult?.(result);\n\n if (!result.ok) {\n // v26.79.0 — 모든 실패는 warn-skip (abort 는 vibe killer 라 미채택). 죽은\n // failureMode/aborted 메커니즘 제거 (사용 자산 0 + 렌더러 미참조).\n warn(` [warn-skip] ${asset.id}: ${result.message ?? \"failed\"}`);\n }\n\n attempted.push(result);\n }\n\n return {\n attempted,\n succeeded: attempted.filter((r) => r.ok).length,\n skipped: attempted.filter((r) => !r.ok).length,\n excludedByCli,\n };\n}\n\n/**\n * 자산 1개 설치. method.kind 별 적절한 명령 실행.\n */\nfunction installOne(\n asset: ExternalAsset,\n ctx: {\n spawn: NonNullable<ExternalInstallerDeps[\"spawn\"]>;\n harnessRoot: string;\n cli: CliTargets;\n scope: InstallScope;\n /** v26.77.0 — spawn cwd. 자산이 올바른 프로젝트에 착지하도록 projectDir 로 고정. */\n projectDir: string;\n },\n): AssetInstallResult {\n const { method } = asset;\n const cwd = ctx.projectDir;\n switch (method.kind) {\n case \"skill\":\n return runSpawn(asset, ctx.spawn, \"npx\", buildSkillArgs(method, ctx.cli, ctx.scope), cwd);\n case \"plugin\":\n return installPlugin(asset, ctx.spawn, method, ctx.scope, cwd);\n case \"npm\": {\n // v26.64.0 (ADR-020) — scope=project 시 devDep, scope=global 시 -g.\n // v26.68.0 — method.kind \"npm-global\" → \"npm\" rename (scope 분기와 무관 의미).\n // v26.80.0 — pinned 버전 설치 (`pkg@version`). vetting 시점의 코드만 실행 (보안 wedge).\n const pinned = `${method.pkg}@${method.version}`;\n return runSpawn(\n asset,\n ctx.spawn,\n \"npm\",\n ctx.scope === \"global\" ? [\"install\", \"-g\", pinned] : [\"install\", \"--save-dev\", pinned],\n cwd,\n );\n }\n case \"npx-run\":\n // v26.80.0 — pinned 버전 실행 (`cmd@version`). 이전 `cmd` 에 \"@latest\" 인라인이던 것을\n // 구조 필드로 분리 (cmd 는 bare 이름 — drift override/라벨이 이름 그대로 사용).\n return runSpawn(\n asset,\n ctx.spawn,\n \"npx\",\n [`${method.cmd}@${method.version}`, ...(method.args ?? [])],\n cwd,\n );\n case \"shell-script\": {\n const scriptPath = join(ctx.harnessRoot, method.script);\n if (!existsSync(scriptPath)) {\n return {\n asset,\n ok: false,\n message: `script not found: ${scriptPath}`,\n };\n }\n return runSpawn(asset, ctx.spawn, \"bash\", [scriptPath, ...method.args], cwd);\n }\n case \"internal\":\n // v26.81.0 (ADR-022) — 도달 불가 (runExternalInstall 이 사전 필터). exhaustive switch\n // + 방어: 도달해도 spawn 없이 ok (Phase 1 manifest 가 실 설치 주체).\n return { asset, ok: true, message: \"internal template (installed by Phase 1 manifest)\" };\n }\n}\n\n/**\n * v26.39.5 fix — `--agent <list>` 명시 추가 (사용자 보고 #3 진짜 fix).\n *\n * `npx skills add` default 동작은 `*` (all installed agents) → universal install →\n * `.factory/skills/`, `.goose/skills/` 자동 생성. v0.8.0 의 `.gitignore` 패턴 추가만으론\n * git noise 만 차단하고 disk 디렉토리 생성은 막지 못함.\n *\n * 본 fix: `spec.cli` 의 base CLI 만 콤마 구분 명시 → 의도된 agent 만 install.\n *\n * v26.39.6 fix — skills CLI agent name 매핑.\n * skills CLI 1.5.5 valid agent 이름은 `claude-code` 인데 우리 CliBase 는 `claude`.\n * 매핑 누락 시 `Invalid agents: claude` 로 exit 1 → 외부 사용자 (실사용 리포\n * reproduce 2026-05-06) 환경에서 7건 skill 자산 100% skip.\n */\nconst SKILLS_CLI_AGENT_MAP: Record<CliTargets[number], string> = {\n claude: \"claude-code\",\n codex: \"codex\",\n opencode: \"opencode\",\n // v26.66.0 — Antigravity (Google) skills agent. `.agents/skills/` 표준 공유 (codex transform 산출과 동일).\n antigravity: \"antigravity\",\n};\n\n/**\n * `npx skills` CLI 고정 버전 — unpinned 면 upstream breaking 이 설치·검증을 동시에 깬다\n * (1.5.5→1.5.7 multi-agent `--agent` 플래그 파손 전례). bump 시 Docker 시나리오 재검증 필수.\n * audit CODE-4/D-1. scripts/verify-catalog.mjs 와 동일 값 유지 (drift 테스트 가드).\n */\nexport const SKILLS_CLI_VERSION = \"1.5.11\";\n\n/** `npx skills <subcommand>` 의 첫 인자 — 항상 버전 고정. */\nexport function skillsCliSpec(): string {\n return `skills@${SKILLS_CLI_VERSION}`;\n}\n\nfunction buildSkillArgs(\n method: { kind: \"skill\"; source: string; skill?: string },\n cli: CliTargets,\n scope: InstallScope,\n): string[] {\n const args = [skillsCliSpec(), \"add\", method.source];\n if (method.skill) {\n args.push(\"--skill\", method.skill);\n }\n if (cli.length > 0) {\n // v26.55.1 — skills cli 1.5.7 부터 multi-agent 는 repeatable `--agent` 만 지원.\n for (const c of cli) {\n args.push(\"--agent\", SKILLS_CLI_AGENT_MAP[c] ?? c);\n }\n }\n // v26.64.0 (ADR-020) — global scope 시 -g. project 는 skills CLI default (project) 따름.\n if (scope === \"global\") {\n args.push(\"-g\");\n }\n args.push(\"--yes\");\n return args;\n}\n\n/**\n * Plugin 은 marketplace add → install 두 단계. marketplace add 실패는 무시 (이미 등록 케이스).\n *\n * v26.64.0 (ADR-020) — `--scope <project|user>` 분기. claude CLI native:\n * - project: --scope project (현재 projectPath 격리, installed_plugins.json 메타 매칭)\n * - global: --scope user (모든 projectPath 에서 활성)\n * fs 적으로는 양쪽 모두 ~/.claude/plugins/cache/ + ~/.claude/plugins/marketplaces/ 에 write\n * (claude CLI 자체 디자인). 격리는 메타데이터.\n */\nfunction installPlugin(\n asset: ExternalAsset,\n spawn: NonNullable<ExternalInstallerDeps[\"spawn\"]>,\n method: { kind: \"plugin\"; marketplace: string; pluginId: string },\n scope: InstallScope,\n cwd: string,\n): AssetInstallResult {\n const claudeScope = scope === \"global\" ? \"user\" : \"project\";\n // v26.77.0 — cwd=projectDir: --scope project 시 claude 가 cwd 기준으로 프로젝트를 탐지하므로\n // installed_plugins.json 의 projectPath 가 올바른 프로젝트로 기록된다.\n spawn(\n \"claude\",\n [\"plugin\", \"marketplace\", \"add\", \"--scope\", claudeScope, method.marketplace],\n spawnOpts(cwd),\n );\n return runSpawn(\n asset,\n spawn,\n \"claude\",\n [\"plugin\", \"install\", \"--scope\", claudeScope, method.pluginId],\n cwd,\n );\n}\n\nfunction runSpawn(\n asset: ExternalAsset,\n spawn: NonNullable<ExternalInstallerDeps[\"spawn\"]>,\n cmd: string,\n args: ReadonlyArray<string>,\n cwd?: string,\n): AssetInstallResult {\n const result = spawn(cmd, args, spawnOpts(cwd));\n if (result.error) {\n return { asset, ok: false, message: result.error.message };\n }\n if ((result.status ?? 1) !== 0) {\n const stderr = (result.stderr ?? \"\").trim();\n const tail = stderr.length > 200 ? `${stderr.slice(0, 200)}…` : stderr;\n return {\n asset,\n ok: false,\n message: `${cmd} exited ${result.status}${tail ? `: ${tail}` : \"\"}`,\n };\n }\n return { asset, ok: true };\n}\n\nfunction spawnOpts(cwd?: string): SpawnOpts {\n return {\n encoding: \"utf8\",\n stdio: \"pipe\",\n timeout: DEFAULT_SPAWN_TIMEOUT_MS,\n ...(cwd ? { cwd } : {}),\n };\n}\n\n/* v8 ignore next 7 — thin dep-inject default. tests 는 항상 spawn 주입. */\nfunction defaultSpawn(\n cmd: string,\n args: ReadonlyArray<string>,\n opts: SpawnOpts,\n): SpawnSyncReturns<string> {\n return spawnSync(cmd, [...args], opts);\n}\n\n/**\n * v26.59.0 — install 후 path 기반 version 추출.\n *\n * 안전 원칙: 실패 시 undefined 반환 (silent). install 성공 자체는 이미 검증됨.\n *\n * - plugin: ~/.claude/plugins/cache/<marketplace>/<plugin>/<VERSION>/ 디렉토리명 (semver-like 만)\n * - npm-global: <npm root -g>/<pkg>/package.json 의 version\n * - skill / npx-run / shell-script: 표준 metadata 위치 없음 → undefined\n */\nfunction detectVersion(\n method: ExternalAssetMethod,\n spawn: NonNullable<ExternalInstallerDeps[\"spawn\"]>,\n): string | undefined {\n try {\n switch (method.kind) {\n case \"plugin\": {\n // pluginId = \"<plugin>@<marketplace-short>\". cache path:\n // ~/.claude/plugins/cache/<marketplace-short>/<plugin>/<VERSION>/\n // method.marketplace 는 GH `<user>/<repo>` (다른 값) 이라 path 에 사용 X.\n const at = method.pluginId.lastIndexOf(\"@\");\n if (at <= 0) return undefined;\n const plugin = method.pluginId.slice(0, at);\n const marketplaceShort = method.pluginId.slice(at + 1);\n const cacheBase = join(homedir(), \".claude/plugins/cache\", marketplaceShort, plugin);\n if (!existsSync(cacheBase)) return undefined;\n const versions = readdirSync(cacheBase)\n .filter((v) => /^\\d/.test(v))\n .sort();\n return versions.at(-1);\n }\n case \"npm\": {\n const npmRoot = getNpmGlobalRoot(spawn);\n if (!npmRoot) return undefined;\n const pkgJson = join(npmRoot, method.pkg, \"package.json\");\n if (!existsSync(pkgJson)) return undefined;\n const parsed = JSON.parse(readFileSync(pkgJson, \"utf8\")) as { version?: string };\n return parsed.version;\n }\n default:\n return undefined;\n }\n } catch {\n return undefined;\n }\n}\n\nlet npmGlobalRootCache: string | undefined;\n\n/* v8 ignore start — npm CLI 실행 + cache. 실 시스템 의존. detectVersion (plugin 외 method) 가 본 함수 호출. */\nfunction getNpmGlobalRoot(spawn: NonNullable<ExternalInstallerDeps[\"spawn\"]>): string | undefined {\n if (npmGlobalRootCache !== undefined) return npmGlobalRootCache || undefined;\n try {\n const r = spawn(\"npm\", [\"root\", \"-g\"], spawnOpts());\n if ((r.status ?? 1) === 0) {\n npmGlobalRootCache = (r.stdout ?? \"\").trim();\n return npmGlobalRootCache || undefined;\n }\n } catch {\n // fallthrough\n }\n npmGlobalRootCache = \"\";\n return undefined;\n}\n/* v8 ignore stop */\n\n/**\n * 누락(skip) 자산 목록을 사용자 보고용 텍스트로 포맷.\n */\nexport function formatSkippedReport(report: ExternalInstallReport): string {\n const failed = report.attempted.filter((r) => !r.ok);\n if (failed.length === 0) return \"\";\n const lines = failed.map((r) => ` • ${r.asset.id} — ${r.message ?? \"failed\"}`);\n return [\n `${failed.length}개 외부 자산이 설치되지 않았습니다 (warn-skip):`,\n ...lines,\n \"\",\n \"Manual install or retry needed. See docs/REFERENCE.md or README.md for details.\",\n ].join(\"\\n\");\n}\n","/**\n * Install log — `.claude/.harness-install.json`.\n *\n * v26.64.0 (ADR-020) — install 종료 시 자산 list + scope + timestamp 기록.\n * uninstall command 가 본 log 를 읽어 정확한 reverse 수행.\n *\n * 글로벌 자산 (scope=global 또는 codexOptIn) 은 log 에 안내용으로만 기록 — uninstall 시 자동 삭제 X (D16).\n */\n\nimport { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { ExternalAsset, ExternalAssetMethod } from \"./external-assets.js\";\nimport type { ExternalInstallReport } from \"./external-installer.js\";\nimport { listFilesRecursive } from \"./fs-ops.js\";\nimport type { InstallScope, InstallSpec } from \"./types.js\";\n\nexport const INSTALL_LOG_FILENAME = \".harness-install.json\";\nexport const INSTALL_LOG_VERSION = 1;\n\nexport interface InstallLogAsset {\n id: string;\n category: string;\n /** External asset method.kind 그대로. uninstall reverse 시 분기 기준. */\n method: ExternalAssetMethod[\"kind\"];\n /** scope=global 자산은 uninstall 시 안내만 (D16 — 글로벌 자동 삭제 금지). */\n scope: InstallScope;\n /** method 별 추가 정보. plugin: marketplace + pluginId. skill: source. npm: pkg. */\n detail: Record<string, string>;\n /** installed 시점 version (detectVersion 결과, 없으면 undefined). */\n version?: string;\n}\n\n/**\n * v26.124.0 (F-1f) — install 이 `.claude/` **밖**에 만들거나 고친 프로젝트 루트 파일.\n *\n * uninstall 은 이 목록을 **안내만 하고 지우지 않는다**. `.mcp.json`/`.gitignore` 에는 사용자\n * 내용이 섞이고, `.github/workflows/` 는 설치 후 사용자 소유물이기 때문 (ci-scaffold.ts 안전\n * 계약 2 · F-1d 와 같은 방침). 기록이 없으면 안내도 없다 — 그래서 install 이 적어 둔다.\n */\nexport interface InstallLogRootFile {\n /** project-relative 경로 (예: `.mcp.json`, `.github/workflows/ci.yml`) */\n path: string;\n /**\n * created = 하네스가 없던 파일을 만들었다 (내용 전부 하네스 것 → 손 안 댔으면 지워도 안전).\n * modified = 이미 있던 사용자 파일에 병합/추가했다 (직접 확인이 필요하다).\n */\n change: \"created\" | \"modified\";\n /** 무엇을 했는지 — uninstall 안내에 그대로 나온다. 재설치 시 합집합으로 누적된다. */\n notes: string[];\n}\n\n/**\n * v26.126.0 (R-3a · ADR-046) — `.claude/skills/` 안 파일 하나의 **설치 시점 기준선**.\n *\n * update 는 이 해시로 \"사용자가 고쳤는가\"를 판정한다. 기록이 없으면 판정이 불가능하고,\n * 그때는 내용 비교로 폴백해 보수적으로 백업한다 (ADR-046 파생규칙 3).\n */\nexport interface InstallLogSkillFile {\n /** `.claude/skills/` 기준 상대 경로 (예: `multi-persona-review/SKILL.md`) */\n path: string;\n /** 하네스가 그 자리에 놓아둔 내용의 sha256. 지금 디스크가 이것과 다르면 = 사용자가 고쳤다. */\n sha256: string;\n}\n\nexport interface InstallLog {\n /** schema version — backward compat 검출용 */\n schemaVersion: number;\n /** harness 가 install 한 시점 ISO timestamp */\n installedAt: string;\n /** 전체 install scope. 자산 per-asset scope 와 동일 (현재는 single global scope) */\n scope: InstallScope;\n /** install 시 spec 요약 (tracks/cli — uninstall reasoning 용) */\n spec: {\n tracks: ReadonlyArray<string>;\n cli: ReadonlyArray<string>;\n };\n /** templates 출처 — uninstall 시 templates 제거 위치 */\n templates: {\n /** .claude/ project local */\n claudeDir: string;\n /** .codex/ project local (cli=codex 시) */\n codexDir?: string;\n /** .opencode/ project local (cli=opencode 시) */\n opencodeDir?: string;\n /**\n * project root CLAUDE.md (cli=claude 시 생성).\n * uninstall 시 sha256 이 install 시점과 동일할 때만 삭제 — 사용자가 수정했으면 보존.\n */\n rootClaudeMd?: { path: string; sha256: string };\n };\n /** external-installer 가 install 한 자산 (ok=true 만) */\n assets: ReadonlyArray<InstallLogAsset>;\n /**\n * v26.124.0 (F-1f) — `.claude/` 밖 루트 파일. 건드린 게 없으면 필드 자체가 없다\n * (v26.123.0 이하 로그도 이 상태 — 읽는 쪽은 부재를 정상으로 다뤄야 한다).\n */\n rootFiles?: ReadonlyArray<InstallLogRootFile>;\n /**\n * v26.126.0 (R-3a · ADR-046) — 스킬 파일 기준선 해시. 스킬을 안 깔았으면 필드 자체가 없다\n * (v26.125.0 이하 로그도 이 상태 — 읽는 쪽은 부재를 정상으로 다뤄야 한다).\n */\n skillFiles?: ReadonlyArray<InstallLogSkillFile>;\n}\n\n/**\n * external-installer 의 result 를 InstallLogAsset 으로 변환.\n * ok=false 자산은 제외 (실제 install 안 됨 → uninstall 대상 아님).\n */\nexport function buildAssetEntries(\n report: ExternalInstallReport | null,\n scope: InstallScope,\n): InstallLogAsset[] {\n if (!report) return [];\n return report.attempted\n .filter((r) => r.ok)\n .map((r) => assetToLogEntry(r.asset, scope, r.version));\n}\n\nfunction assetToLogEntry(\n asset: ExternalAsset,\n scope: InstallScope,\n version: string | undefined,\n): InstallLogAsset {\n const detail = methodDetail(asset.method);\n const entry: InstallLogAsset = {\n id: asset.id,\n category: asset.category,\n method: asset.method.kind,\n scope,\n detail,\n };\n if (version) entry.version = version;\n return entry;\n}\n\nfunction methodDetail(method: ExternalAssetMethod): Record<string, string> {\n switch (method.kind) {\n case \"plugin\":\n return { marketplace: method.marketplace, pluginId: method.pluginId };\n case \"skill\":\n return { source: method.source, ...(method.skill ? { skill: method.skill } : {}) };\n case \"npm\":\n return { pkg: method.pkg };\n case \"npx-run\":\n return { cmd: method.cmd, args: (method.args ?? []).join(\" \") };\n case \"shell-script\":\n return { script: method.script, args: method.args.join(\" \") };\n case \"internal\":\n // v26.81.0 (ADR-022) — Phase 1 manifest 가 설치 주체. external 단계에선 미기록이 정상.\n return { key: method.key };\n }\n}\n\n/**\n * install log 생성. `previous` 가 있으면 **누적**한다 (v26.123.0 — F-1a).\n *\n * install 은 이전에 설치한 것을 지우지 않는다. 그런데 로그는 매번 새로 만들어 덮어썼으므로,\n * 나중에 `install --with <id>` 를 한 번만 해도 1회차 자산이 기록에서 사라지고 **uninstall 이\n * 그걸 못 찾아 남긴다**. 디스크에는 남아 있는데 기록에는 없는 = 로그가 거짓이 되는 상태.\n *\n * 누적 대상은 uninstall 이 실제로 읽는 두 필드뿐이다 (`assets` · `templates`). `spec`(tracks/cli)은\n * 누적하지 않는다: `.claude/` 가 backup 으로 밀리는 설치(reinstall)에선 이전 트랙 파일이 실제로\n * 사라져 합집합이 거짓이 된다. 게다가 uninstall 은 `spec` 을 읽지 않는다 (표시용).\n *\n * `claudeDirMovedAside` = 이번 설치가 `.claude/` 를 backup 으로 rename 했는가. 그 경우\n * **`.claude/` 안에 살던 이전 자산은 실제로 사라졌으므로 누적에서 뺀다** — 안 빼면 F-1a 를\n * 반대 방향으로 재현한다(있지도 않은 걸 있다고 기록). 해당: project scope 의 `skill`\n * (`npx skills add` 가 `.claude/skills/` 에 설치) 와 `shell-script`(ecc-prune →\n * `.claude/local-plugins/`). plugin/npm 은 프로젝트 밖에 살아 남으므로 유지한다.\n */\nexport function buildInstallLog(\n spec: InstallSpec,\n external: ExternalInstallReport | null,\n scope: InstallScope,\n rootClaudeMd?: { path: string; sha256: string } | null,\n previous?: InstallLog | null,\n claudeDirMovedAside = false,\n rootFiles: ReadonlyArray<InstallLogRootFile> = [],\n): InstallLog {\n const templates: InstallLog[\"templates\"] = {\n claudeDir: \".claude/\",\n ...(spec.cli.includes(\"codex\") ? { codexDir: \".codex/\" } : {}),\n ...(spec.cli.includes(\"opencode\") ? { opencodeDir: \".opencode/\" } : {}),\n ...(rootClaudeMd ? { rootClaudeMd } : {}),\n };\n const log: InstallLog = {\n schemaVersion: INSTALL_LOG_VERSION,\n installedAt: new Date().toISOString(),\n scope,\n spec: {\n tracks: spec.tracks,\n cli: spec.cli,\n },\n // 이번 설치가 만든 항목이 이기고, 이번에 안 만든 항목은 이전 값을 그대로 둔다.\n // (예: claude 로 깔고 나중에 codex 만 추가 설치해도 root CLAUDE.md 기록이 살아남는다)\n templates: { ...previous?.templates, ...templates },\n assets: mergeAssets(\n claudeDirMovedAside ? previous?.assets?.filter(survivesClaudeDirRename) : previous?.assets,\n buildAssetEntries(external, scope),\n ),\n };\n // 루트 파일은 `.claude/` 밖이라 backup rename 과 무관하게 살아남는다 → 무조건 누적.\n const mergedRootFiles = mergeRootFiles(previous?.rootFiles, rootFiles);\n if (mergedRootFiles.length > 0) log.rootFiles = mergedRootFiles;\n return log;\n}\n\n/**\n * 경로 기준 합집합. 자산과 달리 **이번 설치분이 이전 것을 덮지 않고 합친다** — `.gitignore` 에\n * 1회차는 `.env`, 2회차는 `.factory/` 를 추가하면 둘 다 디스크에 남아 있으므로 둘 다 알려야 한다.\n * `change` 는 한 번이라도 created 면 created — 하네스가 만든 파일에 나중에 병합한 것뿐이고,\n * 사용자에게는 \"전부 하네스 것\"이 여전히 참이다 (modified 로 낮추면 지워도 될 것을 못 지운다).\n */\nfunction mergeRootFiles(\n previous: ReadonlyArray<InstallLogRootFile> | undefined,\n current: ReadonlyArray<InstallLogRootFile>,\n): InstallLogRootFile[] {\n const byPath = new Map<string, InstallLogRootFile>();\n for (const file of [...(previous ?? []), ...current]) {\n const prior = byPath.get(file.path);\n byPath.set(\n file.path,\n prior\n ? {\n path: file.path,\n change: prior.change === \"created\" ? \"created\" : file.change,\n notes: [...new Set([...prior.notes, ...file.notes])],\n }\n : file,\n );\n }\n return [...byPath.values()];\n}\n\n/**\n * `.claude/` 가 backup 으로 밀려도 살아남는 자산인가 — 산출물이 프로젝트 `.claude/` 밖인가.\n *\n * **exhaustive switch 로 쓴다(default 없음).** method 종류가 늘면 빌드가 깨져서 이 판단을\n * 강제로 하게 만든다 — `!==` 목록이면 새 method 가 조용히 \"살아남음\"으로 분류되고, 그건\n * 곧 없는 걸 있다고 기록하는 것이다 (`no-false-ship` §Drift 구조 차단: 하드코딩 목록에는\n * exhaustiveness 가드 없이 머지 금지, 기본값은 면제가 아니라 검사).\n */\nfunction survivesClaudeDirRename(asset: InstallLogAsset): boolean {\n if (asset.scope === \"global\") return true; // 글로벌 영역은 install 이 건드리지 않는다\n switch (asset.method) {\n case \"plugin\":\n return true; // `~/.claude/plugins/cache` — 프로젝트 밖\n case \"npm\":\n return true; // `node_modules/`\n case \"skill\":\n return false; // `npx skills add` project scope → `.claude/skills/`\n case \"shell-script\":\n return false; // ecc-prune → `.claude/local-plugins/`\n case \"npx-run\":\n // bmad-method 는 `--tools claude-code` 로 `.claude/` 안에 agent command 를 만든다\n // (external-assets.ts 의 cliSupportOverride 주석 + Docker 실증 realcli-workflows-2026-06-06).\n // `_bmad/` 는 루트에 남지만, `.claude/` 산출물이 사라진 이상 \"그대로 설치됨\"이 아니다.\n return false;\n case \"internal\":\n // 실제로는 로그에 실리지 않는다(external-installer 가 사전 제외). 그래도 기본값은 검사.\n return false;\n }\n}\n\n/** id 기준 합집합 — 같은 id 는 이번 설치분이 이긴다 (version/scope 가 최신). 순서는 안정적. */\nfunction mergeAssets(\n previous: ReadonlyArray<InstallLogAsset> | undefined,\n current: ReadonlyArray<InstallLogAsset>,\n): InstallLogAsset[] {\n if (!previous || previous.length === 0) return [...current];\n const currentById = new Map(current.map((a) => [a.id, a]));\n const previousIds = new Set(previous.map((a) => a.id));\n return [\n ...previous.map((a) => currentById.get(a.id) ?? a),\n ...current.filter((a) => !previousIds.has(a.id)),\n ];\n}\n\n/** install log + root CLAUDE.md 등 자산 무결성 비교용 sha256 (hex). */\nexport function hashContent(content: string): string {\n return createHash(\"sha256\").update(content, \"utf8\").digest(\"hex\");\n}\n\n/**\n * `.claude/skills/` 전체를 훑어 파일별 sha256 스냅샷을 만든다 (v26.126.0 · ADR-046).\n *\n * **복사가 끝난 뒤에 호출해야 한다.** 이 값이 \"하네스가 놓아둔 내용\"의 기준선이 되고, 다음\n * update 는 디스크가 이것과 다른지로 사용자 편집을 판정한다. 복사 **전에** 부르면 옛 내용이\n * 기준선이 돼 다음 update 가 멀쩡한 파일을 전부 \"사용자가 고쳤다\"로 오판한다.\n *\n * 누적하지 않고 **매번 통째로 교체**한다 (`rootFiles` 와 반대다) — 이건 이력이 아니라 현재\n * 디스크 상태의 스냅샷이고, 지워진 파일의 해시가 남으면 그 자체로 거짓 기록이 된다.\n */\nexport function collectSkillHashes(projectDir: string): InstallLogSkillFile[] {\n const skillsDir = join(projectDir, \".claude/skills\");\n return listFilesRecursive(skillsDir).map((rel) => ({\n path: rel,\n sha256: hashContent(readFileSync(join(skillsDir, rel), \"utf8\")),\n }));\n}\n\n/**\n * install log write. 위치: `<projectDir>/.claude/.harness-install.json`.\n *\n * `.claude/` 는 cli=claude 일 때 baseline phase 에서 생성되지만, codex/opencode/antigravity\n * 단독(claude 미포함) 설치 시엔 생성되지 않는다. 그 경우에도 uninstall 이 본 log 를 읽을 수 있도록\n * write 직전 디렉토리를 보장한다 (없으면 install log 누락 → uninstall 불가).\n */\nexport function writeInstallLog(projectDir: string, log: InstallLog): string {\n const path = join(projectDir, \".claude\", INSTALL_LOG_FILENAME);\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, `${JSON.stringify(log, null, 2)}\\n`, \"utf8\");\n return path;\n}\n\nexport function readInstallLog(projectDir: string): InstallLog | null {\n const path = join(projectDir, \".claude\", INSTALL_LOG_FILENAME);\n if (!existsSync(path)) return null;\n try {\n const parsed = JSON.parse(readFileSync(path, \"utf8\")) as InstallLog;\n // v26.68.0 — backward compat: method.kind \"npm-global\" → \"npm\" rename.\n // v26.64.0 ~ v26.67.0 시점 install log 가 새 uninstall 에서 작동하도록 normalize.\n if (Array.isArray(parsed.assets)) {\n parsed.assets = parsed.assets.map((a) =>\n (a.method as string) === \"npm-global\" ? { ...a, method: \"npm\" } : a,\n );\n }\n return parsed;\n } catch {\n return null;\n }\n}\n\nexport function installLogPath(projectDir: string): string {\n return join(projectDir, \".claude\", INSTALL_LOG_FILENAME);\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { anyTrack } from \"./track-match.js\";\nimport type { Track } from \"./types.js\";\n\nexport interface McpServerConfig {\n type?: \"stdio\" | \"http\";\n command: string;\n args: string[];\n env?: Record<string, string>;\n}\n\nexport interface McpJson {\n mcpServers: Record<string, McpServerConfig>;\n _comment?: string;\n}\n\nexport interface TrackMcpRow {\n name: string;\n pattern: string;\n command: string;\n args: string[];\n}\n\n/** Parse `templates/track-mcp-map.tsv` (tab-separated, comment-aware). */\nexport function parseTrackMcpMap(raw: string): TrackMcpRow[] {\n const rows: TrackMcpRow[] = [];\n for (const line of raw.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith(\"#\")) {\n continue;\n }\n const parts = line.split(\"\\t\");\n if (parts.length < 4) {\n continue;\n }\n const [name, pattern, command, argsJson] = parts;\n if (!name || !pattern || !command) {\n continue;\n }\n let args: unknown;\n try {\n args = JSON.parse(argsJson ?? \"[]\");\n } catch {\n continue;\n }\n if (!Array.isArray(args) || !args.every((a) => typeof a === \"string\")) {\n continue;\n }\n rows.push({ name, pattern, command, args: args as string[] });\n }\n return rows;\n}\n\n/**\n * Apply track-aware MCP rows to a base `.mcp.json` object.\n * Existing entries (including user customizations) are preserved.\n */\nexport function mergeMcpServers(\n base: McpJson,\n rows: ReadonlyArray<TrackMcpRow>,\n tracks: ReadonlyArray<Track>,\n): McpJson {\n const out: McpJson = {\n ...base,\n mcpServers: { ...base.mcpServers },\n };\n for (const row of rows) {\n if (!anyTrack(tracks, row.pattern)) {\n continue;\n }\n if (out.mcpServers[row.name]) {\n // Preserve existing — do not overwrite user customizations.\n continue;\n }\n out.mcpServers[row.name] = {\n type: \"stdio\",\n command: row.command,\n args: row.args,\n };\n }\n // Strip _comment marker (parity with the bash `jq 'del(._comment)'`).\n delete out._comment;\n return out;\n}\n\n/**\n * Compose the final `.mcp.json` for a project install.\n * Read base template + track map, merge with optional existing user file (additive).\n */\nexport function composeMcpJson(opts: {\n templateMcpPath: string;\n trackMapPath: string;\n existingPath?: string;\n tracks: ReadonlyArray<Track>;\n}): McpJson {\n const base = JSON.parse(readFileSync(opts.templateMcpPath, \"utf8\")) as McpJson;\n const merged =\n opts.existingPath && existsSync(opts.existingPath)\n ? mergeUserBase(base, opts.existingPath)\n : base;\n const mapRaw = existsSync(opts.trackMapPath) ? readFileSync(opts.trackMapPath, \"utf8\") : \"\";\n const rows = parseTrackMcpMap(mapRaw);\n return mergeMcpServers(merged, rows, opts.tracks);\n}\n\nfunction mergeUserBase(base: McpJson, existingPath: string): McpJson {\n try {\n const existing = JSON.parse(readFileSync(existingPath, \"utf8\")) as McpJson;\n return {\n ...base,\n mcpServers: { ...base.mcpServers, ...existing.mcpServers },\n };\n } catch {\n return base;\n }\n}\n\n/** Write the composed `.mcp.json` to disk (2-space pretty). */\nexport function writeMcpJson(path: string, mcp: McpJson): void {\n writeFileSync(path, `${JSON.stringify(mcp, null, 2)}\\n`);\n}\n","/**\n * OpenCode transform orchestrator — SSOT (templates/CLAUDE.md, .mcp.json) →\n * OpenCode 자산.\n *\n * Inputs:\n * - harnessRoot: repository root (templates/ + .mcp.json)\n * - projectDir: target project to receive AGENTS.md + opencode.json + .opencode/\n *\n * Outputs (under projectDir):\n * - AGENTS.md\n * - opencode.json\n * - .opencode/commands/<id>.md (dev-method skills as command fallback)\n *\n * SPEC: docs/specs/opencode-compat.md\n * Phase: C1 (transform orchestrator)\n */\n\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { basename, join } from \"node:path\";\nimport { backupFileIfChanged, ensureDir } from \"../fs-ops.js\";\nimport type { McpJson } from \"../mcp-merge.js\";\nimport { renderFillScaffold } from \"../project-claude-merge.js\";\nimport { renderAgentsMd } from \"./agents-md.js\";\nimport { renderCommandFromSkill } from \"./commands.js\";\nimport { renderOpencodeJson } from \"./opencode-json.js\";\n\nexport interface OpencodeTransformParams {\n harnessRoot: string;\n projectDir: string;\n /**\n * v26.87.0 — dev-method skill ids 선택 목록. OpenCode 는 native skill 개념이 없어 각 skill 을\n * `.opencode/commands/<id>.md` 커맨드 fallback 으로 surface (description = skill frontmatter,\n * body = skill 본문). installer 가 `DEV_METHOD_SKILL_IDS` 필터로 채움.\n */\n selectedInternalSkills?: ReadonlyArray<string>;\n}\n\nexport interface OpencodeTransformReport {\n agentsMdPath: string;\n opencodeJsonPath: string;\n commandFiles: string[];\n}\n\nexport function runOpencodeTransform(params: OpencodeTransformParams): OpencodeTransformReport {\n const { harnessRoot, projectDir, selectedInternalSkills = [] } = params;\n\n const claudeMd = readRequired(join(harnessRoot, \"templates/CLAUDE.md\"));\n const agentsTemplate = readRequired(join(harnessRoot, \"templates/opencode/AGENTS.md.template\"));\n const opencodeTemplate = readRequired(\n join(harnessRoot, \"templates/opencode/opencode.json.template\"),\n );\n const projectName = basename(projectDir);\n const mcp = readOptionalJson(join(harnessRoot, \".mcp.json\"));\n\n // 1. AGENTS.md\n ensureDir(projectDir);\n const agentsMdPath = join(projectDir, \"AGENTS.md\");\n const agentsMdOut = renderAgentsMd({\n template: agentsTemplate,\n claudeMd,\n projectName,\n projectContext: renderFillScaffold(),\n });\n // 사용자가 채운 AGENTS.md 를 재설치(add 모드) 덮어쓰기 전 보존 — 루트 CLAUDE.md 와 대칭.\n backupFileIfChanged(agentsMdPath, agentsMdOut);\n writeFileSync(agentsMdPath, agentsMdOut);\n\n // 2. opencode.json\n const opencodeJsonPath = join(projectDir, \"opencode.json\");\n writeFileSync(opencodeJsonPath, renderOpencodeJson({ template: opencodeTemplate, mcp }));\n\n // 3. v26.87.0 — dev-method skills → .opencode/commands/<id>.md (command fallback).\n // OpenCode 는 native skill 개념이 없어 skill 을 커맨드로 surface.\n const cmdDir = join(projectDir, \".opencode/commands\");\n ensureDir(cmdDir);\n const commandFiles: string[] = [];\n for (const id of selectedInternalSkills) {\n const src = join(harnessRoot, \"templates/skills\", id, \"SKILL.md\");\n if (!existsSync(src)) {\n continue;\n }\n const target = join(cmdDir, `${id}.md`);\n // scripts/ sidecar = the skill shells out to an external CLI → needs a\n // bash-capable agent; plan (bash denied) made such commands a no-op.\n const shellDependent = existsSync(join(harnessRoot, \"templates/skills\", id, \"scripts\"));\n writeFileSync(\n target,\n renderCommandFromSkill(readFileSync(src, \"utf8\"), id, { shellDependent }),\n );\n commandFiles.push(target);\n }\n\n return { agentsMdPath, opencodeJsonPath, commandFiles };\n}\n\nfunction readRequired(path: string): string {\n if (!existsSync(path)) {\n throw new Error(`OpenCode transform: required source missing: ${path}`);\n }\n return readFileSync(path, \"utf8\");\n}\n\nfunction readOptionalJson(path: string): McpJson | null {\n if (!existsSync(path)) {\n return null;\n }\n try {\n return JSON.parse(readFileSync(path, \"utf8\")) as McpJson;\n } catch {\n return null;\n }\n}\n","/**\n * AGENTS.md transform — CLAUDE.md → AGENTS.md (OpenCode flavor).\n *\n * Mirrors `src/codex/agents-md.ts` logic (Codex와 OpenCode 둘 다 콜론 namespace\n * 미사용으로 slash rename 동일). 별도 파일로 유지 — 모듈 독립성.\n *\n * v26.70.0 — section 추출 → CLAUDE.md 전문 embed (`{PROJECT_RULES}`). codex/agents-md 와 동일 fix.\n */\n\n/** Rename Claude slash conventions (`/uzys:foo`) to OpenCode (`/uzys-foo`). */\nexport function renameSlashes(text: string): string {\n return text.replaceAll(\"/uzys:\", \"/uzys-\");\n}\n\nexport interface AgentsMdParams {\n template: string;\n claudeMd: string;\n projectName: string;\n /** Project-context fill scaffold — the same body shipped to the Claude Code CLAUDE.md. */\n projectContext: string;\n}\n\n/**\n * Render the OpenCode AGENTS.md output by embedding the full CLAUDE.md body.\n *\n * Placeholders (matches templates/opencode/AGENTS.md.template):\n * - {PROJECT_NAME} — basename of project dir\n * - {PROJECT_RULES} — full CLAUDE.md body (first h1 stripped)\n * - {PROJECT_CONTEXT} — project-specific fill scaffold (renderFillScaffold())\n */\nexport function renderAgentsMd(params: AgentsMdParams): string {\n const body = params.claudeMd.replace(/^#\\s+.*\\r?\\n/, \"\").trim();\n const replaced = params.template\n .replaceAll(\"{PROJECT_NAME}\", params.projectName)\n .replaceAll(\"{PROJECT_RULES}\", body)\n .replaceAll(\"{PROJECT_CONTEXT}\", params.projectContext);\n return renameSlashes(replaced);\n}\n","/**\n * Bundled SKILL.md → OpenCode `.opencode/commands/<id>.md` command fallback (bundled skills).\n *\n * OpenCode 는 native skill 개념이 없어 각 skill 을 커맨드로 surface:\n * - 파일명 = 슬래시 커맨드명 → `<id>.md`\n * - Frontmatter: `description` (skill frontmatter 에서) + `agent: plan|build`, `name` 필드 없음\n */\nimport { renameSlashes } from \"./agents-md.js\";\n\n/**\n * v26.87.0 — render an OpenCode command from a bundled, already-complete SKILL.md.\n * OpenCode has NO native skill concept, so each selected skill is surfaced as a\n * `.opencode/commands/<id>.md` command fallback: command frontmatter (`description`\n * from the skill's own frontmatter, `agent: …`) + the skill body.\n *\n * Unlike a uzys phase command, there is no slash phase — the id IS the command name\n * (filename). Body slashes are renamed (`/uzys:` → `/uzys-`) for consistency with the\n * other ports.\n *\n * v26.100.0 — `agent` is no longer a blanket `plan`. Dev-method skills are read-heavy\n * (plan is right), but shell-dependent consult skills (gemini-consult / codex-consult —\n * they work ONLY by shelling out to an external CLI) were a no-op under plan, whose\n * profile in templates/opencode/opencode.json.template denies bash. The caller derives\n * `shellDependent` from the skill's bundled `scripts/` sidecar dir (structural signal,\n * no hardcoded id list to drift) and such skills render `agent: build` (bash-capable).\n */\nexport function renderCommandFromSkill(\n source: string,\n id: string,\n opts?: { shellDependent?: boolean },\n): string {\n const { description, body } = parseSkillFrontmatter(source);\n const finalDescription = description || `${id} (dev-method skill, OpenCode command fallback)`;\n const escapedDesc = finalDescription.replace(/\"/g, '\\\\\"');\n const renamedBody = renameSlashes(body).trimEnd();\n const agent = opts?.shellDependent ? \"build\" : \"plan\";\n\n return [\n \"---\",\n `description: \"${escapedDesc}\"`,\n `agent: ${agent}`,\n \"---\",\n \"\",\n renamedBody,\n \"\",\n ].join(\"\\n\");\n}\n\n/**\n * Parse a complete SKILL.md: split frontmatter from body, extracting the `description`\n * scalar. Handles folded/literal block scalars (`description: >-` or `|`) where the value\n * spans subsequent indented lines — the dev-method skills use `>-`. Single-line\n * `description: \"...\"` is also supported.\n */\nfunction parseSkillFrontmatter(source: string): ParsedSource {\n const lines = source.split(/\\r?\\n/);\n if (lines[0] !== \"---\") {\n const firstLine = lines[0] ?? \"\";\n return { description: firstLine.trim(), body: lines.slice(1).join(\"\\n\") };\n }\n let secondDelimAt = -1;\n let description = \"\";\n for (let i = 1; i < lines.length; i++) {\n const line = lines[i] ?? \"\";\n if (line === \"---\") {\n secondDelimAt = i;\n break;\n }\n const inline = line.match(/^description:\\s*(.+)$/);\n if (!inline) {\n continue;\n }\n const raw = (inline[1] ?? \"\").trim();\n if (raw === \">-\" || raw === \">\" || raw === \"|\" || raw === \"|-\") {\n // Folded/literal block scalar — collect following more-indented lines, join folded.\n const collected: string[] = [];\n for (let j = i + 1; j < lines.length; j++) {\n const next = lines[j] ?? \"\";\n if (next === \"---\") {\n break;\n }\n if (next.trim() === \"\" || /^\\s/.test(next)) {\n collected.push(next.trim());\n } else {\n break; // next top-level key\n }\n }\n description = collected.join(\" \").replace(/\\s+/g, \" \").trim();\n } else {\n description = stripQuotes(raw);\n }\n }\n const body =\n secondDelimAt >= 0\n ? lines\n .slice(secondDelimAt + 1)\n .join(\"\\n\")\n .replace(/^\\n+/, \"\")\n : source;\n return { description, body };\n}\n\ninterface ParsedSource {\n description: string;\n body: string;\n}\n\nfunction stripQuotes(raw: string): string {\n const trimmed = raw.trim();\n if (trimmed.startsWith('\"') && trimmed.endsWith('\"')) {\n return trimmed.slice(1, -1);\n }\n return trimmed;\n}\n","/**\n * opencode.json transform — fill template + merge mcp.<name> from .mcp.json.\n *\n * Output: opencode.json (top-level `mcp.<name>` map; OpenCode 1:1 매핑).\n *\n * Codex `[mcp_servers.X]` TOML과 다르게 OpenCode는 JSON이라 Object spread\n * 만으로 충분 (TOML 직렬화 없음).\n */\n\nimport type { McpJson, McpServerConfig } from \"../mcp-merge.js\";\n\nexport interface RenderOpencodeJsonParams {\n /** Template content (templates/opencode/opencode.json.template). */\n template: string;\n /** Source `.mcp.json` (parsed). When provided, top-level `mcp.<name>` is replaced. */\n mcp?: McpJson | null;\n}\n\ninterface OpencodeConfig {\n $schema?: string;\n instructions?: string[];\n mcp?: Record<string, McpServerConfig>;\n command?: Record<string, unknown>;\n agent?: Record<string, unknown>;\n plugin?: string[];\n permission?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n/**\n * Substitute `mcp` in the template with entries from `.mcp.json`.\n * Other keys (`agent`, `command`, `plugin`, `permission`, `instructions`,\n * `$schema`) are preserved from the template.\n */\nexport function renderOpencodeJson(params: RenderOpencodeJsonParams): string {\n const config = parseTemplate(params.template);\n\n if (params.mcp) {\n config.mcp = { ...params.mcp.mcpServers };\n }\n\n return `${JSON.stringify(config, null, 2)}\\n`;\n}\n\nfunction parseTemplate(template: string): OpencodeConfig {\n try {\n return JSON.parse(template) as OpencodeConfig;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`opencode.json template invalid JSON: ${message}`);\n }\n}\n","/**\n * settings.json 부분 머지 — `.claude/settings.json` PreToolUse hook entry 추가.\n *\n * SPEC: docs/specs/karpathy-hook-autowire.md AC2/AC4 — opt-in 시 idempotent 등록.\n *\n * 사용처: karpathy-coder hook auto-wire (v0.6.0). 기존 매처 entry 보존 + 동일 command 중복 X.\n */\n\nexport interface ClaudeHookCommand {\n type: \"command\";\n command: string;\n async?: boolean;\n timeout?: number;\n}\n\nexport interface ClaudeHookMatcher {\n matcher?: string;\n hooks: ClaudeHookCommand[];\n}\n\nexport interface ClaudeSettings {\n // 기타 키 (statusLine, _comment 등) 보존 — 알 필요 없음\n [key: string]: unknown;\n hooks?: {\n [event: string]: ClaudeHookMatcher[];\n };\n}\n\n/**\n * PreToolUse 배열에 hook entry 추가 (idempotent). 기존 settings 객체는 mutation 안 함 (deep clone).\n *\n * 동작:\n * - hooks.PreToolUse 없음 → 생성\n * - matcher 일치하는 entry 없음 → 새 entry 추가\n * - matcher 일치 + command 동일한 hook 있음 → idempotent (변경 없음)\n * - matcher 일치 + command 다름 → hooks 배열에 append\n */\nexport function addPreToolUseHook(\n settings: ClaudeSettings,\n matcher: string,\n command: string,\n): ClaudeSettings {\n const next: ClaudeSettings = JSON.parse(JSON.stringify(settings));\n if (!next.hooks) {\n next.hooks = {};\n }\n if (!next.hooks.PreToolUse) {\n next.hooks.PreToolUse = [];\n }\n const preToolUse = next.hooks.PreToolUse;\n const existing = preToolUse.find((m) => m.matcher === matcher);\n const newHook: ClaudeHookCommand = { type: \"command\", command };\n if (existing) {\n if (existing.hooks.some((h) => h.command === command)) {\n return next; // idempotent — 동일 command 중복 X\n }\n existing.hooks.push(newHook);\n } else {\n preToolUse.push({ matcher, hooks: [newHook] });\n }\n return next;\n}\n","/**\n * update-mode.ts — Update / Add / Reinstall router 액션 처리.\n *\n * SPEC: docs/specs/cli-rewrite-completeness.md F5, F6\n * Source: bash setup-harness.sh@911c246~1 L460~573 (update mode 113 LOC)\n *\n * Update 모드 동작:\n * 1. backup: .claude/ → .claude.backup-<timestamp>/\n * 2. update_dir: target에 이미 존재하는 파일만 templates로 덮어쓰기 (Track 혼입 방지)\n * 3. prune_orphans: templates에 없는데 target에 있는 파일 제거 (예: 폐기된 rule)\n * 4. clean_stale_hook_refs: settings.json hook 참조 중 실존 파일 없는 것 제거\n *\n * 보존: .mcp.json (사용자 추가 항목), docs/SPEC.md, settings.local.json\n */\n\nimport {\n copyFileSync,\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { backupFile, listFilesRecursive } from \"./fs-ops.js\";\nimport {\n collectSkillHashes,\n hashContent,\n type InstallLog,\n readInstallLog,\n writeInstallLog,\n} from \"./install-log.js\";\n\nexport interface UpdateModeReport {\n /** 덮어쓰기된 파일 갯수 (디렉토리별). */\n updated: Record<string, number>;\n /** 제거된 orphan 파일명 목록 (디렉토리별). */\n pruned: Record<string, string[]>;\n /** 제거된 stale hook ref 파일명 목록. */\n staleHookRefs: string[];\n /** 갱신된 CLAUDE.md (true if updated). */\n claudeMdUpdated: boolean;\n /**\n * v26.126.0 (R-3a) — 사용자가 고쳐서 백업본을 남긴 스킬 파일 (`.claude/skills/` 상대경로).\n * 화면에 그대로 노출한다. 안 보이면 사용자는 자기 편집분이 어디 갔는지 알 수 없다.\n */\n skillsBackedUp: string[];\n}\n\n/**\n * Update mode 메인 — backup은 caller가 별도 처리.\n *\n * @param projectDir 대상 프로젝트 root\n * @param templatesDir templates/ 디렉토리 (sync source)\n */\nexport function runUpdateMode(projectDir: string, templatesDir: string): UpdateModeReport {\n const claudeDir = join(projectDir, \".claude\");\n const report: UpdateModeReport = {\n updated: {},\n pruned: {},\n staleHookRefs: [],\n claudeMdUpdated: false,\n skillsBackedUp: [],\n };\n\n // 1) update_dir × 4 (rules/agents/commands/uzys/hooks)\n const targets = [\n {\n target: join(claudeDir, \"rules\"),\n source: join(templatesDir, \"rules\"),\n pattern: \".md\",\n label: \".claude/rules\",\n },\n {\n target: join(claudeDir, \"agents\"),\n source: join(templatesDir, \"agents\"),\n pattern: \".md\",\n label: \".claude/agents\",\n },\n {\n target: join(claudeDir, \"commands/uzys\"),\n source: join(templatesDir, \"commands/uzys\"),\n pattern: \".md\",\n label: \".claude/commands/uzys\",\n },\n {\n target: join(claudeDir, \"hooks\"),\n source: join(templatesDir, \"hooks\"),\n pattern: \".sh\",\n label: \".claude/hooks\",\n },\n ];\n\n for (const t of targets) {\n report.updated[t.label] = updateDir(t.target, t.source, t.pattern);\n report.pruned[t.label] = pruneOrphans(t.target, t.source, t.pattern);\n }\n\n // 1.5) `.claude/skills/` — v26.126.0 (R-3a · ADR-046).\n // 위 4개와 달리 스킬은 디렉터리 단위라 재귀가 필요하고, 사용자 편집분 판정이 붙는다.\n const skillSync = syncSkills(\n join(claudeDir, \"skills\"),\n join(templatesDir, \"skills\"),\n skillBaseline(projectDir),\n );\n report.updated[\".claude/skills\"] = skillSync.updated;\n report.skillsBackedUp = skillSync.backedUp;\n refreshSkillBaseline(projectDir);\n\n // 2) .claude/CLAUDE.md\n const claudeMd = join(claudeDir, \"CLAUDE.md\");\n const templateMd = join(templatesDir, \"CLAUDE.md\");\n if (existsSync(claudeMd) && existsSync(templateMd)) {\n copyFileSync(templateMd, claudeMd);\n report.claudeMdUpdated = true;\n }\n\n // 3) settings.json stale hook ref cleanup\n const settingsPath = join(claudeDir, \"settings.json\");\n if (existsSync(settingsPath)) {\n report.staleHookRefs = cleanStaleHookRefs(settingsPath, join(claudeDir, \"hooks\"));\n }\n\n return report;\n}\n\n/**\n * `target`에 이미 존재하는 파일 중 `source`에 동일 이름 있는 것만 덮어쓰기.\n * Track 혼입 방지 (새 파일 추가 X) — bash update_dir 등가.\n */\nexport function updateDir(target: string, source: string, ext: string): number {\n if (!existsSync(target) || !existsSync(source)) return 0;\n let count = 0;\n for (const file of readdirSync(target)) {\n if (!file.endsWith(ext)) continue;\n const targetFile = join(target, file);\n const sourceFile = join(source, file);\n if (existsSync(sourceFile)) {\n copyFileSync(sourceFile, targetFile);\n count++;\n }\n }\n return count;\n}\n\n/**\n * `.claude/skills/` 를 templates 기준으로 갱신한다 (v26.126.0 · R-3a · ADR-046).\n *\n * **설치된 스킬만 손댄다** — templates 에 있어도 target 에 그 스킬 디렉터리가 없으면 건너뛴다.\n * 스킬은 트랙/opt-in 으로 게이팅돼 설치되므로(`installer.ts` selectedInternalSkills), 전부\n * 복사하면 사용자가 고르지 않은 스킬이 딸려 들어간다 (`updateDir` 의 \"Track 혼입 방지\"와 같은 취지).\n *\n * 파일 단위 판정:\n * | 디스크 vs 기준선 | 뜻 | 처리 |\n * |---|---|---|\n * | 같다 | 사용자가 안 고쳤다 | 조용히 덮어쓴다 |\n * | 다르다 | 사용자가 고쳤다 | `.backup-<stamp>` 남기고 덮어쓴다 |\n * | 기준선 기록 없음 | 판정 불가 | 보수적으로 백업 (레거시 설치의 첫 update 1회) |\n *\n * **orphan prune 은 하지 않는다** — 스킬 디렉터리 안에는 사용자가 자기 참고 파일을 넣을 수 있고,\n * templates 에 없다는 이유로 지우면 그게 곧 사용자 파일 삭제다 (ADR-046 \"지우지 않는다\").\n */\nexport function syncSkills(\n targetDir: string,\n sourceDir: string,\n baseline: ReadonlyMap<string, string>,\n now: Date = new Date(),\n): { updated: number; backedUp: string[] } {\n if (!existsSync(targetDir) || !existsSync(sourceDir)) return { updated: 0, backedUp: [] };\n let updated = 0;\n const backedUp: string[] = [];\n\n for (const skill of readdirSync(sourceDir, { withFileTypes: true })) {\n if (!skill.isDirectory()) continue;\n const targetSkill = join(targetDir, skill.name);\n if (!existsSync(targetSkill)) continue; // 사용자가 선택하지 않은 스킬 — 새로 깔지 않는다\n\n for (const rel of listFilesRecursive(join(sourceDir, skill.name))) {\n const targetFile = join(targetSkill, rel);\n const next = readFileSync(join(sourceDir, skill.name, rel), \"utf8\");\n\n if (!existsSync(targetFile)) {\n // 스킬 안에 새로 생긴 파일 (예: references/ 추가) — 스킬 자체는 이미 설치돼 있다.\n mkdirSync(dirname(targetFile), { recursive: true });\n writeFileSync(targetFile, next);\n updated++;\n continue;\n }\n\n const current = readFileSync(targetFile, \"utf8\");\n if (current === next) continue; // 이미 최신 — 백업도 갱신도 불필요\n\n const recorded = baseline.get(`${skill.name}/${rel}`);\n if (recorded === undefined || hashContent(current) !== recorded) {\n backupFile(targetFile, now);\n backedUp.push(`${skill.name}/${rel}`);\n }\n writeFileSync(targetFile, next);\n updated++;\n }\n }\n return { updated, backedUp };\n}\n\n/** 설치 시점 기준선을 Map 으로. 기록이 없으면 빈 Map — 그때는 보수적 백업으로 폴백한다. */\nfunction skillBaseline(projectDir: string): ReadonlyMap<string, string> {\n const log = readInstallLog(projectDir);\n return new Map((log?.skillFiles ?? []).map((f) => [f.path, f.sha256]));\n}\n\n/**\n * 갱신 직후 기준선을 다시 찍는다.\n *\n * 이걸 빼면 다음 update 가 **방금 자기가 덮어쓴 파일**을 전부 \"사용자가 고쳤다\"로 오판해\n * 백업본을 매번 새로 쌓는다. update 는 install log 를 안 쓰는 단축 경로라\n * (`installer.ts` runUpdateInstall) 여기서 안 하면 아무도 안 한다.\n *\n * 로그가 없으면 **만들지 않는다** — update 가 설치 기록을 날조하면 uninstall 이 그걸 믿는다.\n */\nfunction refreshSkillBaseline(projectDir: string): void {\n const log = readInstallLog(projectDir);\n if (!log) return;\n const skillFiles = collectSkillHashes(projectDir);\n const next: InstallLog = { ...log };\n if (skillFiles.length > 0) next.skillFiles = skillFiles;\n else delete next.skillFiles;\n try {\n writeInstallLog(projectDir, next);\n } catch {\n // 기록 실패가 update 자체를 실패시키지는 않는다 (D16 — 설치/갱신 성공 우선과 같은 방침).\n }\n}\n\n/**\n * Templates에 없는데 target에 있는 파일 제거 (orphan prune) — bash prune_orphans 등가.\n */\nexport function pruneOrphans(target: string, source: string, ext: string): string[] {\n if (!existsSync(target) || !existsSync(source)) return [];\n const removed: string[] = [];\n for (const file of readdirSync(target)) {\n if (!file.endsWith(ext)) continue;\n const sourceFile = join(source, file);\n if (!existsSync(sourceFile)) {\n const targetFile = join(target, file);\n try {\n unlinkSync(targetFile);\n removed.push(file);\n } catch {\n // best-effort — read-only? 다음 update 시 재시도\n }\n }\n }\n return removed;\n}\n\n/**\n * settings.json의 PreToolUse/PostToolUse hooks 중 실존 파일 없는 hook script 참조 제거.\n * bash clean_stale_hook_refs 등가 (jq 의존 없이 JSON 직접 파싱).\n *\n * @returns 제거된 hook script 파일명 목록\n */\nexport function cleanStaleHookRefs(settingsPath: string, hooksDir: string): string[] {\n let settings: SettingsJson;\n try {\n settings = JSON.parse(readFileSync(settingsPath, \"utf8\")) as SettingsJson;\n } catch {\n return [];\n }\n const hookEvents = settings.hooks ?? {};\n const removed: string[] = [];\n const cleanedHooks: Record<string, HookEntry[]> = {};\n\n for (const [eventName, eventEntries] of Object.entries(hookEvents)) {\n if (!Array.isArray(eventEntries)) {\n cleanedHooks[eventName] = eventEntries; // non-array event — 그대로 보존\n continue;\n }\n cleanedHooks[eventName] = eventEntries\n .filter((entry) => Array.isArray(entry?.hooks))\n .map((entry) => ({\n ...entry,\n hooks: entry.hooks.filter((hook) => keepHookRef(hook, hooksDir, removed)),\n }))\n .filter((entry) => entry.hooks.length > 0); // stale 제거 후 hooks 빈 entry 제거\n }\n\n if (removed.length > 0) {\n const next: SettingsJson = { ...settings, hooks: cleanedHooks };\n writeFileSync(settingsPath, `${JSON.stringify(next, null, 2)}\\n`);\n }\n return removed;\n}\n\n/** hook command 가 실존 `.sh` 참조면 true. stale(파일 부재) 이면 removed 에 fname 수집 후 false. */\nfunction keepHookRef(hook: HookCommand, hooksDir: string, removed: string[]): boolean {\n const refMatch = (hook?.command ?? \"\").match(/\\/\\.claude\\/hooks\\/([^\"\\s/]+\\.sh)/);\n if (!refMatch?.[1]) return true; // hook script 참조 아님 — 보존\n const fname = refMatch[1];\n const exists = existsSync(join(hooksDir, fname));\n if (!exists && !removed.includes(fname)) removed.push(fname);\n return exists;\n}\n\ninterface HookCommand {\n type?: string;\n command?: string;\n}\n\ninterface HookEntry {\n matcher?: string;\n hooks: HookCommand[];\n}\n\ninterface SettingsJson {\n hooks?: Record<string, HookEntry[]>;\n [key: string]: unknown;\n}\n","/**\n * Install 출력 렌더 레이어 (v26.82.0, Phase R).\n *\n * `commands/install.ts` 가 979줄(cap 800 초과 — repo 최대 위반)로 비대해진 원인이\n * 렌더 함수 누적이었음 → 본 파일로 추출. install.ts 는 spec 검증 + 파이프라인\n * 오케스트레이션만, 여기는 화면 출력만. 동작 변경 0 (순수 이동).\n */\n\nimport { CATEGORY_TITLES, type Category } from \"../categories.js\";\nimport { targetsInclude } from \"../cli-targets.js\";\nimport { formatResidentCostLine, residentCost, summarizeContextCost } from \"../context-cost.js\";\nimport { assetRow, c, infoRow, padDisplay, sectionHeader, unifiedSection } from \"../design.js\";\nimport {\n assetCliSupport,\n assetReachesCli,\n EXTERNAL_ASSETS,\n type ExternalAsset,\n experimentalOptInCandidates,\n isAssetSelected,\n} from \"../external-assets.js\";\nimport type { AssetInstallResult } from \"../external-installer.js\";\nimport type { BaselineReport, InstallMode, InstallReport, ProgressEvent } from \"../installer.js\";\nimport { buildManifest } from \"../manifest.js\";\nimport { finalSelectedAssets, groupAssetsByCategory } from \"../preset-recommend.js\";\nimport type { CliBase, CliTargets, InstallSpec, OptionFlags } from \"../types.js\";\n\n/**\n * v26.78.1 — Summary `CLI` 행 라벨 (SSOT). spec.cli 에서 derive → 헤더와 일관.\n * 이전 pairwise if-chain 은 codex/opencode 만 열거해 `--cli antigravity` 가 \"Claude\" 로\n * 잘못 출력 (R2). 4 base 전부 매핑.\n */\nconst CLI_SUMMARY_LABELS: Record<CliBase, string> = {\n claude: \"Claude\",\n codex: \"Codex\",\n opencode: \"OpenCode\",\n antigravity: \"Antigravity\",\n};\n\n/** Callbacks for progressive rendering during runInstall (avoids \"Phase 1 silence\" UX). */\nexport interface PipelineCallbacks {\n onProgress?: (event: ProgressEvent) => void;\n externalDeps?: {\n onAssetStart?: (asset: ExternalAsset) => void;\n onAssetResult?: (result: AssetInstallResult) => void;\n };\n}\n\n/** createInstallRenderer 반환 — 스트리밍 콜백 + 렌더 상태 조회. */\nexport interface InstallRenderer {\n callbacks: PipelineCallbacks;\n /** External assets 헤더 출력 여부 — Summary 직전 trailing newline 판단용. */\n phase2HeaderPrinted(): boolean;\n}\n\n/**\n * install header (TARGET / TRACKS / CLI / SCOPE / OPTIONS / ASSETS) 렌더.\n * wizard 모드는 Step 3 review + Step 4 confirm 에서 이미 표시하므로 호출 안 함.\n */\nexport function renderInstallHeader(\n log: (msg: string) => void,\n spec: InstallSpec,\n mode?: InstallMode,\n): void {\n const headerLabel =\n mode === \"update\"\n ? \"uzys-agent-harness · update\"\n : mode === \"add\"\n ? \"uzys-agent-harness · add\"\n : mode === \"reinstall\"\n ? \"uzys-agent-harness · reinstall\"\n : \"uzys-agent-harness · install\";\n log(\"\");\n log(sectionHeader(headerLabel));\n log(\"\");\n log(infoRow(\"TARGET\", shortenPath(spec.projectDir)));\n log(infoRow(\"TRACKS\", spec.tracks.join(\", \")));\n log(infoRow(\"CLI\", spec.cli.join(\" · \")));\n // v26.64.0 (ADR-020) — SCOPE row. 사용자가 매 install 시 어디에 write 되는지 인지 (D16).\n {\n const effectiveScope = spec.scope ?? \"project\";\n const scopeMsg =\n effectiveScope === \"global\"\n ? \"Global — writes to ~/.claude/, ~/.codex/, npm -g\"\n : \"Project — current directory only (no global write)\";\n log(infoRow(\"SCOPE\", scopeMsg));\n }\n log(infoRow(\"OPTIONS\", formatOptions(spec)));\n // v26.82.0 (Phase R, S6) — merge 는 preset-recommend.ts 단일 구현 (이전 computeFinalAssets 중복).\n const finalAssets = finalSelectedAssets(spec.tracks, spec.userOverride);\n if (finalAssets.length > 0) {\n // v26.102.0 (ADR-031) — 선택 수와 실제 설치 수의 어긋남을 약속 시점에 고지 (SOD 리뷰 F3:\n // executive/codex 가 \"4 selected\" 약속 후 0 설치이던 불일치). 숨김 없이 분해만 병기.\n // 미지 id(검증은 install.ts 담당)는 도달 가능으로 취급 — 여기서 이중 판정하지 않는다.\n const unreachable = finalAssets.filter((id) => {\n const asset = EXTERNAL_ASSETS.find((a) => a.id === id);\n return asset ? !assetReachesCli(asset, spec.cli) : false;\n });\n const label =\n unreachable.length > 0\n ? `${finalAssets.length} selected (${unreachable.length} outside [${spec.cli.join(\", \")}] reach — not installed)`\n : `${finalAssets.length} selected`;\n log(infoRow(\"ASSETS\", label));\n for (const [cat, ids] of groupAssetsByCategory(finalAssets)) {\n log(` ${c.dim(`· ${cat}:`)} ${ids.join(\", \")}`);\n }\n // v26.103.0 (ADR-032) — Session-Start Context Cost NSM. 번들 스킬 = frontmatter 실측(~),\n // 외부 자산 = unmeasured 명시 (추정치를 실측처럼 표기 금지).\n const cost = formatResidentCostLine(\n residentCost(buildManifest(spec).filter((e) => e.applies(spec))),\n summarizeContextCost(finalAssets).unmeasuredCount,\n );\n if (cost) log(` ${c.dim(`· ${cost}`)}`);\n }\n log(\"\");\n}\n\n/**\n * runInstall 스트리밍 렌더 콜백 생성 — baseline 완료 시 즉시 Phase 1 rows 출력,\n * external 은 per-asset 스트리밍 + 카테고리 헤더 (ADR-016 grouped progress UX).\n */\nexport function createInstallRenderer(\n log: (msg: string) => void,\n spec: InstallSpec,\n verbose: boolean,\n): InstallRenderer {\n let phase2HeaderPrinted = false;\n // v26.55.0 — Phase 2 grouped progress UX (ADR-016). category 변경 시 ━━ <Title> ━━ 헤더 출력.\n // external-installer 가 카테고리 순서로 정렬해 호출 → 첫 번째 호출이 category 1 의 첫 자산.\n let currentCategory: Category | null = null;\n const callbacks: PipelineCallbacks = {\n onProgress: (event) => {\n if (event.type === \"baseline-complete\") {\n // v26.81.0 (ADR-022) — withEcc boolean 삭제 → ecc-plugin 자산 선택으로 판정 (hint 게이팅).\n // v26.102.0 (ADR-031) — \"선택 = 설치됨\" 은 claude 도달 시에만 성립: codex 단독에선\n // ecc-plugin 이 배제되므로 fallback 힌트가 계속 진실이어야 한다 (SOD 리뷰 F2).\n const claudeSelected = targetsInclude(spec.cli, \"claude\");\n const eccWillInstall =\n claudeSelected &&\n (isAssetSelected(\"ecc-plugin\", spec) || spec.options.withPrune === true);\n renderPhase1Rows(log, event.baseline, verbose, eccWillInstall, claudeSelected);\n } else if (event.type === \"external-start\" && event.assetCount > 0) {\n // v26.63.0 — phaseHeader → unifiedSection. count 헤더에 inline 표시.\n log(unifiedSection(`External assets (${event.assetCount})`));\n log(\"\");\n phase2HeaderPrinted = true;\n } else if (event.type === \"external-complete\") {\n // v26.102.0 (ADR-031, Batch3) — CLI 도달 불가로 시도조차 안 한 자산 고지.\n // 침묵 제외는 \"4-CLI 지원\" 광고와 실동작의 어긋남을 숨긴다 (no-false-ship).\n // 어휘 주의: \"skipped\"(설치 실패)와 구분해 \"not installed\" 사용, 사유는 각 자산의\n // 실 도달 범위에서 derive — \"claude-only\" 하드코딩 금지 (SOD 리뷰 F4/F7/Nit-4).\n const excluded = event.report.excludedByCli;\n if (excluded.length > 0) {\n if (!phase2HeaderPrinted) {\n // attempted=0 인 트랙(executive 등)에서 고지가 헤더 없이 떠도는 것 방지 (F8).\n log(unifiedSection(\"External assets (0)\"));\n phase2HeaderPrinted = true;\n }\n const bySupport = new Map<string, string[]>();\n for (const a of excluded) {\n const key = assetCliSupport(a).join(\"/\");\n bySupport.set(key, [...(bySupport.get(key) ?? []), a.id]);\n }\n log(\"\");\n for (const [support, ids] of bySupport) {\n log(\n ` ${c.dim(`· ${ids.length} asset(s) not installed — requires ${support}, selected [${spec.cli.join(\", \")}]: ${ids.join(\", \")}`)}`,\n );\n }\n }\n }\n },\n externalDeps: {\n onAssetStart: (asset) => {\n // v26.57.0 (F2) — 카테고리 헤더만 출력. 자산 시작 라인 (→) 제거 — ✓ 결과 한 라인으로 1 단위 명확화.\n if (asset.category !== currentCategory) {\n if (currentCategory !== null) log(\"\");\n log(` ${c.bold(`━━ ${CATEGORY_TITLES[asset.category]} ━━`)}`);\n currentCategory = asset.category;\n }\n },\n onAssetResult: (result) => {\n const meta = result.ok\n ? formatAssetMeta(result.asset, result.version)\n : (result.message ?? \"failed\");\n log(` ${assetRow(result.ok ? \"success\" : \"skip\", result.asset.id, meta)}`);\n },\n },\n };\n return { callbacks, phase2HeaderPrinted: () => phase2HeaderPrinted };\n}\n\n/** Update mode 단축 Summary — manifest copy / external 모두 skip 된 경로. */\nexport function renderUpdateSummary(log: (msg: string) => void, report: InstallReport): void {\n log(\"\");\n // v26.63.2 — Summary 도 unifiedSection 으로 통일 (━━ marker). Step 5 안 sub-section 들과 일관.\n log(unifiedSection(\"Summary\"));\n log(\"\");\n log(infoRow(\"STATUS\", c.green(\"Update complete\")));\n log(infoRow(\"MODE\", \"update\"));\n if (report.backup) {\n log(infoRow(\"BACKUP\", shortenPath(report.backup)));\n log(infoRow(\"ROLLBACK\", `rm -rf .claude && mv ${shortenPath(report.backup)} .claude`));\n }\n log(\"\");\n}\n\n/**\n * Codex / OpenCode / Antigravity 산출물 sub-section.\n * v26.78.1 (R2): antigravity 추가 — `--cli antigravity` 시 산출물 invisible 이던 버그 fix.\n * 산출물 report 가 없거나 해당 CLI 미선택 시 출력 없음 (이전 executeSpec 의 게이트 if 이동).\n */\nexport function renderCliArtifacts(\n log: (msg: string) => void,\n spec: InstallSpec,\n report: InstallReport,\n): void {\n const hasArtifacts = Boolean(report.codex || report.opencode || report.antigravity);\n const cliSelected =\n targetsInclude(spec.cli, \"codex\") ||\n targetsInclude(spec.cli, \"opencode\") ||\n targetsInclude(spec.cli, \"antigravity\");\n if (!hasArtifacts || !cliSelected) {\n return;\n }\n log(unifiedSection(formatCliPhaseTitle(spec.cli)));\n log(\"\");\n // AGENTS.md is shared across Codex/OpenCode — render once with shared note\n if (report.codex && report.opencode) {\n log(assetRow(\"success\", \"AGENTS.md\", \"shared (Codex + OpenCode)\"));\n } else if (report.codex || report.opencode) {\n log(assetRow(\"success\", \"AGENTS.md\", \"from .claude/CLAUDE.md\"));\n }\n if (report.codex) {\n log(assetRow(\"success\", \".codex/config.toml\", \"settings + [mcp_servers.*]\"));\n log(assetRow(\"success\", \".codex/hooks/\", `${report.codex.hookFiles.length} files`));\n if (report.codex.skillFiles.length > 0) {\n log(\n assetRow(\n \"success\",\n \".agents/skills/<id>/SKILL.md\",\n `${report.codex.skillFiles.length} skills`,\n ),\n );\n }\n // Codex global opt-in (D16) — config.toml trust entry, only when explicitly enabled.\n if (report.codexOptIn?.trustEntry.enabled) {\n const trust = report.codexOptIn.trustEntry;\n const kind = trust.status === \"error\" ? \"skip\" : \"success\";\n const meta =\n trust.status === \"registered\"\n ? '[projects.\"<dir>\"] trust_level=\"trusted\"'\n : trust.status === \"already-present\"\n ? \"already present\"\n : (trust.message ?? \"error\");\n log(assetRow(kind, \"~/.codex/config.toml trust entry\", meta));\n }\n }\n if (report.opencode) {\n log(assetRow(\"success\", \"opencode.json\", \"$schema + 5 keys\"));\n log(assetRow(\"success\", \".opencode/commands/\", `${report.opencode.commandFiles.length} files`));\n }\n // v26.78.1 (R2) — Antigravity 산출물: rules (항상) + dev-method skills.\n if (report.antigravity) {\n if (report.antigravity.rulesFile) {\n log(assetRow(\"success\", \".agents/rules/uzys-harness.md\", \"from .claude/CLAUDE.md\"));\n }\n if (report.antigravity.skillFiles.length > 0) {\n log(\n assetRow(\n \"success\",\n \".agents/skills/<id>/SKILL.md\",\n `${report.antigravity.skillFiles.length} skills`,\n ),\n );\n }\n }\n log(\"\");\n}\n\n/** 최종 Summary (STATUS / TRACKS / CLI / HOOK / WARN / OPT-IN / NEXT). */\nexport function renderFinalSummary(\n log: (msg: string) => void,\n spec: InstallSpec,\n report: InstallReport,\n fromWizard: boolean,\n): void {\n // v26.63.2 — Summary 도 unifiedSection 으로 통일 (━━ marker).\n log(unifiedSection(\"Summary\"));\n log(\"\");\n log(infoRow(\"STATUS\", c.green(\"Install complete\")));\n log(infoRow(\"TRACKS\", report.installedTracks.join(\", \")));\n // v26.63.4 (P3): install header `CLI` 와 Summary `CLIs` 라벨 불일치 → `CLI` 로 통일.\n // v26.78.1 (R2): pairwise if-chain → spec.cli derive. antigravity 누락 + claude 무조건\n // prepend(claude 미선택 시에도 \"Claude\" 표기) 버그 fix. 헤더와 동일 SSOT.\n log(infoRow(\"CLI\", spec.cli.map((b) => CLI_SUMMARY_LABELS[b]).join(\" · \")));\n // v26.78.1 (R1) — karpathy hook opt-in 결과 렌더. null = 미opt-in(표시 안 함).\n // 이전엔 wired=false(plugin install 실패 등)여도 무음 → 사용자가 hook 안 깔린 걸\n // 모른 채 \"Install complete\" 만 봄 (Rule 12 fail-loud 위반).\n if (report.karpathyHook) {\n const kh = report.karpathyHook;\n if (kh.wired) {\n log(infoRow(\"HOOK\", c.green(\"karpathy-coder pre-commit hook wired\")));\n } else {\n log(infoRow(\"HOOK\", c.yellow(`karpathy hook skipped — ${kh.reason ?? \"unknown\"}`)));\n }\n }\n if (report.external && report.external.skipped > 0) {\n log(\"\");\n log(\n infoRow(\n \"WARN\",\n c.yellow(\n `${report.external.skipped} external asset${report.external.skipped > 1 ? \"s\" : \"\"} skipped (see Phase 2 above)`,\n ),\n ),\n );\n }\n // v26.102.0 (ADR-031) — v26.88.0 의 NOTE(plugin-kind 만 자체 재계산)를 대체: SSOT =\n // report.external.excludedByCli. 구 NOTE 는 ⊘ 고지와 다른 계산식(shell-script 누락)이라\n // 같은 화면에서 숫자가 어긋났고, claude 를 함께 골라 실제 설치된 경우에도 \"not installed\"\n // 를 찍었다 (SOD 리뷰 F4 — no-false-ship \"동일 목록 2곳 하드코딩 금지\").\n if (report.external && report.external.excludedByCli.length > 0) {\n const excluded = report.external.excludedByCli;\n log(\"\");\n log(\n infoRow(\n \"EXCLUDED\",\n c.dim(\n `${excluded.length} asset${excluded.length > 1 ? \"s\" : \"\"} not installed — outside [${spec.cli.join(\", \")}] reach: ${excluded.map((a) => a.id).join(\", \")}`,\n ),\n ),\n );\n }\n // v26.71.1 — experimental(T3) opt-in discoverability (Transparent Defaults — 숨김 0건).\n // 비대화형(--track) 에서 condition 은 맞지만 T3 라 default 제외된 자산을 --with 안내.\n // wizard 모드는 이미 ⚠ 배지로 노출하므로 skip.\n if (!fromWizard) {\n const optIn = experimentalOptInCandidates(spec);\n if (optIn.length > 0) {\n log(\"\");\n log(\n infoRow(\n \"OPT-IN\",\n c.dim(\n `${optIn.length} experimental available — add with --with <id>: ${optIn.map((a) => a.id).join(\", \")}`,\n ),\n ),\n );\n }\n }\n log(\"\");\n const primary = (spec.cli.includes(\"claude\") ? \"claude\" : spec.cli[0]) ?? \"claude\";\n const label = CLI_SUMMARY_LABELS[primary];\n log(infoRow(\"NEXT\", `Open ${c.bold(label)} — installed rules & skills are now active`));\n const scaffoldFiles = scaffoldFilesForCli(spec.cli);\n if (scaffoldFiles.length > 0) {\n log(\n infoRow(\n \"FILL\",\n `${scaffoldFiles.map((f) => c.bold(f)).join(\" · \")} — a fill-in scaffold. Open and paste each ${c.bold(\"<!-- FILL: … -->\")} prompt to your agent to tailor it to this project`,\n ),\n );\n }\n log(\"\");\n}\n\n/**\n * Which project-context scaffold files a given CLI selection actually writes:\n * `CLAUDE.md` only for a claude install, `AGENTS.md` only for a non-claude CLI.\n * The FILL hint must name only files that were written — advertising a file that\n * a given `--cli` never produced is the no-false-ship \"advertised ≠ real\" trap.\n */\nexport function scaffoldFilesForCli(cli: ReadonlyArray<CliBase>): string[] {\n const files: string[] = [];\n if (cli.includes(\"claude\")) {\n files.push(\"CLAUDE.md\");\n }\n if (cli.some((target) => target !== \"claude\")) {\n files.push(\"AGENTS.md\");\n }\n return files;\n}\n\nfunction formatAssetMeta(asset: ExternalAsset, version?: string): string {\n // v26.56.0 (F3) — description 제거. onAssetStart 의 → 라인이 이미 description 표시.\n // result row 는 method + source 만 간결하게 → terminal 120 char 안 wrap 방지.\n // v26.59.0 — plugin / npm-global 에 한해 version 표시 (path 기반 추출).\n const m = asset.method;\n const v = version ? ` ${c.dim(`v${version.replace(/^v/, \"\")}`)}` : \"\";\n switch (m.kind) {\n case \"skill\":\n // v26.63.3 (clarify M1): skill name 이 asset id 와 동일하면 중복 segment 생략.\n // \"skill · pbakaus/impeccable · impeccable\" → \"skill · pbakaus/impeccable\"\n if (m.skill && m.skill !== asset.id) return `skill · ${m.source} · ${m.skill}`;\n return `skill · ${m.source}`;\n case \"plugin\":\n return `plugin · ${m.pluginId}${v}`;\n case \"npm\":\n // A2 (Promise audit) — ADR-020 후 npm 자산 default 는 `--save-dev`(project), `-g` 는 global scope 만.\n // 라벨에 \"-g\" 고정은 scope 거짓 표기 → scope-중립 \"npm\" 으로 정정.\n // v26.80.0 — pinned 버전 표기 (Transparent Defaults: 실행되는 정확한 버전 노출).\n return `npm · ${m.pkg}@${m.version}`;\n case \"npx-run\":\n return `npx · ${m.cmd}@${m.version}`;\n case \"shell-script\":\n return `bash · ${m.script}`;\n case \"internal\":\n // v26.81.0 (ADR-022) — 내부 템플릿 자산 (Phase 1 manifest 가 설치 주체).\n return `internal · templates (${m.key})`;\n }\n}\n\n/**\n * Phase 1 rows 출력. baseline-complete progress event에서 호출 — 외부 자산 설치\n * 시작 전 즉시 화면에 표시되어야 한다 (멈춰 보임 방지).\n */\nfunction renderPhase1Rows(\n log: (msg: string) => void,\n baseline: BaselineReport,\n verbose = false,\n withEcc = false,\n // v26.102.0 (ADR-031) — ecc 힌트의 `--with ecc-plugin` 안내는 claude 도달 시에만 참\n // (plugin 은 claude 전용 — codex 단독에선 그 명령이 no-op, SOD 리뷰 F2).\n claudeSelected = true,\n): void {\n // Update mode rows\n if (baseline.updateMode) {\n if (baseline.backup) {\n log(assetRow(\"success\", \"backup\", shortenPath(baseline.backup)));\n }\n for (const [dir, count] of Object.entries(baseline.updateMode.updated)) {\n if (count > 0) log(assetRow(\"success\", dir, `${count} files updated`));\n }\n for (const [dir, removed] of Object.entries(baseline.updateMode.pruned)) {\n if (removed.length > 0) {\n log(assetRow(\"skip\", `${dir} orphan prune`, `${removed.length} removed`));\n }\n }\n if (baseline.updateMode.claudeMdUpdated) {\n log(assetRow(\"success\", \".claude/CLAUDE.md\", \"refreshed from template\"));\n }\n // v26.126.0 (R-3a) — 편집분을 백업했다는 사실은 **반드시 화면에 남긴다**. 갱신 건수만 보이면\n // 사용자는 자기가 고친 내용이 어디로 갔는지 알 수 없고, 그게 R-3a 를 만든 침묵과 같은 실패다.\n if (baseline.updateMode.skillsBackedUp.length > 0) {\n log(\n assetRow(\n \"skip\",\n \".claude/skills edited files\",\n `${baseline.updateMode.skillsBackedUp.length} backed up as *.backup-<time>`,\n ),\n );\n }\n if (baseline.updateMode.staleHookRefs.length > 0) {\n log(\n assetRow(\n \"skip\",\n \"settings.json stale hook refs\",\n `${baseline.updateMode.staleHookRefs.length} removed`,\n ),\n );\n }\n return;\n }\n\n // Fresh / add / reinstall — Phase 1 rows\n // audit SEC-1/CODE-2 — 기존 settings.json·CLAUDE.md 를 덮어쓰기 전 백업했으면 fail-loud 노출.\n if (baseline.backups) {\n for (const b of baseline.backups) {\n log(assetRow(\"success\", \"backup\", shortenPath(b)));\n }\n }\n // v26.57.1 (F2) — multi-line 구조 (header + use + files). visual hierarchy + width-safe.\n // 사용자 image 검증 (2026-05-17): 단일 라인 description 이 width 좁을 때 wrap → 들여쓰기 깨짐.\n const cats = baseline.categories;\n if (cats) {\n // v26.63.0 — files 라인은 verbose 옵션 시만. 기본은 카운트 + use 1 줄.\n // v26.63.2 — polish: label + count 칼럼 fixed-width 정렬 (28 char). spacing scale 일관.\n const phase1Row = (label: string, count: number, useText: string, files?: string[]) => {\n const labelCol = `${c.bold(label)} ${c.dim(`(${count})`)}`;\n const padded = padDisplay(labelCol, 28);\n log(` ${c.green(\"✓\")} ${padded} ${c.dim(useText)}`);\n if (verbose && files && files.length > 0) {\n log(` ${c.dim(\"└ files:\")} ${c.dim(files.join(\", \"))}`);\n }\n };\n\n if (cats.rules.length > 0) {\n phase1Row(\n \"rules\",\n cats.rules.length,\n \"coding · git/PR · tests · ship checklist · MCP policy\",\n cats.rules,\n );\n }\n if (cats.agents.length > 0) {\n // v26.63.3 (clarify H3): SOD jargon 보강 — independent verifier 명시.\n // v26.63.3 (distill H2): \"Without ECC plugin...\" 반복 제거 — section footer 통합.\n phase1Row(\n \"agents\",\n cats.agents.length,\n \"SOD reviewer (opus, independent verifier) + 3 base\",\n cats.agents,\n );\n }\n if (cats.hooks.length > 0) {\n phase1Row(\n \"hooks\",\n cats.hooks.length,\n \"session-start · spec-drift · checkpoint · mcp-pre-exec (security)\",\n cats.hooks,\n );\n }\n if (cats.commands > 0) {\n phase1Row(\"commands\", cats.commands, \"/ecc:* (ECC plugin OFF fallback)\");\n }\n if (cats.skills.length > 0) {\n phase1Row(\n \"skills\",\n cats.skills.length,\n \"north-star · gh-issue-workflow · ui-visual-review · cl-v2 (modified)\",\n cats.skills,\n );\n }\n } else {\n // v0.6.0 backwards compat — categories 없는 fakeReport 등\n log(assetRow(\"success\", \"rules + hooks + commands + agents\", `${baseline.filesCopied} files`));\n log(assetRow(\"success\", \"skeleton\", `${baseline.dirsCopied} dirs`));\n }\n // v26.63.4 (P3): Templates section 의 assetRow 호출 labelWidth=28 명시 → phase1Row 와 column 정렬.\n // default 40 은 External assets 의 긴 asset id (python-performance-optimization 등) 용 — 별개.\n const TEMPLATES_COL = 28;\n if (baseline.rootClaudeMd) {\n const n = baseline.rootClaudeMd.tracks.length;\n log(\n assetRow(\n \"success\",\n \"CLAUDE.md (root)\",\n `fill-in scaffold · ${n} track${n > 1 ? \"s\" : \"\"} noted`,\n TEMPLATES_COL,\n ),\n );\n }\n // v26.108.0 (ADR-037) — CI 스캐폴드 (opt-in). no-clobber: 기존 파일 보존은 skip 행으로\n // 정직 보고 (숨기면 \"설치됨\" 오인 — no-false-ship).\n if (baseline.ciScaffold) {\n for (const f of baseline.ciScaffold.written) {\n log(assetRow(\"success\", f, \"CI scaffold (fill-in template)\", TEMPLATES_COL));\n }\n for (const f of baseline.ciScaffold.skippedExisting) {\n log(assetRow(\"skip\", f, \"exists — preserved (no overwrite)\", TEMPLATES_COL));\n }\n }\n if (baseline.skipped > 0) {\n log(\n assetRow(\n \"skip\",\n \"manifest entries (applies → false)\",\n `${baseline.skipped} skipped`,\n TEMPLATES_COL,\n ),\n );\n }\n if (baseline.backup) {\n log(assetRow(\"success\", \"backup\", shortenPath(baseline.backup), TEMPLATES_COL));\n }\n const mcpList = baseline.mcpServers.join(\", \") || \"(none)\";\n log(assetRow(\"success\", \".mcp.json\", mcpList, TEMPLATES_COL));\n if (baseline.envFiles.mcpAllowlist) {\n log(\n assetRow(\n \"success\",\n \".mcp-allowlist\",\n `${baseline.envFiles.mcpAllowlist.length} servers (D35 opt-in gate)`,\n TEMPLATES_COL,\n ),\n );\n }\n // v26.63.3 (distill H2): ECC fallback hint — Templates section 마지막에 통합 표시.\n // withEcc=true (ECC plugin opt-in) 사용자에게는 hint 미표시.\n if (!withEcc && baseline.categories) {\n log(\"\");\n log(\n ` ${c.dim(\"·\")} ${c.dim(\"ECC plugin not selected — cherry-pick fallback active (up to 4 agents + 8 skills + 3 commands)\")}`,\n );\n if (claudeSelected) {\n log(` ${c.dim(\"·\")} ${c.dim(\"Use --with ecc-plugin to install ECC plugin instead\")}`);\n }\n }\n if (baseline.envFiles.envExampleCreated) {\n log(assetRow(\"success\", \".env.example\", \"Supabase token guide\"));\n }\n if (baseline.envFiles.gitignoreEnvAdded) {\n log(assetRow(\"success\", \".gitignore\", \"+ .env\"));\n }\n if (baseline.envFiles.gitignoreNpxSkillsAdded.length > 0) {\n log(\n assetRow(\n \"success\",\n \".gitignore\",\n `+ ${baseline.envFiles.gitignoreNpxSkillsAdded.join(\" \")} (npx skills universal install)`,\n ),\n );\n }\n log(\"\");\n}\n\nfunction formatOptions(spec: InstallSpec): string {\n // v26.81.0 (ADR-022) — 자산 플래그 13종 삭제 후 동작 옵션만. 키 순회로 enumeration drift 차단.\n const flags = (Object.keys(spec.options) as Array<keyof OptionFlags>)\n .filter((k) => spec.options[k])\n .map((k) =>\n k\n .replace(/^with/, \"\")\n .replace(/([a-z])([A-Z])/g, \"$1-$2\")\n .toLowerCase(),\n );\n // v26.63.3 (clarify H1): \"(defaults only)\" 모호 → \"(none added)\" 명료.\n return flags.length > 0 ? flags.join(\", \") : c.dim(\"(none added)\");\n}\n\n/**\n * Shorten an absolute path for display:\n * /Users/foo/bar → ~/bar (HOME relative)\n * /private/tmp/x.X → /tmp/x.X\n * /a/very/long/path → …/long/path (≥3 segs from end if > 50 chars)\n *\n * v26.48.0 — export for direct unit test (branch coverage 복구).\n */\nexport function shortenPath(p: string): string {\n if (p.length <= 50) return p;\n const home = process.env.HOME ?? \"\";\n if (home && p.startsWith(home)) {\n const rel = p.slice(home.length);\n return `~${rel.startsWith(\"/\") ? \"\" : \"/\"}${rel}`;\n }\n // private/tmp prefix on macOS — drop /private\n if (p.startsWith(\"/private/tmp/\")) {\n return p.slice(\"/private\".length);\n }\n // Last 3 segments\n const segs = p.split(\"/\").filter(Boolean);\n if (segs.length > 3) {\n return `…/${segs.slice(-3).join(\"/\")}`;\n }\n return p;\n}\n\n/**\n * v0.7.0 — CliTargets에서 codex/opencode 포함 여부에 따라 title 결정.\n * Phase 3는 codex 또는 opencode 1개 이상 포함 시 호출됨.\n * v26.48.0 — export for direct unit test (branch coverage 복구).\n */\nexport function formatCliPhaseTitle(targets: CliTargets): string {\n // v26.78.1 (R2) — antigravity 추가. 누락 시 `--cli antigravity` 산출물 헤더가\n // \"CLI artifacts\" generic 으로만 떠 antigravity 가 invisible 했음.\n const labels: string[] = [];\n if (targets.includes(\"codex\")) labels.push(\"Codex\");\n if (targets.includes(\"opencode\")) labels.push(\"OpenCode\");\n if (targets.includes(\"antigravity\")) labels.push(\"Antigravity\");\n return labels.length > 0 ? `${labels.join(\" + \")} artifacts` : \"CLI artifacts\";\n}\n","/**\n * Preset → Step 2 의 추천 ✓ 자산 매핑 (v26.44.0).\n *\n * Step 1 에서 선택된 preset 들의 condition 을 만족하는 외부 자산(plugin/skill/npm/npx)\n * 의 id 를 반환한다. Step 2 multiselect 의 초기 체크 상태에 사용.\n *\n * Option-gated 자산은 추천에 포함 X — 사용자가 의식적으로 토글해야 함\n * (superpowers, addy-agent-skills, ECC suite 등).\n */\n\nimport { assetTrustTier, EXTERNAL_ASSETS, filterApplicableAssets } from \"./external-assets.js\";\nimport { DEFAULT_OPTIONS, type InstallSpec, type Track } from \"./types.js\";\n\n/**\n * preset 1개 또는 N개 선택 시 추천 ✓ 자산 id 의 안정 정렬 배열.\n * - DEFAULT_OPTIONS 로 호출 → option-gated 자산은 모두 false → 추천에서 제외.\n * - v26.71.0 (PRD v26-71 R6) — experimental(T3) 자산은 pre-check 제외 (opt-in). official/vetted 만 추천.\n * - 결과는 자산 id 알파벳 정렬 (deterministic).\n */\nexport function recommendedExternalAssets(presets: ReadonlyArray<Track>): ReadonlyArray<string> {\n if (presets.length === 0) {\n return [];\n }\n const apps = filterApplicableAssets(EXTERNAL_ASSETS, {\n tracks: presets,\n options: DEFAULT_OPTIONS,\n });\n return apps\n .filter((a) => assetTrustTier(a.id) !== \"experimental\")\n .map((a) => a.id)\n .sort();\n}\n\n/**\n * v26.82.0 (Phase R, S6) — preset recommended + userOverride 적용 후 최종 선택 자산 id (정렬).\n * 이전엔 install.ts `computeFinalAssets` ↔ interactive.ts `formatSummary` 에 동일 merge 가\n * 중복 구현 (v26.62.4 주석이 본 위치를 통합 지점으로 지목). 우선순위: forceExclude > forceInclude.\n */\nexport function finalSelectedAssets(\n tracks: ReadonlyArray<Track>,\n userOverride?: InstallSpec[\"userOverride\"],\n): string[] {\n const selected = new Set(recommendedExternalAssets(tracks));\n if (userOverride) {\n for (const id of userOverride.forceExclude) selected.delete(id);\n for (const id of userOverride.forceInclude) selected.add(id);\n }\n return [...selected].sort();\n}\n\n/**\n * v26.82.0 (Phase R, S6) — 자산 id 를 카테고리별로 묶어 정렬된 entries 반환 (출력 hierarchy 용).\n * install header ASSETS row 와 wizard confirm summary 가 공유.\n */\nexport function groupAssetsByCategory(assetIds: ReadonlyArray<string>): Array<[string, string[]]> {\n const map = new Map<string, string[]>();\n for (const id of assetIds) {\n const asset = EXTERNAL_ASSETS.find((a) => a.id === id);\n const cat = asset?.category ?? \"other\";\n const list = map.get(cat) ?? [];\n list.push(id);\n map.set(cat, list);\n }\n return [...map.entries()];\n}\n","/**\n * List command — v26.123.0 (F-1b).\n *\n * `.claude/.harness-install.json` 을 사람이 읽는 표로 출력한다. 기록은 v26.64.0(ADR-020)부터\n * 있었지만 **사용자가 볼 수단이 없었다** — 무엇이 깔렸는지 알 수 없으면 항목별 제거(`--only`)의\n * 입력값도 알 수 없다. 본 커맨드가 그 입력값(자산 id)을 보여주는 곳이다.\n *\n * 읽기 전용 — 어떤 파일도 쓰지 않는다.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport { c, padDisplay, status } from \"../design.js\";\nimport {\n hashContent,\n type InstallLog,\n type InstallLogAsset,\n type InstallLogRootFile,\n installLogPath,\n readInstallLog,\n} from \"../install-log.js\";\n\nexport interface ListOptions {\n projectDir?: string;\n}\n\nexport interface ListActionDeps {\n log?: (msg: string) => void;\n err?: (msg: string) => void;\n exit?: (code: number) => never;\n}\n\nexport function listAction(options: ListOptions = {}, deps: ListActionDeps = {}): void {\n const log = deps.log ?? console.log;\n const err = deps.err ?? console.error;\n const exit = deps.exit ?? ((code: number) => process.exit(code) as never);\n\n const projectDir = resolve(options.projectDir ?? process.cwd());\n const installLog = readInstallLog(projectDir);\n if (!installLog) {\n err(status.failure(c.red(`ERROR: install log not found at ${installLogPath(projectDir)}`)));\n err(c.dim(\" Nothing installed here by agent-harness.\"));\n exit(1);\n return;\n }\n\n log(\"\");\n log(c.bold(\"uzys-agent-harness · installed\"));\n log(\"\");\n log(c.dim(` installed: ${installLog.installedAt}`));\n log(c.dim(` scope: ${installLog.scope}`));\n log(c.dim(` tracks: ${installLog.spec.tracks.join(\", \") || \"(none)\"}`));\n log(c.dim(` cli: ${installLog.spec.cli.join(\", \") || \"(none)\"}`));\n log(\"\");\n\n log(c.bold(` Assets (${installLog.assets.length})`));\n if (installLog.assets.length === 0) {\n log(c.dim(\" (none — 내부 템플릿만 설치됨)\"));\n }\n for (const line of formatAssetRows(installLog.assets)) {\n log(line);\n }\n\n log(\"\");\n log(c.bold(\" Templates\"));\n for (const line of formatTemplateRows(installLog, projectDir)) {\n log(line);\n }\n\n const rootRows = formatRootFileRows(installLog.rootFiles ?? [], projectDir);\n if (rootRows.length > 0) {\n log(\"\");\n log(c.bold(\" Root files\"));\n log(c.dim(\" (uninstall 이 지우지 않는다 — 사용자 내용이 섞인다)\"));\n for (const line of rootRows) log(line);\n }\n\n log(\"\");\n log(c.dim(\" remove one: agent-harness uninstall --only <id>\"));\n log(c.dim(\" remove all: agent-harness uninstall\"));\n log(\"\");\n exit(0);\n}\n\n/** 자산 행 — id / method / scope / version. global 은 uninstall 이 자동 삭제하지 않으므로 표시한다. */\nexport function formatAssetRows(assets: ReadonlyArray<InstallLogAsset>): string[] {\n const idWidth = Math.max(0, ...assets.map((a) => a.id.length));\n const methodWidth = Math.max(0, ...assets.map((a) => a.method.length));\n return assets.map((a) => {\n const marker = a.scope === \"global\" ? c.yellow(\"!\") : c.green(\"✓\");\n const version = a.version ? c.dim(` v${a.version}`) : \"\";\n const note = a.scope === \"global\" ? c.yellow(\" (manual removal — D16)\") : \"\";\n return ` ${marker} ${padDisplay(a.id, idWidth)} ${c.dim(padDisplay(a.method, methodWidth))} ${c.dim(a.scope)}${version}${note}`;\n });\n}\n\n/** templates 행 — 디렉토리 + root CLAUDE.md 수정 여부(uninstall 이 보존할지 여부와 같은 판정). */\nfunction formatTemplateRows(log: InstallLog, projectDir: string): string[] {\n const dirs = [log.templates.claudeDir, log.templates.codexDir, log.templates.opencodeDir].filter(\n (d): d is string => Boolean(d),\n );\n const rows = [` ${c.dim(dirs.join(\" \"))}`];\n const rootMd = log.templates.rootClaudeMd;\n if (rootMd) {\n const path = join(projectDir, rootMd.path);\n const modified = existsSync(path) && hashContent(readFileSync(path, \"utf8\")) !== rootMd.sha256;\n rows.push(\n modified\n ? ` ${c.dim(rootMd.path)} ${c.yellow(\"(수정됨 — uninstall 시 보존)\")}`\n : ` ${c.dim(rootMd.path)}`,\n );\n }\n return rows;\n}\n\n/**\n * v26.124.0 (F-1f) — `.claude/` 밖 루트 파일 행. uninstall 안내와 같은 규율로\n * **실재하는 것만** 낸다 (사용자가 이미 지운 파일을 인벤토리에 남기면 그게 거짓 기록이다).\n */\nfunction formatRootFileRows(\n rootFiles: ReadonlyArray<InstallLogRootFile>,\n projectDir: string,\n): string[] {\n const present = rootFiles.filter((f) => existsSync(join(projectDir, f.path)));\n const width = Math.max(0, ...present.map((f) => f.path.length));\n return present.map(\n (f) =>\n ` ${c.dim(padDisplay(f.path, width))} ${c.dim(f.change === \"created\" ? \"생성\" : \"병합\")} ${c.dim(f.notes.join(\" / \"))}`,\n );\n}\n\nexport function registerListCommand(cli: import(\"../cli.js\").Cli): void {\n cli\n .command(\"list\", \"Show what agent-harness installed in this project\")\n .option(\"--project-dir <path>\", \"[Project] Target project directory\", {\n default: process.cwd(),\n })\n /* v8 ignore next 3 — cac action callback. listAction 자체는 별도 tests 로 검증. */\n .action((options: ListOptions) => {\n listAction(options);\n });\n}\n","/**\n * Uninstall command — v26.64.0 (ADR-020).\n *\n * 동작:\n * 1. `.claude/.harness-install.json` 읽기.\n * 2. assets[] 별 reverse:\n * - scope=project: 실제 reverse (`claude plugin uninstall --scope project`, `npm uninstall`, fs rm).\n * - scope=global: 안내만 (D16 — 글로벌 영역 자동 삭제 금지). 사용자가 직접 명령 실행.\n * 3. templates 폴더 rm (`.claude/`, `.codex/`, `.opencode/`) — `--keep-templates` 시 보존.\n * 4. install log 자체도 함께 제거.\n *\n * 옵션:\n * --dry-run 실제 변경 없이 reverse list 만 출력.\n * --keep-templates `.claude/`, `.codex/`, `.opencode/` 보존.\n * --only <ids> v26.123.0 (F-1c) — 항목별 제거. templates 미변경 + 로그는 남은 자산으로 재기록.\n *\n * 안전:\n * - log 없으면 명확 에러 + early exit.\n * - scope=global 자산은 절대 자동 삭제 X (D16).\n * - 되돌리기에 성공한 것만 로그에서 뺀다. 자동 경로가 없거나 실패한 자산은 기록에 남기고,\n * 아무것도 못 되돌렸으면 성공으로 보고하지 않는다 (no-false-ship).\n */\n\nimport { type SpawnSyncReturns, spawnSync } from \"node:child_process\";\nimport { existsSync, readFileSync, rmSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport { c, status } from \"../design.js\";\nimport { skillsCliSpec } from \"../external-installer.js\";\nimport {\n hashContent,\n type InstallLog,\n type InstallLogAsset,\n type InstallLogRootFile,\n installLogPath,\n readInstallLog,\n writeInstallLog,\n} from \"../install-log.js\";\nimport { KARPATHY_ASSET_ID, KARPATHY_HOOK_COMMAND, KARPATHY_HOOK_RELPATH } from \"../installer.js\";\nimport type { ClaudeSettings } from \"../settings-merge.js\";\nimport { runInteractiveUninstall } from \"../uninstall-interactive.js\";\n\nexport interface UninstallOptions {\n projectDir?: string;\n dryRun?: boolean;\n keepTemplates?: boolean;\n /**\n * v26.123.0 (F-1c) — 항목별 제거. 쉼표 구분 자산 id.\n * 지정 시 templates(`.claude/` 등)는 건드리지 않고, 로그도 지우지 않고 **남은 자산으로 다시 쓴다**.\n */\n only?: string;\n /** v26.125.0 — 대화형 선택 화면을 건너뛰고 전량 제거 (비대화형 스크립트용). */\n yes?: boolean;\n}\n\nexport interface UninstallActionDeps {\n log?: (msg: string) => void;\n err?: (msg: string) => void;\n exit?: (code: number) => never;\n spawn?: (cmd: string, args: ReadonlyArray<string>) => SpawnSyncReturns<string>;\n rm?: (path: string) => void;\n /** `--only` 후 로그 재기록. 실패 경로를 테스트에서 재현하기 위해 주입 가능. */\n writeLog?: (projectDir: string, log: InstallLog) => void;\n}\n\ninterface ReverseStep {\n /** 어느 자산의 reverse 인지 — `--only` 성공분만 로그에서 빼기 위해 필요. */\n assetId: string;\n /** 사람이 읽는 라벨 (한 줄) */\n label: string;\n /** 실제 동작 — dry-run 일 때는 호출 안 함. */\n execute: () => { ok: boolean; message?: string };\n}\n\ninterface GlobalAdvisory {\n asset: InstallLogAsset;\n /** 사용자에게 안내할 reverse 명령 */\n command: string;\n}\n\n/**\n * 크기 예외 사유 (code-style 50줄 상한): 본 함수의 내용은 **단계의 순서와 전제조건 분기**이고,\n * 각 단계는 이미 이름 있는 함수로 빠져 있다 (`planReverse` → `headerLines` → `dryRunLines` |\n * `executeReverse` → `removeTemplates` → `settleLog` → `advisoryLines` → `summarize`).\n * 남은 것은 early return 3개(로그 없음 / 모르는 id / dry-run)와 호출 순서뿐 — 더 쪼개면\n * 그 순서가 흩어진다.\n */\nexport function uninstallAction(options: UninstallOptions, deps: UninstallActionDeps = {}): void {\n const log = deps.log ?? console.log;\n const err = deps.err ?? console.error;\n const exit = deps.exit ?? ((code: number) => process.exit(code) as never);\n const spawn = deps.spawn ?? defaultSpawn;\n const rm = deps.rm ?? defaultRm;\n const writeLog = deps.writeLog ?? writeInstallLog;\n\n const projectDir = resolve(options.projectDir ?? process.cwd());\n const installLog = readInstallLog(projectDir);\n if (!installLog) {\n err(status.failure(c.red(`ERROR: install log not found at ${installLogPath(projectDir)}`)));\n err(c.dim(\" Was this project installed by agent-harness? Nothing to uninstall.\"));\n exit(1);\n return;\n }\n\n const selectedIds = parseOnly(options.only);\n // `--only ,` 처럼 값이 있는데 id 가 하나도 안 나오면 **전량 제거로 흘려보내지 않는다** —\n // 하나만 빼려던 사용자가 templates 까지 잃는다. 무응답보다 명시적 거절이 안전하다.\n if (options.only !== undefined && selectedIds === null) {\n err(status.failure(c.red(\"ERROR: --only 에 자산 id 가 없다\")));\n err(c.dim(\" 예: --only code-review (id 는 `agent-harness list` 에서 확인)\"));\n exit(1);\n return;\n }\n const unknown = selectedIds ? unknownIds(installLog, selectedIds) : [];\n if (unknown.length > 0) {\n err(status.failure(c.red(`ERROR: not in install log: ${unknown.join(\", \")}`)));\n err(c.dim(` installed: ${installLog.assets.map((a) => a.id).join(\", \") || \"(none)\"}`));\n exit(1);\n return;\n }\n const targetAssets = selectedIds\n ? installLog.assets.filter((a) => selectedIds.includes(a.id))\n : installLog.assets;\n // `--only` 는 자산만 건드린다 — templates 를 지우면 \"하나만 빼기\"가 아니게 된다.\n const keepTemplates = options.keepTemplates || selectedIds !== null;\n\n // v26.124.0 (F-1f) — `.claude/` 밖 루트 파일 안내. `--only` 는 특정 자산만 건드리는 작업이라\n // 설치 전반이 만든 루트 파일은 대상이 아니다. 구 로그(rootFiles 부재)는 빈 배열 = 안내 없음.\n const rootFiles = selectedIds ? [] : (installLog.rootFiles ?? []);\n\n const plan = planReverse(targetAssets, spawn);\n for (const line of headerLines(installLog, selectedIds, targetAssets.length)) log(line);\n\n if (options.dryRun) {\n for (const line of dryRunLines(\n plan,\n installLog,\n projectDir,\n keepTemplates,\n targetAssets,\n rootFiles,\n )) {\n log(line);\n }\n exit(0);\n return;\n }\n\n // 두 사실을 분리해서 쓴다 — 셋을 하나로 묶다 리뷰 3라운드 내리 회귀가 났다.\n // `.claude/` 가 남는가 = keepTemplates (수기 안내 대상 여부)\n // install log 가 남는가 = `--only` 인가 (settleLog: --only 만 재기록, 나머지는 삭제)\n const logSurvives = selectedIds !== null;\n\n const { succeeded, failed, removedIds } = executeReverse(plan, log, logSurvives);\n\n if (!keepTemplates) {\n const { rootClaudeMdKept } = removeTemplates(installLog, projectDir, rm);\n log(` ${status.success(`templates removed: ${formatTemplateList(installLog)}`)}`);\n if (rootClaudeMdKept) {\n log(\n ` ${c.yellow(\"⊘\")} CLAUDE.md kept — modified since install. Remove manually if intended.`,\n );\n }\n }\n\n const logWriteFailed = settleLog(\n { installLog, projectDir, selectedIds, keepTemplates, removedIds },\n { log, err, rm, writeLog },\n );\n\n // 판정 기준은 \"`--only` 인가\"가 아니라 \"`.claude/` 가 남는가\"다 — `--keep-templates` 만 줘도\n // settings.json 은 살아남으므로 안내 대상이다. dry-run 과 같은 값을 넘겨야 미리보기가 맞는다.\n for (const line of advisoryLines(plan, targetAssets, projectDir, keepTemplates, rootFiles)) {\n log(line);\n }\n\n const outcome = summarize({\n succeeded,\n failed,\n logWriteFailed,\n // 제거된 것도 없고 templates 도 안 지웠는데, 사용자에게 줄 방법조차 없을 때만 실패다.\n // ① `--only` = \"이걸 빼라\"는 특정 요청 — 하나도 못 뺐으면 요청 불이행 (C1).\n // ② 자동 경로가 없는 자산이 남았으면 — 안내할 명령조차 없다 (R1).\n // ③ 반면 global 자산만 남은 경우는 **정확한 수기 명령을 출력했으므로** 성공이다.\n // D16 설계대로의 정상이고, 여기까지 묶으면 global scope 사용자는 exit 0 을 영원히\n // 못 받는다 (로그가 지워져 재시도하면 더 나빠진다).\n nothingDone: succeeded === 0 && keepTemplates && (logSurvives || plan.noReversePath.length > 0),\n });\n log(\"\");\n log(outcome.line);\n exit(outcome.code);\n}\n\n/**\n * 종료 보고 — **한 일이 없으면 성공이라 하지 않는다.** 이전 판본은 reverse step 이 0개일 때\n * `0 === 0` 이 성공 판정을 통과해 `✓ uninstall complete` + exit 0 을 찍었다 (SOD CRITICAL).\n */\nfunction summarize(r: {\n succeeded: number;\n failed: number;\n nothingDone: boolean;\n logWriteFailed: boolean;\n}): { line: string; code: number } {\n if (r.failed > 0)\n return {\n line: c.yellow(`uninstall finished with ${r.failed} skip(s) (${r.succeeded} ok)`),\n code: 1,\n };\n if (r.nothingDone)\n return {\n line: c.yellow(\"아무것도 자동 제거되지 않았다 — 위 안내를 따라 직접 처리해야 한다\"),\n code: 1,\n };\n if (r.logWriteFailed)\n return {\n line: c.yellow(\"자산은 제거됐으나 install log 를 갱신하지 못했다 (기록이 실제와 다르다)\"),\n code: 1,\n };\n return { line: status.success(c.green(`uninstall complete (${r.succeeded} asset(s))`)), code: 0 };\n}\n\nfunction headerLines(\n installLog: InstallLog,\n selectedIds: string[] | null,\n targetCount: number,\n): string[] {\n return [\n \"\",\n c.bold(\"uzys-agent-harness · uninstall\"),\n \"\",\n c.dim(` installed: ${installLog.installedAt}`),\n c.dim(` scope: ${installLog.scope}`),\n c.dim(\n selectedIds\n ? ` assets: ${targetCount} selected of ${installLog.assets.length} (--only)`\n : ` assets: ${installLog.assets.length}`,\n ),\n \"\",\n ];\n}\n\nfunction executeReverse(\n plan: ReversePlan,\n log: (msg: string) => void,\n logSurvives: boolean,\n): { succeeded: number; failed: number; removedIds: string[] } {\n let succeeded = 0;\n let failed = 0;\n const removedIds: string[] = [];\n for (const step of plan.reverseSteps) {\n const result = step.execute();\n if (result.ok) {\n log(` ${status.success(step.label)}`);\n removedIds.push(step.assetId);\n succeeded++;\n } else {\n log(` ${c.yellow(\"⊘\")} ${step.label} (${result.message ?? \"failed\"})`);\n failed++;\n }\n }\n // 자동 되돌리기 경로가 없는 자산은 **말한다.** 조용히 넘기면 `uninstall complete` 가\n // 아무것도 안 한 실행에 붙어 거짓 보고가 된다 (no-false-ship).\n // \"기록 유지\"는 **로그가 남을 때만** 참이다. `--keep-templates` 는 `.claude/` 를 남기면서도\n // 로그는 지우므로(settleLog), templates 보존 여부로 판단하면 지워질 기록을 유지한다고 말한다.\n const tail = logSurvives ? \"자동 되돌리기 경로 없음, 기록 유지\" : \"자동 되돌리기 경로 없음\";\n for (const asset of plan.noReversePath) {\n log(` ${c.yellow(\"⊘\")} ${asset.id} (${asset.method}) — ${tail}`);\n }\n return { succeeded, failed, removedIds };\n}\n\n/** 제거 후 로그 처리. @returns 재기록에 실패했는가 (실패해도 uninstall 을 죽이지 않는다). */\nfunction settleLog(\n ctx: {\n installLog: InstallLog;\n projectDir: string;\n selectedIds: string[] | null;\n keepTemplates: boolean;\n removedIds: string[];\n },\n io: {\n log: (msg: string) => void;\n err: (msg: string) => void;\n rm: (path: string) => void;\n writeLog: (projectDir: string, log: InstallLog) => void;\n },\n): boolean {\n const { installLog, projectDir, selectedIds, keepTemplates, removedIds } = ctx;\n if (selectedIds) {\n // v26.123.0 (F-1c) — 로그를 지우는 게 아니라 **되돌린 것만 빼고 다시 쓴다**.\n // 실패한 항목은 남긴다 — 실제로 안 지워진 걸 기록에서 지우면 그게 곧 거짓 기록이다.\n const remaining = installLog.assets.filter((a) => !removedIds.includes(a.id));\n try {\n io.writeLog(projectDir, { ...installLog, assets: remaining });\n io.log(` ${status.success(`install log updated (${remaining.length} asset(s) remain)`)}`);\n } catch (e) {\n // 되돌리기는 이미 끝난 뒤다 — 스택트레이스로 죽으면 무엇이 지워졌는지도 사라진다.\n io.err(status.failure(c.red(`ERROR: install log 갱신 실패 — ${installLogPath(projectDir)}`)));\n io.err(c.dim(` ${e instanceof Error ? e.message : String(e)}`));\n io.err(c.dim(` 실제로 제거된 자산: ${removedIds.join(\", \") || \"(없음)\"}`));\n return true;\n }\n } else if (keepTemplates) {\n // install log 자체도 함께 제거 (templates 제거 시 .claude/ 통째 사라짐 → log 도 자동 사라짐.\n // keepTemplates 시 .claude/ 유지 → log 만 명시 제거).\n io.rm(installLogPath(projectDir));\n io.log(` ${status.success(\"install log removed (templates kept)\")}`);\n }\n return false;\n}\n\n/** dry-run 미리보기 — 실행 경로와 같은 판정을 쓴다 (미리보기가 실제와 어긋나면 미리보기가 아니다). */\nfunction dryRunLines(\n plan: ReversePlan,\n installLog: InstallLog,\n projectDir: string,\n keepTemplates: boolean,\n targetAssets: ReadonlyArray<InstallLogAsset>,\n rootFiles: ReadonlyArray<InstallLogRootFile>,\n): string[] {\n const lines = [c.yellow(\"[DRY RUN] reverse list (실제 변경 없음):\"), \"\"];\n if (plan.reverseSteps.length === 0) {\n lines.push(c.dim(\" (no project-scope assets to reverse)\"));\n }\n lines.push(...plan.reverseSteps.map((s) => ` ○ ${s.label}`));\n lines.push(\n ...plan.noReversePath.map((a) =>\n c.dim(` ⊘ ${a.id} (${a.method}) — 자동 되돌리기 경로 없음, 기록 유지`),\n ),\n );\n if (!keepTemplates) {\n lines.push(` ○ remove templates: ${formatTemplateList(installLog)}`);\n if (installLog.templates.rootClaudeMd) {\n lines.push(\n rootClaudeMdModified(installLog, projectDir)\n ? \" ○ keep CLAUDE.md (modified since install — preserved)\"\n : \" ○ remove CLAUDE.md\",\n );\n }\n }\n // keepTemplates=false 면 실제 실행은 `.claude/` 를 통째로 지운다 → 수기 안내 대상 자체가\n // 사라지므로 미리보기에서도 안내하지 않는다. 안 그러면 곧 삭제될 파일을 손보라고 시킨다.\n lines.push(...advisoryLines(plan, targetAssets, projectDir, keepTemplates, rootFiles), \"\");\n return lines;\n}\n\n/** global(D16) + 수기 표면 + 루트 파일 안내. dry-run 과 실행 경로가 같은 함수를 쓴다. */\nfunction advisoryLines(\n plan: ReversePlan,\n targetAssets: ReadonlyArray<InstallLogAsset>,\n projectDir: string,\n templatesKept: boolean,\n rootFiles: ReadonlyArray<InstallLogRootFile>,\n): string[] {\n const lines: string[] = [];\n if (plan.globalAdvisories.length > 0) {\n lines.push(\n \"\",\n c.yellow(\n `[GLOBAL] ${plan.globalAdvisories.length} asset(s) at scope=global — manual removal required (D16):`,\n ),\n );\n for (const adv of plan.globalAdvisories) {\n lines.push(c.dim(` · ${adv.asset.id} (${adv.asset.method})`), c.dim(` ${adv.command}`));\n }\n }\n if (templatesKept) lines.push(...manualAdvisoryLines(targetAssets, projectDir));\n // templatesKept 와 무관하다 — `.claude/` 를 통째로 지우는 경로야말로 밖에 남는 것을\n // 사용자가 존재조차 모르게 되는 경우다. 그게 F-1f 가 잡는 구멍이다.\n lines.push(...rootFileAdvisoryLines(rootFiles, projectDir));\n return lines;\n}\n\n/**\n * v26.124.0 (F-1f) — `.claude/` 밖에 남는 것 안내. **지우지 않는다**:\n * `.mcp.json`/`.gitignore` 는 사용자 내용이 섞이고, `.github/workflows/` 는 설치 후 사용자\n * 소유물이다 (ci-scaffold.ts 안전 계약 2). 기계적 되돌리기는 손실 위험이라 안내로 넘긴다.\n *\n * manualAdvisoryLines 와 같은 규율 — **예측이 아니라 현재 파일 상태를 읽어** 실재하는 것만 낸다.\n */\nfunction rootFileAdvisoryLines(\n rootFiles: ReadonlyArray<InstallLogRootFile>,\n projectDir: string,\n): string[] {\n const present = rootFiles.filter((f) => existsSync(join(projectDir, f.path)));\n if (present.length === 0) return [];\n return [\n \"\",\n c.yellow(\"[ROOT] `.claude/` 밖에 남는 것 (자동으로 지우지 않는다):\"),\n ...present.flatMap((f) => [\n c.dim(\n ` · ${f.path} — ${\n f.change === \"created\"\n ? \"하네스가 생성 (수정한 적 없으면 삭제해도 안전)\"\n : \"기존 사용자 파일에 병합 (직접 확인 필요)\"\n }`,\n ),\n c.dim(` ${f.notes.join(\" / \")}`),\n ]),\n ];\n}\n\ninterface ReversePlan {\n reverseSteps: ReverseStep[];\n globalAdvisories: GlobalAdvisory[];\n /**\n * 자동 되돌리기 경로가 없는 자산 (npx-run / shell-script / internal). 전량 uninstall 에선\n * `.claude/` 통째 제거가 덮지만, `--only` 에선 **아무 일도 안 일어난다** — 그래서 따로 센다.\n */\n noReversePath: InstallLogAsset[];\n}\n\nfunction planReverse(\n assets: ReadonlyArray<InstallLogAsset>,\n spawn: (cmd: string, args: ReadonlyArray<string>) => SpawnSyncReturns<string>,\n): ReversePlan {\n const reverseSteps: ReverseStep[] = [];\n const globalAdvisories: GlobalAdvisory[] = [];\n const noReversePath: InstallLogAsset[] = [];\n\n for (const asset of assets) {\n if (asset.scope === \"global\") {\n globalAdvisories.push({ asset, command: buildGlobalAdvisoryCmd(asset) });\n continue;\n }\n const step = buildProjectReverseStep(asset, spawn);\n if (step) reverseSteps.push(step);\n else noReversePath.push(asset);\n }\n\n return { reverseSteps, globalAdvisories, noReversePath };\n}\n\nfunction buildProjectReverseStep(\n asset: InstallLogAsset,\n spawn: (cmd: string, args: ReadonlyArray<string>) => SpawnSyncReturns<string>,\n): ReverseStep | null {\n switch (asset.method) {\n case \"plugin\": {\n const pluginId = asset.detail.pluginId ?? asset.id;\n return {\n assetId: asset.id,\n label: `claude plugin uninstall --scope project ${pluginId}`,\n execute: () => {\n const r = spawn(\"claude\", [\"plugin\", \"uninstall\", \"--scope\", \"project\", pluginId]);\n return r.status === 0 ? { ok: true } : { ok: false, message: (r.stderr || \"\").trim() };\n },\n };\n }\n case \"skill\": {\n // skills CLI default 가 project — `skills remove <source>` (no -g).\n // 일부 source 는 폴더 경로/직접 id — npx skills remove 가 처리.\n const source = asset.detail.source ?? asset.id;\n return {\n assetId: asset.id,\n label: `npx skills remove ${source}`,\n execute: () => {\n const r = spawn(\"npx\", [skillsCliSpec(), \"remove\", source, \"--yes\"]);\n return r.status === 0 ? { ok: true } : { ok: false, message: (r.stderr || \"\").trim() };\n },\n };\n }\n case \"npm\": {\n const pkg = asset.detail.pkg ?? asset.id;\n return {\n assetId: asset.id,\n label: `npm uninstall --save-dev ${pkg}`,\n execute: () => {\n const r = spawn(\"npm\", [\"uninstall\", \"--save-dev\", pkg]);\n return r.status === 0 ? { ok: true } : { ok: false, message: (r.stderr || \"\").trim() };\n },\n };\n }\n case \"npx-run\":\n // fire-and-forget — reverse 없음 (예: GSD orchestrator).\n return null;\n case \"shell-script\":\n // 로컬 script 호출 — 일반 reverse 없음 (script 별 별도 cleanup 필요).\n return null;\n case \"internal\":\n // v26.81.0 (ADR-022) — 내부 템플릿 — removeTemplates 가 .claude/ 전체로 처리.\n return null;\n }\n}\n\n/**\n * `.claude/settings.json` 의 hook command 존재 여부. **파싱해서** 본다 — 원문 substring 매치는\n * JSON 이스케이프(`\\\"`) 때문에 실제로 등록된 훅을 놓친다 (도입 시 테스트가 잡은 실패).\n */\nfunction settingsHasHookCommand(projectDir: string, command: string): boolean {\n const path = join(projectDir, \".claude\", \"settings.json\");\n if (!existsSync(path)) return false;\n try {\n const parsed = JSON.parse(readFileSync(path, \"utf8\")) as ClaudeSettings;\n return Object.values(parsed.hooks ?? {}).some((matchers) =>\n matchers.some((m) => m.hooks?.some((h) => h.command === command)),\n );\n } catch {\n return false; // 깨진 settings.json — 안내를 못 만들 뿐, uninstall 을 막지는 않는다.\n }\n}\n\n/**\n * 로그에 없는 `--only` id — 오타로 엉뚱한 자산이 남지 않도록 **아무것도 실행하기 전에** 본다\n * (gates-taxonomy Pre-flight: 전제조건 미충족 시 차단, 부분 작업 없음).\n */\nfunction unknownIds(installLog: InstallLog, selectedIds: ReadonlyArray<string>): string[] {\n const known = new Set(installLog.assets.map((a) => a.id));\n return selectedIds.filter((id) => !known.has(id));\n}\n\n/** `--only <a,b>` → [\"a\",\"b\"]. 미지정이면 null (= 전량 제거, 기존 동작). */\nfunction parseOnly(only: string | undefined): string[] | null {\n if (!only) return null;\n const ids = only\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n return ids.length > 0 ? ids : null;\n}\n\n/**\n * v26.123.0 (F-1d) — 자산 제거로 **끊어진 참조가 남는 표면**을 알려준다. 자동으로 안 고치는 이유:\n * `.claude/settings.json` 과 hook 파일에는 사용자 편집이 섞이므로 기계적 되돌리기가 손실 위험이다\n * (사용자 방침 — 위험한 표면은 반자동 안내).\n *\n * 예측이 아니라 **현재 파일 상태를 읽어** 실제로 남아 있는 것만 출력한다.\n */\nfunction manualAdvisoryLines(\n targetAssets: ReadonlyArray<InstallLogAsset>,\n projectDir: string,\n): string[] {\n if (!targetAssets.some((a) => a.id === KARPATHY_ASSET_ID)) return [];\n\n const items: string[] = [];\n if (settingsHasHookCommand(projectDir, KARPATHY_HOOK_COMMAND))\n items.push(\n `.claude/settings.json — hooks.PreToolUse 에서 다음 command 항목 삭제:\\n ${KARPATHY_HOOK_COMMAND}`,\n );\n if (existsSync(join(projectDir, KARPATHY_HOOK_RELPATH)))\n items.push(`\\`${KARPATHY_HOOK_RELPATH}\\` — 삭제`);\n\n if (items.length === 0) return [];\n return [\n \"\",\n c.yellow(\"[MANUAL] 자동으로 되돌리지 않은 것 (사용자 편집이 섞이는 표면):\"),\n ...items.map((i) => c.dim(` · ${i}`)),\n ];\n}\n\nfunction buildGlobalAdvisoryCmd(asset: InstallLogAsset): string {\n switch (asset.method) {\n case \"plugin\": {\n const pid = asset.detail.pluginId ?? asset.id;\n return `claude plugin uninstall --scope user ${pid}`;\n }\n case \"skill\": {\n const s = asset.detail.source ?? asset.id;\n return `npx skills remove -g ${s}`;\n }\n case \"npm\": {\n const pkg = asset.detail.pkg ?? asset.id;\n return `npm uninstall -g ${pkg}`;\n }\n case \"npx-run\":\n case \"shell-script\":\n case \"internal\":\n return \"(no standard reverse — manual)\";\n }\n}\n\nfunction removeTemplates(\n log: InstallLog,\n projectDir: string,\n rm: (path: string) => void,\n): { rootClaudeMdKept: boolean } {\n rm(join(projectDir, log.templates.claudeDir));\n if (log.templates.codexDir) rm(join(projectDir, log.templates.codexDir));\n if (log.templates.opencodeDir) rm(join(projectDir, log.templates.opencodeDir));\n // root CLAUDE.md — install 원본 그대로일 때만 삭제. 사용자가 수정했으면 보존.\n const rootMd = log.templates.rootClaudeMd;\n if (rootMd) {\n if (rootClaudeMdModified(log, projectDir)) return { rootClaudeMdKept: true };\n rm(join(projectDir, rootMd.path));\n }\n return { rootClaudeMdKept: false };\n}\n\n/** root CLAUDE.md 가 install 이후 수정됐는지. log 에 없거나 파일 부재 시 false (= 삭제 대상). */\nfunction rootClaudeMdModified(log: InstallLog, projectDir: string): boolean {\n const rootMd = log.templates.rootClaudeMd;\n if (!rootMd) return false;\n const path = join(projectDir, rootMd.path);\n if (!existsSync(path)) return false;\n return hashContent(readFileSync(path, \"utf8\")) !== rootMd.sha256;\n}\n\nfunction formatTemplateList(log: InstallLog): string {\n const items: string[] = [log.templates.claudeDir];\n if (log.templates.codexDir) items.push(log.templates.codexDir);\n if (log.templates.opencodeDir) items.push(log.templates.opencodeDir);\n return items.join(\", \");\n}\n\n/* v8 ignore start — thin dep-inject defaults. tests 는 항상 mock 주입. */\nfunction defaultSpawn(cmd: string, args: ReadonlyArray<string>): SpawnSyncReturns<string> {\n return spawnSync(cmd, [...args], { encoding: \"utf8\", stdio: \"pipe\", timeout: 120_000 });\n}\n\nfunction defaultRm(path: string): void {\n if (existsSync(path)) {\n rmSync(path, { recursive: true, force: true });\n }\n}\n/* v8 ignore stop */\n\nexport function registerUninstallCommand(cli: import(\"../cli.js\").Cli): void {\n cli\n .command(\"uninstall\", \"Uninstall harness assets (log-based reverse)\")\n .option(\"--project-dir <path>\", \"[Project] Target project directory\", {\n default: process.cwd(),\n })\n .option(\"--dry-run\", \"[Mode] List reverse steps without executing\")\n .option(\n \"--keep-templates\",\n \"[Mode] Keep `.claude/`, `.codex/`, `.opencode/` templates (remove only external assets)\",\n )\n .option(\n \"--only <ids>\",\n \"[Scope] Remove only these assets (comma-separated ids from `agent-harness list`). Templates untouched\",\n )\n .option(\"--yes\", \"[Mode] Skip the interactive picker and remove everything (non-interactive)\")\n /* v8 ignore next 3 — cac action callback. 분기 판정은 shouldRunInteractive 가 갖고 tests 로 검증. */\n .action(async (options: UninstallOptions) => {\n await dispatchUninstall(options);\n });\n}\n\n/**\n * v26.125.0 — 대화형 선택 화면으로 들어갈 것인가.\n *\n * 들어가지 **않는** 조건은 전부 \"사용자가 이미 무엇을 원하는지 말한 경우\"다:\n * `--only` = 뺄 대상을 지정함 · `--dry-run` = 미리보기 · `--yes` = 묻지 말라는 명시.\n * 그 외 TTY 라면 화면으로 들어간다 — 플래그 없는 `uninstall` 이 즉시 전량 삭제하던 것이\n * 이 명령에서 가장 위험한 기본값이었다. TTY 가 아니면(CI·파이프) 기존 동작 그대로다.\n */\nexport function shouldRunInteractive(options: UninstallOptions, isTty: boolean): boolean {\n if (!isTty) return false;\n if (options.yes || options.dryRun) return false;\n return options.only === undefined;\n}\n\n/* v8 ignore start — 얇은 배선. 판정은 shouldRunInteractive, 선택은 uninstall-interactive, 실행은 uninstallAction 이 각각 tests 로 검증. */\nasync function dispatchUninstall(options: UninstallOptions): Promise<void> {\n if (!shouldRunInteractive(options, Boolean(process.stdin.isTTY))) {\n uninstallAction(options);\n return;\n }\n const projectDir = resolve(options.projectDir ?? process.cwd());\n const picked = await runInteractiveUninstall(projectDir);\n if (!picked.ok || !picked.options) {\n if (picked.reason === \"no-log\") {\n console.error(\n status.failure(c.red(`ERROR: install log not found at ${installLogPath(projectDir)}`)),\n );\n console.error(c.dim(\" Nothing installed here by agent-harness.\"));\n process.exit(1);\n }\n // no-tty 는 위 분기에서 이미 걸러졌고, 나머지(cancelled/nothing-selected)는 정상 종료다.\n return;\n }\n uninstallAction(picked.options);\n}\n/* v8 ignore stop */\n","/**\n * Interactive uninstall — v26.125.0 (사용자 요청 2026-07-19).\n *\n * `agent-harness uninstall` 을 TTY 에서 실행하면 **무엇을 뺄지 고르는 화면**으로 들어간다.\n *\n * 왜 install 위저드가 아니라 별도 명령인가 (사용자 결정): install 화면의 체크 해제는\n * \"이번에 설치하지 않음\"이지 제거가 아니다. 설치 화면 안에서 삭제가 일어나면 실수 한 번이\n * 되돌릴 수 없는 삭제가 되고, \"install 은 지우지 않는다\"는 불변식도 깨진다. 그래서 제거는\n * 이 명령으로만 들어온다.\n *\n * 본 모듈은 **선택만** 한다 — 실제 되돌리기는 기존 `uninstallAction` 이 그대로 수행한다.\n * 두 모드가 각각 기존 경로 하나에 1:1 로 대응하므로 새로운 파괴적 조합이 생기지 않는다:\n * 선택 제거 → `--only <ids>` (templates 유지, 로그는 남은 자산으로 재기록)\n * 전량 제거 → 플래그 없음 (templates 포함)\n */\n\nimport { cancel, confirm, intro, isCancel, multiselect, outro, select } from \"@clack/prompts\";\nimport { type InstallLog, type InstallLogAsset, readInstallLog } from \"./install-log.js\";\n\nexport interface RemovableRow {\n value: string;\n label: string;\n hint: string;\n}\n\nexport type UninstallMode = \"selected\" | \"all\";\n\nexport interface UninstallPrompts {\n intro: (msg: string) => void;\n outro: (msg: string) => void;\n cancel: (msg: string) => void;\n /** null = ESC/취소 */\n selectMode: (rowCount: number) => Promise<UninstallMode | null>;\n /** null = ESC/취소. 빈 배열 = 아무것도 안 고름 */\n selectAssets: (rows: ReadonlyArray<RemovableRow>) => Promise<ReadonlyArray<string> | null>;\n confirm: (summary: string) => Promise<boolean | null>;\n}\n\nexport interface InteractiveUninstallDeps {\n prompts?: UninstallPrompts;\n isTty?: () => boolean;\n readLog?: (projectDir: string) => InstallLog | null;\n}\n\nexport interface InteractiveUninstallResult {\n ok: boolean;\n /** ok=true 일 때 `uninstallAction` 에 그대로 넘길 옵션. */\n options?: { projectDir: string; only?: string };\n reason?: \"no-tty\" | \"no-log\" | \"cancelled\" | \"nothing-selected\";\n message?: string;\n}\n\n/**\n * 로그의 자산 → 선택 화면 행.\n *\n * hint 에 **고르면 실제로 무슨 일이 일어나는지**를 적는다. global(D16) 과 자동 되돌리기 경로가\n * 없는 method 는 골라도 자동 삭제되지 않으므로, 고르기 전에 말해야 한다 — 안 그러면 사용자가\n * 체크하고 Enter 를 눌렀는데 아무 일도 안 일어나는 것을 결과 화면에서야 알게 된다.\n */\nexport function buildRemovableRows(\n assets: ReadonlyArray<InstallLogAsset>,\n): ReadonlyArray<RemovableRow> {\n return assets.map((a) => ({\n value: a.id,\n label: `${a.id} [${a.method}]${a.version ? ` v${a.version}` : \"\"}`,\n hint: hintFor(a),\n }));\n}\n\nfunction hintFor(asset: InstallLogAsset): string {\n if (asset.scope === \"global\") return \"global scope — 자동 삭제 안 함, 수기 제거 명령을 출력한다\";\n switch (asset.method) {\n case \"plugin\":\n return \"claude plugin uninstall --scope project\";\n case \"skill\":\n return \"npx skills remove\";\n case \"npm\":\n return \"npm uninstall --save-dev\";\n case \"npx-run\":\n case \"shell-script\":\n case \"internal\":\n return \"자동 되돌리기 경로 없음 — 전량 제거(`.claude/` 삭제)로만 사라진다\";\n }\n}\n\nexport async function runInteractiveUninstall(\n projectDir: string,\n deps: InteractiveUninstallDeps = {},\n): Promise<InteractiveUninstallResult> {\n const prompts = deps.prompts ?? defaultUninstallPrompts();\n const isTty = deps.isTty ?? (() => Boolean(process.stdin.isTTY));\n const readLog = deps.readLog ?? readInstallLog;\n\n // CI/파이프에서 프롬프트가 뜨면 그대로 멈춘다 — install 위저드와 같은 게이트.\n if (!isTty()) return { ok: false, reason: \"no-tty\" };\n\n const log = readLog(projectDir);\n if (!log) return { ok: false, reason: \"no-log\" };\n\n prompts.intro(\"uzys-agent-harness · uninstall\");\n const rows = buildRemovableRows(log.assets);\n\n const mode = await prompts.selectMode(rows.length);\n if (mode === null) {\n prompts.cancel(\"Cancelled.\");\n return { ok: false, reason: \"cancelled\" };\n }\n\n if (mode === \"all\") {\n const ok = await prompts.confirm(\n [\n \"전량 제거 — 되돌릴 수 없다:\",\n ` · 자산 ${log.assets.length}개 (자동 경로가 있는 것만 실제 제거)`,\n \" · templates 삭제: `.claude/` 등 (설치 기록도 함께 사라진다)\",\n \" · `.claude/` 밖 파일(`.mcp.json` 등)은 삭제하지 않고 안내만 한다\",\n ].join(\"\\n\"),\n );\n if (!ok) {\n prompts.cancel(\"Cancelled.\");\n return { ok: false, reason: \"cancelled\" };\n }\n return { ok: true, options: { projectDir } };\n }\n\n const picked = await prompts.selectAssets(rows);\n if (picked === null) {\n prompts.cancel(\"Cancelled.\");\n return { ok: false, reason: \"cancelled\" };\n }\n // 빈 선택을 그대로 흘리면 `--only` 가 비어 **전량 제거로 떨어진다**. 하나만 빼려던 사용자가\n // templates 까지 잃는 경로라 여기서 끊는다 (uninstall.ts 의 `--only ,` 방어와 같은 이유).\n if (picked.length === 0) {\n prompts.outro(\"아무것도 선택하지 않았다 — 변경 없음.\");\n return { ok: false, reason: \"nothing-selected\" };\n }\n\n const ok = await prompts.confirm(\n [\n `선택 제거 (${picked.length}개):`,\n ...picked.map((id) => ` · ${id}`),\n \"\",\n \"templates 는 그대로 둔다.\",\n ].join(\"\\n\"),\n );\n if (!ok) {\n prompts.cancel(\"Cancelled.\");\n return { ok: false, reason: \"cancelled\" };\n }\n return { ok: true, options: { projectDir, only: picked.join(\",\") } };\n}\n\n/* v8 ignore start — @clack/prompts 어댑터. 선택 로직은 위 순수 함수들이 갖고 tests 로 검증. */\nfunction defaultUninstallPrompts(): UninstallPrompts {\n return {\n intro: (m) => intro(m),\n outro: (m) => outro(m),\n cancel: (m) => cancel(m),\n selectMode: async (rowCount) => {\n const r = await select({\n message: `무엇을 제거할까? (설치된 자산 ${rowCount}개)`,\n options: [\n {\n value: \"selected\",\n label: \"항목 선택해서 제거\",\n hint: \"templates(`.claude/` 등)는 그대로 둔다\",\n },\n {\n value: \"all\",\n label: \"전부 제거\",\n hint: \"자산 + templates. 설치 기록도 사라진다\",\n },\n ],\n });\n return isCancel(r) ? null : (r as UninstallMode);\n },\n selectAssets: async (rows) => {\n if (rows.length === 0) return [];\n const r = await multiselect({\n message: \"제거할 항목 (Space 토글 · Enter 확정 · ESC 취소)\",\n options: rows.map((x) => ({ value: x.value, label: x.label, hint: x.hint })),\n required: false,\n });\n return isCancel(r) ? null : (r as string[]);\n },\n confirm: async (summary) => {\n const r = await confirm({ message: `${summary}\\n\\n진행할까?`, initialValue: false });\n return isCancel(r) ? null : r;\n },\n };\n}\n/* v8 ignore stop */\n",null,"/* IMPORT */\nimport fastStringTruncatedWidth from 'fast-string-truncated-width';\n/* HELPERS */\nconst NO_TRUNCATION = {\n limit: Infinity,\n ellipsis: '',\n ellipsisWidth: 0,\n};\n/* MAIN */\nconst fastStringWidth = (input, options = {}) => {\n return fastStringTruncatedWidth(input, NO_TRUNCATION, options).width;\n};\n/* EXPORT */\nexport default fastStringWidth;\n","/* IMPORT */\nimport { getCodePointsLength, isFullWidth, isWideNotCJKTNotEmoji } from './utils.js';\n/* HELPERS */\nconst ANSI_RE = /[\\u001b\\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\\u001b\\]8;[^;]*;.*?(?:\\u0007|\\u001b\\u005c)/y;\nconst CONTROL_RE = /[\\x00-\\x08\\x0A-\\x1F\\x7F-\\x9F]{1,1000}/y;\nconst CJKT_WIDE_RE = /(?:(?![\\uFF61-\\uFF9F\\uFF00-\\uFFEF])[\\p{Script=Han}\\p{Script=Hiragana}\\p{Script=Katakana}\\p{Script=Hangul}\\p{Script=Tangut}]){1,1000}/yu;\nconst TAB_RE = /\\t{1,1000}/y;\nconst EMOJI_RE = /[\\u{1F1E6}-\\u{1F1FF}]{2}|\\u{1F3F4}[\\u{E0061}-\\u{E007A}]{2}[\\u{E0030}-\\u{E0039}\\u{E0061}-\\u{E007A}]{1,3}\\u{E007F}|(?:\\p{Emoji}\\uFE0F\\u20E3?|\\p{Emoji_Modifier_Base}\\p{Emoji_Modifier}?|\\p{Emoji_Presentation})(?:\\u200D(?:\\p{Emoji_Modifier_Base}\\p{Emoji_Modifier}?|\\p{Emoji_Presentation}|\\p{Emoji}\\uFE0F\\u20E3?))*/yu;\nconst LATIN_RE = /(?:[\\x20-\\x7E\\xA0-\\xFF](?!\\uFE0F)){1,1000}/y;\nconst MODIFIER_RE = /\\p{M}+/gu;\nconst NO_TRUNCATION = { limit: Infinity, ellipsis: '' };\n/* MAIN */\nconst getStringTruncatedWidth = (input, truncationOptions = {}, widthOptions = {}) => {\n /* CONSTANTS */\n const LIMIT = truncationOptions.limit ?? Infinity;\n const ELLIPSIS = truncationOptions.ellipsis ?? '';\n const ELLIPSIS_WIDTH = truncationOptions?.ellipsisWidth ?? (ELLIPSIS ? getStringTruncatedWidth(ELLIPSIS, NO_TRUNCATION, widthOptions).width : 0);\n const ANSI_WIDTH = 0;\n const CONTROL_WIDTH = widthOptions.controlWidth ?? 0;\n const TAB_WIDTH = widthOptions.tabWidth ?? 8;\n const EMOJI_WIDTH = widthOptions.emojiWidth ?? 2;\n const FULL_WIDTH_WIDTH = 2;\n const REGULAR_WIDTH = widthOptions.regularWidth ?? 1;\n const WIDE_WIDTH = widthOptions.wideWidth ?? FULL_WIDTH_WIDTH;\n const PARSE_BLOCKS = [\n [LATIN_RE, REGULAR_WIDTH],\n [ANSI_RE, ANSI_WIDTH],\n [CONTROL_RE, CONTROL_WIDTH],\n [TAB_RE, TAB_WIDTH],\n [EMOJI_RE, EMOJI_WIDTH],\n [CJKT_WIDE_RE, WIDE_WIDTH],\n ];\n /* STATE */\n let indexPrev = 0;\n let index = 0;\n let length = input.length;\n let lengthExtra = 0;\n let truncationEnabled = false;\n let truncationIndex = length;\n let truncationLimit = Math.max(0, LIMIT - ELLIPSIS_WIDTH);\n let unmatchedStart = 0;\n let unmatchedEnd = 0;\n let width = 0;\n let widthExtra = 0;\n /* PARSE LOOP */\n outer: while (true) {\n /* UNMATCHED */\n if ((unmatchedEnd > unmatchedStart) || (index >= length && index > indexPrev)) {\n const unmatched = input.slice(unmatchedStart, unmatchedEnd) || input.slice(indexPrev, index);\n lengthExtra = 0;\n for (const char of unmatched.replaceAll(MODIFIER_RE, '')) {\n const codePoint = char.codePointAt(0) || 0;\n if (isFullWidth(codePoint)) {\n widthExtra = FULL_WIDTH_WIDTH;\n }\n else if (isWideNotCJKTNotEmoji(codePoint)) {\n widthExtra = WIDE_WIDTH;\n }\n else {\n widthExtra = REGULAR_WIDTH;\n }\n if ((width + widthExtra) > truncationLimit) {\n truncationIndex = Math.min(truncationIndex, Math.max(unmatchedStart, indexPrev) + lengthExtra);\n }\n if ((width + widthExtra) > LIMIT) {\n truncationEnabled = true;\n break outer;\n }\n lengthExtra += char.length;\n width += widthExtra;\n }\n unmatchedStart = unmatchedEnd = 0;\n }\n /* EXITING */\n if (index >= length) {\n break outer;\n }\n /* PARSE BLOCKS */\n for (let i = 0, l = PARSE_BLOCKS.length; i < l; i++) {\n const [BLOCK_RE, BLOCK_WIDTH] = PARSE_BLOCKS[i];\n BLOCK_RE.lastIndex = index;\n if (BLOCK_RE.test(input)) {\n lengthExtra = BLOCK_RE === CJKT_WIDE_RE ? getCodePointsLength(input.slice(index, BLOCK_RE.lastIndex)) : BLOCK_RE === EMOJI_RE ? 1 : BLOCK_RE.lastIndex - index;\n widthExtra = lengthExtra * BLOCK_WIDTH;\n if ((width + widthExtra) > truncationLimit) {\n truncationIndex = Math.min(truncationIndex, index + Math.floor((truncationLimit - width) / BLOCK_WIDTH));\n }\n if ((width + widthExtra) > LIMIT) {\n truncationEnabled = true;\n break outer;\n }\n width += widthExtra;\n unmatchedStart = indexPrev;\n unmatchedEnd = index;\n index = indexPrev = BLOCK_RE.lastIndex;\n continue outer;\n }\n }\n /* UNMATCHED INDEX */\n index += 1;\n }\n /* RETURN */\n return {\n width: truncationEnabled ? truncationLimit : width,\n index: truncationEnabled ? truncationIndex : length,\n truncated: truncationEnabled,\n ellipsed: truncationEnabled && LIMIT >= ELLIPSIS_WIDTH\n };\n};\n/* EXPORT */\nexport default getStringTruncatedWidth;\n","/* MAIN */\nconst getCodePointsLength = (() => {\n const SURROGATE_PAIR_RE = /[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]/g;\n return (input) => {\n let surrogatePairsNr = 0;\n SURROGATE_PAIR_RE.lastIndex = 0;\n while (SURROGATE_PAIR_RE.test(input)) {\n surrogatePairsNr += 1;\n }\n return input.length - surrogatePairsNr;\n };\n})();\nconst isFullWidth = (x) => {\n return x === 0x3000 || x >= 0xFF01 && x <= 0xFF60 || x >= 0xFFE0 && x <= 0xFFE6;\n};\nconst isWideNotCJKTNotEmoji = (x) => {\n return x === 0x231B || x === 0x2329 || x >= 0x2FF0 && x <= 0x2FFF || x >= 0x3001 && x <= 0x303E || x >= 0x3099 && x <= 0x30FF || x >= 0x3105 && x <= 0x312F || x >= 0x3131 && x <= 0x318E || x >= 0x3190 && x <= 0x31E3 || x >= 0x31EF && x <= 0x321E || x >= 0x3220 && x <= 0x3247 || x >= 0x3250 && x <= 0x4DBF || x >= 0xFE10 && x <= 0xFE19 || x >= 0xFE30 && x <= 0xFE52 || x >= 0xFE54 && x <= 0xFE66 || x >= 0xFE68 && x <= 0xFE6B || x >= 0x1F200 && x <= 0x1F202 || x >= 0x1F210 && x <= 0x1F23B || x >= 0x1F240 && x <= 0x1F248 || x >= 0x20000 && x <= 0x2FFFD || x >= 0x30000 && x <= 0x3FFFD;\n};\n/* EXPORT */\nexport { getCodePointsLength, isFullWidth, isWideNotCJKTNotEmoji };\n","export function findCursor<T extends { disabled?: boolean }>(\n\tcursor: number,\n\tdelta: number,\n\toptions: T[]\n) {\n\tconst hasEnabledOptions = options.some((opt) => !opt.disabled);\n\tif (!hasEnabledOptions) {\n\t\treturn cursor;\n\t}\n\tconst newCursor = cursor + delta;\n\tconst maxCursor = Math.max(options.length - 1, 0);\n\tconst clampedCursor = newCursor < 0 ? maxCursor : newCursor > maxCursor ? 0 : newCursor;\n\tconst newOption = options[clampedCursor];\n\tif (newOption.disabled) {\n\t\treturn findCursor(clampedCursor, delta < 0 ? -1 : 1, options);\n\t}\n\treturn clampedCursor;\n}\n\nexport function findTextCursor(\n\tcursor: number,\n\tdeltaX: number,\n\tdeltaY: number,\n\tvalue: string\n): number {\n\tconst lines = value.split('\\n');\n\tlet cursorY = 0;\n\tlet cursorX = cursor;\n\n\tfor (const line of lines) {\n\t\tif (cursorX <= line.length) {\n\t\t\tbreak;\n\t\t}\n\t\tcursorX -= line.length + 1;\n\t\tcursorY++;\n\t}\n\n\tcursorY = Math.max(0, Math.min(lines.length - 1, cursorY + deltaY));\n\n\tcursorX = Math.min(cursorX, lines[cursorY].length) + deltaX;\n\twhile (cursorX < 0 && cursorY > 0) {\n\t\tcursorY--;\n\t\tcursorX += lines[cursorY].length + 1;\n\t}\n\twhile (cursorX > lines[cursorY].length && cursorY < lines.length - 1) {\n\t\tcursorX -= lines[cursorY].length + 1;\n\t\tcursorY++;\n\t}\n\tcursorX = Math.max(0, Math.min(lines[cursorY].length, cursorX));\n\n\tlet newCursor = 0;\n\tfor (let i = 0; i < cursorY; i++) {\n\t\tnewCursor += lines[i].length + 1;\n\t}\n\treturn newCursor + cursorX;\n}\n","const actions = ['up', 'down', 'left', 'right', 'space', 'enter', 'cancel'] as const;\nexport type Action = (typeof actions)[number];\n\nconst DEFAULT_MONTH_NAMES = [\n\t'January',\n\t'February',\n\t'March',\n\t'April',\n\t'May',\n\t'June',\n\t'July',\n\t'August',\n\t'September',\n\t'October',\n\t'November',\n\t'December',\n];\n\n/** Global settings for Clack programs, stored in memory */\ninterface InternalClackSettings {\n\tactions: Set<Action>;\n\taliases: Map<string, Action>;\n\tmessages: {\n\t\tcancel: string;\n\t\terror: string;\n\t};\n\twithGuide: boolean;\n\tdate: {\n\t\tmonthNames: string[];\n\t\tmessages: {\n\t\t\tinvalidMonth: string;\n\t\t\trequired: string;\n\t\t\tinvalidDay: (days: number, month: string) => string;\n\t\t\tafterMin: (min: Date) => string;\n\t\t\tbeforeMax: (max: Date) => string;\n\t\t};\n\t};\n}\n\nexport const settings: InternalClackSettings = {\n\tactions: new Set(actions),\n\taliases: new Map<string, Action>([\n\t\t// vim support\n\t\t['k', 'up'],\n\t\t['j', 'down'],\n\t\t['h', 'left'],\n\t\t['l', 'right'],\n\t\t['\\x03', 'cancel'],\n\t\t// opinionated defaults!\n\t\t['escape', 'cancel'],\n\t]),\n\tmessages: {\n\t\tcancel: 'Canceled',\n\t\terror: 'Something went wrong',\n\t},\n\twithGuide: true,\n\tdate: {\n\t\tmonthNames: [...DEFAULT_MONTH_NAMES],\n\t\tmessages: {\n\t\t\trequired: 'Please enter a valid date',\n\t\t\tinvalidMonth: 'There are only 12 months in a year',\n\t\t\tinvalidDay: (days, month) => `There are only ${days} days in ${month}`,\n\t\t\tafterMin: (min) => `Date must be on or after ${min.toISOString().slice(0, 10)}`,\n\t\t\tbeforeMax: (max) => `Date must be on or before ${max.toISOString().slice(0, 10)}`,\n\t\t},\n\t},\n};\n\nexport interface ClackSettings {\n\t/**\n\t * Set custom global aliases for the default actions.\n\t * This will not overwrite existing aliases, it will only add new ones!\n\t *\n\t * @param aliases - An object that maps aliases to actions\n\t * @default { k: 'up', j: 'down', h: 'left', l: 'right', '\\x03': 'cancel', 'escape': 'cancel' }\n\t */\n\taliases?: Record<string, Action>;\n\n\t/**\n\t * Custom messages for prompts\n\t */\n\tmessages?: {\n\t\t/**\n\t\t * Custom message to display when a spinner is cancelled\n\t\t * @default \"Canceled\"\n\t\t */\n\t\tcancel?: string;\n\t\t/**\n\t\t * Custom message to display when a spinner encounters an error\n\t\t * @default \"Something went wrong\"\n\t\t */\n\t\terror?: string;\n\t};\n\n\twithGuide?: boolean;\n\n\t/**\n\t * Date prompt localization\n\t */\n\tdate?: {\n\t\t/** Month names for validation messages (January, February, ...) */\n\t\tmonthNames?: string[];\n\t\tmessages?: {\n\t\t\t/** Shown when date is missing */\n\t\t\trequired?: string;\n\t\t\t/** Shown when month > 12 */\n\t\t\tinvalidMonth?: string;\n\t\t\t/** (days, monthName) => message for invalid day */\n\t\t\tinvalidDay?: (days: number, month: string) => string;\n\t\t\t/** (min) => message when date is before minDate */\n\t\t\tafterMin?: (min: Date) => string;\n\t\t\t/** (max) => message when date is after maxDate */\n\t\t\tbeforeMax?: (max: Date) => string;\n\t\t};\n\t};\n}\n\nexport function updateSettings(updates: ClackSettings) {\n\t// Handle each property in the updates\n\tif (updates.aliases !== undefined) {\n\t\tconst aliases = updates.aliases;\n\t\tfor (const alias in aliases) {\n\t\t\tif (!Object.hasOwn(aliases, alias)) continue;\n\n\t\t\tconst action = aliases[alias];\n\t\t\tif (!settings.actions.has(action)) continue;\n\n\t\t\tif (!settings.aliases.has(alias)) {\n\t\t\t\tsettings.aliases.set(alias, action);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (updates.messages !== undefined) {\n\t\tconst messages = updates.messages;\n\t\tif (messages.cancel !== undefined) {\n\t\t\tsettings.messages.cancel = messages.cancel;\n\t\t}\n\t\tif (messages.error !== undefined) {\n\t\t\tsettings.messages.error = messages.error;\n\t\t}\n\t}\n\n\tif (updates.withGuide !== undefined) {\n\t\tsettings.withGuide = updates.withGuide !== false;\n\t}\n\n\tif (updates.date !== undefined) {\n\t\tconst date = updates.date;\n\t\tif (date.monthNames !== undefined) {\n\t\t\tsettings.date.monthNames = [...date.monthNames];\n\t\t}\n\t\tif (date.messages !== undefined) {\n\t\t\tif (date.messages.required !== undefined) {\n\t\t\t\tsettings.date.messages.required = date.messages.required;\n\t\t\t}\n\t\t\tif (date.messages.invalidMonth !== undefined) {\n\t\t\t\tsettings.date.messages.invalidMonth = date.messages.invalidMonth;\n\t\t\t}\n\t\t\tif (date.messages.invalidDay !== undefined) {\n\t\t\t\tsettings.date.messages.invalidDay = date.messages.invalidDay;\n\t\t\t}\n\t\t\tif (date.messages.afterMin !== undefined) {\n\t\t\t\tsettings.date.messages.afterMin = date.messages.afterMin;\n\t\t\t}\n\t\t\tif (date.messages.beforeMax !== undefined) {\n\t\t\t\tsettings.date.messages.beforeMax = date.messages.beforeMax;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Check if a key is an alias for a default action\n * @param key - The raw key which might match to an action\n * @param action - The action to match\n * @returns boolean\n */\nexport function isActionKey(key: string | Array<string | undefined>, action: Action) {\n\tif (typeof key === 'string') {\n\t\treturn settings.aliases.get(key) === action;\n\t}\n\n\tfor (const value of key) {\n\t\tif (value === undefined) continue;\n\t\tif (isActionKey(value, action)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n","export function diffLines(a: string, b: string) {\n\tif (a === b) return;\n\n\tconst aLines = a.split('\\n');\n\tconst bLines = b.split('\\n');\n\tconst numLines = Math.max(aLines.length, bLines.length);\n\tconst diff: number[] = [];\n\n\tfor (let i = 0; i < numLines; i++) {\n\t\tif (aLines[i] !== bLines[i]) diff.push(i);\n\t}\n\n\treturn {\n\t\tlines: diff,\n\t\tnumLinesBefore: aLines.length,\n\t\tnumLinesAfter: bLines.length,\n\t\tnumLines,\n\t};\n}\n","import { stdin, stdout } from 'node:process';\nimport type { Key } from 'node:readline';\nimport * as readline from 'node:readline';\nimport type { Readable, Writable } from 'node:stream';\nimport { ReadStream } from 'node:tty';\nimport { wrapAnsi } from 'fast-wrap-ansi';\nimport { cursor } from 'sisteransi';\nimport { isActionKey } from './settings.js';\n\nexport * from './settings.js';\nexport * from './string.js';\n\nconst isWindows = globalThis.process.platform.startsWith('win');\n\nexport const CANCEL_SYMBOL = Symbol('clack:cancel');\n\nexport function isCancel(value: unknown): value is symbol {\n\treturn value === CANCEL_SYMBOL;\n}\n\nexport function setRawMode(input: Readable, value: boolean) {\n\tconst i = input as typeof stdin;\n\n\tif (i.isTTY) i.setRawMode(value);\n}\n\ninterface BlockOptions {\n\tinput?: Readable;\n\toutput?: Writable;\n\toverwrite?: boolean;\n\thideCursor?: boolean;\n}\n\nexport function block({\n\tinput = stdin,\n\toutput = stdout,\n\toverwrite = true,\n\thideCursor = true,\n}: BlockOptions = {}) {\n\tconst rl = readline.createInterface({\n\t\tinput,\n\t\toutput,\n\t\tprompt: '',\n\t\ttabSize: 1,\n\t});\n\treadline.emitKeypressEvents(input, rl);\n\n\tif (input instanceof ReadStream && input.isTTY) {\n\t\tinput.setRawMode(true);\n\t}\n\n\tconst clear = (data: Buffer, { name, sequence }: Key) => {\n\t\tconst str = String(data);\n\t\tif (isActionKey([str, name, sequence], 'cancel')) {\n\t\t\tif (hideCursor) output.write(cursor.show);\n\t\t\tprocess.exit(0);\n\t\t\treturn;\n\t\t}\n\t\tif (!overwrite) return;\n\t\tconst dx = name === 'return' ? 0 : -1;\n\t\tconst dy = name === 'return' ? -1 : 0;\n\n\t\treadline.moveCursor(output, dx, dy, () => {\n\t\t\treadline.clearLine(output, 1, () => {\n\t\t\t\tinput.once('keypress', clear);\n\t\t\t});\n\t\t});\n\t};\n\tif (hideCursor) output.write(cursor.hide);\n\tinput.once('keypress', clear);\n\n\treturn () => {\n\t\tinput.off('keypress', clear);\n\t\tif (hideCursor) output.write(cursor.show);\n\n\t\t// Prevent Windows specific issues: https://github.com/bombshell-dev/clack/issues/176\n\t\tif (input instanceof ReadStream && input.isTTY && !isWindows) {\n\t\t\tinput.setRawMode(false);\n\t\t}\n\n\t\t// @ts-expect-error fix for https://github.com/nodejs/node/issues/31762#issuecomment-1441223907\n\t\trl.terminal = false;\n\t\trl.close();\n\t};\n}\n\nexport const getColumns = (output: Writable): number => {\n\tif ('columns' in output && typeof output.columns === 'number') {\n\t\treturn output.columns;\n\t}\n\treturn 80;\n};\n\nexport const getRows = (output: Writable): number => {\n\tif ('rows' in output && typeof output.rows === 'number') {\n\t\treturn output.rows;\n\t}\n\treturn 20;\n};\n\nexport function wrapTextWithPrefix(\n\toutput: Writable | undefined,\n\ttext: string,\n\tprefix: string,\n\tstartPrefix: string = prefix,\n\tlineFormatter?: (line: string, index: number) => string\n): string {\n\tconst columns = getColumns(output ?? stdout);\n\tconst wrapped = wrapAnsi(text, columns - prefix.length, {\n\t\thard: true,\n\t\ttrim: false,\n\t});\n\tconst lines = wrapped\n\t\t.split('\\n')\n\t\t.map((line, index) => {\n\t\t\tconst lineString = lineFormatter ? lineFormatter(line, index) : line;\n\t\t\treturn `${index === 0 ? startPrefix : prefix}${lineString}`;\n\t\t})\n\t\t.join('\\n');\n\treturn lines;\n}\n","import { stdin, stdout } from 'node:process';\nimport readline, { type Key, type ReadLine } from 'node:readline';\nimport type { Readable, Writable } from 'node:stream';\nimport { wrapAnsi } from 'fast-wrap-ansi';\nimport { cursor, erase } from 'sisteransi';\nimport type { ClackEvents, ClackState } from '../types.js';\nimport type { Action } from '../utils/index.js';\nimport {\n\tCANCEL_SYMBOL,\n\tdiffLines,\n\tgetRows,\n\tisActionKey,\n\tsetRawMode,\n\tsettings,\n} from '../utils/index.js';\n\nexport interface PromptOptions<TValue, Self extends Prompt<TValue>> {\n\trender(this: Omit<Self, 'prompt'>): string | undefined;\n\tinitialValue?: any;\n\tinitialUserInput?: string;\n\tvalidate?: ((value: TValue | undefined) => string | Error | undefined) | undefined;\n\tinput?: Readable;\n\toutput?: Writable;\n\tsignal?: AbortSignal;\n}\n\nexport default class Prompt<TValue> {\n\tprotected input: Readable;\n\tprotected output: Writable;\n\tprivate _abortSignal?: AbortSignal;\n\n\tprivate rl: ReadLine | undefined;\n\tprivate opts: Omit<PromptOptions<TValue, Prompt<TValue>>, 'render' | 'input' | 'output'>;\n\tprivate _render: (context: Omit<Prompt<TValue>, 'prompt'>) => string | undefined;\n\tprivate _track = false;\n\tprivate _prevFrame = '';\n\tprivate _subscribers = new Map<string, { cb: (...args: any) => any; once?: boolean }[]>();\n\tprotected _cursor = 0;\n\n\tpublic state: ClackState = 'initial';\n\tpublic error = '';\n\tpublic value: TValue | undefined;\n\tpublic userInput = '';\n\n\tconstructor(options: PromptOptions<TValue, Prompt<TValue>>, trackValue = true) {\n\t\tconst { input = stdin, output = stdout, render, signal, ...opts } = options;\n\n\t\tthis.opts = opts;\n\t\tthis.onKeypress = this.onKeypress.bind(this);\n\t\tthis.close = this.close.bind(this);\n\t\tthis.render = this.render.bind(this);\n\t\tthis._render = render.bind(this);\n\t\tthis._track = trackValue;\n\t\tthis._abortSignal = signal;\n\n\t\tthis.input = input;\n\t\tthis.output = output;\n\t}\n\n\t/**\n\t * Unsubscribe all listeners\n\t */\n\tprotected unsubscribe() {\n\t\tthis._subscribers.clear();\n\t}\n\n\t/**\n\t * Set a subscriber with opts\n\t * @param event - The event name\n\t */\n\tprivate setSubscriber<T extends keyof ClackEvents<TValue>>(\n\t\tevent: T,\n\t\topts: { cb: ClackEvents<TValue>[T]; once?: boolean }\n\t) {\n\t\tconst params = this._subscribers.get(event) ?? [];\n\t\tparams.push(opts);\n\t\tthis._subscribers.set(event, params);\n\t}\n\n\t/**\n\t * Subscribe to an event\n\t * @param event - The event name\n\t * @param cb - The callback\n\t */\n\tpublic on<T extends keyof ClackEvents<TValue>>(event: T, cb: ClackEvents<TValue>[T]) {\n\t\tthis.setSubscriber(event, { cb });\n\t}\n\n\t/**\n\t * Subscribe to an event once\n\t * @param event - The event name\n\t * @param cb - The callback\n\t */\n\tpublic once<T extends keyof ClackEvents<TValue>>(event: T, cb: ClackEvents<TValue>[T]) {\n\t\tthis.setSubscriber(event, { cb, once: true });\n\t}\n\n\t/**\n\t * Emit an event with data\n\t * @param event - The event name\n\t * @param data - The data to pass to the callback\n\t */\n\tpublic emit<T extends keyof ClackEvents<TValue>>(\n\t\tevent: T,\n\t\t...data: Parameters<ClackEvents<TValue>[T]>\n\t) {\n\t\tconst cbs = this._subscribers.get(event) ?? [];\n\t\tconst cleanup: (() => void)[] = [];\n\n\t\tfor (const subscriber of cbs) {\n\t\t\tsubscriber.cb(...data);\n\n\t\t\tif (subscriber.once) {\n\t\t\t\tcleanup.push(() => cbs.splice(cbs.indexOf(subscriber), 1));\n\t\t\t}\n\t\t}\n\n\t\tfor (const cb of cleanup) {\n\t\t\tcb();\n\t\t}\n\t}\n\n\tpublic prompt() {\n\t\treturn new Promise<TValue | symbol | undefined>((resolve) => {\n\t\t\tif (this._abortSignal) {\n\t\t\t\tif (this._abortSignal.aborted) {\n\t\t\t\t\tthis.state = 'cancel';\n\n\t\t\t\t\tthis.close();\n\t\t\t\t\treturn resolve(CANCEL_SYMBOL);\n\t\t\t\t}\n\n\t\t\t\tthis._abortSignal.addEventListener(\n\t\t\t\t\t'abort',\n\t\t\t\t\t() => {\n\t\t\t\t\t\tthis.state = 'cancel';\n\t\t\t\t\t\tthis.close();\n\t\t\t\t\t},\n\t\t\t\t\t{ once: true }\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.rl = readline.createInterface({\n\t\t\t\tinput: this.input,\n\t\t\t\ttabSize: 2,\n\t\t\t\tprompt: '',\n\t\t\t\tescapeCodeTimeout: 50,\n\t\t\t\tterminal: true,\n\t\t\t});\n\t\t\tthis.rl.prompt();\n\n\t\t\tif (this.opts.initialUserInput !== undefined) {\n\t\t\t\tthis._setUserInput(this.opts.initialUserInput, true);\n\t\t\t}\n\n\t\t\tthis.input.on('keypress', this.onKeypress);\n\t\t\tsetRawMode(this.input, true);\n\t\t\tthis.output.on('resize', this.render);\n\n\t\t\tthis.render();\n\n\t\t\tthis.once('submit', () => {\n\t\t\t\tthis.output.write(cursor.show);\n\t\t\t\tthis.output.off('resize', this.render);\n\t\t\t\tsetRawMode(this.input, false);\n\t\t\t\tresolve(this.value);\n\t\t\t});\n\t\t\tthis.once('cancel', () => {\n\t\t\t\tthis.output.write(cursor.show);\n\t\t\t\tthis.output.off('resize', this.render);\n\t\t\t\tsetRawMode(this.input, false);\n\t\t\t\tresolve(CANCEL_SYMBOL);\n\t\t\t});\n\t\t});\n\t}\n\n\tprotected _isActionKey(char: string | undefined, _key: Key): boolean {\n\t\treturn char === '\\t';\n\t}\n\n\tprotected _shouldSubmit(_char: string | undefined, _key: Key): boolean {\n\t\treturn true;\n\t}\n\n\tprotected _setValue(value: TValue | undefined): void {\n\t\tthis.value = value;\n\t\tthis.emit('value', this.value);\n\t}\n\n\tprotected _setUserInput(value: string | undefined, write?: boolean): void {\n\t\tthis.userInput = value ?? '';\n\t\tthis.emit('userInput', this.userInput);\n\t\tif (write && this._track && this.rl) {\n\t\t\tthis.rl.write(this.userInput);\n\t\t\tthis._cursor = this.rl.cursor;\n\t\t}\n\t}\n\n\tprotected _clearUserInput(): void {\n\t\tthis.rl?.write(null, { ctrl: true, name: 'u' });\n\t\tthis._setUserInput('');\n\t}\n\n\tprivate onKeypress(char: string | undefined, key: Key) {\n\t\tif (this._track && key.name !== 'return') {\n\t\t\tif (key.name && this._isActionKey(char, key)) {\n\t\t\t\tthis.rl?.write(null, { ctrl: true, name: 'h' });\n\t\t\t}\n\t\t\tthis._cursor = this.rl?.cursor ?? 0;\n\t\t\tthis._setUserInput(this.rl?.line);\n\t\t}\n\n\t\tif (this.state === 'error') {\n\t\t\tthis.state = 'active';\n\t\t}\n\t\tif (key?.name) {\n\t\t\tif (!this._track && settings.aliases.has(key.name)) {\n\t\t\t\tthis.emit('cursor', settings.aliases.get(key.name));\n\t\t\t}\n\t\t\tif (settings.actions.has(key.name as Action)) {\n\t\t\t\tthis.emit('cursor', key.name as Action);\n\t\t\t}\n\t\t}\n\t\tif (char && (char.toLowerCase() === 'y' || char.toLowerCase() === 'n')) {\n\t\t\tthis.emit('confirm', char.toLowerCase() === 'y');\n\t\t}\n\n\t\t// Call the key event handler and emit the key event\n\t\tthis.emit('key', char?.toLowerCase(), key);\n\n\t\tif (key?.name === 'return' && this._shouldSubmit(char, key)) {\n\t\t\tif (this.opts.validate) {\n\t\t\t\tconst problem = this.opts.validate(this.value);\n\t\t\t\tif (problem) {\n\t\t\t\t\tthis.error = problem instanceof Error ? problem.message : problem;\n\t\t\t\t\tthis.state = 'error';\n\t\t\t\t\tthis.rl?.write(this.userInput);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this.state !== 'error') {\n\t\t\t\tthis.state = 'submit';\n\t\t\t}\n\t\t}\n\n\t\tif (isActionKey([char, key?.name, key?.sequence], 'cancel')) {\n\t\t\tthis.state = 'cancel';\n\t\t}\n\n\t\tif (this.state === 'submit' || this.state === 'cancel') {\n\t\t\tthis.emit('finalize');\n\t\t}\n\t\tthis.render();\n\t\tif (this.state === 'submit' || this.state === 'cancel') {\n\t\t\tthis.close();\n\t\t}\n\t}\n\n\tprotected close() {\n\t\tthis.input.unpipe();\n\t\tthis.input.removeListener('keypress', this.onKeypress);\n\t\tthis.output.write('\\n');\n\t\tsetRawMode(this.input, false);\n\t\tthis.rl?.close();\n\t\tthis.rl = undefined;\n\t\tthis.emit(`${this.state}`, this.value);\n\t\tthis.unsubscribe();\n\t}\n\n\tprivate restoreCursor() {\n\t\tconst lines =\n\t\t\twrapAnsi(this._prevFrame, process.stdout.columns, { hard: true, trim: false }).split('\\n')\n\t\t\t\t.length - 1;\n\t\tthis.output.write(cursor.move(-999, lines * -1));\n\t}\n\n\tprivate render() {\n\t\tconst frame = wrapAnsi(this._render(this) ?? '', process.stdout.columns, {\n\t\t\thard: true,\n\t\t\ttrim: false,\n\t\t});\n\t\tif (frame === this._prevFrame) return;\n\n\t\tif (this.state === 'initial') {\n\t\t\tthis.output.write(cursor.hide);\n\t\t} else {\n\t\t\tconst diff = diffLines(this._prevFrame, frame);\n\t\t\tconst rows = getRows(this.output);\n\t\t\tthis.restoreCursor();\n\t\t\tif (diff) {\n\t\t\t\tconst diffOffsetAfter = Math.max(0, diff.numLinesAfter - rows);\n\t\t\t\tconst diffOffsetBefore = Math.max(0, diff.numLinesBefore - rows);\n\t\t\t\tlet diffLine = diff.lines.find((line) => line >= diffOffsetAfter);\n\n\t\t\t\tif (diffLine === undefined) {\n\t\t\t\t\tthis._prevFrame = frame;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// If a single line has changed, only update that line\n\t\t\t\tif (diff.lines.length === 1) {\n\t\t\t\t\tthis.output.write(cursor.move(0, diffLine - diffOffsetBefore));\n\t\t\t\t\tthis.output.write(erase.lines(1));\n\t\t\t\t\tconst lines = frame.split('\\n');\n\t\t\t\t\tthis.output.write(lines[diffLine]);\n\t\t\t\t\tthis._prevFrame = frame;\n\t\t\t\t\tthis.output.write(cursor.move(0, lines.length - diffLine - 1));\n\t\t\t\t\treturn;\n\t\t\t\t\t// If many lines have changed, rerender everything past the first line\n\t\t\t\t} else if (diff.lines.length > 1) {\n\t\t\t\t\tif (diffOffsetAfter < diffOffsetBefore) {\n\t\t\t\t\t\tdiffLine = diffOffsetAfter;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst adjustedDiffLine = diffLine - diffOffsetBefore;\n\t\t\t\t\t\tif (adjustedDiffLine > 0) {\n\t\t\t\t\t\t\tthis.output.write(cursor.move(0, adjustedDiffLine));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthis.output.write(erase.down());\n\t\t\t\t\tconst lines = frame.split('\\n');\n\t\t\t\t\tconst newLines = lines.slice(diffLine);\n\t\t\t\t\tthis.output.write(newLines.join('\\n'));\n\t\t\t\t\tthis._prevFrame = frame;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.output.write(erase.down());\n\t\t}\n\n\t\tthis.output.write(frame);\n\t\tif (this.state === 'initial') {\n\t\t\tthis.state = 'active';\n\t\t}\n\t\tthis._prevFrame = frame;\n\t}\n}\n","import type { Key } from 'node:readline';\nimport { styleText } from 'node:util';\nimport { findCursor } from '../utils/cursor.js';\nimport Prompt, { type PromptOptions } from './prompt.js';\n\ninterface OptionLike {\n\tvalue: unknown;\n\tlabel?: string;\n\tdisabled?: boolean;\n}\n\ntype FilterFunction<T extends OptionLike> = (search: string, opt: T) => boolean;\n\nfunction getCursorForValue<T extends OptionLike>(\n\tselected: T['value'] | undefined,\n\titems: T[]\n): number {\n\tif (selected === undefined) {\n\t\treturn 0;\n\t}\n\n\tconst currLength = items.length;\n\n\t// If filtering changed the available options, update cursor\n\tif (currLength === 0) {\n\t\treturn 0;\n\t}\n\n\t// Try to maintain the same selected item\n\tconst index = items.findIndex((item) => item.value === selected);\n\treturn index !== -1 ? index : 0;\n}\n\nfunction defaultFilter<T extends OptionLike>(input: string, option: T): boolean {\n\tconst label = option.label ?? String(option.value);\n\treturn label.toLowerCase().includes(input.toLowerCase());\n}\n\nfunction normalisedValue<T>(multiple: boolean, values: T[] | undefined): T | T[] | undefined {\n\tif (!values) {\n\t\treturn undefined;\n\t}\n\tif (multiple) {\n\t\treturn values;\n\t}\n\treturn values[0];\n}\n\nexport interface AutocompleteOptions<T extends OptionLike>\n\textends PromptOptions<T['value'] | T['value'][], AutocompletePrompt<T>> {\n\toptions: T[] | ((this: AutocompletePrompt<T>) => T[]);\n\tfilter?: FilterFunction<T>;\n\tmultiple?: boolean;\n\t/**\n\t * When set (non-empty), pressing Tab with no input fills the field with this value\n\t * and runs the normal filter/selection logic so the user can confirm with Enter.\n\t * Tab only fills the input when the placeholder matches at least one option under\n\t * the prompt's filter (so the value remains selectable).\n\t */\n\tplaceholder?: string;\n}\n\nexport default class AutocompletePrompt<T extends OptionLike> extends Prompt<\n\tT['value'] | T['value'][]\n> {\n\tfilteredOptions: T[];\n\tmultiple: boolean;\n\tisNavigating = false;\n\tselectedValues: Array<T['value']> = [];\n\n\tfocusedValue: T['value'] | undefined;\n\t#cursor = 0;\n\t#lastUserInput = '';\n\t#filterFn: FilterFunction<T> | undefined;\n\t#options: T[] | (() => T[]);\n\t#placeholder: string | undefined;\n\n\tget cursor(): number {\n\t\treturn this.#cursor;\n\t}\n\n\tget userInputWithCursor() {\n\t\tif (!this.userInput) {\n\t\t\treturn styleText(['inverse', 'hidden'], '_');\n\t\t}\n\t\tif (this._cursor >= this.userInput.length) {\n\t\t\treturn `${this.userInput}█`;\n\t\t}\n\t\tconst s1 = this.userInput.slice(0, this._cursor);\n\t\tconst [s2, ...s3] = this.userInput.slice(this._cursor);\n\t\treturn `${s1}${styleText('inverse', s2)}${s3.join('')}`;\n\t}\n\n\tget options(): T[] {\n\t\tif (typeof this.#options === 'function') {\n\t\t\treturn this.#options();\n\t\t}\n\t\treturn this.#options;\n\t}\n\n\tconstructor(opts: AutocompleteOptions<T>) {\n\t\tsuper(opts);\n\n\t\tthis.#options = opts.options;\n\t\tthis.#placeholder = opts.placeholder;\n\t\tconst options = this.options;\n\t\tthis.filteredOptions = [...options];\n\t\tthis.multiple = opts.multiple === true;\n\t\tthis.#filterFn =\n\t\t\ttypeof opts.options === 'function' ? opts.filter : (opts.filter ?? defaultFilter);\n\t\tlet initialValues: unknown[] | undefined;\n\t\tif (opts.initialValue && Array.isArray(opts.initialValue)) {\n\t\t\tif (this.multiple) {\n\t\t\t\tinitialValues = opts.initialValue;\n\t\t\t} else {\n\t\t\t\tinitialValues = opts.initialValue.slice(0, 1);\n\t\t\t}\n\t\t} else {\n\t\t\tif (!this.multiple && this.options.length > 0) {\n\t\t\t\tinitialValues = [this.options[0].value];\n\t\t\t}\n\t\t}\n\n\t\tif (initialValues) {\n\t\t\tfor (const selectedValue of initialValues) {\n\t\t\t\tconst selectedIndex = options.findIndex((opt) => opt.value === selectedValue);\n\t\t\t\tif (selectedIndex !== -1) {\n\t\t\t\t\tthis.toggleSelected(selectedValue);\n\t\t\t\t\tthis.#cursor = selectedIndex;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.focusedValue = this.options[this.#cursor]?.value;\n\n\t\tthis.on('key', (char, key) => this.#onKey(char, key));\n\t\tthis.on('userInput', (value) => this.#onUserInputChanged(value));\n\t}\n\n\tprotected override _isActionKey(char: string | undefined, key: Key): boolean {\n\t\treturn (\n\t\t\tchar === '\\t' ||\n\t\t\t(this.multiple &&\n\t\t\t\tthis.isNavigating &&\n\t\t\t\tkey.name === 'space' &&\n\t\t\t\tchar !== undefined &&\n\t\t\t\tchar !== '')\n\t\t);\n\t}\n\n\t#onKey(_char: string | undefined, key: Key): void {\n\t\tconst isUpKey = key.name === 'up';\n\t\tconst isDownKey = key.name === 'down';\n\t\tconst isReturnKey = key.name === 'return';\n\n\t\t// Tab with empty input and placeholder: fill input with placeholder to trigger autocomplete\n\t\t// Only when the placeholder matches at least one (non-disabled) option so the value remains selectable\n\t\tconst isEmptyOrOnlyTab = this.userInput === '' || this.userInput === '\\t';\n\t\tconst placeholder = this.#placeholder;\n\t\tconst options = this.options;\n\t\tconst placeholderMatchesOption =\n\t\t\tplaceholder !== undefined &&\n\t\t\tplaceholder !== '' &&\n\t\t\toptions.some(\n\t\t\t\t(opt) => !opt.disabled && (this.#filterFn ? this.#filterFn(placeholder, opt) : true)\n\t\t\t);\n\t\tif (key.name === 'tab' && isEmptyOrOnlyTab && placeholderMatchesOption) {\n\t\t\tif (this.userInput === '\\t') {\n\t\t\t\tthis._clearUserInput();\n\t\t\t}\n\t\t\tthis._setUserInput(placeholder, true);\n\t\t\tthis.isNavigating = false;\n\t\t\treturn;\n\t\t}\n\n\t\t// Start navigation mode with up/down arrows\n\t\tif (isUpKey || isDownKey) {\n\t\t\tthis.#cursor = findCursor(this.#cursor, isUpKey ? -1 : 1, this.filteredOptions);\n\t\t\tthis.focusedValue = this.filteredOptions[this.#cursor]?.value;\n\t\t\tif (!this.multiple) {\n\t\t\t\tthis.selectedValues = [this.focusedValue];\n\t\t\t}\n\t\t\tthis.isNavigating = true;\n\t\t} else if (isReturnKey) {\n\t\t\tthis.value = normalisedValue(this.multiple, this.selectedValues);\n\t\t} else {\n\t\t\tif (this.multiple) {\n\t\t\t\tif (\n\t\t\t\t\tthis.focusedValue !== undefined &&\n\t\t\t\t\t(key.name === 'tab' || (this.isNavigating && key.name === 'space'))\n\t\t\t\t) {\n\t\t\t\t\tthis.toggleSelected(this.focusedValue);\n\t\t\t\t} else {\n\t\t\t\t\tthis.isNavigating = false;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (this.focusedValue) {\n\t\t\t\t\tthis.selectedValues = [this.focusedValue];\n\t\t\t\t}\n\t\t\t\tthis.isNavigating = false;\n\t\t\t}\n\t\t}\n\t}\n\n\tdeselectAll() {\n\t\tthis.selectedValues = [];\n\t}\n\n\ttoggleSelected(value: T['value']) {\n\t\tif (this.filteredOptions.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.multiple) {\n\t\t\tif (this.selectedValues.includes(value)) {\n\t\t\t\tthis.selectedValues = this.selectedValues.filter((v) => v !== value);\n\t\t\t} else {\n\t\t\t\tthis.selectedValues = [...this.selectedValues, value];\n\t\t\t}\n\t\t} else {\n\t\t\tthis.selectedValues = [value];\n\t\t}\n\t}\n\n\t#onUserInputChanged(value: string): void {\n\t\tif (value !== this.#lastUserInput) {\n\t\t\tthis.#lastUserInput = value;\n\n\t\t\tconst options = this.options;\n\n\t\t\tif (value && this.#filterFn) {\n\t\t\t\tthis.filteredOptions = options.filter((opt) => this.#filterFn?.(value, opt));\n\t\t\t} else {\n\t\t\t\tthis.filteredOptions = [...options];\n\t\t\t}\n\t\t\tconst valueCursor = getCursorForValue(this.focusedValue, this.filteredOptions);\n\t\t\tthis.#cursor = findCursor(valueCursor, 0, this.filteredOptions);\n\t\t\tconst focusedOption = this.filteredOptions[this.#cursor];\n\t\t\tif (focusedOption && !focusedOption.disabled) {\n\t\t\t\tthis.focusedValue = focusedOption.value;\n\t\t\t} else {\n\t\t\t\tthis.focusedValue = undefined;\n\t\t\t}\n\t\t\tif (!this.multiple) {\n\t\t\t\tif (this.focusedValue !== undefined) {\n\t\t\t\t\tthis.toggleSelected(this.focusedValue);\n\t\t\t\t} else {\n\t\t\t\t\tthis.deselectAll();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n","import { cursor } from 'sisteransi';\nimport Prompt, { type PromptOptions } from './prompt.js';\n\nexport interface ConfirmOptions extends PromptOptions<boolean, ConfirmPrompt> {\n\tactive: string;\n\tinactive: string;\n\tinitialValue?: boolean;\n}\n\nexport default class ConfirmPrompt extends Prompt<boolean> {\n\tget cursor() {\n\t\treturn this.value ? 0 : 1;\n\t}\n\n\tprivate get _value() {\n\t\treturn this.cursor === 0;\n\t}\n\n\tconstructor(opts: ConfirmOptions) {\n\t\tsuper(opts, false);\n\t\tthis.value = !!opts.initialValue;\n\n\t\tthis.on('userInput', () => {\n\t\t\tthis.value = this._value;\n\t\t});\n\n\t\tthis.on('confirm', (confirm) => {\n\t\t\tthis.output.write(cursor.move(0, -1));\n\t\t\tthis.value = confirm;\n\t\t\tthis.state = 'submit';\n\t\t\tthis.close();\n\t\t});\n\n\t\tthis.on('cursor', () => {\n\t\t\tthis.value = !this.value;\n\t\t});\n\t}\n}\n","import type { Key } from 'node:readline';\nimport { settings } from '../utils/settings.js';\nimport Prompt, { type PromptOptions } from './prompt.js';\n\ninterface SegmentConfig {\n\ttype: 'year' | 'month' | 'day';\n\tlen: number;\n}\n\nexport interface DateParts {\n\tyear: string;\n\tmonth: string;\n\tday: string;\n}\n\nexport type DateFormat = 'YMD' | 'MDY' | 'DMY';\n\nconst SEGMENTS: Record<string, SegmentConfig> = {\n\tY: { type: 'year', len: 4 },\n\tM: { type: 'month', len: 2 },\n\tD: { type: 'day', len: 2 },\n} as const;\n\nfunction segmentsFor(fmt: DateFormat): SegmentConfig[] {\n\treturn [...fmt].map((c) => SEGMENTS[c as keyof typeof SEGMENTS]);\n}\n\nfunction detectLocaleFormat(locale?: string): { segments: SegmentConfig[]; separator: string } {\n\tconst fmt = new Intl.DateTimeFormat(locale, {\n\t\tyear: 'numeric',\n\t\tmonth: '2-digit',\n\t\tday: '2-digit',\n\t});\n\tconst parts = fmt.formatToParts(new Date(2000, 0, 15));\n\tconst segments: SegmentConfig[] = [];\n\tlet separator = '/';\n\tfor (const p of parts) {\n\t\tif (p.type === 'literal') {\n\t\t\tseparator = p.value.trim() || p.value;\n\t\t} else if (p.type === 'year' || p.type === 'month' || p.type === 'day') {\n\t\t\tsegments.push({ type: p.type, len: p.type === 'year' ? 4 : 2 });\n\t\t}\n\t}\n\treturn { segments, separator };\n}\n\n/** Parse string segment values to numbers, treating blanks as 0 */\nfunction parseSegmentToNum(s: string): number {\n\treturn Number.parseInt((s || '0').replace(/_/g, '0'), 10) || 0;\n}\n\nfunction parse(parts: DateParts): { year: number; month: number; day: number } {\n\treturn {\n\t\tyear: parseSegmentToNum(parts.year),\n\t\tmonth: parseSegmentToNum(parts.month),\n\t\tday: parseSegmentToNum(parts.day),\n\t};\n}\n\nfunction daysInMonth(year: number, month: number): number {\n\treturn new Date(year || 2001, month || 1, 0).getDate();\n}\n\n/** Validate and return calendar parts, or undefined if invalid */\nfunction validParts(parts: DateParts): { year: number; month: number; day: number } | undefined {\n\tconst { year, month, day } = parse(parts);\n\tif (!year || year < 0 || year > 9999) return undefined;\n\tif (!month || month < 1 || month > 12) return undefined;\n\tif (!day || day < 1) return undefined;\n\tconst d = new Date(Date.UTC(year, month - 1, day));\n\tif (d.getUTCFullYear() !== year || d.getUTCMonth() !== month - 1 || d.getUTCDate() !== day)\n\t\treturn undefined;\n\treturn { year, month, day };\n}\n\nfunction toDate(parts: DateParts): Date | undefined {\n\tconst p = validParts(parts);\n\treturn p ? new Date(Date.UTC(p.year, p.month - 1, p.day)) : undefined;\n}\n\nfunction segmentBounds(\n\ttype: 'year' | 'month' | 'day',\n\tctx: { year: number; month: number },\n\tminDate: Date | undefined,\n\tmaxDate: Date | undefined\n): { min: number; max: number } {\n\tconst minP = minDate\n\t\t? {\n\t\t\t\tyear: minDate.getUTCFullYear(),\n\t\t\t\tmonth: minDate.getUTCMonth() + 1,\n\t\t\t\tday: minDate.getUTCDate(),\n\t\t\t}\n\t\t: null;\n\tconst maxP = maxDate\n\t\t? {\n\t\t\t\tyear: maxDate.getUTCFullYear(),\n\t\t\t\tmonth: maxDate.getUTCMonth() + 1,\n\t\t\t\tday: maxDate.getUTCDate(),\n\t\t\t}\n\t\t: null;\n\n\tif (type === 'year') {\n\t\treturn { min: minP?.year ?? 1, max: maxP?.year ?? 9999 };\n\t}\n\tif (type === 'month') {\n\t\treturn {\n\t\t\tmin: minP && ctx.year === minP.year ? minP.month : 1,\n\t\t\tmax: maxP && ctx.year === maxP.year ? maxP.month : 12,\n\t\t};\n\t}\n\treturn {\n\t\tmin: minP && ctx.year === minP.year && ctx.month === minP.month ? minP.day : 1,\n\t\tmax:\n\t\t\tmaxP && ctx.year === maxP.year && ctx.month === maxP.month\n\t\t\t\t? maxP.day\n\t\t\t\t: daysInMonth(ctx.year, ctx.month),\n\t};\n}\n\nexport interface DateOptions extends PromptOptions<Date, DatePrompt> {\n\tformat?: DateFormat;\n\tlocale?: string;\n\tseparator?: string;\n\tdefaultValue?: Date;\n\tinitialValue?: Date;\n\tminDate?: Date;\n\tmaxDate?: Date;\n}\n\nexport default class DatePrompt extends Prompt<Date> {\n\t#segments: SegmentConfig[];\n\t#separator: string;\n\t#segmentValues: DateParts;\n\t#minDate: Date | undefined;\n\t#maxDate: Date | undefined;\n\t#cursor = { segmentIndex: 0, positionInSegment: 0 };\n\t#segmentSelected = true;\n\t#pendingTensDigit: string | null = null;\n\n\tinlineError = '';\n\n\tget segmentCursor() {\n\t\treturn { ...this.#cursor };\n\t}\n\n\tget segmentValues(): DateParts {\n\t\treturn { ...this.#segmentValues };\n\t}\n\n\tget segments(): readonly SegmentConfig[] {\n\t\treturn this.#segments;\n\t}\n\n\tget separator(): string {\n\t\treturn this.#separator;\n\t}\n\n\tget formattedValue(): string {\n\t\treturn this.#format(this.#segmentValues);\n\t}\n\n\t#format(parts: DateParts): string {\n\t\treturn this.#segments.map((s) => parts[s.type]).join(this.#separator);\n\t}\n\n\t#refresh() {\n\t\tthis._setUserInput(this.#format(this.#segmentValues));\n\t\tthis._setValue(toDate(this.#segmentValues) ?? undefined);\n\t}\n\n\tconstructor(opts: DateOptions) {\n\t\tconst detected = opts.format\n\t\t\t? { segments: segmentsFor(opts.format), separator: opts.separator ?? '/' }\n\t\t\t: detectLocaleFormat(opts.locale);\n\t\tconst sep = opts.separator ?? detected.separator;\n\t\tconst segments = opts.format ? segmentsFor(opts.format) : detected.segments;\n\n\t\tconst initialDate = opts.initialValue ?? opts.defaultValue;\n\t\tconst segmentValues: DateParts = initialDate\n\t\t\t? {\n\t\t\t\t\tyear: String(initialDate.getUTCFullYear()).padStart(4, '0'),\n\t\t\t\t\tmonth: String(initialDate.getUTCMonth() + 1).padStart(2, '0'),\n\t\t\t\t\tday: String(initialDate.getUTCDate()).padStart(2, '0'),\n\t\t\t\t}\n\t\t\t: { year: '____', month: '__', day: '__' };\n\n\t\tconst initialDisplay = segments.map((s) => segmentValues[s.type]).join(sep);\n\n\t\tsuper({ ...opts, initialUserInput: initialDisplay }, false);\n\t\tthis.#segments = segments;\n\t\tthis.#separator = sep;\n\t\tthis.#segmentValues = segmentValues;\n\t\tthis.#minDate = opts.minDate;\n\t\tthis.#maxDate = opts.maxDate;\n\t\tthis.#refresh();\n\n\t\tthis.on('cursor', (key) => this.#onCursor(key));\n\t\tthis.on('key', (char, key) => this.#onKey(char, key));\n\t\tthis.on('finalize', () => this.#onFinalize(opts));\n\t}\n\n\t#seg(): { segment: SegmentConfig; index: number } | undefined {\n\t\tconst index = Math.max(0, Math.min(this.#cursor.segmentIndex, this.#segments.length - 1));\n\t\tconst segment = this.#segments[index];\n\t\tif (!segment) return undefined;\n\t\tthis.#cursor.positionInSegment = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.#cursor.positionInSegment, segment.len - 1)\n\t\t);\n\t\treturn { segment, index };\n\t}\n\n\t#navigate(direction: 1 | -1) {\n\t\tthis.inlineError = '';\n\t\tthis.#pendingTensDigit = null;\n\t\tconst ctx = this.#seg();\n\t\tif (!ctx) return;\n\t\tthis.#cursor.segmentIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.#segments.length - 1, ctx.index + direction)\n\t\t);\n\t\tthis.#cursor.positionInSegment = 0;\n\t\tthis.#segmentSelected = true;\n\t}\n\n\t#adjust(direction: 1 | -1) {\n\t\tconst ctx = this.#seg();\n\t\tif (!ctx) return;\n\t\tconst { segment } = ctx;\n\t\tconst raw = this.#segmentValues[segment.type];\n\t\tconst isBlank = !raw || raw.replace(/_/g, '') === '';\n\t\tconst num = Number.parseInt((raw || '0').replace(/_/g, '0'), 10) || 0;\n\t\tconst bounds = segmentBounds(\n\t\t\tsegment.type,\n\t\t\tparse(this.#segmentValues),\n\t\t\tthis.#minDate,\n\t\t\tthis.#maxDate\n\t\t);\n\n\t\tlet next: number;\n\t\tif (isBlank) {\n\t\t\tnext = direction === 1 ? bounds.min : bounds.max;\n\t\t} else {\n\t\t\tnext = Math.max(Math.min(bounds.max, num + direction), bounds.min);\n\t\t}\n\n\t\tthis.#segmentValues = {\n\t\t\t...this.#segmentValues,\n\t\t\t[segment.type]: next.toString().padStart(segment.len, '0'),\n\t\t};\n\t\tthis.#segmentSelected = true;\n\t\tthis.#pendingTensDigit = null;\n\t\tthis.#refresh();\n\t}\n\n\t#onCursor(key?: string) {\n\t\tif (!key) return;\n\t\tswitch (key) {\n\t\t\tcase 'right':\n\t\t\t\treturn this.#navigate(1);\n\t\t\tcase 'left':\n\t\t\t\treturn this.#navigate(-1);\n\t\t\tcase 'up':\n\t\t\t\treturn this.#adjust(1);\n\t\t\tcase 'down':\n\t\t\t\treturn this.#adjust(-1);\n\t\t}\n\t}\n\n\t#onKey(char: string | undefined, key: Key) {\n\t\t// Backspace\n\t\tconst isBackspace =\n\t\t\tkey?.name === 'backspace' ||\n\t\t\tkey?.sequence === '\\x7f' ||\n\t\t\tkey?.sequence === '\\b' ||\n\t\t\tchar === '\\x7f' ||\n\t\t\tchar === '\\b';\n\t\tif (isBackspace) {\n\t\t\tthis.inlineError = '';\n\t\t\tconst ctx = this.#seg();\n\t\t\tif (!ctx) return;\n\t\t\tif (!this.#segmentValues[ctx.segment.type].replace(/_/g, '')) {\n\t\t\t\tthis.#navigate(-1);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.#segmentValues[ctx.segment.type] = '_'.repeat(ctx.segment.len);\n\t\t\tthis.#segmentSelected = true;\n\t\t\tthis.#cursor.positionInSegment = 0;\n\t\t\tthis.#refresh();\n\t\t\treturn;\n\t\t}\n\n\t\t// Tab navigation\n\t\tif (key?.name === 'tab') {\n\t\t\tthis.inlineError = '';\n\t\t\tconst ctx = this.#seg();\n\t\t\tif (!ctx) return;\n\t\t\tconst dir = key.shift ? -1 : 1;\n\t\t\tconst next = ctx.index + dir;\n\t\t\tif (next >= 0 && next < this.#segments.length) {\n\t\t\t\tthis.#cursor.segmentIndex = next;\n\t\t\t\tthis.#cursor.positionInSegment = 0;\n\t\t\t\tthis.#segmentSelected = true;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Digit input\n\t\tif (char && /^[0-9]$/.test(char)) {\n\t\t\tconst ctx = this.#seg();\n\t\t\tif (!ctx) return;\n\t\t\tconst { segment } = ctx;\n\t\t\tconst isBlank = !this.#segmentValues[segment.type].replace(/_/g, '');\n\n\t\t\t// Pending tens digit: complete the two-digit entry\n\t\t\tif (this.#segmentSelected && this.#pendingTensDigit !== null && !isBlank) {\n\t\t\t\tconst newVal = this.#pendingTensDigit + char;\n\t\t\t\tconst newParts = { ...this.#segmentValues, [segment.type]: newVal };\n\t\t\t\tconst err = this.#validateSegment(newParts, segment);\n\t\t\t\tif (err) {\n\t\t\t\t\tthis.inlineError = err;\n\t\t\t\t\tthis.#pendingTensDigit = null;\n\t\t\t\t\tthis.#segmentSelected = false;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.inlineError = '';\n\t\t\t\tthis.#segmentValues[segment.type] = newVal;\n\t\t\t\tthis.#pendingTensDigit = null;\n\t\t\t\tthis.#segmentSelected = false;\n\t\t\t\tthis.#refresh();\n\t\t\t\tif (ctx.index < this.#segments.length - 1) {\n\t\t\t\t\tthis.#cursor.segmentIndex = ctx.index + 1;\n\t\t\t\t\tthis.#cursor.positionInSegment = 0;\n\t\t\t\t\tthis.#segmentSelected = true;\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Clear-on-type: typing into a selected filled segment clears it first\n\t\t\tif (this.#segmentSelected && !isBlank) {\n\t\t\t\tthis.#segmentValues[segment.type] = '_'.repeat(segment.len);\n\t\t\t\tthis.#cursor.positionInSegment = 0;\n\t\t\t}\n\t\t\tthis.#segmentSelected = false;\n\t\t\tthis.#pendingTensDigit = null;\n\n\t\t\tconst display = this.#segmentValues[segment.type];\n\t\t\tconst firstBlank = display.indexOf('_');\n\t\t\tconst pos =\n\t\t\t\tfirstBlank >= 0 ? firstBlank : Math.min(this.#cursor.positionInSegment, segment.len - 1);\n\t\t\tif (pos < 0 || pos >= segment.len) return;\n\n\t\t\tlet newVal = display.slice(0, pos) + char + display.slice(pos + 1);\n\n\t\t\t// Smart digit placement\n\t\t\tlet shouldStaySelected = false;\n\t\t\tif (pos === 0 && display === '__' && (segment.type === 'month' || segment.type === 'day')) {\n\t\t\t\tconst digit = Number.parseInt(char, 10);\n\t\t\t\tnewVal = `0${char}`;\n\t\t\t\tshouldStaySelected = digit <= (segment.type === 'month' ? 1 : 2);\n\t\t\t}\n\t\t\tif (segment.type === 'year') {\n\t\t\t\tconst digits = display.replace(/_/g, '');\n\t\t\t\tnewVal = (digits + char).padStart(segment.len, '_');\n\t\t\t}\n\n\t\t\tif (!newVal.includes('_')) {\n\t\t\t\tconst newParts = { ...this.#segmentValues, [segment.type]: newVal };\n\t\t\t\tconst err = this.#validateSegment(newParts, segment);\n\t\t\t\tif (err) {\n\t\t\t\t\tthis.inlineError = err;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.inlineError = '';\n\n\t\t\tthis.#segmentValues[segment.type] = newVal;\n\n\t\t\t// Clamp only when the current segment is fully entered\n\t\t\tconst parsed = !newVal.includes('_') ? validParts(this.#segmentValues) : undefined;\n\t\t\tif (parsed) {\n\t\t\t\tconst { year, month } = parsed;\n\t\t\t\tconst maxDay = daysInMonth(year, month);\n\t\t\t\tthis.#segmentValues = {\n\t\t\t\t\tyear: String(Math.max(0, Math.min(9999, year))).padStart(4, '0'),\n\t\t\t\t\tmonth: String(Math.max(1, Math.min(12, month))).padStart(2, '0'),\n\t\t\t\t\tday: String(Math.max(1, Math.min(maxDay, parsed.day))).padStart(2, '0'),\n\t\t\t\t};\n\t\t\t}\n\t\t\tthis.#refresh();\n\n\t\t\t// Advance cursor\n\t\t\tconst nextBlank = newVal.indexOf('_');\n\t\t\tif (shouldStaySelected) {\n\t\t\t\tthis.#segmentSelected = true;\n\t\t\t\tthis.#pendingTensDigit = char;\n\t\t\t} else if (nextBlank >= 0) {\n\t\t\t\tthis.#cursor.positionInSegment = nextBlank;\n\t\t\t} else if (firstBlank >= 0 && ctx.index < this.#segments.length - 1) {\n\t\t\t\tthis.#cursor.segmentIndex = ctx.index + 1;\n\t\t\t\tthis.#cursor.positionInSegment = 0;\n\t\t\t\tthis.#segmentSelected = true;\n\t\t\t} else {\n\t\t\t\tthis.#cursor.positionInSegment = Math.min(pos + 1, segment.len - 1);\n\t\t\t}\n\t\t}\n\t}\n\n\t#validateSegment(parts: DateParts, seg: SegmentConfig): string | undefined {\n\t\tconst { month, day } = parse(parts);\n\t\tif (seg.type === 'month' && (month < 0 || month > 12)) {\n\t\t\treturn settings.date.messages.invalidMonth;\n\t\t}\n\t\tif (seg.type === 'day' && (day < 0 || day > 31)) {\n\t\t\treturn settings.date.messages.invalidDay(31, 'any month');\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t#onFinalize(opts: DateOptions) {\n\t\tconst { year, month, day } = parse(this.#segmentValues);\n\t\tif (year && month && day) {\n\t\t\tconst maxDay = daysInMonth(year, month);\n\t\t\tthis.#segmentValues = {\n\t\t\t\t...this.#segmentValues,\n\t\t\t\tday: String(Math.min(day, maxDay)).padStart(2, '0'),\n\t\t\t};\n\t\t}\n\t\tthis.value = toDate(this.#segmentValues) ?? opts.defaultValue ?? undefined;\n\t}\n}\n","import Prompt, { type PromptOptions } from './prompt.js';\n\nexport interface GroupMultiSelectOptions<T extends { value: any }>\n\textends PromptOptions<T['value'][], GroupMultiSelectPrompt<T>> {\n\toptions: Record<string, T[]>;\n\tinitialValues?: T['value'][];\n\trequired?: boolean;\n\tcursorAt?: T['value'];\n\tselectableGroups?: boolean;\n}\nexport default class GroupMultiSelectPrompt<T extends { value: any }> extends Prompt<T['value'][]> {\n\toptions: (T & { group: string | boolean })[];\n\tcursor = 0;\n\t#selectableGroups: boolean;\n\n\tgetGroupItems(group: string): T[] {\n\t\treturn this.options.filter((o) => o.group === group);\n\t}\n\n\tisGroupSelected(group: string) {\n\t\tconst items = this.getGroupItems(group);\n\t\tconst value = this.value;\n\t\tif (value === undefined) {\n\t\t\treturn false;\n\t\t}\n\t\treturn items.every((i) => value.includes(i.value));\n\t}\n\n\tprivate toggleValue() {\n\t\tconst item = this.options[this.cursor];\n\t\tif (this.value === undefined) {\n\t\t\tthis.value = [];\n\t\t}\n\t\tif (item.group === true) {\n\t\t\tconst group = item.value;\n\t\t\tconst groupedItems = this.getGroupItems(group);\n\t\t\tif (this.isGroupSelected(group)) {\n\t\t\t\tthis.value = this.value.filter(\n\t\t\t\t\t(v: string) => groupedItems.findIndex((i) => i.value === v) === -1\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tthis.value = [...this.value, ...groupedItems.map((i) => i.value)];\n\t\t\t}\n\t\t\tthis.value = Array.from(new Set(this.value));\n\t\t} else {\n\t\t\tconst selected = this.value.includes(item.value);\n\t\t\tthis.value = selected\n\t\t\t\t? this.value.filter((v: T['value']) => v !== item.value)\n\t\t\t\t: [...this.value, item.value];\n\t\t}\n\t}\n\n\tconstructor(opts: GroupMultiSelectOptions<T>) {\n\t\tsuper(opts, false);\n\t\tconst { options } = opts;\n\t\tthis.#selectableGroups = opts.selectableGroups !== false;\n\t\tthis.options = Object.entries(options).flatMap(([key, option]) => [\n\t\t\t{ value: key, group: true, label: key },\n\t\t\t...option.map((opt) => ({ ...opt, group: key })),\n\t\t]) as any;\n\t\tthis.value = [...(opts.initialValues ?? [])];\n\t\tthis.cursor = Math.max(\n\t\t\tthis.options.findIndex(({ value }) => value === opts.cursorAt),\n\t\t\tthis.#selectableGroups ? 0 : 1\n\t\t);\n\n\t\tthis.on('cursor', (key) => {\n\t\t\tswitch (key) {\n\t\t\t\tcase 'left':\n\t\t\t\tcase 'up': {\n\t\t\t\t\tthis.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;\n\t\t\t\t\tconst currentIsGroup = this.options[this.cursor]?.group === true;\n\t\t\t\t\tif (!this.#selectableGroups && currentIsGroup) {\n\t\t\t\t\t\tthis.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'down':\n\t\t\t\tcase 'right': {\n\t\t\t\t\tthis.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;\n\t\t\t\t\tconst currentIsGroup = this.options[this.cursor]?.group === true;\n\t\t\t\t\tif (!this.#selectableGroups && currentIsGroup) {\n\t\t\t\t\t\tthis.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'space':\n\t\t\t\t\tthis.toggleValue();\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t});\n\t}\n}\n","import type { Key } from 'node:readline';\nimport { styleText } from 'node:util';\nimport { findTextCursor } from '../utils/cursor.js';\nimport { type Action, settings } from '../utils/index.js';\nimport Prompt, { type PromptOptions } from './prompt.js';\n\nexport interface MultiLineOptions extends PromptOptions<string, MultiLinePrompt> {\n\tplaceholder?: string;\n\tdefaultValue?: string;\n\tshowSubmit?: boolean;\n}\n\nexport default class MultiLinePrompt extends Prompt<string> {\n\t#lastKeyWasReturn = false;\n\t#showSubmit: boolean;\n\tpublic focused: 'editor' | 'submit' = 'editor';\n\n\tget userInputWithCursor() {\n\t\tif (this.state === 'submit') {\n\t\t\treturn this.userInput;\n\t\t}\n\t\tconst userInput = this.userInput;\n\t\tif (this.cursor >= userInput.length) {\n\t\t\treturn `${userInput}█`;\n\t\t}\n\t\tconst s1 = userInput.slice(0, this.cursor);\n\t\tconst s2 = userInput[this.cursor];\n\t\tconst s3 = userInput.slice(this.cursor + 1);\n\t\tif (s2 === '\\n') return `${s1}█\\n${s3}`;\n\t\treturn `${s1}${styleText('inverse', s2)}${s3}`;\n\t}\n\tget cursor() {\n\t\treturn this._cursor;\n\t}\n\t#insertAtCursor(char: string) {\n\t\tif (this.userInput.length === 0) {\n\t\t\tthis._setUserInput(char);\n\t\t\treturn;\n\t\t}\n\t\tthis._setUserInput(\n\t\t\tthis.userInput.slice(0, this.cursor) + char + this.userInput.slice(this.cursor)\n\t\t);\n\t}\n\t#handleCursor(key?: Action) {\n\t\tconst text = this.value ?? '';\n\t\tswitch (key) {\n\t\t\tcase 'up':\n\t\t\t\tthis._cursor = findTextCursor(this._cursor, 0, -1, text);\n\t\t\t\treturn;\n\t\t\tcase 'down':\n\t\t\t\tthis._cursor = findTextCursor(this._cursor, 0, 1, text);\n\t\t\t\treturn;\n\t\t\tcase 'left':\n\t\t\t\tthis._cursor = findTextCursor(this._cursor, -1, 0, text);\n\t\t\t\treturn;\n\t\t\tcase 'right':\n\t\t\t\tthis._cursor = findTextCursor(this._cursor, 1, 0, text);\n\t\t\t\treturn;\n\t\t}\n\t}\n\n\tprotected override _shouldSubmit(_char: string | undefined, _key: Key): boolean {\n\t\tif (this.#showSubmit) {\n\t\t\tif (this.focused === 'submit') {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tthis.#insertAtCursor('\\n');\n\t\t\tthis._cursor++;\n\t\t\treturn false;\n\t\t}\n\t\tconst wasReturn = this.#lastKeyWasReturn;\n\t\tthis.#lastKeyWasReturn = true;\n\t\tif (wasReturn) {\n\t\t\tif (this.userInput[this.cursor - 1] === '\\n') {\n\t\t\t\tthis._setUserInput(\n\t\t\t\t\tthis.userInput.slice(0, this.cursor - 1) + this.userInput.slice(this.cursor)\n\t\t\t\t);\n\t\t\t\tthis._cursor--;\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\tthis.#insertAtCursor('\\n');\n\t\tthis._cursor++;\n\t\treturn false;\n\t}\n\n\tconstructor(opts: MultiLineOptions) {\n\t\tsuper(opts, false);\n\t\tthis.#showSubmit = opts.showSubmit ?? false;\n\n\t\tthis.on('key', (char, key) => {\n\t\t\tif (key?.name && settings.actions.has(key.name as Action)) {\n\t\t\t\tthis.#handleCursor(key.name as Action);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (char === '\\t' && this.#showSubmit) {\n\t\t\t\tthis.focused = this.focused === 'editor' ? 'submit' : 'editor';\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (key?.name === 'return') {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.#lastKeyWasReturn = false;\n\t\t\tif (key?.name === 'backspace' && this.cursor > 0) {\n\t\t\t\tthis._setUserInput(\n\t\t\t\t\tthis.userInput.slice(0, this.cursor - 1) + this.userInput.slice(this.cursor)\n\t\t\t\t);\n\t\t\t\tthis._cursor--;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (key?.name === 'delete' && this.cursor < this.userInput.length) {\n\t\t\t\tthis._setUserInput(\n\t\t\t\t\tthis.userInput.slice(0, this.cursor) + this.userInput.slice(this.cursor + 1)\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (char) {\n\t\t\t\tif (this.#showSubmit && this.focused === 'submit') {\n\t\t\t\t\tthis.focused = 'editor';\n\t\t\t\t}\n\t\t\t\tthis.#insertAtCursor(char ?? '');\n\t\t\t\tthis._cursor++;\n\t\t\t}\n\t\t});\n\n\t\tthis.on('userInput', (input) => {\n\t\t\tthis._setValue(input);\n\t\t});\n\t\tthis.on('finalize', () => {\n\t\t\tif (!this.value) {\n\t\t\t\tthis.value = opts.defaultValue;\n\t\t\t}\n\t\t\tif (this.value === undefined) {\n\t\t\t\tthis.value = '';\n\t\t\t}\n\t\t});\n\t}\n}\n","import { findCursor } from '../utils/cursor.js';\nimport Prompt, { type PromptOptions } from './prompt.js';\n\ninterface OptionLike {\n\tvalue: any;\n\tdisabled?: boolean;\n}\n\nexport interface MultiSelectOptions<T extends OptionLike>\n\textends PromptOptions<T['value'][], MultiSelectPrompt<T>> {\n\toptions: T[];\n\tinitialValues?: T['value'][];\n\trequired?: boolean;\n\tcursorAt?: T['value'];\n}\nexport default class MultiSelectPrompt<T extends OptionLike> extends Prompt<T['value'][]> {\n\toptions: T[];\n\tcursor = 0;\n\n\tprivate get _value(): T['value'] {\n\t\treturn this.options[this.cursor].value;\n\t}\n\n\tprivate get _enabledOptions(): T[] {\n\t\treturn this.options.filter((option) => option.disabled !== true);\n\t}\n\n\tprivate toggleAll() {\n\t\tconst enabledOptions = this._enabledOptions;\n\t\tconst allSelected = this.value !== undefined && this.value.length === enabledOptions.length;\n\t\tthis.value = allSelected ? [] : enabledOptions.map((v) => v.value);\n\t}\n\n\tprivate toggleInvert() {\n\t\tconst value = this.value;\n\t\tif (!value) {\n\t\t\treturn;\n\t\t}\n\t\tconst notSelected = this._enabledOptions.filter((v) => !value.includes(v.value));\n\t\tthis.value = notSelected.map((v) => v.value);\n\t}\n\n\tprivate toggleValue() {\n\t\tif (this.value === undefined) {\n\t\t\tthis.value = [];\n\t\t}\n\t\tconst selected = this.value.includes(this._value);\n\t\tthis.value = selected\n\t\t\t? this.value.filter((value) => value !== this._value)\n\t\t\t: [...this.value, this._value];\n\t}\n\n\tconstructor(opts: MultiSelectOptions<T>) {\n\t\tsuper(opts, false);\n\n\t\tthis.options = opts.options;\n\t\tthis.value = [...(opts.initialValues ?? [])];\n\t\tconst cursor = Math.max(\n\t\t\tthis.options.findIndex(({ value }) => value === opts.cursorAt),\n\t\t\t0\n\t\t);\n\t\tthis.cursor = this.options[cursor].disabled ? findCursor<T>(cursor, 1, this.options) : cursor;\n\t\tthis.on('key', (char) => {\n\t\t\tif (char === 'a') {\n\t\t\t\tthis.toggleAll();\n\t\t\t}\n\t\t\tif (char === 'i') {\n\t\t\t\tthis.toggleInvert();\n\t\t\t}\n\t\t});\n\n\t\tthis.on('cursor', (key) => {\n\t\t\tswitch (key) {\n\t\t\t\tcase 'left':\n\t\t\t\tcase 'up':\n\t\t\t\t\tthis.cursor = findCursor<T>(this.cursor, -1, this.options);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'down':\n\t\t\t\tcase 'right':\n\t\t\t\t\tthis.cursor = findCursor<T>(this.cursor, 1, this.options);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'space':\n\t\t\t\t\tthis.toggleValue();\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t});\n\t}\n}\n","import { styleText } from 'node:util';\nimport Prompt, { type PromptOptions } from './prompt.js';\n\nexport interface PasswordOptions extends PromptOptions<string, PasswordPrompt> {\n\tmask?: string;\n}\nexport default class PasswordPrompt extends Prompt<string> {\n\tprivate _mask = '•';\n\tget cursor() {\n\t\treturn this._cursor;\n\t}\n\tget masked() {\n\t\treturn this.userInput.replaceAll(/./g, this._mask);\n\t}\n\tget userInputWithCursor() {\n\t\tif (this.state === 'submit' || this.state === 'cancel') {\n\t\t\treturn this.masked;\n\t\t}\n\t\tconst userInput = this.userInput;\n\t\tif (this.cursor >= userInput.length) {\n\t\t\treturn `${this.masked}${styleText(['inverse', 'hidden'], '_')}`;\n\t\t}\n\t\tconst masked = this.masked;\n\t\tconst s1 = masked.slice(0, this.cursor);\n\t\tconst s2 = masked.slice(this.cursor);\n\t\treturn `${s1}${styleText('inverse', s2[0])}${s2.slice(1)}`;\n\t}\n\tclear() {\n\t\tthis._clearUserInput();\n\t}\n\tconstructor({ mask, ...opts }: PasswordOptions) {\n\t\tsuper(opts);\n\t\tthis._mask = mask ?? '•';\n\t\tthis.on('userInput', (input) => {\n\t\t\tthis._setValue(input);\n\t\t});\n\t}\n}\n","import { findCursor } from '../utils/cursor.js';\nimport Prompt, { type PromptOptions } from './prompt.js';\n\nexport interface SelectOptions<T extends { value: any; disabled?: boolean }>\n\textends PromptOptions<T['value'], SelectPrompt<T>> {\n\toptions: T[];\n\tinitialValue?: T['value'];\n}\nexport default class SelectPrompt<T extends { value: any; disabled?: boolean }> extends Prompt<\n\tT['value']\n> {\n\toptions: T[];\n\tcursor = 0;\n\n\tprivate get _selectedValue() {\n\t\treturn this.options[this.cursor];\n\t}\n\n\tprivate changeValue() {\n\t\tthis.value = this._selectedValue.value;\n\t}\n\n\tconstructor(opts: SelectOptions<T>) {\n\t\tsuper(opts, false);\n\n\t\tthis.options = opts.options;\n\n\t\tconst initialCursor = this.options.findIndex(({ value }) => value === opts.initialValue);\n\t\tconst cursor = initialCursor === -1 ? 0 : initialCursor;\n\t\tthis.cursor = this.options[cursor].disabled ? findCursor<T>(cursor, 1, this.options) : cursor;\n\t\tthis.changeValue();\n\n\t\tthis.on('cursor', (key) => {\n\t\t\tswitch (key) {\n\t\t\t\tcase 'left':\n\t\t\t\tcase 'up':\n\t\t\t\t\tthis.cursor = findCursor<T>(this.cursor, -1, this.options);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'down':\n\t\t\t\tcase 'right':\n\t\t\t\t\tthis.cursor = findCursor<T>(this.cursor, 1, this.options);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tthis.changeValue();\n\t\t});\n\t}\n}\n","import Prompt, { type PromptOptions } from './prompt.js';\n\nexport interface SelectKeyOptions<T extends { value: string }>\n\textends PromptOptions<T['value'], SelectKeyPrompt<T>> {\n\toptions: T[];\n\tcaseSensitive?: boolean;\n}\nexport default class SelectKeyPrompt<T extends { value: string }> extends Prompt<T['value']> {\n\toptions: T[];\n\tcursor = 0;\n\n\tconstructor(opts: SelectKeyOptions<T>) {\n\t\tsuper(opts, false);\n\n\t\tthis.options = opts.options;\n\t\tconst caseSensitive = opts.caseSensitive === true;\n\t\tconst keys = this.options.map(({ value: [initial] }) => {\n\t\t\treturn caseSensitive ? initial : initial?.toLowerCase();\n\t\t});\n\t\tthis.cursor = Math.max(keys.indexOf(opts.initialValue), 0);\n\n\t\tthis.on('key', (key, keyInfo) => {\n\t\t\tif (!key) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst casedKey = caseSensitive && keyInfo.shift ? key.toUpperCase() : key;\n\t\t\tif (!keys.includes(casedKey)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst value = this.options.find(({ value: [initial] }) => {\n\t\t\t\treturn caseSensitive ? initial === casedKey : initial?.toLowerCase() === key;\n\t\t\t});\n\t\t\tif (value) {\n\t\t\t\tthis.value = value.value;\n\t\t\t\tthis.state = 'submit';\n\t\t\t\tthis.emit('submit');\n\t\t\t}\n\t\t});\n\t}\n}\n","import { styleText } from 'node:util';\nimport Prompt, { type PromptOptions } from './prompt.js';\n\nexport interface TextOptions extends PromptOptions<string, TextPrompt> {\n\tplaceholder?: string;\n\tdefaultValue?: string;\n}\n\nexport default class TextPrompt extends Prompt<string> {\n\tget userInputWithCursor() {\n\t\tif (this.state === 'submit') {\n\t\t\treturn this.userInput;\n\t\t}\n\t\tconst userInput = this.userInput;\n\t\tif (this.cursor >= userInput.length) {\n\t\t\treturn `${this.userInput}█`;\n\t\t}\n\t\tconst s1 = userInput.slice(0, this.cursor);\n\t\tconst [s2, ...s3] = userInput.slice(this.cursor);\n\t\treturn `${s1}${styleText('inverse', s2)}${s3.join('')}`;\n\t}\n\tget cursor() {\n\t\treturn this._cursor;\n\t}\n\tconstructor(opts: TextOptions) {\n\t\tsuper({\n\t\t\t...opts,\n\t\t\tinitialUserInput: opts.initialUserInput ?? opts.initialValue,\n\t\t});\n\n\t\tthis.on('userInput', (input) => {\n\t\t\tthis._setValue(input);\n\t\t});\n\t\tthis.on('finalize', () => {\n\t\t\tif (!this.value) {\n\t\t\t\tthis.value = opts.defaultValue;\n\t\t\t}\n\t\t\tif (this.value === undefined) {\n\t\t\t\tthis.value = '';\n\t\t\t}\n\t\t});\n\t}\n}\n","import process from 'node:process';\n\nexport default function isUnicodeSupported() {\n\tif (process.platform !== 'win32') {\n\t\treturn process.env.TERM !== 'linux'; // Linux console (kernel)\n\t}\n\n\treturn Boolean(process.env.CI)\n\t\t|| Boolean(process.env.WT_SESSION) // Windows Terminal\n\t\t|| Boolean(process.env.TERMINUS_SUBLIME) // Terminus (<0.2.27)\n\t\t|| process.env.ConEmuTask === '{cmd::Cmder}' // ConEmu and cmder\n\t\t|| process.env.TERM_PROGRAM === 'Terminus-Sublime'\n\t\t|| process.env.TERM_PROGRAM === 'vscode'\n\t\t|| process.env.TERM === 'xterm-256color'\n\t\t|| process.env.TERM === 'alacritty'\n\t\t|| process.env.TERMINAL_EMULATOR === 'JetBrains-JediTerm';\n}\n","import type { Readable, Writable } from 'node:stream';\nimport { styleText } from 'node:util';\nimport type { State } from '@clack/core';\nimport isUnicodeSupported from 'is-unicode-supported';\n\nexport const unicode = isUnicodeSupported();\nexport const isCI = (): boolean => process.env.CI === 'true';\nexport const isTTY = (output: Writable): boolean => {\n\treturn (output as Writable & { isTTY?: boolean }).isTTY === true;\n};\nexport const unicodeOr = (c: string, fallback: string) => (unicode ? c : fallback);\nexport const S_STEP_ACTIVE = unicodeOr('◆', '*');\nexport const S_STEP_CANCEL = unicodeOr('■', 'x');\nexport const S_STEP_ERROR = unicodeOr('▲', 'x');\nexport const S_STEP_SUBMIT = unicodeOr('◇', 'o');\n\nexport const S_BAR_START = unicodeOr('┌', 'T');\nexport const S_BAR = unicodeOr('│', '|');\nexport const S_BAR_END = unicodeOr('└', '—');\nexport const S_BAR_START_RIGHT = unicodeOr('┐', 'T');\nexport const S_BAR_END_RIGHT = unicodeOr('┘', '—');\n\nexport const S_RADIO_ACTIVE = unicodeOr('●', '>');\nexport const S_RADIO_INACTIVE = unicodeOr('○', ' ');\nexport const S_CHECKBOX_ACTIVE = unicodeOr('◻', '[•]');\nexport const S_CHECKBOX_SELECTED = unicodeOr('◼', '[+]');\nexport const S_CHECKBOX_INACTIVE = unicodeOr('◻', '[ ]');\nexport const S_PASSWORD_MASK = unicodeOr('▪', '•');\n\nexport const S_BAR_H = unicodeOr('─', '-');\nexport const S_CORNER_TOP_RIGHT = unicodeOr('╮', '+');\nexport const S_CONNECT_LEFT = unicodeOr('├', '+');\nexport const S_CORNER_BOTTOM_RIGHT = unicodeOr('╯', '+');\nexport const S_CORNER_BOTTOM_LEFT = unicodeOr('╰', '+');\nexport const S_CORNER_TOP_LEFT = unicodeOr('╭', '+');\n\nexport const S_INFO = unicodeOr('●', '•');\nexport const S_SUCCESS = unicodeOr('◆', '*');\nexport const S_WARN = unicodeOr('▲', '!');\nexport const S_ERROR = unicodeOr('■', 'x');\n\nexport const symbol = (state: State) => {\n\tswitch (state) {\n\t\tcase 'initial':\n\t\tcase 'active':\n\t\t\treturn styleText('cyan', S_STEP_ACTIVE);\n\t\tcase 'cancel':\n\t\t\treturn styleText('red', S_STEP_CANCEL);\n\t\tcase 'error':\n\t\t\treturn styleText('yellow', S_STEP_ERROR);\n\t\tcase 'submit':\n\t\t\treturn styleText('green', S_STEP_SUBMIT);\n\t}\n};\n\nexport const symbolBar = (state: State) => {\n\tswitch (state) {\n\t\tcase 'initial':\n\t\tcase 'active':\n\t\t\treturn styleText('cyan', S_BAR);\n\t\tcase 'cancel':\n\t\t\treturn styleText('red', S_BAR);\n\t\tcase 'error':\n\t\t\treturn styleText('yellow', S_BAR);\n\t\tcase 'submit':\n\t\t\treturn styleText('green', S_BAR);\n\t}\n};\n\nexport interface CommonOptions {\n\tinput?: Readable;\n\toutput?: Writable;\n\tsignal?: AbortSignal;\n\twithGuide?: boolean;\n}\n","import { styleText } from 'node:util';\nimport { getColumns, getRows } from '@clack/core';\nimport { wrapAnsi } from 'fast-wrap-ansi';\nimport type { CommonOptions } from './common.js';\n\nexport interface LimitOptionsParams<TOption> extends CommonOptions {\n\toptions: TOption[];\n\tcursor: number;\n\tstyle: (option: TOption, active: boolean) => string;\n\tmaxItems?: number;\n\tcolumnPadding?: number;\n\trowPadding?: number;\n}\n\nconst trimLines = (\n\tgroups: Array<string[]>,\n\tinitialLineCount: number,\n\tstartIndex: number,\n\tendIndex: number,\n\tmaxLines: number\n) => {\n\tlet lineCount = initialLineCount;\n\tlet removals = 0;\n\tfor (let i = startIndex; i < endIndex; i++) {\n\t\tconst group = groups[i];\n\t\tlineCount = lineCount - group.length;\n\t\tremovals++;\n\t\tif (lineCount <= maxLines) {\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn { lineCount, removals };\n};\n\nexport const limitOptions = <TOption>({\n\tcursor,\n\toptions,\n\tstyle,\n\toutput = process.stdout,\n\tmaxItems = Number.POSITIVE_INFINITY,\n\tcolumnPadding = 0,\n\trowPadding = 4,\n}: LimitOptionsParams<TOption>): string[] => {\n\tconst columns = getColumns(output);\n\tconst maxWidth = columns - columnPadding;\n\tconst rows = getRows(output);\n\tconst overflowFormat = styleText('dim', '...');\n\n\tconst outputMaxItems = Math.max(rows - rowPadding, 0);\n\t// We clamp to minimum 5 because anything less doesn't make sense UX wise\n\tconst computedMaxItems = Math.max(Math.min(maxItems, outputMaxItems), 5);\n\tlet slidingWindowLocation = 0;\n\n\tif (cursor >= computedMaxItems - 3) {\n\t\tslidingWindowLocation = Math.max(\n\t\t\tMath.min(cursor - computedMaxItems + 3, options.length - computedMaxItems),\n\t\t\t0\n\t\t);\n\t}\n\n\tlet shouldRenderTopEllipsis = computedMaxItems < options.length && slidingWindowLocation > 0;\n\tlet shouldRenderBottomEllipsis =\n\t\tcomputedMaxItems < options.length && slidingWindowLocation + computedMaxItems < options.length;\n\n\tconst slidingWindowLocationEnd = Math.min(\n\t\tslidingWindowLocation + computedMaxItems,\n\t\toptions.length\n\t);\n\tconst lineGroups: Array<string[]> = [];\n\tlet lineCount = 0;\n\tif (shouldRenderTopEllipsis) {\n\t\tlineCount++;\n\t}\n\tif (shouldRenderBottomEllipsis) {\n\t\tlineCount++;\n\t}\n\n\tconst slidingWindowLocationWithEllipsis =\n\t\tslidingWindowLocation + (shouldRenderTopEllipsis ? 1 : 0);\n\tconst slidingWindowLocationEndWithEllipsis =\n\t\tslidingWindowLocationEnd - (shouldRenderBottomEllipsis ? 1 : 0);\n\n\tfor (let i = slidingWindowLocationWithEllipsis; i < slidingWindowLocationEndWithEllipsis; i++) {\n\t\tconst wrappedLines = wrapAnsi(style(options[i], i === cursor), maxWidth, {\n\t\t\thard: true,\n\t\t\ttrim: false,\n\t\t}).split('\\n');\n\t\tlineGroups.push(wrappedLines);\n\t\tlineCount += wrappedLines.length;\n\t}\n\n\tif (lineCount > outputMaxItems) {\n\t\tlet precedingRemovals = 0;\n\t\tlet followingRemovals = 0;\n\t\tlet newLineCount = lineCount;\n\t\tconst cursorGroupIndex = cursor - slidingWindowLocationWithEllipsis;\n\t\tconst trimLinesLocal = (startIndex: number, endIndex: number) =>\n\t\t\ttrimLines(lineGroups, newLineCount, startIndex, endIndex, outputMaxItems);\n\n\t\tif (shouldRenderTopEllipsis) {\n\t\t\t({ lineCount: newLineCount, removals: precedingRemovals } = trimLinesLocal(\n\t\t\t\t0,\n\t\t\t\tcursorGroupIndex\n\t\t\t));\n\t\t\tif (newLineCount > outputMaxItems) {\n\t\t\t\t({ lineCount: newLineCount, removals: followingRemovals } = trimLinesLocal(\n\t\t\t\t\tcursorGroupIndex + 1,\n\t\t\t\t\tlineGroups.length\n\t\t\t\t));\n\t\t\t}\n\t\t} else {\n\t\t\t({ lineCount: newLineCount, removals: followingRemovals } = trimLinesLocal(\n\t\t\t\tcursorGroupIndex + 1,\n\t\t\t\tlineGroups.length\n\t\t\t));\n\t\t\tif (newLineCount > outputMaxItems) {\n\t\t\t\t({ lineCount: newLineCount, removals: precedingRemovals } = trimLinesLocal(\n\t\t\t\t\t0,\n\t\t\t\t\tcursorGroupIndex\n\t\t\t\t));\n\t\t\t}\n\t\t}\n\n\t\tif (precedingRemovals > 0) {\n\t\t\tshouldRenderTopEllipsis = true;\n\t\t\tlineGroups.splice(0, precedingRemovals);\n\t\t}\n\t\tif (followingRemovals > 0) {\n\t\t\tshouldRenderBottomEllipsis = true;\n\t\t\tlineGroups.splice(lineGroups.length - followingRemovals, followingRemovals);\n\t\t}\n\t}\n\n\tconst result: string[] = [];\n\tif (shouldRenderTopEllipsis) {\n\t\tresult.push(overflowFormat);\n\t}\n\tfor (const lineGroup of lineGroups) {\n\t\tfor (const line of lineGroup) {\n\t\t\tresult.push(line);\n\t\t}\n\t}\n\tif (shouldRenderBottomEllipsis) {\n\t\tresult.push(overflowFormat);\n\t}\n\n\treturn result;\n};\n","import { styleText } from 'node:util';\nimport { AutocompletePrompt, settings } from '@clack/core';\nimport {\n\ttype CommonOptions,\n\tS_BAR,\n\tS_BAR_END,\n\tS_CHECKBOX_INACTIVE,\n\tS_CHECKBOX_SELECTED,\n\tS_RADIO_ACTIVE,\n\tS_RADIO_INACTIVE,\n\tsymbol,\n} from './common.js';\nimport { limitOptions } from './limit-options.js';\nimport type { Option } from './select.js';\n\nfunction getLabel<T>(option: Option<T>) {\n\treturn option.label ?? String(option.value ?? '');\n}\n\nfunction getFilteredOption<T>(searchText: string, option: Option<T>): boolean {\n\tif (!searchText) {\n\t\treturn true;\n\t}\n\tconst label = (option.label ?? String(option.value ?? '')).toLowerCase();\n\tconst hint = (option.hint ?? '').toLowerCase();\n\tconst value = String(option.value).toLowerCase();\n\tconst term = searchText.toLowerCase();\n\n\treturn label.includes(term) || hint.includes(term) || value.includes(term);\n}\n\nfunction getSelectedOptions<T>(values: T[], options: Option<T>[]): Option<T>[] {\n\tconst results: Option<T>[] = [];\n\n\tfor (const option of options) {\n\t\tif (values.includes(option.value)) {\n\t\t\tresults.push(option);\n\t\t}\n\t}\n\n\treturn results;\n}\n\ninterface AutocompleteSharedOptions<Value> extends CommonOptions {\n\t/**\n\t * The message to display to the user.\n\t */\n\tmessage: string;\n\t/**\n\t * Available options for the autocomplete prompt.\n\t */\n\toptions: Option<Value>[] | ((this: AutocompletePrompt<Option<Value>>) => Option<Value>[]);\n\t/**\n\t * Maximum number of items to display at once.\n\t */\n\tmaxItems?: number;\n\t/**\n\t * Placeholder text to display when no input is provided.\n\t */\n\tplaceholder?: string;\n\t/**\n\t * Validates the value\n\t */\n\tvalidate?: (value: Value | Value[] | undefined) => string | Error | undefined;\n\t/**\n\t * Custom filter function to match options against search input.\n\t * If not provided, a default filter that matches label, hint, and value is used.\n\t */\n\tfilter?: (search: string, option: Option<Value>) => boolean;\n}\n\nexport interface AutocompleteOptions<Value> extends AutocompleteSharedOptions<Value> {\n\t/**\n\t * The initial selected value.\n\t */\n\tinitialValue?: Value;\n\t/**\n\t * The initial user input\n\t */\n\tinitialUserInput?: string;\n}\n\nexport const autocomplete = <Value>(opts: AutocompleteOptions<Value>) => {\n\tconst prompt = new AutocompletePrompt({\n\t\toptions: opts.options,\n\t\tinitialValue: opts.initialValue ? [opts.initialValue] : undefined,\n\t\tinitialUserInput: opts.initialUserInput,\n\t\tplaceholder: opts.placeholder,\n\t\tfilter:\n\t\t\topts.filter ??\n\t\t\t((search: string, opt: Option<Value>) => {\n\t\t\t\treturn getFilteredOption(search, opt);\n\t\t\t}),\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\toutput: opts.output,\n\t\tvalidate: opts.validate,\n\t\trender() {\n\t\t\tconst hasGuide = opts.withGuide ?? settings.withGuide;\n\t\t\t// Title and message display\n\t\t\tconst headings = hasGuide\n\t\t\t\t? [`${styleText('gray', S_BAR)}`, `${symbol(this.state)} ${opts.message}`]\n\t\t\t\t: [`${symbol(this.state)} ${opts.message}`];\n\t\t\tconst userInput = this.userInput;\n\t\t\tconst options = this.options;\n\t\t\tconst placeholder = opts.placeholder;\n\t\t\tconst showPlaceholder = userInput === '' && placeholder !== undefined;\n\t\t\tconst opt = (option: Option<Value>, state: 'inactive' | 'active' | 'disabled') => {\n\t\t\t\tconst label = getLabel(option);\n\t\t\t\tconst hint =\n\t\t\t\t\toption.hint && option.value === this.focusedValue\n\t\t\t\t\t\t? styleText('dim', ` (${option.hint})`)\n\t\t\t\t\t\t: '';\n\t\t\t\tswitch (state) {\n\t\t\t\t\tcase 'active':\n\t\t\t\t\t\treturn `${styleText('green', S_RADIO_ACTIVE)} ${label}${hint}`;\n\t\t\t\t\tcase 'inactive':\n\t\t\t\t\t\treturn `${styleText('dim', S_RADIO_INACTIVE)} ${styleText('dim', label)}`;\n\t\t\t\t\tcase 'disabled':\n\t\t\t\t\t\treturn `${styleText('gray', S_RADIO_INACTIVE)} ${styleText(['strikethrough', 'gray'], label)}`;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// Handle different states\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'submit': {\n\t\t\t\t\t// Show selected value\n\t\t\t\t\tconst selected = getSelectedOptions(this.selectedValues, options);\n\t\t\t\t\tconst label =\n\t\t\t\t\t\tselected.length > 0 ? ` ${styleText('dim', selected.map(getLabel).join(', '))}` : '';\n\t\t\t\t\tconst submitPrefix = hasGuide ? styleText('gray', S_BAR) : '';\n\t\t\t\t\treturn `${headings.join('\\n')}\\n${submitPrefix}${label}`;\n\t\t\t\t}\n\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst userInputText = userInput\n\t\t\t\t\t\t? ` ${styleText(['strikethrough', 'dim'], userInput)}`\n\t\t\t\t\t\t: '';\n\t\t\t\t\tconst cancelPrefix = hasGuide ? styleText('gray', S_BAR) : '';\n\t\t\t\t\treturn `${headings.join('\\n')}\\n${cancelPrefix}${userInputText}`;\n\t\t\t\t}\n\n\t\t\t\tdefault: {\n\t\t\t\t\tconst barStyle = this.state === 'error' ? 'yellow' : 'cyan';\n\t\t\t\t\tconst guidePrefix = hasGuide ? `${styleText(barStyle, S_BAR)} ` : '';\n\t\t\t\t\tconst guidePrefixEnd = hasGuide ? styleText(barStyle, S_BAR_END) : '';\n\t\t\t\t\t// Display cursor position - show plain text in navigation mode\n\t\t\t\t\tlet searchText = '';\n\t\t\t\t\tif (this.isNavigating || showPlaceholder) {\n\t\t\t\t\t\tconst searchTextValue = showPlaceholder ? placeholder : userInput;\n\t\t\t\t\t\tsearchText = searchTextValue !== '' ? ` ${styleText('dim', searchTextValue)}` : '';\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsearchText = ` ${this.userInputWithCursor}`;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Show match count if filtered\n\t\t\t\t\tconst matches =\n\t\t\t\t\t\tthis.filteredOptions.length !== options.length\n\t\t\t\t\t\t\t? styleText(\n\t\t\t\t\t\t\t\t\t'dim',\n\t\t\t\t\t\t\t\t\t` (${this.filteredOptions.length} match${this.filteredOptions.length === 1 ? '' : 'es'})`\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: '';\n\n\t\t\t\t\t// No matches message\n\t\t\t\t\tconst noResults =\n\t\t\t\t\t\tthis.filteredOptions.length === 0 && userInput\n\t\t\t\t\t\t\t? [`${guidePrefix}${styleText('yellow', 'No matches found')}`]\n\t\t\t\t\t\t\t: [];\n\n\t\t\t\t\tconst validationError =\n\t\t\t\t\t\tthis.state === 'error' ? [`${guidePrefix}${styleText('yellow', this.error)}`] : [];\n\n\t\t\t\t\tif (hasGuide) {\n\t\t\t\t\t\theadings.push(`${guidePrefix.trimEnd()}`);\n\t\t\t\t\t}\n\t\t\t\t\theadings.push(\n\t\t\t\t\t\t`${guidePrefix}${styleText('dim', 'Search:')}${searchText}${matches}`,\n\t\t\t\t\t\t...noResults,\n\t\t\t\t\t\t...validationError\n\t\t\t\t\t);\n\n\t\t\t\t\t// Show instructions\n\t\t\t\t\tconst instructions = [\n\t\t\t\t\t\t`${styleText('dim', '↑/↓')} to select`,\n\t\t\t\t\t\t`${styleText('dim', 'Enter:')} confirm`,\n\t\t\t\t\t\t`${styleText('dim', 'Type:')} to search`,\n\t\t\t\t\t];\n\n\t\t\t\t\tconst footers = [`${guidePrefix}${instructions.join(' • ')}`, guidePrefixEnd];\n\n\t\t\t\t\t// Render options with selection\n\t\t\t\t\tconst displayOptions =\n\t\t\t\t\t\tthis.filteredOptions.length === 0\n\t\t\t\t\t\t\t? []\n\t\t\t\t\t\t\t: limitOptions({\n\t\t\t\t\t\t\t\t\tcursor: this.cursor,\n\t\t\t\t\t\t\t\t\toptions: this.filteredOptions,\n\t\t\t\t\t\t\t\t\tcolumnPadding: hasGuide ? 3 : 0, // for `| ` when guide is shown\n\t\t\t\t\t\t\t\t\trowPadding: headings.length + footers.length,\n\t\t\t\t\t\t\t\t\tstyle: (option, active) => {\n\t\t\t\t\t\t\t\t\t\treturn opt(\n\t\t\t\t\t\t\t\t\t\t\toption,\n\t\t\t\t\t\t\t\t\t\t\toption.disabled ? 'disabled' : active ? 'active' : 'inactive'\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tmaxItems: opts.maxItems,\n\t\t\t\t\t\t\t\t\toutput: opts.output,\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t// Return the formatted prompt\n\t\t\t\t\treturn [\n\t\t\t\t\t\t...headings,\n\t\t\t\t\t\t...displayOptions.map((option) => `${guidePrefix}${option}`),\n\t\t\t\t\t\t...footers,\n\t\t\t\t\t].join('\\n');\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t});\n\n\t// Return the result or cancel symbol\n\treturn prompt.prompt() as Promise<Value | symbol>;\n};\n\n// Type definition for the autocompleteMultiselect component\nexport interface AutocompleteMultiSelectOptions<Value> extends AutocompleteSharedOptions<Value> {\n\t/**\n\t * The initial selected values\n\t */\n\tinitialValues?: Value[];\n\t/**\n\t * If true, at least one option must be selected\n\t */\n\trequired?: boolean;\n}\n\n/**\n * Integrated autocomplete multiselect - combines type-ahead filtering with multiselect in one UI\n */\nexport const autocompleteMultiselect = <Value>(opts: AutocompleteMultiSelectOptions<Value>) => {\n\tconst formatOption = (\n\t\toption: Option<Value>,\n\t\tactive: boolean,\n\t\tselectedValues: Value[],\n\t\tfocusedValue: Value | undefined\n\t) => {\n\t\tconst isSelected = selectedValues.includes(option.value);\n\t\tconst label = option.label ?? String(option.value ?? '');\n\t\tconst hint =\n\t\t\toption.hint && focusedValue !== undefined && option.value === focusedValue\n\t\t\t\t? styleText('dim', ` (${option.hint})`)\n\t\t\t\t: '';\n\t\tconst checkbox = isSelected\n\t\t\t? styleText('green', S_CHECKBOX_SELECTED)\n\t\t\t: styleText('dim', S_CHECKBOX_INACTIVE);\n\n\t\tif (option.disabled) {\n\t\t\treturn `${styleText('gray', S_CHECKBOX_INACTIVE)} ${styleText(['strikethrough', 'gray'], label)}`;\n\t\t}\n\t\tif (active) {\n\t\t\treturn `${checkbox} ${label}${hint}`;\n\t\t}\n\t\treturn `${checkbox} ${styleText('dim', label)}`;\n\t};\n\n\t// Create text prompt which we'll use as foundation\n\tconst prompt = new AutocompletePrompt<Option<Value>>({\n\t\toptions: opts.options,\n\t\tmultiple: true,\n\t\tplaceholder: opts.placeholder,\n\t\tfilter:\n\t\t\topts.filter ??\n\t\t\t((search, opt) => {\n\t\t\t\treturn getFilteredOption(search, opt);\n\t\t\t}),\n\t\tvalidate: () => {\n\t\t\tif (opts.required && prompt.selectedValues.length === 0) {\n\t\t\t\treturn 'Please select at least one item';\n\t\t\t}\n\t\t\treturn undefined;\n\t\t},\n\t\tinitialValue: opts.initialValues,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\toutput: opts.output,\n\t\trender() {\n\t\t\tconst hasGuide = opts.withGuide ?? settings.withGuide;\n\t\t\t// Title and symbol\n\t\t\tconst title = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${symbol(this.state)} ${\n\t\t\t\topts.message\n\t\t\t}\\n`;\n\n\t\t\t// Selection counter\n\t\t\tconst userInput = this.userInput;\n\t\t\tconst placeholder = opts.placeholder;\n\t\t\tconst showPlaceholder = userInput === '' && placeholder !== undefined;\n\n\t\t\t// Search input display\n\t\t\tconst searchText =\n\t\t\t\tthis.isNavigating || showPlaceholder\n\t\t\t\t\t? styleText('dim', showPlaceholder ? placeholder : userInput) // Just show plain text when in navigation mode\n\t\t\t\t\t: this.userInputWithCursor;\n\n\t\t\tconst options = this.options;\n\n\t\t\tconst matches =\n\t\t\t\tthis.filteredOptions.length !== options.length\n\t\t\t\t\t? styleText(\n\t\t\t\t\t\t\t'dim',\n\t\t\t\t\t\t\t` (${this.filteredOptions.length} match${this.filteredOptions.length === 1 ? '' : 'es'})`\n\t\t\t\t\t\t)\n\t\t\t\t\t: '';\n\n\t\t\t// Render prompt state\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'submit': {\n\t\t\t\t\treturn `${title}${hasGuide ? `${styleText('gray', S_BAR)} ` : ''}${styleText(\n\t\t\t\t\t\t'dim',\n\t\t\t\t\t\t`${this.selectedValues.length} items selected`\n\t\t\t\t\t)}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\treturn `${title}${hasGuide ? `${styleText('gray', S_BAR)} ` : ''}${styleText(\n\t\t\t\t\t\t['strikethrough', 'dim'],\n\t\t\t\t\t\tuserInput\n\t\t\t\t\t)}`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst barStyle = this.state === 'error' ? 'yellow' : 'cyan';\n\t\t\t\t\tconst guidePrefix = hasGuide ? `${styleText(barStyle, S_BAR)} ` : '';\n\t\t\t\t\tconst guidePrefixEnd = hasGuide ? styleText(barStyle, S_BAR_END) : '';\n\t\t\t\t\t// Instructions\n\t\t\t\t\tconst instructions = [\n\t\t\t\t\t\t`${styleText('dim', '↑/↓')} to navigate`,\n\t\t\t\t\t\t`${styleText('dim', this.isNavigating ? 'Space/Tab:' : 'Tab:')} select`,\n\t\t\t\t\t\t`${styleText('dim', 'Enter:')} confirm`,\n\t\t\t\t\t\t`${styleText('dim', 'Type:')} to search`,\n\t\t\t\t\t];\n\n\t\t\t\t\t// No results message\n\t\t\t\t\tconst noResults =\n\t\t\t\t\t\tthis.filteredOptions.length === 0 && userInput\n\t\t\t\t\t\t\t? [`${guidePrefix}${styleText('yellow', 'No matches found')}`]\n\t\t\t\t\t\t\t: [];\n\n\t\t\t\t\tconst errorMessage =\n\t\t\t\t\t\tthis.state === 'error' ? [`${guidePrefix}${styleText('yellow', this.error)}`] : [];\n\n\t\t\t\t\t// Calculate header and footer line counts for rowPadding\n\t\t\t\t\tconst headerLines = [\n\t\t\t\t\t\t...`${title}${hasGuide ? styleText(barStyle, S_BAR) : ''}`.split('\\n'),\n\t\t\t\t\t\t`${guidePrefix}${styleText('dim', 'Search:')} ${searchText}${matches}`,\n\t\t\t\t\t\t...noResults,\n\t\t\t\t\t\t...errorMessage,\n\t\t\t\t\t];\n\t\t\t\t\tconst footerLines = [`${guidePrefix}${instructions.join(' • ')}`, guidePrefixEnd];\n\n\t\t\t\t\t// Get limited options for display\n\t\t\t\t\tconst displayOptions = limitOptions({\n\t\t\t\t\t\tcursor: this.cursor,\n\t\t\t\t\t\toptions: this.filteredOptions,\n\t\t\t\t\t\tstyle: (option, active) =>\n\t\t\t\t\t\t\tformatOption(option, active, this.selectedValues, this.focusedValue),\n\t\t\t\t\t\tmaxItems: opts.maxItems,\n\t\t\t\t\t\toutput: opts.output,\n\t\t\t\t\t\trowPadding: headerLines.length + footerLines.length,\n\t\t\t\t\t});\n\n\t\t\t\t\t// Build the prompt display\n\t\t\t\t\treturn [\n\t\t\t\t\t\t...headerLines,\n\t\t\t\t\t\t...displayOptions.map((option) => `${guidePrefix}${option}`),\n\t\t\t\t\t\t...footerLines,\n\t\t\t\t\t].join('\\n');\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t});\n\n\t// Return the result or cancel symbol\n\treturn prompt.prompt() as Promise<Value[] | symbol>;\n};\n","import type { Writable } from 'node:stream';\nimport { getColumns, settings } from '@clack/core';\nimport stringWidth from 'fast-string-width';\nimport { wrapAnsi } from 'fast-wrap-ansi';\nimport {\n\ttype CommonOptions,\n\tS_BAR,\n\tS_BAR_END,\n\tS_BAR_END_RIGHT,\n\tS_BAR_H,\n\tS_BAR_START,\n\tS_BAR_START_RIGHT,\n\tS_CORNER_BOTTOM_LEFT,\n\tS_CORNER_BOTTOM_RIGHT,\n\tS_CORNER_TOP_LEFT,\n\tS_CORNER_TOP_RIGHT,\n} from './common.js';\n\nexport type BoxAlignment = 'left' | 'center' | 'right';\n\ntype BoxSymbols = [topLeft: string, topRight: string, bottomLeft: string, bottomRight: string];\n\nconst roundedSymbols: BoxSymbols = [\n\tS_CORNER_TOP_LEFT,\n\tS_CORNER_TOP_RIGHT,\n\tS_CORNER_BOTTOM_LEFT,\n\tS_CORNER_BOTTOM_RIGHT,\n];\nconst squareSymbols: BoxSymbols = [S_BAR_START, S_BAR_START_RIGHT, S_BAR_END, S_BAR_END_RIGHT];\n\nexport interface BoxOptions extends CommonOptions {\n\tcontentAlign?: BoxAlignment;\n\ttitleAlign?: BoxAlignment;\n\twidth?: number | 'auto';\n\ttitlePadding?: number;\n\tcontentPadding?: number;\n\trounded?: boolean;\n\tformatBorder?: (text: string) => string;\n}\n\nfunction getPaddingForLine(\n\tlineLength: number,\n\tinnerWidth: number,\n\tpadding: number,\n\tcontentAlign: BoxAlignment | undefined\n): [number, number] {\n\tlet leftPadding = padding;\n\tlet rightPadding = padding;\n\tif (contentAlign === 'center') {\n\t\tleftPadding = Math.floor((innerWidth - lineLength) / 2);\n\t} else if (contentAlign === 'right') {\n\t\tleftPadding = innerWidth - lineLength - padding;\n\t}\n\n\trightPadding = innerWidth - leftPadding - lineLength;\n\n\treturn [leftPadding, rightPadding];\n}\n\nconst defaultFormatBorder = (text: string) => text;\n\nexport const box = (message = '', title = '', opts?: BoxOptions) => {\n\tconst output: Writable = opts?.output ?? process.stdout;\n\tconst columns = getColumns(output);\n\tconst borderWidth = 1;\n\tconst borderTotalWidth = borderWidth * 2;\n\tconst titlePadding = opts?.titlePadding ?? 1;\n\tconst contentPadding = opts?.contentPadding ?? 2;\n\tconst width = opts?.width === undefined || opts.width === 'auto' ? 1 : Math.min(1, opts.width);\n\tconst hasGuide = opts?.withGuide ?? settings.withGuide;\n\tconst linePrefix = !hasGuide ? '' : `${S_BAR} `;\n\tconst formatBorder = opts?.formatBorder ?? defaultFormatBorder;\n\tconst symbols = (opts?.rounded ? roundedSymbols : squareSymbols).map(formatBorder);\n\tconst hSymbol = formatBorder(S_BAR_H);\n\tconst vSymbol = formatBorder(S_BAR);\n\tconst linePrefixWidth = stringWidth(linePrefix);\n\tconst titleWidth = stringWidth(title);\n\tconst maxBoxWidth = columns - linePrefixWidth;\n\tlet boxWidth = Math.floor(columns * width) - linePrefixWidth;\n\tif (opts?.width === 'auto') {\n\t\tconst lines = message.split('\\n');\n\t\tlet longestLine = titleWidth + titlePadding * 2;\n\t\tfor (const line of lines) {\n\t\t\tconst lineWithPadding = stringWidth(line) + contentPadding * 2;\n\t\t\tif (lineWithPadding > longestLine) {\n\t\t\t\tlongestLine = lineWithPadding;\n\t\t\t}\n\t\t}\n\t\tconst longestLineWidth = longestLine + borderTotalWidth;\n\t\tif (longestLineWidth < boxWidth) {\n\t\t\tboxWidth = longestLineWidth;\n\t\t}\n\t}\n\tif (boxWidth % 2 !== 0) {\n\t\tif (boxWidth < maxBoxWidth) {\n\t\t\tboxWidth++;\n\t\t} else {\n\t\t\tboxWidth--;\n\t\t}\n\t}\n\tconst innerWidth = boxWidth - borderTotalWidth;\n\tconst maxTitleLength = innerWidth - titlePadding * 2;\n\tconst truncatedTitle =\n\t\ttitleWidth > maxTitleLength ? `${title.slice(0, maxTitleLength - 3)}...` : title;\n\tconst [titlePaddingLeft, titlePaddingRight] = getPaddingForLine(\n\t\tstringWidth(truncatedTitle),\n\t\tinnerWidth,\n\t\ttitlePadding,\n\t\topts?.titleAlign\n\t);\n\tconst wrappedMessage = wrapAnsi(message, innerWidth - contentPadding * 2, {\n\t\thard: true,\n\t\ttrim: false,\n\t});\n\toutput.write(\n\t\t`${linePrefix}${symbols[0]}${hSymbol.repeat(titlePaddingLeft)}${truncatedTitle}${hSymbol.repeat(titlePaddingRight)}${symbols[1]}\\n`\n\t);\n\tconst wrappedLines = wrappedMessage.split('\\n');\n\tfor (const line of wrappedLines) {\n\t\tconst [leftLinePadding, rightLinePadding] = getPaddingForLine(\n\t\t\tstringWidth(line),\n\t\t\tinnerWidth,\n\t\t\tcontentPadding,\n\t\t\topts?.contentAlign\n\t\t);\n\t\toutput.write(\n\t\t\t`${linePrefix}${vSymbol}${' '.repeat(leftLinePadding)}${line}${' '.repeat(rightLinePadding)}${vSymbol}\\n`\n\t\t);\n\t}\n\toutput.write(`${linePrefix}${symbols[2]}${hSymbol.repeat(innerWidth)}${symbols[3]}\\n`);\n};\n","import { styleText } from 'node:util';\nimport { ConfirmPrompt, settings, wrapTextWithPrefix } from '@clack/core';\nimport {\n\ttype CommonOptions,\n\tS_BAR,\n\tS_BAR_END,\n\tS_RADIO_ACTIVE,\n\tS_RADIO_INACTIVE,\n\tsymbol,\n} from './common.js';\n\nexport interface ConfirmOptions extends CommonOptions {\n\tmessage: string;\n\tactive?: string;\n\tinactive?: string;\n\tinitialValue?: boolean;\n\tvertical?: boolean;\n}\nexport const confirm = (opts: ConfirmOptions) => {\n\tconst active = opts.active ?? 'Yes';\n\tconst inactive = opts.inactive ?? 'No';\n\treturn new ConfirmPrompt({\n\t\tactive,\n\t\tinactive,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\toutput: opts.output,\n\t\tinitialValue: opts.initialValue ?? true,\n\t\trender() {\n\t\t\tconst hasGuide = opts.withGuide ?? settings.withGuide;\n\t\t\tconst titlePrefix = `${symbol(this.state)} `;\n\t\t\tconst titlePrefixBar = hasGuide ? `${styleText('gray', S_BAR)} ` : '';\n\t\t\tconst messageLines = wrapTextWithPrefix(\n\t\t\t\topts.output,\n\t\t\t\topts.message,\n\t\t\t\ttitlePrefixBar,\n\t\t\t\ttitlePrefix\n\t\t\t);\n\t\t\tconst title = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${messageLines}\\n`;\n\t\t\tconst value = this.value ? active : inactive;\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst submitPrefix = hasGuide ? `${styleText('gray', S_BAR)} ` : '';\n\t\t\t\t\treturn `${title}${submitPrefix}${styleText('dim', value)}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst cancelPrefix = hasGuide ? `${styleText('gray', S_BAR)} ` : '';\n\t\t\t\t\treturn `${title}${cancelPrefix}${styleText(['strikethrough', 'dim'], value)}${\n\t\t\t\t\t\thasGuide ? `\\n${styleText('gray', S_BAR)}` : ''\n\t\t\t\t\t}`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst defaultPrefix = hasGuide ? `${styleText('cyan', S_BAR)} ` : '';\n\t\t\t\t\tconst defaultPrefixEnd = hasGuide ? styleText('cyan', S_BAR_END) : '';\n\t\t\t\t\treturn `${title}${defaultPrefix}${\n\t\t\t\t\t\tthis.value\n\t\t\t\t\t\t\t? `${styleText('green', S_RADIO_ACTIVE)} ${active}`\n\t\t\t\t\t\t\t: `${styleText('dim', S_RADIO_INACTIVE)} ${styleText('dim', active)}`\n\t\t\t\t\t}${opts.vertical ? (hasGuide ? `\\n${styleText('cyan', S_BAR)} ` : '\\n') : ` ${styleText('dim', '/')} `}${\n\t\t\t\t\t\t!this.value\n\t\t\t\t\t\t\t? `${styleText('green', S_RADIO_ACTIVE)} ${inactive}`\n\t\t\t\t\t\t\t: `${styleText('dim', S_RADIO_INACTIVE)} ${styleText('dim', inactive)}`\n\t\t\t\t\t}\\n${defaultPrefixEnd}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<boolean | symbol>;\n};\n","import { styleText } from 'node:util';\nimport type { DateFormat, State } from '@clack/core';\nimport { DatePrompt, settings } from '@clack/core';\nimport { type CommonOptions, S_BAR, S_BAR_END, symbol } from './common.js';\n\nexport type { DateFormat };\n\nexport interface DateOptions extends CommonOptions {\n\tmessage: string;\n\tformat?: DateFormat;\n\tlocale?: string;\n\tdefaultValue?: Date;\n\tinitialValue?: Date;\n\tminDate?: Date;\n\tmaxDate?: Date;\n\tvalidate?: (value: Date | undefined) => string | Error | undefined;\n}\n\nexport const date = (opts: DateOptions) => {\n\tconst validate = opts.validate;\n\treturn new DatePrompt({\n\t\t...opts,\n\t\tvalidate(value: Date | undefined) {\n\t\t\tif (value === undefined) {\n\t\t\t\tif (opts.defaultValue !== undefined) return undefined;\n\t\t\t\tif (validate) return validate(value);\n\t\t\t\treturn settings.date.messages.required;\n\t\t\t}\n\t\t\tconst iso = (d: Date) => d.toISOString().slice(0, 10);\n\t\t\tif (opts.minDate && iso(value) < iso(opts.minDate)) {\n\t\t\t\treturn settings.date.messages.afterMin(opts.minDate);\n\t\t\t}\n\t\t\tif (opts.maxDate && iso(value) > iso(opts.maxDate)) {\n\t\t\t\treturn settings.date.messages.beforeMax(opts.maxDate);\n\t\t\t}\n\t\t\tif (validate) return validate(value);\n\t\t\treturn undefined;\n\t\t},\n\t\trender() {\n\t\t\tconst hasGuide = (opts?.withGuide ?? settings.withGuide) !== false;\n\t\t\tconst titlePrefix = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${symbol(this.state)} `;\n\t\t\tconst title = `${titlePrefix}${opts.message}\\n`;\n\n\t\t\tconst state = this.state !== 'initial' ? this.state : 'active';\n\n\t\t\tconst userInput = renderDate(this, state);\n\t\t\tconst value = this.value instanceof Date ? this.formattedValue : '';\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'error': {\n\t\t\t\t\tconst errorText = this.error ? ` ${styleText('yellow', this.error)}` : '';\n\t\t\t\t\tconst bar = hasGuide ? `${styleText('yellow', S_BAR)} ` : '';\n\t\t\t\t\tconst barEnd = hasGuide ? styleText('yellow', S_BAR_END) : '';\n\t\t\t\t\treturn `${title.trim()}\\n${bar}${userInput}\\n${barEnd}${errorText}\\n`;\n\t\t\t\t}\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst valueText = value ? ` ${styleText('dim', value)}` : '';\n\t\t\t\t\tconst bar = hasGuide ? styleText('gray', S_BAR) : '';\n\t\t\t\t\treturn `${title}${bar}${valueText}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst valueText = value ? ` ${styleText(['strikethrough', 'dim'], value)}` : '';\n\t\t\t\t\tconst bar = hasGuide ? styleText('gray', S_BAR) : '';\n\t\t\t\t\treturn `${title}${bar}${valueText}${value.trim() ? `\\n${bar}` : ''}`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst bar = hasGuide ? `${styleText('cyan', S_BAR)} ` : '';\n\t\t\t\t\tconst barEnd = hasGuide ? styleText('cyan', S_BAR_END) : '';\n\t\t\t\t\tconst inlineBar = hasGuide ? `${styleText('cyan', S_BAR)} ` : '';\n\t\t\t\t\tconst inlineError = this.inlineError\n\t\t\t\t\t\t? `\\n${inlineBar}${styleText('yellow', this.inlineError)}`\n\t\t\t\t\t\t: '';\n\t\t\t\t\treturn `${title}${bar}${userInput}${inlineError}\\n${barEnd}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<Date | symbol>;\n};\n\nfunction renderDate(prompt: Omit<InstanceType<typeof DatePrompt>, 'prompt'>, state: State): string {\n\tconst parts = prompt.segmentValues;\n\tconst cursor = prompt.segmentCursor;\n\n\tif (state === 'submit' || state === 'cancel') {\n\t\treturn prompt.formattedValue;\n\t}\n\n\tconst sep = styleText('gray', prompt.separator);\n\treturn prompt.segments\n\t\t.map((seg, i) => {\n\t\t\tconst isActive = i === cursor.segmentIndex && !['submit', 'cancel'].includes(state);\n\t\t\tconst label = DEFAULT_LABELS[seg.type];\n\t\t\treturn renderSegment(parts[seg.type], { isActive, label });\n\t\t})\n\t\t.join(sep);\n}\n\ninterface SegmentOptions {\n\tisActive: boolean;\n\tlabel: string;\n}\nfunction renderSegment(value: string, opts: SegmentOptions): string {\n\tconst isBlank = !value || value.replace(/_/g, '') === '';\n\tif (opts.isActive) return styleText('inverse', isBlank ? opts.label : value.replace(/_/g, ' '));\n\tif (isBlank) return styleText('dim', opts.label);\n\treturn value.replace(/_/g, styleText('dim', ' '));\n}\n\nconst DEFAULT_LABELS: Record<'year' | 'month' | 'day', string> = {\n\tyear: 'yyyy',\n\tmonth: 'mm',\n\tday: 'dd',\n};\n","import { isCancel } from '@clack/core';\n\ntype Prettify<T> = {\n\t[P in keyof T]: T[P];\n} & {};\n\nexport type PromptGroupAwaitedReturn<T> = {\n\t[P in keyof T]: Exclude<Awaited<T[P]>, symbol>;\n};\n\nexport interface PromptGroupOptions<T> {\n\t/**\n\t * Control how the group can be canceled\n\t * if one of the prompts is canceled.\n\t */\n\tonCancel?: (opts: { results: Prettify<Partial<PromptGroupAwaitedReturn<T>>> }) => void;\n}\n\nexport type PromptGroup<T> = {\n\t[P in keyof T]: (opts: {\n\t\tresults: Prettify<Partial<PromptGroupAwaitedReturn<Omit<T, P>>>>;\n\t}) => undefined | Promise<T[P] | undefined>;\n};\n\n/**\n * Define a group of prompts to be displayed\n * and return a results of objects within the group\n */\nexport const group = async <T>(\n\tprompts: PromptGroup<T>,\n\topts?: PromptGroupOptions<T>\n): Promise<Prettify<PromptGroupAwaitedReturn<T>>> => {\n\tconst results = {} as any;\n\tconst promptNames = Object.keys(prompts);\n\n\tfor (const name of promptNames) {\n\t\tconst prompt = prompts[name as keyof T];\n\t\tconst result = await prompt({ results })?.catch((e) => {\n\t\t\tthrow e;\n\t\t});\n\n\t\t// Pass the results to the onCancel function\n\t\t// so the user can decide what to do with the results\n\t\t// TODO: Switch to callback within core to avoid isCancel Fn\n\t\tif (typeof opts?.onCancel === 'function' && isCancel(result)) {\n\t\t\tresults[name] = 'canceled';\n\t\t\topts.onCancel({ results });\n\t\t\tcontinue;\n\t\t}\n\n\t\tresults[name] = result;\n\t}\n\n\treturn results;\n};\n","import { styleText } from 'node:util';\nimport { GroupMultiSelectPrompt, settings } from '@clack/core';\nimport {\n\ttype CommonOptions,\n\tS_BAR,\n\tS_BAR_END,\n\tS_CHECKBOX_ACTIVE,\n\tS_CHECKBOX_INACTIVE,\n\tS_CHECKBOX_SELECTED,\n\tsymbol,\n} from './common.js';\nimport type { Option } from './select.js';\n\nexport interface GroupMultiSelectOptions<Value> extends CommonOptions {\n\tmessage: string;\n\toptions: Record<string, Option<Value>[]>;\n\tinitialValues?: Value[];\n\trequired?: boolean;\n\tcursorAt?: Value;\n\tselectableGroups?: boolean;\n\tgroupSpacing?: number;\n}\nexport const groupMultiselect = <Value>(opts: GroupMultiSelectOptions<Value>) => {\n\tconst { selectableGroups = true, groupSpacing = 0 } = opts;\n\tconst opt = (\n\t\toption: Option<Value> & { group: string | boolean },\n\t\tstate:\n\t\t\t| 'inactive'\n\t\t\t| 'active'\n\t\t\t| 'selected'\n\t\t\t| 'active-selected'\n\t\t\t| 'group-active'\n\t\t\t| 'group-active-selected'\n\t\t\t| 'submitted'\n\t\t\t| 'cancelled',\n\t\toptions: (Option<Value> & { group: string | boolean })[] = []\n\t) => {\n\t\tconst label = option.label ?? String(option.value);\n\t\tconst isItem = typeof option.group === 'string';\n\t\tconst next = isItem && (options[options.indexOf(option) + 1] ?? { group: true });\n\t\tconst isLast = isItem && next && next.group === true;\n\t\tconst prefix = isItem ? (selectableGroups ? `${isLast ? S_BAR_END : S_BAR} ` : ' ') : '';\n\t\tlet spacingPrefix = '';\n\t\tif (groupSpacing > 0 && !isItem) {\n\t\t\tconst spacingPrefixText = `\\n${styleText('cyan', S_BAR)}`;\n\t\t\tspacingPrefix = `${spacingPrefixText.repeat(groupSpacing - 1)}${spacingPrefixText} `;\n\t\t}\n\n\t\tif (state === 'active') {\n\t\t\treturn `${spacingPrefix}${styleText('dim', prefix)}${styleText('cyan', S_CHECKBOX_ACTIVE)} ${label}${\n\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t\t}`;\n\t\t}\n\t\tif (state === 'group-active') {\n\t\t\treturn `${spacingPrefix}${prefix}${styleText('cyan', S_CHECKBOX_ACTIVE)} ${styleText('dim', label)}`;\n\t\t}\n\t\tif (state === 'group-active-selected') {\n\t\t\treturn `${spacingPrefix}${prefix}${styleText('green', S_CHECKBOX_SELECTED)} ${styleText('dim', label)}`;\n\t\t}\n\t\tif (state === 'selected') {\n\t\t\tconst selectedCheckbox =\n\t\t\t\tisItem || selectableGroups ? styleText('green', S_CHECKBOX_SELECTED) : '';\n\t\t\treturn `${spacingPrefix}${styleText('dim', prefix)}${selectedCheckbox} ${styleText('dim', label)}${\n\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t\t}`;\n\t\t}\n\t\tif (state === 'cancelled') {\n\t\t\treturn `${styleText(['strikethrough', 'dim'], label)}`;\n\t\t}\n\t\tif (state === 'active-selected') {\n\t\t\treturn `${spacingPrefix}${styleText('dim', prefix)}${styleText('green', S_CHECKBOX_SELECTED)} ${label}${\n\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t\t}`;\n\t\t}\n\t\tif (state === 'submitted') {\n\t\t\treturn `${styleText('dim', label)}`;\n\t\t}\n\t\tconst unselectedCheckbox =\n\t\t\tisItem || selectableGroups ? styleText('dim', S_CHECKBOX_INACTIVE) : '';\n\t\treturn `${spacingPrefix}${styleText('dim', prefix)}${unselectedCheckbox} ${styleText('dim', label)}`;\n\t};\n\tconst required = opts.required ?? true;\n\n\treturn new GroupMultiSelectPrompt({\n\t\toptions: opts.options,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\toutput: opts.output,\n\t\tinitialValues: opts.initialValues,\n\t\trequired,\n\t\tcursorAt: opts.cursorAt,\n\t\tselectableGroups,\n\t\tvalidate(selected: Value[] | undefined) {\n\t\t\tif (required && (selected === undefined || selected.length === 0))\n\t\t\t\treturn `Please select at least one option.\\n${styleText(\n\t\t\t\t\t'reset',\n\t\t\t\t\tstyleText(\n\t\t\t\t\t\t'dim',\n\t\t\t\t\t\t`Press ${styleText(['gray', 'bgWhite', 'inverse'], ' space ')} to select, ${styleText(\n\t\t\t\t\t\t\t'gray',\n\t\t\t\t\t\t\tstyleText(['bgWhite', 'inverse'], ' enter ')\n\t\t\t\t\t\t)} to submit`\n\t\t\t\t\t)\n\t\t\t\t)}`;\n\t\t},\n\t\trender() {\n\t\t\tconst hasGuide = opts.withGuide ?? settings.withGuide;\n\t\t\tconst title = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${symbol(this.state)} ${opts.message}\\n`;\n\t\t\tconst value = this.value ?? [];\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst selectedOptions = this.options\n\t\t\t\t\t\t.filter(({ value: optionValue }) => value.includes(optionValue))\n\t\t\t\t\t\t.map((option) => opt(option, 'submitted'));\n\t\t\t\t\tconst optionsText =\n\t\t\t\t\t\tselectedOptions.length === 0 ? '' : ` ${selectedOptions.join(styleText('dim', ', '))}`;\n\t\t\t\t\treturn `${title}${hasGuide ? styleText('gray', S_BAR) : ''}${optionsText}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst label = this.options\n\t\t\t\t\t\t.filter(({ value: optionValue }) => value.includes(optionValue))\n\t\t\t\t\t\t.map((option) => opt(option, 'cancelled'))\n\t\t\t\t\t\t.join(styleText('dim', ', '));\n\t\t\t\t\treturn `${title}${hasGuide ? `${styleText('gray', S_BAR)} ` : ''}${\n\t\t\t\t\t\tlabel.trim() ? `${label}${hasGuide ? `\\n${styleText('gray', S_BAR)}` : ''}` : ''\n\t\t\t\t\t}`;\n\t\t\t\t}\n\t\t\t\tcase 'error': {\n\t\t\t\t\tconst footer = this.error\n\t\t\t\t\t\t.split('\\n')\n\t\t\t\t\t\t.map((ln, i) =>\n\t\t\t\t\t\t\ti === 0\n\t\t\t\t\t\t\t\t? `${hasGuide ? `${styleText('yellow', S_BAR_END)} ` : ''}${styleText('yellow', ln)}`\n\t\t\t\t\t\t\t\t: ` ${ln}`\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.join('\\n');\n\t\t\t\t\treturn `${title}${hasGuide ? `${styleText('yellow', S_BAR)} ` : ''}${this.options\n\t\t\t\t\t\t.map((option, i, options) => {\n\t\t\t\t\t\t\tconst selected =\n\t\t\t\t\t\t\t\tvalue.includes(option.value) ||\n\t\t\t\t\t\t\t\t(option.group === true && this.isGroupSelected(`${option.value}`));\n\t\t\t\t\t\t\tconst active = i === this.cursor;\n\t\t\t\t\t\t\tconst groupActive =\n\t\t\t\t\t\t\t\t!active &&\n\t\t\t\t\t\t\t\ttypeof option.group === 'string' &&\n\t\t\t\t\t\t\t\tthis.options[this.cursor].value === option.group;\n\t\t\t\t\t\t\tif (groupActive) {\n\t\t\t\t\t\t\t\treturn opt(option, selected ? 'group-active-selected' : 'group-active', options);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (active && selected) {\n\t\t\t\t\t\t\t\treturn opt(option, 'active-selected', options);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (selected) {\n\t\t\t\t\t\t\t\treturn opt(option, 'selected', options);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn opt(option, active ? 'active' : 'inactive', options);\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.join(`\\n${hasGuide ? `${styleText('yellow', S_BAR)} ` : ''}`)}\\n${footer}\\n`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst optionsText = this.options\n\t\t\t\t\t\t.map((option, i, options) => {\n\t\t\t\t\t\t\tconst selected =\n\t\t\t\t\t\t\t\tvalue.includes(option.value) ||\n\t\t\t\t\t\t\t\t(option.group === true && this.isGroupSelected(`${option.value}`));\n\t\t\t\t\t\t\tconst active = i === this.cursor;\n\t\t\t\t\t\t\tconst groupActive =\n\t\t\t\t\t\t\t\t!active &&\n\t\t\t\t\t\t\t\ttypeof option.group === 'string' &&\n\t\t\t\t\t\t\t\tthis.options[this.cursor].value === option.group;\n\t\t\t\t\t\t\tlet optionText = '';\n\t\t\t\t\t\t\tif (groupActive) {\n\t\t\t\t\t\t\t\toptionText = opt(\n\t\t\t\t\t\t\t\t\toption,\n\t\t\t\t\t\t\t\t\tselected ? 'group-active-selected' : 'group-active',\n\t\t\t\t\t\t\t\t\toptions\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} else if (active && selected) {\n\t\t\t\t\t\t\t\toptionText = opt(option, 'active-selected', options);\n\t\t\t\t\t\t\t} else if (selected) {\n\t\t\t\t\t\t\t\toptionText = opt(option, 'selected', options);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\toptionText = opt(option, active ? 'active' : 'inactive', options);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst prefix = i !== 0 && !optionText.startsWith('\\n') ? ' ' : '';\n\t\t\t\t\t\t\treturn `${prefix}${optionText}`;\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.join(`\\n${hasGuide ? styleText('cyan', S_BAR) : ''}`);\n\t\t\t\t\tconst optionsPrefix = optionsText.startsWith('\\n') ? '' : ' ';\n\t\t\t\t\treturn `${title}${hasGuide ? styleText('cyan', S_BAR) : ''}${optionsPrefix}${optionsText}\\n${\n\t\t\t\t\t\thasGuide ? styleText('cyan', S_BAR_END) : ''\n\t\t\t\t\t}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<Value[] | symbol>;\n};\n","import { styleText } from 'node:util';\nimport { settings } from '@clack/core';\nimport {\n\ttype CommonOptions,\n\tS_BAR,\n\tS_ERROR,\n\tS_INFO,\n\tS_STEP_SUBMIT,\n\tS_SUCCESS,\n\tS_WARN,\n} from './common.js';\n\nexport interface LogMessageOptions extends CommonOptions {\n\tsymbol?: string;\n\tspacing?: number;\n\tsecondarySymbol?: string;\n}\n\nexport const log = {\n\tmessage: (\n\t\tmessage: string | string[] = [],\n\t\t{\n\t\t\tsymbol = styleText('gray', S_BAR),\n\t\t\tsecondarySymbol = styleText('gray', S_BAR),\n\t\t\toutput = process.stdout,\n\t\t\tspacing = 1,\n\t\t\twithGuide,\n\t\t}: LogMessageOptions = {}\n\t) => {\n\t\tconst parts: string[] = [];\n\t\tconst hasGuide = withGuide ?? settings.withGuide;\n\t\tconst spacingString = !hasGuide ? '' : secondarySymbol;\n\t\tconst prefix = !hasGuide ? '' : `${symbol} `;\n\t\tconst secondaryPrefix = !hasGuide ? '' : `${secondarySymbol} `;\n\n\t\tfor (let i = 0; i < spacing; i++) {\n\t\t\tparts.push(spacingString);\n\t\t}\n\n\t\tconst messageParts = Array.isArray(message) ? message : message.split('\\n');\n\t\tif (messageParts.length > 0) {\n\t\t\tconst [firstLine, ...lines] = messageParts;\n\t\t\tif (firstLine.length > 0) {\n\t\t\t\tparts.push(`${prefix}${firstLine}`);\n\t\t\t} else {\n\t\t\t\tparts.push(hasGuide ? symbol : '');\n\t\t\t}\n\t\t\tfor (const ln of lines) {\n\t\t\t\tif (ln.length > 0) {\n\t\t\t\t\tparts.push(`${secondaryPrefix}${ln}`);\n\t\t\t\t} else {\n\t\t\t\t\tparts.push(hasGuide ? secondarySymbol : '');\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\toutput.write(`${parts.join('\\n')}\\n`);\n\t},\n\tinfo: (message: string, opts?: LogMessageOptions) => {\n\t\tlog.message(message, { ...opts, symbol: styleText('blue', S_INFO) });\n\t},\n\tsuccess: (message: string, opts?: LogMessageOptions) => {\n\t\tlog.message(message, { ...opts, symbol: styleText('green', S_SUCCESS) });\n\t},\n\tstep: (message: string, opts?: LogMessageOptions) => {\n\t\tlog.message(message, { ...opts, symbol: styleText('green', S_STEP_SUBMIT) });\n\t},\n\twarn: (message: string, opts?: LogMessageOptions) => {\n\t\tlog.message(message, { ...opts, symbol: styleText('yellow', S_WARN) });\n\t},\n\t/** alias for `log.warn()`. */\n\twarning: (message: string, opts?: LogMessageOptions) => {\n\t\tlog.warn(message, opts);\n\t},\n\terror: (message: string, opts?: LogMessageOptions) => {\n\t\tlog.message(message, { ...opts, symbol: styleText('red', S_ERROR) });\n\t},\n};\n","import type { Writable } from 'node:stream';\nimport { styleText } from 'node:util';\nimport { settings } from '@clack/core';\nimport { type CommonOptions, S_BAR, S_BAR_END, S_BAR_START } from './common.js';\n\nexport const cancel = (message = '', opts?: CommonOptions) => {\n\tconst output: Writable = opts?.output ?? process.stdout;\n\tconst hasGuide = opts?.withGuide ?? settings.withGuide;\n\tconst prefix = hasGuide ? `${styleText('gray', S_BAR_END)} ` : '';\n\toutput.write(`${prefix}${styleText('red', message)}\\n\\n`);\n};\n\nexport const intro = (title = '', opts?: CommonOptions) => {\n\tconst output: Writable = opts?.output ?? process.stdout;\n\tconst hasGuide = opts?.withGuide ?? settings.withGuide;\n\tconst prefix = hasGuide ? `${styleText('gray', S_BAR_START)} ` : '';\n\toutput.write(`${prefix}${title}\\n`);\n};\n\nexport const outro = (message = '', opts?: CommonOptions) => {\n\tconst output: Writable = opts?.output ?? process.stdout;\n\tconst hasGuide = opts?.withGuide ?? settings.withGuide;\n\tconst prefix = hasGuide ? `${styleText('gray', S_BAR)}\\n${styleText('gray', S_BAR_END)} ` : '';\n\toutput.write(`${prefix}${message}\\n\\n`);\n};\n","import { styleText } from 'node:util';\nimport { MultiLinePrompt, settings, wrapTextWithPrefix } from '@clack/core';\nimport { S_BAR, S_BAR_END, symbol } from './common.js';\nimport type { TextOptions } from './text.js';\n\nexport interface MultiLineOptions extends TextOptions {\n\tshowSubmit?: boolean;\n}\n\nexport const multiline = (opts: MultiLineOptions) => {\n\treturn new MultiLinePrompt({\n\t\tvalidate: opts.validate,\n\t\tplaceholder: opts.placeholder,\n\t\tdefaultValue: opts.defaultValue,\n\t\tinitialValue: opts.initialValue,\n\t\tshowSubmit: opts.showSubmit,\n\t\toutput: opts.output,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\trender() {\n\t\t\tconst hasGuide = opts?.withGuide ?? settings.withGuide;\n\t\t\tconst titlePrefix = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${symbol(this.state)} `;\n\t\t\tconst title = `${titlePrefix}${opts.message}\\n`;\n\t\t\tconst placeholder = opts.placeholder\n\t\t\t\t? styleText('inverse', opts.placeholder[0]) + styleText('dim', opts.placeholder.slice(1))\n\t\t\t\t: styleText(['inverse', 'hidden'], '_');\n\t\t\tconst userInput = !this.userInput ? placeholder : this.userInputWithCursor;\n\t\t\tconst value = this.value ?? '';\n\t\t\tconst submitButton = opts.showSubmit\n\t\t\t\t? `\\n ${styleText(this.focused === 'submit' ? 'cyan' : 'dim', '[ submit ]')}`\n\t\t\t\t: '';\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'error': {\n\t\t\t\t\tconst errorPrefix = `${styleText('yellow', S_BAR)} `;\n\t\t\t\t\tconst lines = hasGuide\n\t\t\t\t\t\t? wrapTextWithPrefix(opts.output, userInput, errorPrefix, undefined)\n\t\t\t\t\t\t: userInput;\n\t\t\t\t\tconst errorPrefixEnd = styleText('yellow', S_BAR_END);\n\t\t\t\t\treturn `${title}${lines}\\n${errorPrefixEnd} ${styleText('yellow', this.error)}${submitButton}\\n`;\n\t\t\t\t}\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst submitPrefix = `${styleText('gray', S_BAR)} `;\n\t\t\t\t\tconst lines = hasGuide\n\t\t\t\t\t\t? wrapTextWithPrefix(opts.output, value, submitPrefix, undefined, (str) =>\n\t\t\t\t\t\t\t\tstyleText('dim', str)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t: value\n\t\t\t\t\t\t\t? styleText('dim', value)\n\t\t\t\t\t\t\t: '';\n\t\t\t\t\treturn `${title}${lines}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst cancelPrefix = `${styleText('gray', S_BAR)} `;\n\t\t\t\t\tconst lines = hasGuide\n\t\t\t\t\t\t? wrapTextWithPrefix(opts.output, value, cancelPrefix, undefined, (str) =>\n\t\t\t\t\t\t\t\tstyleText(['strikethrough', 'dim'], str)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t: value\n\t\t\t\t\t\t\t? styleText(['strikethrough', 'dim'], value)\n\t\t\t\t\t\t\t: '';\n\t\t\t\t\treturn `${title}${lines}`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst defaultPrefix = hasGuide ? `${styleText('cyan', S_BAR)} ` : '';\n\t\t\t\t\tconst defaultPrefixEnd = hasGuide ? styleText('cyan', S_BAR_END) : '';\n\t\t\t\t\tconst lines = hasGuide\n\t\t\t\t\t\t? wrapTextWithPrefix(opts.output, userInput, defaultPrefix)\n\t\t\t\t\t\t: userInput;\n\t\t\t\t\treturn `${title}${lines}\\n${defaultPrefixEnd}${submitButton}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<string | symbol>;\n};\n","import { styleText } from 'node:util';\nimport { MultiSelectPrompt, settings, wrapTextWithPrefix } from '@clack/core';\nimport {\n\ttype CommonOptions,\n\tS_BAR,\n\tS_BAR_END,\n\tS_CHECKBOX_ACTIVE,\n\tS_CHECKBOX_INACTIVE,\n\tS_CHECKBOX_SELECTED,\n\tsymbol,\n\tsymbolBar,\n} from './common.js';\nimport { limitOptions } from './limit-options.js';\nimport type { Option } from './select.js';\n\nexport interface MultiSelectOptions<Value> extends CommonOptions {\n\tmessage: string;\n\toptions: Option<Value>[];\n\tinitialValues?: Value[];\n\tmaxItems?: number;\n\trequired?: boolean;\n\tcursorAt?: Value;\n}\nconst computeLabel = (label: string, format: (text: string) => string) => {\n\treturn label\n\t\t.split('\\n')\n\t\t.map((line) => format(line))\n\t\t.join('\\n');\n};\n\nexport const multiselect = <Value>(opts: MultiSelectOptions<Value>) => {\n\tconst opt = (\n\t\toption: Option<Value>,\n\t\tstate:\n\t\t\t| 'inactive'\n\t\t\t| 'active'\n\t\t\t| 'selected'\n\t\t\t| 'active-selected'\n\t\t\t| 'submitted'\n\t\t\t| 'cancelled'\n\t\t\t| 'disabled'\n\t) => {\n\t\tconst label = option.label ?? String(option.value);\n\t\tif (state === 'disabled') {\n\t\t\treturn `${styleText('gray', S_CHECKBOX_INACTIVE)} ${computeLabel(label, (str) => styleText(['strikethrough', 'gray'], str))}${\n\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint ?? 'disabled'})`)}` : ''\n\t\t\t}`;\n\t\t}\n\t\tif (state === 'active') {\n\t\t\treturn `${styleText('cyan', S_CHECKBOX_ACTIVE)} ${label}${\n\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t\t}`;\n\t\t}\n\t\tif (state === 'selected') {\n\t\t\treturn `${styleText('green', S_CHECKBOX_SELECTED)} ${computeLabel(label, (text) => styleText('dim', text))}${\n\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t\t}`;\n\t\t}\n\t\tif (state === 'cancelled') {\n\t\t\treturn `${computeLabel(label, (text) => styleText(['strikethrough', 'dim'], text))}`;\n\t\t}\n\t\tif (state === 'active-selected') {\n\t\t\treturn `${styleText('green', S_CHECKBOX_SELECTED)} ${label}${\n\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t\t}`;\n\t\t}\n\t\tif (state === 'submitted') {\n\t\t\treturn `${computeLabel(label, (text) => styleText('dim', text))}`;\n\t\t}\n\t\treturn `${styleText('dim', S_CHECKBOX_INACTIVE)} ${computeLabel(label, (text) => styleText('dim', text))}`;\n\t};\n\tconst required = opts.required ?? true;\n\n\treturn new MultiSelectPrompt({\n\t\toptions: opts.options,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\toutput: opts.output,\n\t\tinitialValues: opts.initialValues,\n\t\trequired,\n\t\tcursorAt: opts.cursorAt,\n\t\tvalidate(selected: Value[] | undefined) {\n\t\t\tif (required && (selected === undefined || selected.length === 0))\n\t\t\t\treturn `Please select at least one option.\\n${styleText(\n\t\t\t\t\t'reset',\n\t\t\t\t\tstyleText(\n\t\t\t\t\t\t'dim',\n\t\t\t\t\t\t`Press ${styleText(['gray', 'bgWhite', 'inverse'], ' space ')} to select, ${styleText(\n\t\t\t\t\t\t\t'gray',\n\t\t\t\t\t\t\tstyleText('bgWhite', styleText('inverse', ' enter '))\n\t\t\t\t\t\t)} to submit`\n\t\t\t\t\t)\n\t\t\t\t)}`;\n\t\t},\n\t\trender() {\n\t\t\tconst hasGuide = opts.withGuide ?? settings.withGuide;\n\t\t\tconst wrappedMessage = wrapTextWithPrefix(\n\t\t\t\topts.output,\n\t\t\t\topts.message,\n\t\t\t\thasGuide ? `${symbolBar(this.state)} ` : '',\n\t\t\t\t`${symbol(this.state)} `\n\t\t\t);\n\t\t\tconst title = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${wrappedMessage}\\n`;\n\t\t\tconst value = this.value ?? [];\n\n\t\t\tconst styleOption = (option: Option<Value>, active: boolean) => {\n\t\t\t\tif (option.disabled) {\n\t\t\t\t\treturn opt(option, 'disabled');\n\t\t\t\t}\n\t\t\t\tconst selected = value.includes(option.value);\n\t\t\t\tif (active && selected) {\n\t\t\t\t\treturn opt(option, 'active-selected');\n\t\t\t\t}\n\t\t\t\tif (selected) {\n\t\t\t\t\treturn opt(option, 'selected');\n\t\t\t\t}\n\t\t\t\treturn opt(option, active ? 'active' : 'inactive');\n\t\t\t};\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst submitText =\n\t\t\t\t\t\tthis.options\n\t\t\t\t\t\t\t.filter(({ value: optionValue }) => value.includes(optionValue))\n\t\t\t\t\t\t\t.map((option) => opt(option, 'submitted'))\n\t\t\t\t\t\t\t.join(styleText('dim', ', ')) || styleText('dim', 'none');\n\t\t\t\t\tconst wrappedSubmitText = wrapTextWithPrefix(\n\t\t\t\t\t\topts.output,\n\t\t\t\t\t\tsubmitText,\n\t\t\t\t\t\thasGuide ? `${styleText('gray', S_BAR)} ` : ''\n\t\t\t\t\t);\n\t\t\t\t\treturn `${title}${wrappedSubmitText}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst label = this.options\n\t\t\t\t\t\t.filter(({ value: optionValue }) => value.includes(optionValue))\n\t\t\t\t\t\t.map((option) => opt(option, 'cancelled'))\n\t\t\t\t\t\t.join(styleText('dim', ', '));\n\t\t\t\t\tif (label.trim() === '') {\n\t\t\t\t\t\treturn `${title}${styleText('gray', S_BAR)}`;\n\t\t\t\t\t}\n\t\t\t\t\tconst wrappedLabel = wrapTextWithPrefix(\n\t\t\t\t\t\topts.output,\n\t\t\t\t\t\tlabel,\n\t\t\t\t\t\thasGuide ? `${styleText('gray', S_BAR)} ` : ''\n\t\t\t\t\t);\n\t\t\t\t\treturn `${title}${wrappedLabel}${hasGuide ? `\\n${styleText('gray', S_BAR)}` : ''}`;\n\t\t\t\t}\n\t\t\t\tcase 'error': {\n\t\t\t\t\tconst prefix = hasGuide ? `${styleText('yellow', S_BAR)} ` : '';\n\t\t\t\t\tconst footer = this.error\n\t\t\t\t\t\t.split('\\n')\n\t\t\t\t\t\t.map((ln, i) =>\n\t\t\t\t\t\t\ti === 0\n\t\t\t\t\t\t\t\t? `${hasGuide ? `${styleText('yellow', S_BAR_END)} ` : ''}${styleText('yellow', ln)}`\n\t\t\t\t\t\t\t\t: ` ${ln}`\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.join('\\n');\n\t\t\t\t\t// Calculate rowPadding: title lines + footer lines (error message + trailing newline)\n\t\t\t\t\tconst titleLineCount = title.split('\\n').length;\n\t\t\t\t\tconst footerLineCount = footer.split('\\n').length + 1; // footer + trailing newline\n\t\t\t\t\treturn `${title}${prefix}${limitOptions({\n\t\t\t\t\t\toutput: opts.output,\n\t\t\t\t\t\toptions: this.options,\n\t\t\t\t\t\tcursor: this.cursor,\n\t\t\t\t\t\tmaxItems: opts.maxItems,\n\t\t\t\t\t\tcolumnPadding: prefix.length,\n\t\t\t\t\t\trowPadding: titleLineCount + footerLineCount,\n\t\t\t\t\t\tstyle: styleOption,\n\t\t\t\t\t}).join(`\\n${prefix}`)}\\n${footer}\\n`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst prefix = hasGuide ? `${styleText('cyan', S_BAR)} ` : '';\n\t\t\t\t\t// Calculate rowPadding: title lines + footer lines (S_BAR_END + trailing newline)\n\t\t\t\t\tconst titleLineCount = title.split('\\n').length;\n\t\t\t\t\tconst footerLineCount = hasGuide ? 2 : 1; // S_BAR_END + trailing newline\n\t\t\t\t\treturn `${title}${prefix}${limitOptions({\n\t\t\t\t\t\toutput: opts.output,\n\t\t\t\t\t\toptions: this.options,\n\t\t\t\t\t\tcursor: this.cursor,\n\t\t\t\t\t\tmaxItems: opts.maxItems,\n\t\t\t\t\t\tcolumnPadding: prefix.length,\n\t\t\t\t\t\trowPadding: titleLineCount + footerLineCount,\n\t\t\t\t\t\tstyle: styleOption,\n\t\t\t\t\t}).join(`\\n${prefix}`)}\\n${hasGuide ? styleText('cyan', S_BAR_END) : ''}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<Value[] | symbol>;\n};\n","import process from 'node:process';\nimport type { Writable } from 'node:stream';\nimport { styleText } from 'node:util';\nimport { getColumns, settings } from '@clack/core';\nimport stringWidth from 'fast-string-width';\nimport { type Options as WrapAnsiOptions, wrapAnsi } from 'fast-wrap-ansi';\nimport {\n\ttype CommonOptions,\n\tS_BAR,\n\tS_BAR_H,\n\tS_CONNECT_LEFT,\n\tS_CORNER_BOTTOM_LEFT,\n\tS_CORNER_BOTTOM_RIGHT,\n\tS_CORNER_TOP_RIGHT,\n\tS_STEP_SUBMIT,\n} from './common.js';\n\ntype FormatFn = (line: string) => string;\nexport interface NoteOptions extends CommonOptions {\n\tformat?: FormatFn;\n}\n\nconst defaultNoteFormatter = (line: string): string => styleText('dim', line);\n\nconst wrapWithFormat = (message: string, width: number, format: FormatFn): string => {\n\tconst opts: WrapAnsiOptions = {\n\t\thard: true,\n\t\ttrim: false,\n\t};\n\tconst wrapMsg = wrapAnsi(message, width, opts).split('\\n');\n\tconst maxWidthNormal = wrapMsg.reduce((sum, ln) => Math.max(stringWidth(ln), sum), 0);\n\tconst maxWidthFormat = wrapMsg.map(format).reduce((sum, ln) => Math.max(stringWidth(ln), sum), 0);\n\tconst wrapWidth = width - (maxWidthFormat - maxWidthNormal);\n\treturn wrapAnsi(message, wrapWidth, opts);\n};\n\nexport const note = (message = '', title = '', opts?: NoteOptions) => {\n\tconst output: Writable = opts?.output ?? process.stdout;\n\tconst hasGuide = opts?.withGuide ?? settings.withGuide;\n\tconst format = opts?.format ?? defaultNoteFormatter;\n\tconst wrapMsg = wrapWithFormat(message, getColumns(output) - 6, format);\n\tconst lines = ['', ...wrapMsg.split('\\n').map(format), ''];\n\tconst titleLen = stringWidth(title);\n\tconst len =\n\t\tMath.max(\n\t\t\tlines.reduce((sum, ln) => {\n\t\t\t\tconst width = stringWidth(ln);\n\t\t\t\treturn width > sum ? width : sum;\n\t\t\t}, 0),\n\t\t\ttitleLen\n\t\t) + 2;\n\tconst msg = lines\n\t\t.map(\n\t\t\t(ln) =>\n\t\t\t\t`${styleText('gray', S_BAR)} ${ln}${' '.repeat(len - stringWidth(ln))}${styleText('gray', S_BAR)}`\n\t\t)\n\t\t.join('\\n');\n\tconst leadingBorder = hasGuide ? `${styleText('gray', S_BAR)}\\n` : '';\n\tconst bottomLeft = hasGuide ? S_CONNECT_LEFT : S_CORNER_BOTTOM_LEFT;\n\toutput.write(\n\t\t`${leadingBorder}${styleText('green', S_STEP_SUBMIT)} ${styleText('reset', title)} ${styleText(\n\t\t\t'gray',\n\t\t\tS_BAR_H.repeat(Math.max(len - titleLen - 1, 1)) + S_CORNER_TOP_RIGHT\n\t\t)}\\n${msg}\\n${styleText('gray', bottomLeft + S_BAR_H.repeat(len + 2) + S_CORNER_BOTTOM_RIGHT)}\\n`\n\t);\n};\n","import { styleText } from 'node:util';\nimport { PasswordPrompt, settings } from '@clack/core';\nimport { type CommonOptions, S_BAR, S_BAR_END, S_PASSWORD_MASK, symbol } from './common.js';\n\nexport interface PasswordOptions extends CommonOptions {\n\tmessage: string;\n\tmask?: string;\n\tvalidate?: (value: string | undefined) => string | Error | undefined;\n\tclearOnError?: boolean;\n}\nexport const password = (opts: PasswordOptions) => {\n\treturn new PasswordPrompt({\n\t\tvalidate: opts.validate,\n\t\tmask: opts.mask ?? S_PASSWORD_MASK,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\toutput: opts.output,\n\t\trender() {\n\t\t\tconst hasGuide = opts.withGuide ?? settings.withGuide;\n\t\t\tconst title = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${symbol(this.state)} ${opts.message}\\n`;\n\t\t\tconst userInput = this.userInputWithCursor;\n\t\t\tconst masked = this.masked;\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'error': {\n\t\t\t\t\tconst errorPrefix = hasGuide ? `${styleText('yellow', S_BAR)} ` : '';\n\t\t\t\t\tconst errorPrefixEnd = hasGuide ? `${styleText('yellow', S_BAR_END)} ` : '';\n\t\t\t\t\tconst maskedText = masked ?? '';\n\t\t\t\t\tif (opts.clearOnError) {\n\t\t\t\t\t\tthis.clear();\n\t\t\t\t\t}\n\t\t\t\t\treturn `${title.trim()}\\n${errorPrefix}${maskedText}\\n${errorPrefixEnd}${styleText('yellow', this.error)}\\n`;\n\t\t\t\t}\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst submitPrefix = hasGuide ? `${styleText('gray', S_BAR)} ` : '';\n\t\t\t\t\tconst maskedText = masked ? styleText('dim', masked) : '';\n\t\t\t\t\treturn `${title}${submitPrefix}${maskedText}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst cancelPrefix = hasGuide ? `${styleText('gray', S_BAR)} ` : '';\n\t\t\t\t\tconst maskedText = masked ? styleText(['strikethrough', 'dim'], masked) : '';\n\t\t\t\t\treturn `${title}${cancelPrefix}${maskedText}${\n\t\t\t\t\t\tmasked && hasGuide ? `\\n${styleText('gray', S_BAR)}` : ''\n\t\t\t\t\t}`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst defaultPrefix = hasGuide ? `${styleText('cyan', S_BAR)} ` : '';\n\t\t\t\t\tconst defaultPrefixEnd = hasGuide ? styleText('cyan', S_BAR_END) : '';\n\t\t\t\t\treturn `${title}${defaultPrefix}${userInput}\\n${defaultPrefixEnd}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<string | symbol>;\n};\n","import { existsSync, lstatSync, readdirSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { autocomplete } from './autocomplete.js';\nimport type { CommonOptions } from './common.js';\n\nexport interface PathOptions extends CommonOptions {\n\troot?: string;\n\tdirectory?: boolean;\n\tinitialValue?: string;\n\tmessage: string;\n\tvalidate?: (value: string | undefined) => string | Error | undefined;\n}\n\nexport const path = (opts: PathOptions) => {\n\tconst validate = opts.validate;\n\n\treturn autocomplete({\n\t\t...opts,\n\t\tinitialUserInput: opts.initialValue ?? opts.root ?? process.cwd(),\n\t\tmaxItems: 5,\n\t\tvalidate(value) {\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\t// Shouldn't ever happen since we don't enable `multiple: true`\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tif (!value) {\n\t\t\t\treturn 'Please select a path';\n\t\t\t}\n\t\t\tif (validate) {\n\t\t\t\treturn validate(value);\n\t\t\t}\n\t\t\treturn undefined;\n\t\t},\n\t\toptions() {\n\t\t\tconst userInput = this.userInput;\n\t\t\tif (userInput === '') {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tlet searchPath: string;\n\n\t\t\t\tif (!existsSync(userInput)) {\n\t\t\t\t\tsearchPath = dirname(userInput);\n\t\t\t\t} else {\n\t\t\t\t\tconst stat = lstatSync(userInput);\n\t\t\t\t\tif (stat.isDirectory() && (!opts.directory || userInput.endsWith('/'))) {\n\t\t\t\t\t\tsearchPath = userInput;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsearchPath = dirname(userInput);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Strip trailing slash so startsWith matches the directory itself among its siblings\n\t\t\t\tconst prefix =\n\t\t\t\t\tuserInput.length > 1 && userInput.endsWith('/') ? userInput.slice(0, -1) : userInput;\n\n\t\t\t\tconst items = readdirSync(searchPath)\n\t\t\t\t\t.map((item) => {\n\t\t\t\t\t\tconst path = join(searchPath, item);\n\t\t\t\t\t\tconst stats = lstatSync(path);\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tname: item,\n\t\t\t\t\t\t\tpath,\n\t\t\t\t\t\t\tisDirectory: stats.isDirectory(),\n\t\t\t\t\t\t};\n\t\t\t\t\t})\n\t\t\t\t\t.filter(\n\t\t\t\t\t\t({ path, isDirectory }) => path.startsWith(prefix) && (isDirectory || !opts.directory)\n\t\t\t\t\t);\n\n\t\t\t\treturn items.map((item) => ({\n\t\t\t\t\tvalue: item.path,\n\t\t\t\t}));\n\t\t\t} catch (_e) {\n\t\t\t\treturn [];\n\t\t\t}\n\t\t},\n\t});\n};\n","import { styleText } from 'node:util';\nimport { block, getColumns, settings } from '@clack/core';\nimport { wrapAnsi } from 'fast-wrap-ansi';\nimport { cursor, erase } from 'sisteransi';\nimport {\n\ttype CommonOptions,\n\tisCI as isCIFn,\n\tS_BAR,\n\tS_STEP_CANCEL,\n\tS_STEP_ERROR,\n\tS_STEP_SUBMIT,\n\tunicode,\n} from './common.js';\n\nexport interface SpinnerOptions extends CommonOptions {\n\tindicator?: 'dots' | 'timer';\n\tonCancel?: () => void;\n\tcancelMessage?: string;\n\terrorMessage?: string;\n\tframes?: string[];\n\tdelay?: number;\n\tstyleFrame?: (frame: string) => string;\n}\n\nexport interface SpinnerResult {\n\tstart(msg?: string): void;\n\tstop(msg?: string): void;\n\tcancel(msg?: string): void;\n\terror(msg?: string): void;\n\tmessage(msg?: string): void;\n\tclear(): void;\n\treadonly isCancelled: boolean;\n}\n\nconst defaultStyleFn: SpinnerOptions['styleFrame'] = (frame) => styleText('magenta', frame);\n\nexport const spinner = ({\n\tindicator = 'dots',\n\tonCancel,\n\toutput = process.stdout,\n\tcancelMessage,\n\terrorMessage,\n\tframes = unicode ? ['◒', '◐', '◓', '◑'] : ['•', 'o', 'O', '0'],\n\tdelay = unicode ? 80 : 120,\n\tsignal,\n\t...opts\n}: SpinnerOptions = {}): SpinnerResult => {\n\tconst isCI = isCIFn();\n\n\tlet unblock: () => void;\n\tlet loop: NodeJS.Timeout;\n\tlet isSpinnerActive = false;\n\tlet isCancelled = false;\n\tlet _message = '';\n\tlet _prevMessage: string | undefined;\n\tlet _origin: number = performance.now();\n\tconst columns = getColumns(output);\n\tconst styleFn = opts?.styleFrame ?? defaultStyleFn;\n\n\tconst handleExit = (code: number) => {\n\t\tconst msg =\n\t\t\tcode > 1\n\t\t\t\t? (errorMessage ?? settings.messages.error)\n\t\t\t\t: (cancelMessage ?? settings.messages.cancel);\n\t\tisCancelled = code === 1;\n\t\tif (isSpinnerActive) {\n\t\t\t_stop(msg, code);\n\t\t\tif (isCancelled && typeof onCancel === 'function') {\n\t\t\t\tonCancel();\n\t\t\t}\n\t\t}\n\t};\n\n\tconst errorEventHandler = () => handleExit(2);\n\tconst signalEventHandler = () => handleExit(1);\n\n\tconst registerHooks = () => {\n\t\t// Reference: https://nodejs.org/api/process.html#event-uncaughtexception\n\t\tprocess.on('uncaughtExceptionMonitor', errorEventHandler);\n\t\t// Reference: https://nodejs.org/api/process.html#event-unhandledrejection\n\t\tprocess.on('unhandledRejection', errorEventHandler);\n\t\t// Reference Signal Events: https://nodejs.org/api/process.html#signal-events\n\t\tprocess.on('SIGINT', signalEventHandler);\n\t\tprocess.on('SIGTERM', signalEventHandler);\n\t\tprocess.on('exit', handleExit);\n\n\t\tif (signal) {\n\t\t\tsignal.addEventListener('abort', signalEventHandler);\n\t\t}\n\t};\n\n\tconst clearHooks = () => {\n\t\tprocess.removeListener('uncaughtExceptionMonitor', errorEventHandler);\n\t\tprocess.removeListener('unhandledRejection', errorEventHandler);\n\t\tprocess.removeListener('SIGINT', signalEventHandler);\n\t\tprocess.removeListener('SIGTERM', signalEventHandler);\n\t\tprocess.removeListener('exit', handleExit);\n\n\t\tif (signal) {\n\t\t\tsignal.removeEventListener('abort', signalEventHandler);\n\t\t}\n\t};\n\n\tconst clearPrevMessage = () => {\n\t\tif (_prevMessage === undefined) return;\n\t\tif (isCI) output.write('\\n');\n\t\tconst wrapped = wrapAnsi(_prevMessage, columns, {\n\t\t\thard: true,\n\t\t\ttrim: false,\n\t\t});\n\t\tconst prevLines = wrapped.split('\\n');\n\t\tif (prevLines.length > 1) {\n\t\t\toutput.write(cursor.up(prevLines.length - 1));\n\t\t}\n\t\toutput.write(cursor.to(0));\n\t\toutput.write(erase.down());\n\t};\n\n\tconst removeTrailingDots = (msg: string): string => {\n\t\treturn msg.replace(/\\.+$/, '');\n\t};\n\n\tconst formatTimer = (origin: number): string => {\n\t\tconst duration = (performance.now() - origin) / 1000;\n\t\tconst min = Math.floor(duration / 60);\n\t\tconst secs = Math.floor(duration % 60);\n\t\treturn min > 0 ? `[${min}m ${secs}s]` : `[${secs}s]`;\n\t};\n\n\tconst hasGuide = opts.withGuide ?? settings.withGuide;\n\n\tconst start = (msg = ''): void => {\n\t\tisSpinnerActive = true;\n\t\tunblock = block({ output });\n\t\t_message = removeTrailingDots(msg);\n\t\t_origin = performance.now();\n\t\tif (hasGuide) {\n\t\t\toutput.write(`${styleText('gray', S_BAR)}\\n`);\n\t\t}\n\t\tlet frameIndex = 0;\n\t\tlet indicatorTimer = 0;\n\t\tregisterHooks();\n\t\tloop = setInterval(() => {\n\t\t\tif (isCI && _message === _prevMessage) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tclearPrevMessage();\n\t\t\t_prevMessage = _message;\n\t\t\tconst frame = styleFn(frames[frameIndex]);\n\t\t\tlet outputMessage: string;\n\n\t\t\tif (isCI) {\n\t\t\t\toutputMessage = `${frame} ${_message}...`;\n\t\t\t} else if (indicator === 'timer') {\n\t\t\t\toutputMessage = `${frame} ${_message} ${formatTimer(_origin)}`;\n\t\t\t} else {\n\t\t\t\tconst loadingDots = '.'.repeat(Math.floor(indicatorTimer)).slice(0, 3);\n\t\t\t\toutputMessage = `${frame} ${_message}${loadingDots}`;\n\t\t\t}\n\n\t\t\tconst wrapped = wrapAnsi(outputMessage, columns, {\n\t\t\t\thard: true,\n\t\t\t\ttrim: false,\n\t\t\t});\n\t\t\toutput.write(wrapped);\n\n\t\t\tframeIndex = frameIndex + 1 < frames.length ? frameIndex + 1 : 0;\n\t\t\t// indicator increase by 1 every 8 frames\n\t\t\tindicatorTimer = indicatorTimer < 4 ? indicatorTimer + 0.125 : 0;\n\t\t}, delay);\n\t};\n\n\tconst _stop = (msg = '', code = 0, silent: boolean = false): void => {\n\t\tif (!isSpinnerActive) return;\n\t\tisSpinnerActive = false;\n\t\tclearInterval(loop);\n\t\tclearPrevMessage();\n\t\tconst step =\n\t\t\tcode === 0\n\t\t\t\t? styleText('green', S_STEP_SUBMIT)\n\t\t\t\t: code === 1\n\t\t\t\t\t? styleText('red', S_STEP_CANCEL)\n\t\t\t\t\t: styleText('red', S_STEP_ERROR);\n\t\t_message = msg ?? _message;\n\t\tif (!silent) {\n\t\t\tif (indicator === 'timer') {\n\t\t\t\toutput.write(`${step} ${_message} ${formatTimer(_origin)}\\n`);\n\t\t\t} else {\n\t\t\t\toutput.write(`${step} ${_message}\\n`);\n\t\t\t}\n\t\t}\n\t\tclearHooks();\n\t\tunblock();\n\t};\n\n\tconst stop = (msg = ''): void => _stop(msg, 0);\n\tconst cancel = (msg = ''): void => _stop(msg, 1);\n\tconst error = (msg = ''): void => _stop(msg, 2);\n\t// TODO (43081j): this will leave the initial S_BAR since we purposely\n\t// don't erase that in `clearPrevMessage`. In future, we may want to treat\n\t// `clear` as a special case and remove the bar too.\n\tconst clear = (): void => _stop('', 0, true);\n\n\tconst message = (msg = ''): void => {\n\t\t_message = removeTrailingDots(msg ?? _message);\n\t};\n\n\treturn {\n\t\tstart,\n\t\tstop,\n\t\tmessage,\n\t\tcancel,\n\t\terror,\n\t\tclear,\n\t\tget isCancelled() {\n\t\t\treturn isCancelled;\n\t\t},\n\t};\n};\n","import { styleText } from 'node:util';\nimport type { State } from '@clack/core';\nimport { unicodeOr } from './common.js';\nimport { type SpinnerOptions, type SpinnerResult, spinner } from './spinner.js';\n\nconst S_PROGRESS_CHAR: Record<NonNullable<ProgressOptions['style']>, string> = {\n\tlight: unicodeOr('─', '-'),\n\theavy: unicodeOr('━', '='),\n\tblock: unicodeOr('█', '#'),\n};\n\nexport interface ProgressOptions extends SpinnerOptions {\n\tstyle?: 'light' | 'heavy' | 'block';\n\tmax?: number;\n\tsize?: number;\n}\n\nexport interface ProgressResult extends SpinnerResult {\n\tadvance(step?: number, msg?: string): void;\n}\n\nexport function progress({\n\tstyle = 'heavy',\n\tmax: userMax = 100,\n\tsize: userSize = 40,\n\t...spinnerOptions\n}: ProgressOptions = {}): ProgressResult {\n\tconst spin = spinner(spinnerOptions);\n\tlet value = 0;\n\tlet previousMessage = '';\n\n\tconst max = Math.max(1, userMax);\n\tconst size = Math.max(1, userSize);\n\n\tconst activeStyle = (state: State) => {\n\t\tswitch (state) {\n\t\t\tcase 'initial':\n\t\t\tcase 'active':\n\t\t\t\treturn (text: string) => styleText('magenta', text);\n\t\t\tcase 'error':\n\t\t\tcase 'cancel':\n\t\t\t\treturn (text: string) => styleText('red', text);\n\t\t\tcase 'submit':\n\t\t\t\treturn (text: string) => styleText('green', text);\n\t\t\tdefault:\n\t\t\t\treturn (text: string) => styleText('magenta', text);\n\t\t}\n\t};\n\tconst drawProgress = (state: State, msg: string) => {\n\t\tconst active = Math.floor((value / max) * size);\n\t\treturn `${activeStyle(state)(S_PROGRESS_CHAR[style].repeat(active))}${styleText('dim', S_PROGRESS_CHAR[style].repeat(size - active))} ${msg}`;\n\t};\n\n\tconst start = (msg = '') => {\n\t\tpreviousMessage = msg;\n\t\tspin.start(drawProgress('initial', msg));\n\t};\n\tconst advance = (step = 1, msg?: string): void => {\n\t\tvalue = Math.min(max, step + value);\n\t\tspin.message(drawProgress('active', msg ?? previousMessage));\n\t\tpreviousMessage = msg ?? previousMessage;\n\t};\n\treturn {\n\t\tstart,\n\t\tstop: spin.stop,\n\t\tcancel: spin.cancel,\n\t\terror: spin.error,\n\t\tclear: spin.clear,\n\t\tadvance,\n\t\tisCancelled: spin.isCancelled,\n\t\tmessage: (msg: string) => advance(0, msg),\n\t};\n}\n","import { styleText } from 'node:util';\nimport { SelectPrompt, settings, wrapTextWithPrefix } from '@clack/core';\nimport {\n\ttype CommonOptions,\n\tS_BAR,\n\tS_BAR_END,\n\tS_RADIO_ACTIVE,\n\tS_RADIO_INACTIVE,\n\tsymbol,\n\tsymbolBar,\n} from './common.js';\nimport { limitOptions } from './limit-options.js';\n\ntype Primitive = Readonly<string | boolean | number>;\n\nexport type Option<Value> = Value extends Primitive\n\t? {\n\t\t\t/**\n\t\t\t * Internal data for this option.\n\t\t\t */\n\t\t\tvalue: Value;\n\t\t\t/**\n\t\t\t * The optional, user-facing text for this option.\n\t\t\t *\n\t\t\t * By default, the `value` is converted to a string.\n\t\t\t */\n\t\t\tlabel?: string;\n\t\t\t/**\n\t\t\t * An optional hint to display to the user when\n\t\t\t * this option might be selected.\n\t\t\t *\n\t\t\t * By default, no `hint` is displayed.\n\t\t\t */\n\t\t\thint?: string;\n\t\t\t/**\n\t\t\t * Whether this option is disabled.\n\t\t\t * Disabled options are visible but cannot be selected.\n\t\t\t *\n\t\t\t * By default, options are not disabled.\n\t\t\t */\n\t\t\tdisabled?: boolean;\n\t\t}\n\t: {\n\t\t\t/**\n\t\t\t * Internal data for this option.\n\t\t\t */\n\t\t\tvalue: Value;\n\t\t\t/**\n\t\t\t * Required. The user-facing text for this option.\n\t\t\t */\n\t\t\tlabel: string;\n\t\t\t/**\n\t\t\t * An optional hint to display to the user when\n\t\t\t * this option might be selected.\n\t\t\t *\n\t\t\t * By default, no `hint` is displayed.\n\t\t\t */\n\t\t\thint?: string;\n\t\t\t/**\n\t\t\t * Whether this option is disabled.\n\t\t\t * Disabled options are visible but cannot be selected.\n\t\t\t *\n\t\t\t * By default, options are not disabled.\n\t\t\t */\n\t\t\tdisabled?: boolean;\n\t\t};\n\nexport interface SelectOptions<Value> extends CommonOptions {\n\tmessage: string;\n\toptions: Option<Value>[];\n\tinitialValue?: Value;\n\tmaxItems?: number;\n}\n\nconst computeLabel = (label: string, format: (text: string) => string) => {\n\tif (!label.includes('\\n')) {\n\t\treturn format(label);\n\t}\n\treturn label\n\t\t.split('\\n')\n\t\t.map((line) => format(line))\n\t\t.join('\\n');\n};\n\nexport const select = <Value>(opts: SelectOptions<Value>) => {\n\tconst opt = (\n\t\toption: Option<Value>,\n\t\tstate: 'inactive' | 'active' | 'selected' | 'cancelled' | 'disabled'\n\t) => {\n\t\tconst label = option.label ?? String(option.value);\n\t\tswitch (state) {\n\t\t\tcase 'disabled':\n\t\t\t\treturn `${styleText('gray', S_RADIO_INACTIVE)} ${computeLabel(label, (text) => styleText('gray', text))}${\n\t\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint ?? 'disabled'})`)}` : ''\n\t\t\t\t}`;\n\t\t\tcase 'selected':\n\t\t\t\treturn `${computeLabel(label, (text) => styleText('dim', text))}`;\n\t\t\tcase 'active':\n\t\t\t\treturn `${styleText('green', S_RADIO_ACTIVE)} ${label}${\n\t\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t\t\t}`;\n\t\t\tcase 'cancelled':\n\t\t\t\treturn `${computeLabel(label, (str) => styleText(['strikethrough', 'dim'], str))}`;\n\t\t\tdefault:\n\t\t\t\treturn `${styleText('dim', S_RADIO_INACTIVE)} ${computeLabel(label, (text) => styleText('dim', text))}`;\n\t\t}\n\t};\n\n\treturn new SelectPrompt({\n\t\toptions: opts.options,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\toutput: opts.output,\n\t\tinitialValue: opts.initialValue,\n\t\trender() {\n\t\t\tconst hasGuide = opts.withGuide ?? settings.withGuide;\n\t\t\tconst titlePrefix = `${symbol(this.state)} `;\n\t\t\tconst titlePrefixBar = `${symbolBar(this.state)} `;\n\t\t\tconst messageLines = wrapTextWithPrefix(\n\t\t\t\topts.output,\n\t\t\t\topts.message,\n\t\t\t\ttitlePrefixBar,\n\t\t\t\ttitlePrefix\n\t\t\t);\n\t\t\tconst title = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${messageLines}\\n`;\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst submitPrefix = hasGuide ? `${styleText('gray', S_BAR)} ` : '';\n\t\t\t\t\tconst wrappedLines = wrapTextWithPrefix(\n\t\t\t\t\t\topts.output,\n\t\t\t\t\t\topt(this.options[this.cursor], 'selected'),\n\t\t\t\t\t\tsubmitPrefix\n\t\t\t\t\t);\n\t\t\t\t\treturn `${title}${wrappedLines}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst cancelPrefix = hasGuide ? `${styleText('gray', S_BAR)} ` : '';\n\t\t\t\t\tconst wrappedLines = wrapTextWithPrefix(\n\t\t\t\t\t\topts.output,\n\t\t\t\t\t\topt(this.options[this.cursor], 'cancelled'),\n\t\t\t\t\t\tcancelPrefix\n\t\t\t\t\t);\n\t\t\t\t\treturn `${title}${wrappedLines}${hasGuide ? `\\n${styleText('gray', S_BAR)}` : ''}`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst prefix = hasGuide ? `${styleText('cyan', S_BAR)} ` : '';\n\t\t\t\t\tconst prefixEnd = hasGuide ? styleText('cyan', S_BAR_END) : '';\n\t\t\t\t\t// Calculate rowPadding: title lines + footer lines (S_BAR_END + trailing newline)\n\t\t\t\t\tconst titleLineCount = title.split('\\n').length;\n\t\t\t\t\tconst footerLineCount = hasGuide ? 2 : 1; // S_BAR_END + trailing newline (or just trailing newline)\n\t\t\t\t\treturn `${title}${prefix}${limitOptions({\n\t\t\t\t\t\toutput: opts.output,\n\t\t\t\t\t\tcursor: this.cursor,\n\t\t\t\t\t\toptions: this.options,\n\t\t\t\t\t\tmaxItems: opts.maxItems,\n\t\t\t\t\t\tcolumnPadding: prefix.length,\n\t\t\t\t\t\trowPadding: titleLineCount + footerLineCount,\n\t\t\t\t\t\tstyle: (item, active) =>\n\t\t\t\t\t\t\topt(item, item.disabled ? 'disabled' : active ? 'active' : 'inactive'),\n\t\t\t\t\t}).join(`\\n${prefix}`)}\\n${prefixEnd}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<Value | symbol>;\n};\n","import { styleText } from 'node:util';\nimport { SelectKeyPrompt, settings, wrapTextWithPrefix } from '@clack/core';\nimport { type CommonOptions, S_BAR, S_BAR_END, symbol } from './common.js';\nimport type { Option } from './select.js';\n\nexport interface SelectKeyOptions<Value extends string> extends CommonOptions {\n\tmessage: string;\n\toptions: Option<Value>[];\n\tinitialValue?: Value;\n\tcaseSensitive?: boolean;\n}\n\nexport const selectKey = <Value extends string>(opts: SelectKeyOptions<Value>) => {\n\tconst opt = (\n\t\toption: Option<Value>,\n\t\tstate: 'inactive' | 'active' | 'selected' | 'cancelled' = 'inactive'\n\t) => {\n\t\tconst label = option.label ?? String(option.value);\n\t\tif (state === 'selected') {\n\t\t\treturn `${styleText('dim', label)}`;\n\t\t}\n\t\tif (state === 'cancelled') {\n\t\t\treturn `${styleText(['strikethrough', 'dim'], label)}`;\n\t\t}\n\t\tif (state === 'active') {\n\t\t\treturn `${styleText(['bgCyan', 'gray'], ` ${option.value} `)} ${label}${\n\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t\t}`;\n\t\t}\n\t\treturn `${styleText(['gray', 'bgWhite', 'inverse'], ` ${option.value} `)} ${label}${\n\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t}`;\n\t};\n\n\treturn new SelectKeyPrompt({\n\t\toptions: opts.options,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\toutput: opts.output,\n\t\tinitialValue: opts.initialValue,\n\t\tcaseSensitive: opts.caseSensitive,\n\t\trender() {\n\t\t\tconst hasGuide = opts.withGuide ?? settings.withGuide;\n\t\t\tconst title = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${symbol(this.state)} ${opts.message}\\n`;\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst submitPrefix = hasGuide ? `${styleText('gray', S_BAR)} ` : '';\n\t\t\t\t\tconst selectedOption =\n\t\t\t\t\t\tthis.options.find((opt) => opt.value === this.value) ?? opts.options[0];\n\t\t\t\t\tconst wrapped = wrapTextWithPrefix(\n\t\t\t\t\t\topts.output,\n\t\t\t\t\t\topt(selectedOption, 'selected'),\n\t\t\t\t\t\tsubmitPrefix\n\t\t\t\t\t);\n\t\t\t\t\treturn `${title}${wrapped}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst cancelPrefix = hasGuide ? `${styleText('gray', S_BAR)} ` : '';\n\t\t\t\t\tconst wrapped = wrapTextWithPrefix(\n\t\t\t\t\t\topts.output,\n\t\t\t\t\t\topt(this.options[0], 'cancelled'),\n\t\t\t\t\t\tcancelPrefix\n\t\t\t\t\t);\n\t\t\t\t\treturn `${title}${wrapped}${hasGuide ? `\\n${styleText('gray', S_BAR)}` : ''}`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst defaultPrefix = hasGuide ? `${styleText('cyan', S_BAR)} ` : '';\n\t\t\t\t\tconst defaultPrefixEnd = hasGuide ? styleText('cyan', S_BAR_END) : '';\n\t\t\t\t\tconst wrapped = this.options\n\t\t\t\t\t\t.map((option, i) =>\n\t\t\t\t\t\t\twrapTextWithPrefix(\n\t\t\t\t\t\t\t\topts.output,\n\t\t\t\t\t\t\t\topt(option, i === this.cursor ? 'active' : 'inactive'),\n\t\t\t\t\t\t\t\tdefaultPrefix\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.join('\\n');\n\t\t\t\t\treturn `${title}${wrapped}\\n${defaultPrefixEnd}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<Value | symbol>;\n};\n","import { stripVTControlCharacters as strip, styleText } from 'node:util';\nimport { S_BAR, S_ERROR, S_INFO, S_STEP_SUBMIT, S_SUCCESS, S_WARN } from './common.js';\nimport type { LogMessageOptions } from './log.js';\n\nconst prefix = `${styleText('gray', S_BAR)} `;\n\n// TODO (43081j): this currently doesn't support custom `output` writables\n// because we rely on `columns` existing (i.e. `process.stdout.columns).\n//\n// If we want to support `output` being passed in, we will need to use\n// a condition like `if (output insance Writable)` to check if it has columns\nexport const stream = {\n\tmessage: async (\n\t\titerable: Iterable<string> | AsyncIterable<string>,\n\t\t{ symbol = styleText('gray', S_BAR) }: LogMessageOptions = {}\n\t) => {\n\t\tprocess.stdout.write(`${styleText('gray', S_BAR)}\\n${symbol} `);\n\t\tlet lineWidth = 3;\n\t\tfor await (let chunk of iterable) {\n\t\t\tchunk = chunk.replace(/\\n/g, `\\n${prefix}`);\n\t\t\tif (chunk.includes('\\n')) {\n\t\t\t\tlineWidth = 3 + strip(chunk.slice(chunk.lastIndexOf('\\n'))).length;\n\t\t\t}\n\t\t\tconst chunkLen = strip(chunk).length;\n\t\t\tif (lineWidth + chunkLen < process.stdout.columns) {\n\t\t\t\tlineWidth += chunkLen;\n\t\t\t\tprocess.stdout.write(chunk);\n\t\t\t} else {\n\t\t\t\tprocess.stdout.write(`\\n${prefix}${chunk.trimStart()}`);\n\t\t\t\tlineWidth = 3 + strip(chunk.trimStart()).length;\n\t\t\t}\n\t\t}\n\t\tprocess.stdout.write('\\n');\n\t},\n\tinfo: (iterable: Iterable<string> | AsyncIterable<string>) => {\n\t\treturn stream.message(iterable, { symbol: styleText('blue', S_INFO) });\n\t},\n\tsuccess: (iterable: Iterable<string> | AsyncIterable<string>) => {\n\t\treturn stream.message(iterable, { symbol: styleText('green', S_SUCCESS) });\n\t},\n\tstep: (iterable: Iterable<string> | AsyncIterable<string>) => {\n\t\treturn stream.message(iterable, { symbol: styleText('green', S_STEP_SUBMIT) });\n\t},\n\twarn: (iterable: Iterable<string> | AsyncIterable<string>) => {\n\t\treturn stream.message(iterable, { symbol: styleText('yellow', S_WARN) });\n\t},\n\t/** alias for `log.warn()`. */\n\twarning: (iterable: Iterable<string> | AsyncIterable<string>) => {\n\t\treturn stream.warn(iterable);\n\t},\n\terror: (iterable: Iterable<string> | AsyncIterable<string>) => {\n\t\treturn stream.message(iterable, { symbol: styleText('red', S_ERROR) });\n\t},\n};\n","import type { CommonOptions } from './common.js';\nimport { spinner } from './spinner.js';\n\nexport type Task = {\n\t/**\n\t * Task title\n\t */\n\ttitle: string;\n\t/**\n\t * Task function\n\t */\n\ttask: (message: (string: string) => void) => string | Promise<string> | void | Promise<void>;\n\n\t/**\n\t * If enabled === false the task will be skipped\n\t */\n\tenabled?: boolean;\n};\n\n/**\n * Define a group of tasks to be executed\n */\nexport const tasks = async (tasks: Task[], opts?: CommonOptions) => {\n\tfor (const task of tasks) {\n\t\tif (task.enabled === false) continue;\n\n\t\tconst s = spinner(opts);\n\t\ts.start(task.title);\n\t\tconst result = await task.task(s.message);\n\t\ts.stop(result || task.title);\n\t}\n};\n","import type { Writable } from 'node:stream';\nimport { styleText } from 'node:util';\nimport { getColumns } from '@clack/core';\nimport { erase } from 'sisteransi';\nimport {\n\ttype CommonOptions,\n\tisCI as isCIFn,\n\tisTTY as isTTYFn,\n\tS_BAR,\n\tS_STEP_SUBMIT,\n} from './common.js';\nimport { log } from './log.js';\n\nexport interface TaskLogOptions extends CommonOptions {\n\ttitle: string;\n\tlimit?: number;\n\tspacing?: number;\n\tretainLog?: boolean;\n}\n\nexport interface TaskLogMessageOptions {\n\traw?: boolean;\n}\n\nexport interface TaskLogCompletionOptions {\n\tshowLog?: boolean;\n}\n\ninterface BufferEntry {\n\theader?: string;\n\tvalue: string;\n\tfull: string;\n\tresult?: {\n\t\tstatus: 'success' | 'error';\n\t\tmessage: string;\n\t};\n}\n\nconst stripDestructiveANSI = (input: string): string => {\n\t// biome-ignore lint/suspicious/noControlCharactersInRegex: intentional\n\treturn input.replace(/\\x1b\\[(?:\\d+;)*\\d*[ABCDEFGHfJKSTsu]|\\x1b\\[(s|u)/g, '');\n};\n\n/**\n * Renders a log which clears on success and remains on failure\n */\nexport const taskLog = (opts: TaskLogOptions) => {\n\tconst output: Writable = opts.output ?? process.stdout;\n\tconst columns = getColumns(output);\n\tconst secondarySymbol = styleText('gray', S_BAR);\n\tconst spacing = opts.spacing ?? 1;\n\tconst barSize = 3;\n\tconst retainLog = opts.retainLog === true;\n\tconst isTTY = !isCIFn() && isTTYFn(output);\n\n\toutput.write(`${secondarySymbol}\\n`);\n\toutput.write(`${styleText('green', S_STEP_SUBMIT)} ${opts.title}\\n`);\n\tfor (let i = 0; i < spacing; i++) {\n\t\toutput.write(`${secondarySymbol}\\n`);\n\t}\n\n\tconst buffers: BufferEntry[] = [\n\t\t{\n\t\t\tvalue: '',\n\t\t\tfull: '',\n\t\t},\n\t];\n\tlet lastMessageWasRaw = false;\n\n\tconst clear = (clearTitle: boolean): void => {\n\t\tif (buffers.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet lines = 0;\n\n\t\tif (clearTitle) {\n\t\t\tlines += spacing + 2;\n\t\t}\n\n\t\tfor (const buffer of buffers) {\n\t\t\tconst { value, result } = buffer;\n\t\t\tlet text = result?.message ?? value;\n\n\t\t\tif (text.length === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (result === undefined && buffer.header !== undefined && buffer.header !== '') {\n\t\t\t\ttext += `\\n${buffer.header}`;\n\t\t\t}\n\n\t\t\tconst bufferHeight = text.split('\\n').reduce((count, line) => {\n\t\t\t\tif (line === '') {\n\t\t\t\t\treturn count + 1;\n\t\t\t\t}\n\t\t\t\treturn count + Math.ceil((line.length + barSize) / columns);\n\t\t\t}, 0);\n\n\t\t\tlines += bufferHeight;\n\t\t}\n\n\t\tif (lines > 0) {\n\t\t\tlines += 1;\n\t\t\toutput.write(erase.lines(lines));\n\t\t}\n\t};\n\tconst printBuffer = (buffer: BufferEntry, messageSpacing?: number, full?: boolean): void => {\n\t\tconst messages = full ? `${buffer.full}\\n${buffer.value}` : buffer.value;\n\t\tif (buffer.header !== undefined && buffer.header !== '') {\n\t\t\tlog.message(\n\t\t\t\tbuffer.header.split('\\n').map((line) => styleText('bold', line)),\n\t\t\t\t{\n\t\t\t\t\toutput,\n\t\t\t\t\tsecondarySymbol,\n\t\t\t\t\tsymbol: secondarySymbol,\n\t\t\t\t\tspacing: 0,\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\t\tlog.message(\n\t\t\tmessages.split('\\n').map((line) => styleText('dim', line)),\n\t\t\t{\n\t\t\t\toutput,\n\t\t\t\tsecondarySymbol,\n\t\t\t\tsymbol: secondarySymbol,\n\t\t\t\tspacing: messageSpacing ?? spacing,\n\t\t\t}\n\t\t);\n\t};\n\tconst renderBuffer = (): void => {\n\t\tfor (const buffer of buffers) {\n\t\t\tconst { header, value, full } = buffer;\n\t\t\tif ((header === undefined || header.length === 0) && value.length === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tprintBuffer(buffer, undefined, retainLog === true && full.length > 0);\n\t\t}\n\t};\n\tconst message = (buffer: BufferEntry, msg: string, mopts?: TaskLogMessageOptions) => {\n\t\tclear(false);\n\t\tif ((mopts?.raw !== true || !lastMessageWasRaw) && buffer.value !== '') {\n\t\t\tbuffer.value += '\\n';\n\t\t}\n\t\tbuffer.value += stripDestructiveANSI(msg);\n\t\tlastMessageWasRaw = mopts?.raw === true;\n\t\tif (opts.limit !== undefined) {\n\t\t\tconst lines = buffer.value.split('\\n');\n\t\t\tconst linesToRemove = lines.length - opts.limit;\n\t\t\tif (linesToRemove > 0) {\n\t\t\t\tconst removedLines = lines.splice(0, linesToRemove);\n\t\t\t\tif (retainLog) {\n\t\t\t\t\tbuffer.full += (buffer.full === '' ? '' : '\\n') + removedLines.join('\\n');\n\t\t\t\t}\n\t\t\t}\n\t\t\tbuffer.value = lines.join('\\n');\n\t\t}\n\t\tif (isTTY) {\n\t\t\tprintBuffers();\n\t\t}\n\t};\n\tconst printBuffers = (): void => {\n\t\tfor (const buffer of buffers) {\n\t\t\tif (buffer.result) {\n\t\t\t\tif (buffer.result.status === 'error') {\n\t\t\t\t\tlog.error(buffer.result.message, { output, secondarySymbol, spacing: 0 });\n\t\t\t\t} else {\n\t\t\t\t\tlog.success(buffer.result.message, { output, secondarySymbol, spacing: 0 });\n\t\t\t\t}\n\t\t\t} else if (buffer.value !== '') {\n\t\t\t\tprintBuffer(buffer, 0);\n\t\t\t}\n\t\t}\n\t};\n\tconst completeBuffer = (buffer: BufferEntry, result: BufferEntry['result']): void => {\n\t\tclear(false);\n\n\t\tbuffer.result = result;\n\n\t\tif (isTTY) {\n\t\t\tprintBuffers();\n\t\t}\n\t};\n\n\treturn {\n\t\tmessage(msg: string, mopts?: TaskLogMessageOptions) {\n\t\t\tmessage(buffers[0], msg, mopts);\n\t\t},\n\t\tgroup(name: string) {\n\t\t\tconst buffer: BufferEntry = {\n\t\t\t\theader: name,\n\t\t\t\tvalue: '',\n\t\t\t\tfull: '',\n\t\t\t};\n\t\t\tbuffers.push(buffer);\n\t\t\treturn {\n\t\t\t\tmessage(msg: string, mopts?: TaskLogMessageOptions) {\n\t\t\t\t\tmessage(buffer, msg, mopts);\n\t\t\t\t},\n\t\t\t\terror(message: string) {\n\t\t\t\t\tcompleteBuffer(buffer, {\n\t\t\t\t\t\tstatus: 'error',\n\t\t\t\t\t\tmessage,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tsuccess(message: string) {\n\t\t\t\t\tcompleteBuffer(buffer, {\n\t\t\t\t\t\tstatus: 'success',\n\t\t\t\t\t\tmessage,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\terror(message: string, opts?: TaskLogCompletionOptions): void {\n\t\t\tclear(true);\n\t\t\tlog.error(message, { output, secondarySymbol, spacing: 1 });\n\t\t\tif (opts?.showLog !== false) {\n\t\t\t\trenderBuffer();\n\t\t\t}\n\t\t\t// clear buffer since error is an end state\n\t\t\tbuffers.splice(1, buffers.length - 1);\n\t\t\tbuffers[0].value = '';\n\t\t\tbuffers[0].full = '';\n\t\t},\n\t\tsuccess(message: string, opts?: TaskLogCompletionOptions): void {\n\t\t\tclear(true);\n\t\t\tlog.success(message, { output, secondarySymbol, spacing: 1 });\n\t\t\tif (opts?.showLog === true) {\n\t\t\t\trenderBuffer();\n\t\t\t}\n\t\t\t// clear buffer since success is an end state\n\t\t\tbuffers.splice(1, buffers.length - 1);\n\t\t\tbuffers[0].value = '';\n\t\t\tbuffers[0].full = '';\n\t\t},\n\t};\n};\n","import { styleText } from 'node:util';\nimport { settings, TextPrompt } from '@clack/core';\nimport { type CommonOptions, S_BAR, S_BAR_END, symbol } from './common.js';\n\nexport interface TextOptions extends CommonOptions {\n\tmessage: string;\n\tplaceholder?: string;\n\tdefaultValue?: string;\n\tinitialValue?: string;\n\tvalidate?: (value: string | undefined) => string | Error | undefined;\n}\n\nexport const text = (opts: TextOptions) => {\n\treturn new TextPrompt({\n\t\tvalidate: opts.validate,\n\t\tplaceholder: opts.placeholder,\n\t\tdefaultValue: opts.defaultValue,\n\t\tinitialValue: opts.initialValue,\n\t\toutput: opts.output,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\trender() {\n\t\t\tconst hasGuide = opts?.withGuide ?? settings.withGuide;\n\t\t\tconst titlePrefix = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${symbol(this.state)} `;\n\t\t\tconst title = `${titlePrefix}${opts.message}\\n`;\n\t\t\tconst placeholder = opts.placeholder\n\t\t\t\t? styleText('inverse', opts.placeholder[0]) + styleText('dim', opts.placeholder.slice(1))\n\t\t\t\t: styleText(['inverse', 'hidden'], '_');\n\t\t\tconst userInput = !this.userInput ? placeholder : this.userInputWithCursor;\n\t\t\tconst value = this.value ?? '';\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'error': {\n\t\t\t\t\tconst errorText = this.error ? ` ${styleText('yellow', this.error)}` : '';\n\t\t\t\t\tconst errorPrefix = hasGuide ? `${styleText('yellow', S_BAR)} ` : '';\n\t\t\t\t\tconst errorPrefixEnd = hasGuide ? styleText('yellow', S_BAR_END) : '';\n\t\t\t\t\treturn `${title.trim()}\\n${errorPrefix}${userInput}\\n${errorPrefixEnd}${errorText}\\n`;\n\t\t\t\t}\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst valueText = value ? ` ${styleText('dim', value)}` : '';\n\t\t\t\t\tconst submitPrefix = hasGuide ? styleText('gray', S_BAR) : '';\n\t\t\t\t\treturn `${title}${submitPrefix}${valueText}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst valueText = value ? ` ${styleText(['strikethrough', 'dim'], value)}` : '';\n\t\t\t\t\tconst cancelPrefix = hasGuide ? styleText('gray', S_BAR) : '';\n\t\t\t\t\treturn `${title}${cancelPrefix}${valueText}${value.trim() ? `\\n${cancelPrefix}` : ''}`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst defaultPrefix = hasGuide ? `${styleText('cyan', S_BAR)} ` : '';\n\t\t\t\t\tconst defaultPrefixEnd = hasGuide ? styleText('cyan', S_BAR_END) : '';\n\t\t\t\t\treturn `${title}${defaultPrefix}${userInput}\\n${defaultPrefixEnd}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<string | symbol>;\n};\n","import { formatResidentCostLine, residentCost, summarizeContextCost } from \"./context-cost.js\";\nimport { assetReachesCli, EXTERNAL_ASSETS } from \"./external-assets.js\";\nimport { readInstallLog } from \"./install-log.js\";\nimport type { InstallMode } from \"./installer.js\";\nimport { buildManifest } from \"./manifest.js\";\nimport {\n finalSelectedAssets,\n groupAssetsByCategory,\n recommendedExternalAssets,\n} from \"./preset-recommend.js\";\nimport {\n defaultPrompts,\n type InstallTargetId,\n type Prompts,\n VISIBLE_OPTION_DEFS,\n} from \"./prompts.js\";\nimport { type DetectedInstall, detectInstallState } from \"./state.js\";\nimport type { InstallSpec, OptionFlags, Track } from \"./types.js\";\nimport { stepLabel, WIZARD } from \"./wizard-steps.js\";\n\n/**\n * v26.54.0 — All-in-one 결과 → option keys + asset id list 분리.\n * `option:<key>` → OptionFlags key\n * `asset:<id>` → EXTERNAL_ASSETS id\n */\nexport function splitInstallTargets(targets: ReadonlyArray<InstallTargetId>): {\n optionKeys: Array<keyof OptionFlags>;\n assetIds: Array<string>;\n} {\n const optionKeys: Array<keyof OptionFlags> = [];\n const assetIds: Array<string> = [];\n for (const t of targets) {\n if (t.startsWith(\"option:\")) {\n optionKeys.push(t.slice(\"option:\".length) as keyof OptionFlags);\n } else if (t.startsWith(\"asset:\")) {\n assetIds.push(t.slice(\"asset:\".length));\n }\n }\n return { optionKeys, assetIds };\n}\n\n/**\n * v26.81.0 (ADR-022) — 자산 1:1 boolean 13종 삭제 후 잔존 동작 옵션만 매핑.\n * wizard 의 자산 선택은 전부 `asset:<id>` → userOverride.forceInclude 경로.\n */\nexport function toOptionFlags(keys: ReadonlyArray<keyof OptionFlags>): OptionFlags {\n const picked = new Set<keyof OptionFlags>(keys);\n return {\n withPrune: picked.has(\"withPrune\"),\n withCodexTrust: picked.has(\"withCodexTrust\"),\n withKarpathyHook: picked.has(\"withKarpathyHook\"),\n };\n}\n\nexport interface InteractiveDeps {\n prompts?: Prompts;\n detect?: (projectDir: string) => DetectedInstall;\n isTty?: () => boolean;\n /** v26.125.0 — 설치 상태 주입 (테스트용). 미주입 시 install log 를 읽는다. */\n readInstalled?: (projectDir: string) => InstalledTargetState;\n}\n\n/**\n * v26.125.0 — wizard 가 참조하는 설치 상태.\n *\n * `installed` 와 `projectScoped` 를 나누는 이유: global scope 자산까지 사전 체크하면\n * step 4 에서 project 를 고른 순간 **같은 자산이 project 에 한 벌 더 깔린다**. 그래서\n * 표시(마커)는 전부 하고, 사전 체크는 project scope 만 한다.\n */\nexport interface InstalledTargetState {\n /** 마커를 붙일 자산 id — scope 무관 (설치돼 있다는 사실 자체는 참) */\n installed: ReadonlyArray<string>;\n /** 사전 체크할 자산 id — project scope 만 */\n projectScoped: ReadonlyArray<string>;\n}\n\n/** install log → wizard 표시용 설치 상태. 로그가 없으면(최초 설치) 빈 상태. */\nexport function installedTargetState(projectDir: string): InstalledTargetState {\n const log = readInstallLog(projectDir);\n if (!log) return { installed: [], projectScoped: [] };\n return {\n installed: log.assets.map((a) => a.id),\n projectScoped: log.assets.filter((a) => a.scope !== \"global\").map((a) => a.id),\n };\n}\n\n/**\n * step 3 의 초기 체크 = **트랙 추천 ∪ 이미 설치된 project 자산**.\n *\n * 추천만 쓰면 추천 밖의 설치된 자산이 빈칸으로 보여, 사용자가 \"안 깔렸다\"고 읽는다.\n * 합집합이므로 중복은 생기지 않는다 (헤더의 `n/m ✓` 카운트가 거짓이 되지 않아야 한다).\n */\nexport function initialTargetSelection(\n tracks: ReadonlyArray<Track>,\n installedProjectAssetIds: ReadonlyArray<string>,\n): InstallTargetId[] {\n const ids = new Set<string>(recommendedExternalAssets(tracks));\n for (const id of installedProjectAssetIds) ids.add(id);\n return [...ids].map((id) => `asset:${id}` as InstallTargetId);\n}\n\nexport interface InteractiveResult {\n ok: boolean;\n spec?: InstallSpec;\n mode?: InstallMode;\n reason?: \"no-tty\" | \"cancelled\" | \"disabled-action\" | \"exit\";\n message?: string;\n}\n\n/**\n * v26.54.0 — 3-step wizard. SPEC: docs/specs/v26-54-all-in-one-installer.md\n *\n * Step 1: tracks (ESC = exit + cancel msg)\n * Step 2: cli (ESC = silent back to tracks)\n * Step 3: install-targets all-in-one (ESC = silent back to cli)\n * confirm prompt (ESC = silent back to targets)\n *\n * 이전 5-step 의 options + 2-tier asset navigator 를 step 3 1 화면 group multiselect 로 흡수.\n */\nexport async function runInteractive(\n projectDir: string,\n deps: InteractiveDeps = {},\n): Promise<InteractiveResult> {\n const prompts = deps.prompts ?? defaultPrompts;\n const detect = deps.detect ?? detectInstallState;\n const isTty = deps.isTty ?? (() => Boolean(process.stdin.isTTY));\n\n if (!isTty()) {\n return {\n ok: false,\n reason: \"no-tty\",\n message:\n \"Interactive mode requires a TTY. Use `agent-harness install --track <name>` for non-interactive use.\",\n };\n }\n\n prompts.intro(\"uzys-agent-harness installer\");\n const state = detect(projectDir);\n // v26.125.0 — 위저드가 설치 상태를 읽는다. 이전에는 step 3 의 체크가 트랙 추천에서만 나와\n // **이미 깔린 자산이 빈칸으로 보였다** — 사용자가 그 체크박스를 설치 상태로 읽으므로 화면이\n // 거짓을 말한 셈이다. 마커는 표시 전용이고 체크를 풀어도 제거되지 않는다 (제거 = `uninstall`).\n const installed = (deps.readInstalled ?? installedTargetState)(projectDir);\n\n let initialTracks: Track[] | undefined;\n let mode: InstallMode = \"fresh\";\n if (state.state === \"existing\") {\n const action = await prompts.selectAction(state);\n if (action === null) {\n prompts.cancel(\"Cancelled.\");\n return { ok: false, reason: \"cancelled\" };\n }\n if (action === \"exit\") {\n prompts.outro(\"Exiting without changes.\");\n return { ok: false, reason: \"exit\" };\n }\n if (action === \"remove\") {\n prompts.cancel(\"Track removal is not automated — manually edit `.claude/`. Aborting.\");\n return { ok: false, reason: \"disabled-action\" };\n }\n if (action === \"update\") {\n mode = \"update\";\n const summary = formatSummary({\n tracks: state.tracks,\n options: toOptionFlags([]),\n cli: [\"claude\"],\n projectDir,\n });\n const confirmed = await prompts.confirmInstall(`UPDATE policy files only:\\n${summary}`);\n if (!confirmed) {\n prompts.outro(\"Cancelled.\");\n return { ok: false, reason: \"cancelled\" };\n }\n prompts.outro(\"Running update mode...\");\n return {\n ok: true,\n mode: \"update\",\n spec: {\n tracks: state.tracks,\n options: toOptionFlags([]),\n cli: [\"claude\"],\n projectDir,\n },\n };\n }\n if (action === \"add\") {\n mode = \"add\";\n initialTracks = state.tracks;\n } else if (action === \"reinstall\") {\n mode = \"reinstall\";\n }\n }\n\n // v26.64.0 (ADR-020) — scope step 추가. Default \"project\". Step 3.5 (targets 직후, confirm 직전).\n type Step = \"tracks\" | \"cli\" | \"targets\" | \"scope\" | \"confirm\";\n let step: Step = \"tracks\";\n let tracks: Track[] | null = null;\n let cli: import(\"./types.js\").CliTargets | null = null;\n let targetSelections: ReadonlyArray<InstallTargetId> | null = null;\n let scope: import(\"./types.js\").InstallScope = \"project\";\n\n while (true) {\n if (step === \"tracks\") {\n const result = await prompts.selectTracks(tracks ?? initialTracks, WIZARD.TRACKS);\n if (result === null) {\n // Step 1 ESC = exit with cancel message (only step where ESC is \"cancel\")\n prompts.cancel(\"Cancelled.\");\n return { ok: false, reason: \"cancelled\" };\n }\n // preset 변경 감지 → install-targets reset (v26.50 정책 유지)\n if (tracks !== null && !tracksEqual(tracks, result)) {\n targetSelections = null;\n }\n tracks = result;\n step = \"cli\";\n } else if (step === \"cli\") {\n const result = await prompts.selectCli(cli ?? [\"claude\"], WIZARD.CLI);\n if (result === null) {\n step = \"tracks\"; // silent back\n continue;\n }\n cli = result;\n step = \"targets\";\n } else if (step === \"targets\") {\n const initial: InstallTargetId[] =\n targetSelections !== null\n ? [...targetSelections]\n : initialTargetSelection(tracks ?? [], installed.projectScoped);\n // v26.65.0 — step indicator SSOT (wizard-steps.ts). Phase: 3 targets → 4 scope → 5 confirm → 6 install.\n const result = await prompts.selectInstallTargets(initial, WIZARD.TARGETS, {\n tracks: tracks ?? [],\n cli: cli ?? [\"claude\"],\n installed: installed.installed.map((id) => `asset:${id}`),\n });\n if (result === null) {\n step = \"cli\"; // silent back\n continue;\n }\n targetSelections = result;\n step = \"scope\";\n } else if (step === \"scope\") {\n // v26.64.0 (ADR-020) — Installation scope select. Default \"project\" (D16).\n const result = await prompts.selectScope(scope, WIZARD.SCOPE);\n if (result === null) {\n step = \"targets\"; // silent back\n continue;\n }\n scope = result;\n step = \"confirm\";\n } else {\n // confirm\n // biome-ignore lint/style/noNonNullAssertion: confirm step 도달 = 모든 이전 step 완료 보장\n const finalTracks = tracks!;\n // biome-ignore lint/style/noNonNullAssertion: same as above\n const finalCli = cli!;\n const { optionKeys, assetIds } = splitInstallTargets(targetSelections ?? []);\n const options = toOptionFlags(optionKeys);\n const userOverride =\n targetSelections === null ? undefined : computeUserOverride(finalTracks, assetIds);\n // v26.64.0 (ADR-020) — Confirm summary 에 SCOPE 명시 (사용자 인지 + D16).\n const scopeLabel =\n scope === \"global\"\n ? \"Global (writes to ~/.claude/, ~/.codex/, npm -g)\"\n : \"Project (current directory only)\";\n const summary = `${formatSummary({\n tracks: finalTracks,\n options,\n cli: finalCli,\n projectDir,\n ...(userOverride ? { userOverride } : {}),\n })}\\n SCOPE ${scopeLabel}`;\n const confirmed = await prompts.confirmInstall(\n `${stepLabel(WIZARD.CONFIRM, \"Confirm\")}\\n${summary}`,\n );\n if (confirmed === null) {\n step = \"scope\"; // silent back\n continue;\n }\n if (!confirmed) {\n prompts.outro(\"Cancelled by user.\");\n return { ok: false, reason: \"cancelled\" };\n }\n prompts.outro(stepLabel(WIZARD.INSTALL, \"Installing...\"));\n return {\n ok: true,\n mode,\n spec: {\n tracks: finalTracks,\n options,\n cli: finalCli,\n projectDir,\n scope,\n ...(userOverride ? { userOverride } : {}),\n },\n };\n }\n }\n}\n\n/**\n * Track 배열 동등 비교 (순서 무관). Preset 변경 감지에 사용.\n */\nfunction tracksEqual(a: ReadonlyArray<Track>, b: ReadonlyArray<Track>): boolean {\n if (a.length !== b.length) return false;\n const sortedA = [...a].sort();\n const sortedB = [...b].sort();\n return sortedA.every((t, i) => t === sortedB[i]);\n}\n\n/**\n * v26.54.0 — Asset 선택 결과 (id 만) 와 preset 추천 비교 → forceInclude / forceExclude.\n * - `recommended - selected` → forceExclude (사용자가 unchecked)\n * - `selected - recommended` → forceInclude (사용자가 추가 선택)\n * 둘 다 비어있으면 undefined (no override).\n */\nexport function computeUserOverride(\n tracks: ReadonlyArray<Track>,\n assetIds: ReadonlyArray<string>,\n): { forceInclude: ReadonlyArray<string>; forceExclude: ReadonlyArray<string> } | undefined {\n const recommended = new Set(recommendedExternalAssets(tracks));\n const selected = new Set(assetIds);\n const forceExclude = [...recommended].filter((id) => !selected.has(id)).sort();\n const forceInclude = [...selected].filter((id) => !recommended.has(id)).sort();\n if (forceInclude.length === 0 && forceExclude.length === 0) return undefined;\n return { forceInclude, forceExclude };\n}\n\nexport function formatSummary(spec: InstallSpec): string {\n const opts = (Object.keys(spec.options) as Array<keyof OptionFlags>)\n .filter((k) => spec.options[k])\n .map((k) => k.replace(/^with/, \"\").toLowerCase());\n // v26.63.3 (clarify H1): \"(defaults only)\" 모호 → \"(none added)\" 명료.\n const optsLabel = opts.length > 0 ? opts.join(\", \") : \"(none added)\";\n const lines = [\n `Tracks: ${spec.tracks.join(\", \")}`,\n `Options: ${optsLabel}`,\n `CLI: ${spec.cli.join(\" · \")}`,\n `Target: ${spec.projectDir}`,\n ];\n\n // v26.62.3 — 실제 install 될 자산 list 명시. defaults 만으로는 사용자가\n // Step 3 에서 무엇을 confirm 했는지 알 수 없음. preset recommended +\n // userOverride 적용 후 최종 selected assets list 표시.\n // v26.82.0 (Phase R, S6) — merge/그룹화는 preset-recommend.ts 단일 구현 사용 (중복 제거).\n const finalAssets = finalSelectedAssets(spec.tracks, spec.userOverride);\n if (finalAssets.length > 0) {\n // v26.102.0 (ADR-031) — confirm 화면의 약속 숫자에 CLI 도달 분해 병기 (SOD 리뷰 F3:\n // \"4 selected\" 확정 후 0 설치이던 불일치 — 숨김 없이 고지만).\n const unreachable = finalAssets.filter((id) => {\n const asset = EXTERNAL_ASSETS.find((a) => a.id === id);\n return asset ? !assetReachesCli(asset, spec.cli) : false;\n });\n lines.push(\n unreachable.length > 0\n ? `Assets: ${finalAssets.length} selected (${unreachable.length} outside [${spec.cli.join(\", \")}] reach — not installed)`\n : `Assets: ${finalAssets.length} selected`,\n );\n for (const [cat, ids] of groupAssetsByCategory(finalAssets)) {\n lines.push(` · ${cat}: ${ids.join(\", \")}`);\n }\n // v26.103.0 (ADR-032) — header 와 동일 문구 (표면별 상이 문구 금지, v26.88.0 교훈).\n const cost = formatResidentCostLine(\n residentCost(buildManifest(spec).filter((e) => e.applies(spec))),\n summarizeContextCost(finalAssets).unmeasuredCount,\n );\n if (cost) lines.push(` · ${cost}`);\n }\n\n if (spec.userOverride) {\n if (spec.userOverride.forceInclude.length > 0) {\n lines.push(` +User added: ${spec.userOverride.forceInclude.join(\", \")}`);\n }\n if (spec.userOverride.forceExclude.length > 0) {\n lines.push(` -User removed: ${spec.userOverride.forceExclude.join(\", \")}`);\n }\n }\n return lines.join(\"\\n\");\n}\n\n// v26.54.0 — Re-exports to keep test imports stable (test의 mock 구조 변경 없음)\nexport { EXTERNAL_ASSETS, VISIBLE_OPTION_DEFS };\n","// prompts.ts is a thin adapter over @clack/prompts. It deliberately contains\n// no transformation logic — interactive.ts owns the business rules. This file\n// is excluded from coverage in vitest.config.ts (justification at exclude line).\n\nimport {\n cancel,\n confirm,\n groupMultiselect,\n intro,\n isCancel,\n multiselect,\n outro,\n select,\n} from \"@clack/prompts\";\nimport { CATEGORIES, CATEGORY_TITLES, type Category } from \"./categories.js\";\nimport { CLI_BASE_SORT_ORDER } from \"./cli-targets.js\";\nimport { assetTrustTier, DEV_METHOD_SKILL_IDS, EXTERNAL_ASSETS } from \"./external-assets.js\";\nimport { buildRouterChoices, type RouterAction, summarizeState } from \"./router.js\";\nimport type { DetectedInstall } from \"./state.js\";\nimport {\n type CliBase,\n type CliTargets,\n type InstallScope,\n type OptionFlags,\n TRACKS,\n type Track,\n} from \"./types.js\";\nimport { stepLabel, type WizardStep } from \"./wizard-steps.js\";\n\n/**\n * v26.54.0 — All-in-one install-targets value scheme.\n * groupMultiselect 의 단일 string value 에 두 source 통합:\n * - `option:<key>` → OPTION_DEFS 의 manifest-영향 build option (현재 빈 배열 — 아래 OPTION_DEFS 참조)\n * - `asset:<id>` → EXTERNAL_ASSETS 의 외부 자산\n * 다른 OptionFlags 항목 (withGsd, withEcc, withPrune, withTob, withKarpathyHook,\n * withAddyAgentSkills, withSuperpowers, withWshobsonAgents, withOpenspec, withBmad) 은\n * EXTERNAL_ASSETS 에 1:1 자산이 있어\n * 자산 체크 → userOverride.forceInclude 로 처리. UI 중복 표시 없음.\n */\nexport type InstallTargetId = `option:${keyof OptionFlags}` | `asset:${string}`;\n\nexport interface Prompts {\n intro: (msg: string) => void;\n outro: (msg: string) => void;\n cancel: (msg: string) => void;\n\n /**\n * v26.65.0 — step optional 두 번째 인자. 호출자가 `WIZARD.TRACKS` 전달 시 message 에\n * \"Step N/M — Select Track(s)\" 형식 indicator 자동 삽입. 미전달 시 prefix 없이 raw label.\n */\n selectTracks: (initial?: Track[], step?: WizardStep) => Promise<Track[] | null>;\n /** v0.7.0 — single select → multiselect (3 base 체크박스). default `[\"claude\"]`. */\n selectCli: (initial?: CliTargets, step?: WizardStep) => Promise<CliTargets | null>;\n selectAction: (state: DetectedInstall) => Promise<RouterAction | null>;\n /**\n * v26.64.0 (ADR-020) — Installation scope 선택. Default = \"project\" (pre-selected).\n * Global 은 사용자 명시 opt-in. null = silent back.\n */\n selectScope: (initial?: InstallScope, step?: WizardStep) => Promise<InstallScope | null>;\n confirmInstall: (summary: string) => Promise<boolean | null>;\n\n /**\n * v26.54.0 — Step 3 (all-in-one). EXTERNAL_ASSETS + 표시-대상 OPTION_DEFS 를\n * 카테고리 그룹화. 추천 ✓ pre-check. ESC → null (silent back).\n * v26.61.0 — recap (tracks/cli) 추가. alt screen 안에서 동작 — terminal scrollback\n * 본질 차단 → wizard scroll 시 cursor highlight 항상 visible.\n */\n selectInstallTargets: (\n initialChecked: ReadonlyArray<InstallTargetId>,\n step: { current: number; total: number },\n recap?: {\n tracks: ReadonlyArray<Track>;\n cli: CliTargets;\n /**\n * v26.125.0 — 이미 설치된 target id (표시 전용 마커). 체크를 풀어도 제거되지 않는다 —\n * 제거는 `agent-harness uninstall` 을 따로 실행한다 (사용자 결정 2026-07-19).\n */\n installed?: ReadonlyArray<string>;\n },\n ) => Promise<ReadonlyArray<InstallTargetId> | null>;\n}\n\nconst TRACK_LABELS: Record<Track, string> = {\n tooling: \"tooling — Bash + Markdown meta-project\",\n \"csr-supabase\": \"csr-supabase — Vite + React + Supabase\",\n \"csr-fastify\": \"csr-fastify — Vite + React + Fastify\",\n \"csr-fastapi\": \"csr-fastapi — Vite + React + FastAPI\",\n \"ssr-htmx\": \"ssr-htmx — htmx + FastAPI\",\n \"ssr-nextjs\": \"ssr-nextjs — Next.js (App Router)\",\n data: \"data — Python data / DuckDB / PySide6\",\n executive: \"executive — proposals / DD / pitch (no agent-skills)\",\n full: \"full — all dev capabilities\",\n \"project-management\": \"project-management — PM / Scrum / Jira / Confluence\",\n \"growth-marketing\": \"growth-marketing — Growth / Marketing / Content\",\n};\n\ninterface OptionDef {\n key: keyof OptionFlags;\n label: string;\n hint: string;\n category: Category;\n source: string;\n}\n\n/**\n * v26.54.0 — 표시 대상 OPTION_DEFS.\n * v26.81.0 (ADR-022) — **빈 배열로 소멸**. 마지막 항목(withTauri)이 내부\n * 자산(tauri-desktop — EXTERNAL_ASSETS `kind:\"internal\"`)으로 흡수돼 wizard 의\n * `option:` 특례가 사라짐. 자산 선택은 전부 `asset:<id>` 경로. 잔존 동작 옵션(D16 글로벌\n * 4종/karpathy hook/prune)은 wizard 미노출 (CLI `--with-*` 동작 플래그 전용 — 기존과 동일).\n */\nexport const VISIBLE_OPTION_DEFS: ReadonlyArray<OptionDef> = [];\n\nconst CLI_BASE_LABELS: Record<CliBase, string> = {\n claude: \"Claude Code\",\n codex: \"Codex (OpenAI)\",\n opencode: \"OpenCode (anomalyco)\",\n antigravity: \"Antigravity (Google)\",\n};\n\n/**\n * v26.78.1 — Step 3 wizard page layout (SSOT). 카테고리를 페이지로 묶어 clack\n * groupMultiselect 의 maxItems 한계(페이지당 옵션 ≤ ~30)를 우회.\n *\n * ⚠️ drift 가드 (no-false-ship): 모든 Category 는 정확히 한 페이지에 등장해야 한다.\n * 누락 시 해당 카테고리 자산이 wizard 에서 선택 불가가 되어 \"출하 거짓 광고\"가 된다\n * (v26.78.0 understanding 누락 회귀 — pages 가 selectInstallTargets 안에 하드코딩되어\n * CATEGORIES 추가와 drift). 아래 assertPagesCoverAllCategories 가 모듈 로드 시점에\n * 강제 — 신규 카테고리 미배치 시 즉시 throw. (tests/wizard-page-parity.test.ts 가 이중 가드)\n *\n * v26.99.0 — Dev 단일 페이지가 37행(옵션 32 + 헤더 5)으로 위 \"≤ ~30\" 제약을 스스로 위반하고\n * 있었다(실측). 터미널을 넘겨 스크롤이 생기는 것이 사용자가 보고한 \"선택 row 가 너무 많다\"의\n * 실제 메커니즘. → Dev 를 도메인(Core)과 도구(Tools)로 분할. 번들링(아래 DEV_METHOD_BUNDLE)만으론\n * 33행이라 부족했다 — Dev 32항목 중 dev-method 는 4개뿐이고, 번들 row 는 workflow 에 렌더되어\n * Dev 페이지에 남지 않으므로 37-4=33. ADR-028.\n *\n * 페이지 묶음 (전 페이지 ≤ 30 행):\n * Page 1: Dev Core — frontend + backend + data (20행)\n * Page 2: Dev Tools — dev-tools + understanding (13행)\n * Page 3: Business — business (documents) ( 9행)\n * Page 4: Visual&Media — visual-media (slides·diagrams·motion·video) (10행)\n * Page 5: Workflow/ECC — workflow(+ 방법론 번들 1행) + ecc-suite (10행)\n */\nexport interface InstallTargetPage {\n label: string;\n cats: ReadonlyArray<Category>;\n}\n\nexport const INSTALL_TARGET_PAGES: ReadonlyArray<InstallTargetPage> = [\n { label: \"Dev Core (Frontend · Backend · Data)\", cats: [\"frontend\", \"backend\", \"data\"] },\n { label: \"Dev Tools (Security · Quality · Understanding)\", cats: [\"dev-tools\", \"understanding\"] },\n { label: \"Business (PM · Executive · Documents)\", cats: [\"business\"] },\n // v26.85.0 — 코드-퍼스트 비주얼/미디어 제작 (용도별 섹션, 전부 opt-in).\n { label: \"Visual & Media (Slides · Diagrams · Motion · Video)\", cats: [\"visual-media\"] },\n { label: \"Workflow & ECC Suite\", cats: [\"workflow\", \"ecc-suite\"] },\n];\n\n/**\n * v26.99.0 (ADR-028) — dev-method 방법론 스킬 8종을 wizard 에서 **단일 row** 로 접는다.\n *\n * WHY: 8종은 전부 `has-dev-track` = 기본 설치다. 즉 **사실상 선택이 아닌데** 체크박스 8행을\n * 점유해, 진짜 선택인 서드파티 큐레이션을 밀어냈다(사용자 지적 2026-07-16). 8종은 개념적으로\n * 하나 — \"이 하네스의 작업 방법론\" — 이므로 한 줄이 정직한 표현이다.\n *\n * 순수 **표현 계층** 변환이다. 입력 시 접고(collapse) 제출 시 8개 asset id 로 펼쳐(expand)\n * 돌려주므로 downstream(computeUserOverride·installer·설치 보고)은 8개를 그대로 본다 —\n * **번들이 \"무엇이 설치되는지\"를 숨기지 않는다**(사용자 요구 가드). 구성원은\n * `DEV_METHOD_SKILL_IDS` 에서 derive → 자산 추가 시 자동 반영(하드코딩 금지, no-false-ship).\n *\n * 해제 시맨틱(사용자 확정 2026-07-16): 체크박스 1개 = 의미 1개 → **해제하면 8종 전부 제외**.\n * 개별 제어는 `--with <id>` / `--without <id>`.\n *\n * all-or-none 불변식: 8종이 **같은 condition(`has-dev-track`)** 을 공유하므로\n * `recommendedExternalAssets` 는 8개를 전부 넣거나 전부 뺀다 → 부분 선택 상태가 생기지 않는다.\n * 이 불변식이 깨지면 접기가 자산을 조용히 추가/삭제할 수 있으므로\n * `tests/wizard-bundle.test.ts` 가 강제한다 (Rule 12 fail loud).\n */\nexport const DEV_METHOD_BUNDLE_VALUE = \"bundle:dev-method\";\n\n/**\n * 번들 row 가 렌더되는 카테고리 — 방법론 = 개발 사이클 도구라 workflow.\n * export = SSOT (테스트가 `\"workflow\"` 를 재차 하드코딩하면 번들 위치 변경 시 게이트 수식이\n * 렌더와 조용히 갈린다 — no-false-ship \"2곳 이상 하드코딩 금지\").\n */\nexport const DEV_METHOD_BUNDLE_CATEGORY: Category = \"workflow\";\n\nconst bundleMemberValues = (): ReadonlyArray<string> =>\n DEV_METHOD_SKILL_IDS.map((id) => `asset:${id}`);\n\n/** 입력 접기 — dev-method 멤버가 (불변식상 전부) 있으면 번들 row 체크로 치환. */\nexport function collapseDevMethodBundle(ids: ReadonlyArray<string>): ReadonlyArray<string> {\n const members = new Set(bundleMemberValues());\n const rest = ids.filter((v) => !members.has(v));\n const anyMember = ids.some((v) => members.has(v));\n return anyMember ? [...rest, DEV_METHOD_BUNDLE_VALUE] : rest;\n}\n\n/** 제출 펼치기 — 번들 row 체크 → 8개 asset id. downstream 은 개별 자산만 본다. */\nexport function expandDevMethodBundle(ids: ReadonlyArray<string>): ReadonlyArray<string> {\n const rest = ids.filter((v) => v !== DEV_METHOD_BUNDLE_VALUE);\n return ids.includes(DEV_METHOD_BUNDLE_VALUE) ? [...rest, ...bundleMemberValues()] : rest;\n}\n\nexport interface PageItem {\n value: string;\n label: string;\n hint?: string;\n}\n\n/**\n * v26.99.0 (ADR-028) — Step 3 한 페이지의 group/item 구성. clack 의존 0 인 순수 함수.\n *\n * `selectInstallTargets` 안의 클로저였으나 export 로 승격했다 (SOD 리뷰 Important #2):\n * **이 함수가 dev-method 스킬 전원을 wizard 에서 도달 가능하게 만드는 유일한 코드**인데, 테스트가\n * 하나도 닿지 않았다. `wizard-page-parity` 는 \"자산의 **카테고리**가 페이지에 있다\"만 보는데,\n * 8종은 자기 카테고리에서 필터링되고 번들 row 로만 대표되므로 그 단언은 이제 8종에 대해\n * 비논리(non sequitur)다 — 번들 row 블록을 지워도 parity 는 통과하고 CI 는 green 인 채\n * 8종이 **어디서도 선택 불가**가 된다. v26.78.0 거짓출하의 정확한 재현이다.\n * (`prompts.ts` 는 coverage 제외 대상이라 커버리지 수치도 이 코드에 대해 아무 보장을 못 준다.)\n */\nexport function buildPageGroups(\n cats: ReadonlyArray<Category>,\n initialSet: ReadonlySet<string>,\n /**\n * v26.125.0 — 이미 설치된 target id. 라벨에 `● installed` 마커만 붙인다.\n * **체크 상태와 별개다** — 체크는 \"이번에 설치할 것\", 마커는 \"이미 있는 것\"이고,\n * 체크를 풀어도 제거되지 않는다(제거는 `uninstall` 을 따로 실행).\n */\n installedSet: ReadonlySet<string> = new Set(),\n): { groups: Record<string, PageItem[]>; flatItems: PageItem[] } {\n const installedMark = (value: string): string => (installedSet.has(value) ? \" ● installed\" : \"\");\n const groups: Record<string, PageItem[]> = {};\n const flatItems: PageItem[] = [];\n for (const cat of cats) {\n const items: PageItem[] = [];\n for (const o of VISIBLE_OPTION_DEFS.filter((d) => d.category === cat)) {\n items.push({\n value: `option:${o.key}`,\n // v26.62.3 — group header 와 옵션 사이 시각 hierarchy 강화. label prefix 4 space.\n label: ` ${o.label} [${o.source}]${installedMark(`option:${o.key}`)}`,\n hint: o.hint,\n });\n }\n // v26.99.0 (ADR-028) — 방법론 번들 row. 개별 8행 대신 1행. hint 에 구성원 id 를 전부\n // 노출 — 접는 것이 \"무엇이 설치되는지\" 를 숨기면 안 된다.\n if (cat === DEV_METHOD_BUNDLE_CATEGORY) {\n items.push({\n value: DEV_METHOD_BUNDLE_VALUE,\n label: ` uzys 하네스 방법론 ${DEV_METHOD_SKILL_IDS.length}종 [uzys] ★ official${installedMark(DEV_METHOD_BUNDLE_VALUE)}`,\n hint: DEV_METHOD_SKILL_IDS.join(\", \"),\n });\n }\n // v26.71.0 (PRD v26-71) — tier 우선 정렬 (official → vetted → experimental) + 배지.\n const tierOrder = { official: 0, vetted: 1, experimental: 2 } as const;\n const devMethod = new Set<string>(DEV_METHOD_SKILL_IDS);\n const catAssets = [...EXTERNAL_ASSETS.filter((x) => x.category === cat)]\n // 번들 구성원은 개별 row 로 렌더하지 않는다 (번들 1행이 대표).\n .filter((x) => !devMethod.has(x.id))\n .sort((a, b) => tierOrder[assetTrustTier(a.id)] - tierOrder[assetTrustTier(b.id)]);\n for (const a of catAssets) {\n const tier = assetTrustTier(a.id);\n const badge =\n tier === \"official\"\n ? \" ★ official\"\n : tier === \"experimental\"\n ? \" ⚠ experimental (opt-in)\"\n : \"\";\n items.push({\n value: `asset:${a.id}`,\n label: ` ${a.id} [${a.source}]${badge}${installedMark(`asset:${a.id}`)}`,\n hint: a.description,\n });\n }\n if (items.length === 0) continue;\n const selectedInCat = items.filter((it) => initialSet.has(it.value)).length;\n const header = `${CATEGORY_TITLES[cat]} [${selectedInCat}/${items.length} ✓ default]`;\n groups[header] = items;\n flatItems.push(...items);\n }\n return { groups, flatItems };\n}\n\n/**\n * 모든 Category 가 정확히 한 페이지에 등장하는지 모듈 로드 시 검증.\n * 누락(미배치) 또는 중복(2개 페이지)이면 throw — 값싼 fail-loud pre-flight.\n */\nfunction assertPagesCoverAllCategories(pages: ReadonlyArray<InstallTargetPage>): void {\n const counts = new Map<Category, number>();\n for (const page of pages) {\n for (const cat of page.cats) counts.set(cat, (counts.get(cat) ?? 0) + 1);\n }\n const missing = CATEGORIES.filter((c) => !counts.has(c));\n const duplicated = CATEGORIES.filter((c) => (counts.get(c) ?? 0) > 1);\n if (missing.length > 0 || duplicated.length > 0) {\n throw new Error(\n `INSTALL_TARGET_PAGES drift vs CATEGORIES — missing=[${missing.join(\", \")}] ` +\n `duplicated=[${duplicated.join(\", \")}]. 모든 카테고리는 정확히 한 페이지에 배치해야 한다 ` +\n `(no-false-ship: wizard 미노출 = 거짓 광고).`,\n );\n }\n}\n\nassertPagesCoverAllCategories(INSTALL_TARGET_PAGES);\n\n/**\n * v26.58.1 — Wizard viewport size. clack 의 limitOptions 가 maxItems 안에서만\n * cursor follow + ↕ ... indicator. 미지정 시 Infinity → terminal height 초과 시\n * 위 항목이 scrollback 으로 밀려 selected indicator 안 보임 (사용자 보고된 문제).\n *\n * rowPadding 10 = message line + status footer + safety margin.\n * floor 8 = 너무 작아도 최소한의 viewport 보장.\n */\nfunction viewportItems(itemCount: number): number {\n const rows = process.stdout.rows ?? 24;\n return Math.max(8, Math.min(itemCount, rows - 10));\n}\n\nexport const defaultPrompts: Prompts = {\n intro: (msg) => intro(msg),\n outro: (msg) => outro(msg),\n cancel: (msg) => cancel(msg),\n\n selectTracks: async (initial, step) => {\n // v26.65.0 — step indicator SSOT (wizard-steps.ts). 6-step 통합 (1 tracks · 2 cli · 3 targets · 4 scope · 5 confirm · 6 installing).\n const result = await multiselect({\n message: stepLabel(step, \"Select Track(s)\"),\n options: TRACKS.map((t) => ({ value: t, label: TRACK_LABELS[t] })),\n ...(initial ? { initialValues: initial } : {}),\n maxItems: viewportItems(11),\n required: true,\n });\n return isCancel(result) ? null : (result as Track[]);\n },\n\n selectCli: async (initial, step) => {\n const initialValues: CliBase[] = initial && initial.length > 0 ? [...initial] : [\"claude\"];\n const result = await multiselect({\n message: stepLabel(step, \"Target CLI(s)\"),\n options: [\n { value: \"claude\" as const, label: CLI_BASE_LABELS.claude },\n { value: \"codex\" as const, label: CLI_BASE_LABELS.codex },\n { value: \"opencode\" as const, label: CLI_BASE_LABELS.opencode },\n { value: \"antigravity\" as const, label: CLI_BASE_LABELS.antigravity },\n ],\n initialValues,\n required: true,\n });\n if (isCancel(result)) return null;\n return [...(result as CliBase[])].sort(\n (a, b) => CLI_BASE_SORT_ORDER[a] - CLI_BASE_SORT_ORDER[b],\n );\n },\n\n selectAction: async (state) => {\n const result = await select({\n message: summarizeState(state),\n options: buildRouterChoices(state).map((c) => {\n const label = c.enabled ? c.label : `${c.label} [disabled]`;\n // disabled:true → clack 이 cursor skip + strikethrough (선택 자체 차단).\n return {\n value: c.value,\n label,\n ...(c.hint ? { hint: c.hint } : {}),\n ...(c.enabled ? {} : { disabled: true }),\n };\n }),\n });\n return isCancel(result) ? null : (result as RouterAction);\n },\n\n /**\n * v26.64.0 (ADR-020) — Installation scope select. Default Project (D16 — no global write).\n * Global 은 사용자 명시 opt-in 시에만.\n */\n selectScope: async (initial = \"project\", step) => {\n const result = await select({\n message: stepLabel(step, \"Installation scope\"),\n initialValue: initial,\n options: [\n {\n value: \"project\",\n label: \"Project\",\n hint: \"Install in current directory (committed with your project)\",\n },\n {\n value: \"global\",\n label: \"Global\",\n hint: \"Write to ~/.claude/, ~/.codex/, npm -g (shared across all projects)\",\n },\n ],\n });\n return isCancel(result) ? null : (result as InstallScope);\n },\n\n confirmInstall: async (summary) => {\n const result = await confirm({\n message: `${summary}\\n\\nProceed?`,\n initialValue: true,\n });\n return isCancel(result) ? null : result;\n },\n\n selectInstallTargets: async (initialChecked, step, recap) => {\n // v26.62.2 — groupMultiselect 복귀 + page paginate.\n // v26.62.1 에서 multiselect + disabled separator 시도 → clack 가 disabled option 에\n // 체크박스 강제 + dim/strikethrough 효과 → 카테고리 헤더가 \"옵션 같지만 선택 불가\"\n // 처럼 보여 사용자 보고. groupMultiselect 의 group header 는 라이브러리에서 본래\n // 설명 라인 형태로 자연 표시 → 시각 명료.\n //\n // maxItems 한계 (GroupMultiSelectPrompt 미지원) 는 page 묶음으로 cover:\n // 한 page 안 옵션 ≤ ~30 → 사용자 iTerm2 (30+ rows) 환경에서 fit. 매우 작은 terminal\n // (< 25 rows) 한계는 follow-up.\n //\n // 페이지 정의 = 모듈 스코프 INSTALL_TARGET_PAGES (SSOT, 카테고리 전수 가드됨).\n const pages = INSTALL_TARGET_PAGES;\n // v26.99.0 (ADR-028) — 표현 계층에서만 번들로 접는다. 제출 시 다시 펼쳐 돌려주므로\n // downstream 계약(개별 asset id)은 불변.\n const displayInitial = collapseDevMethodBundle(initialChecked);\n const initialSet = new Set<string>(displayInitial);\n const collected = new Set<string>(displayInitial);\n\n const recapLine = recap\n ? `Tracks: ${recap.tracks.join(\", \")} · CLIs: ${recap.cli.join(\", \")}`\n : \"\";\n // v26.125.0 — 마커 전용. 체크 상태와 별개이며, 체크를 풀어도 제거되지 않는다.\n const installedSet = new Set<string>(\n collapseDevMethodBundle((recap?.installed ?? []) as ReadonlyArray<InstallTargetId>),\n );\n\n // alt screen for the whole Step 3 loop. page 전환 시 buffer 안에서 redraw.\n process.stdout.write(\"\\x1b[?1049h\");\n let resultIds: ReadonlyArray<InstallTargetId> | null = null;\n let aborted = false;\n try {\n let pageIdx = 0;\n while (pageIdx < pages.length) {\n const page = pages[pageIdx];\n if (!page) break;\n const { groups, flatItems } = buildPageGroups(page.cats, initialSet, installedSet);\n const selectedNow = flatItems.filter((it) => collected.has(it.value)).map((it) => it.value);\n const pageDefault = flatItems.filter((it) => initialSet.has(it.value)).length;\n const totalSelected = collected.size;\n const message = [\n `Step ${step.current}/${step.total} · Page ${pageIdx + 1}/${pages.length} · ${page.label}`,\n recapLine ? ` ${recapLine}` : \"\",\n ` Selected so far: ${totalSelected} items · This page default ✓ ${pageDefault}/${flatItems.length}`,\n // 마커의 뜻을 화면에서 바로 알려준다 — 체크 해제를 제거로 오해하는 것이 이 화면의\n // 원래 문제였으므로, 마커가 보일 때는 제거 경로를 같은 자리에서 말한다.\n installedSet.size > 0\n ? \" ● installed = 이미 설치됨 · 체크 해제해도 제거되지 않는다 (제거: agent-harness uninstall)\"\n : \"\",\n \" Space toggle · Enter → next · ESC → prev\",\n ]\n .filter(Boolean)\n .join(\"\\n\");\n\n const groupOpts = {\n message,\n options: groups,\n initialValues: selectedNow,\n required: false,\n selectableGroups: false,\n } as Parameters<typeof groupMultiselect>[0];\n const result = await groupMultiselect(groupOpts);\n if (isCancel(result)) {\n if (pageIdx === 0) {\n aborted = true; // first page ESC → Step 2 back\n break;\n }\n pageIdx--; // prev page\n continue;\n }\n // update collected: remove page items + add the new selection\n for (const it of flatItems) collected.delete(it.value);\n for (const v of result as ReadonlyArray<string>) collected.add(v);\n pageIdx++;\n }\n if (!aborted) {\n // 번들 → 개별 asset id 로 펼쳐 반환. 설치·보고는 멤버 전원을 개별로 본다.\n resultIds = expandDevMethodBundle([...collected]) as ReadonlyArray<InstallTargetId>;\n }\n } finally {\n process.stdout.write(\"\\x1b[?1049l\");\n }\n // v26.63.1 — alt screen exit 후 main buffer 에 Step 3 완료 라인 출력. alt buffer\n // 안 동작은 main 에 흔적 0 → Step 1·2·4 사이 Step 3 missing → 사용자 보고.\n // clack `◇` marker + `│` line 으로 다른 step 과 시각 일관성 유지.\n if (resultIds !== null) {\n process.stdout.write(\n `◇ Step ${step.current}/${step.total} — Install targets · ${resultIds.length} selected\\n│\\n`,\n );\n }\n return resultIds;\n },\n};\n","import type { DetectedInstall } from \"./state.js\";\n\nexport type RouterAction = \"add\" | \"update\" | \"remove\" | \"reinstall\" | \"exit\";\n\nexport interface RouterChoice {\n value: RouterAction;\n label: string;\n hint?: string;\n enabled: boolean;\n}\n\n/**\n * 5-action menu for an existing install. Mirrors prompt_action_router (setup-harness.sh:255).\n *\n * \"remove\" is exposed but disabled — no reliable file-ownership mapping yet (would risk data loss).\n */\nexport function buildRouterChoices(state: DetectedInstall): RouterChoice[] {\n const detected = state.tracks.length > 0 ? state.tracks.join(\", \") : \"(none detected)\";\n return [\n {\n value: \"add\",\n label: \"Add a new Track\",\n hint: `Current: ${detected}`,\n enabled: true,\n },\n {\n value: \"update\",\n label: \"Update policy files (auto-backup)\",\n // v26.126.0 (R-3a) — skills 가 목록에 들어왔다. 이 문구가 곧 update 의 광고이고\n // (update 는 위저드로만 도달한다) 실동작과 어긋나면 그 자체로 거짓출하다.\n hint: \"Refresh rules / agents / commands / hooks / skills — your edits are backed up\",\n enabled: true,\n },\n {\n value: \"remove\",\n label: \"Remove a Track (unsupported)\",\n hint: \"Manual edit of .claude/ required — not automated\",\n enabled: false,\n },\n {\n value: \"reinstall\",\n label: \"Reinstall (backs up current .claude/ first)\",\n hint: \"Use when state is corrupted\",\n enabled: true,\n },\n {\n value: \"exit\",\n label: \"Exit\",\n enabled: true,\n },\n ];\n}\n\nexport function summarizeState(state: DetectedInstall): string {\n if (state.state === \"new\") {\n return \"No prior install detected — new install flow.\";\n }\n const trackList = state.tracks.length > 0 ? state.tracks.join(\", \") : \"(no tracks resolved)\";\n const sourceLabel =\n state.source === \"metafile\"\n ? \"via .claude/.installed-tracks\"\n : state.source === \"legacy\"\n ? \"via legacy rules/*.md heuristic\"\n : \"via no source\";\n return `Existing install detected ${sourceLabel}. Tracks: ${trackList}.`;\n}\n","/**\n * Wizard step single source of truth — v26.65.0.\n *\n * v26.64.0 에서 wizard 가 5→6 step 으로 변경됐는데 prompts.ts 의 message 가 hardcoded\n * (\"Step 1/5\") 였음 → step indicator drift 가 무성. 본 모듈이 SSOT.\n *\n * 추가 step 도입 시 본 파일만 수정 → message 자동 정합.\n */\n\nexport interface WizardStep {\n current: number;\n total: number;\n}\n\nexport const WIZARD_TOTAL = 6;\n\nexport const WIZARD: {\n TRACKS: WizardStep;\n CLI: WizardStep;\n TARGETS: WizardStep;\n SCOPE: WizardStep;\n CONFIRM: WizardStep;\n INSTALL: WizardStep;\n} = {\n TRACKS: { current: 1, total: WIZARD_TOTAL },\n CLI: { current: 2, total: WIZARD_TOTAL },\n TARGETS: { current: 3, total: WIZARD_TOTAL },\n SCOPE: { current: 4, total: WIZARD_TOTAL },\n CONFIRM: { current: 5, total: WIZARD_TOTAL },\n INSTALL: { current: 6, total: WIZARD_TOTAL },\n};\n\n/**\n * Wizard step header — `Step N/M — <suffix>` 형식.\n *\n * step 미지정 시 suffix 만 반환 (backward compat — tests / non-wizard 호출).\n */\nexport function stepLabel(step: WizardStep | undefined, suffix: string): string {\n if (!step) return suffix;\n return `Step ${step.current}/${step.total} — ${suffix}`;\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { isTrack, type Track } from \"./types.js\";\n\nexport type InstallState = \"new\" | \"existing\";\n\nexport interface DetectedInstall {\n state: InstallState;\n tracks: Track[];\n /** Source of the detected tracks: \"metafile\" (v27.17+), \"legacy\" (rules/*.md heuristic), or \"none\". */\n source: \"metafile\" | \"legacy\" | \"none\";\n hasClaudeDir: boolean;\n}\n\nconst META_FILE = \".claude/.installed-tracks\";\n\ninterface LegacySignature {\n rule: string;\n track: Track;\n}\n\nconst LEGACY_SIGNATURES: readonly LegacySignature[] = [\n { rule: \"htmx.md\", track: \"ssr-htmx\" },\n { rule: \"nextjs.md\", track: \"ssr-nextjs\" },\n { rule: \"data-analysis.md\", track: \"data\" },\n { rule: \"pyside6.md\", track: \"data\" },\n { rule: \"cli-development.md\", track: \"tooling\" },\n];\n\n/**\n * Detect what was previously installed in the given project directory.\n * Mirrors the v27.17 detect_install_state shell function (setup-harness.sh:191).\n */\nexport function detectInstallState(projectDir: string): DetectedInstall {\n const claudeDir = join(projectDir, \".claude\");\n const hasClaudeDir = existsSync(claudeDir);\n\n if (!hasClaudeDir) {\n return { state: \"new\", tracks: [], source: \"none\", hasClaudeDir: false };\n }\n\n const metaPath = join(projectDir, META_FILE);\n if (existsSync(metaPath)) {\n const tracks = readMetafile(metaPath);\n return { state: \"existing\", tracks, source: \"metafile\", hasClaudeDir: true };\n }\n\n const tracks = inferFromLegacySignatures(projectDir);\n return { state: \"existing\", tracks, source: \"legacy\", hasClaudeDir: true };\n}\n\nfunction readMetafile(path: string): Track[] {\n const raw = readFileSync(path, \"utf8\");\n const seen = new Set<Track>();\n for (const line of raw.split(/\\s+/)) {\n const trimmed = line.trim();\n if (isTrack(trimmed)) {\n seen.add(trimmed);\n }\n }\n return [...seen].sort();\n}\n\nfunction inferFromLegacySignatures(projectDir: string): Track[] {\n const rulesDir = join(projectDir, \".claude/rules\");\n if (!existsSync(rulesDir)) {\n return [];\n }\n const found = new Set<Track>();\n for (const sig of LEGACY_SIGNATURES) {\n if (existsSync(join(rulesDir, sig.rule))) {\n found.add(sig.track);\n }\n }\n return [...found].sort();\n}\n"],"mappings":"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","names":["ESC","CSI","k","j","v","b","cli","resolve","b","chmodSync","existsSync","mkdirSync","readdirSync","readFileSync","writeFileSync","basename","dirname","join","existsSync","readFileSync","join","d","join","existsSync","readFileSync","existsSync","join","v","join","existsSync","join","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","e","join","existsSync","readFileSync","writeFileSync","basename","join","k","v","join","basename","writeFileSync","existsSync","readFileSync","existsSync","readFileSync","writeFileSync","join","existsSync","readdirSync","readFileSync","homedir","join","b","cli","v","join","existsSync","c","at","homedir","readdirSync","readFileSync","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","join","join","readFileSync","mkdirSync","dirname","writeFileSync","existsSync","existsSync","readFileSync","writeFileSync","readFileSync","existsSync","writeFileSync","existsSync","readFileSync","writeFileSync","basename","join","renameSlashes","renderAgentsMd","renameSlashes","j","readRequired","join","basename","readOptionalJson","renderAgentsMd","writeFileSync","existsSync","readFileSync","h","copyFileSync","existsSync","mkdirSync","readdirSync","readFileSync","writeFileSync","dirname","join","join","existsSync","copyFileSync","readdirSync","readFileSync","mkdirSync","dirname","writeFileSync","join","existsSync","readFileSync","e","chmodSync","writeFileSync","mkdirSync","dirname","basename","readdirSync","e","b","cli","v","k","p","w","resolve","e","cli","existsSync","readFileSync","join","resolve","resolve","d","join","existsSync","readFileSync","cli","spawnSync","existsSync","readFileSync","join","resolve","NO_TRUNCATION","dist_default","dist_default","findCursor","cursor","delta","options","opt","newCursor","maxCursor","clampedCursor","actions","DEFAULT_MONTH_NAMES","settings","days","month","min","max","isActionKey","key","action","settings","value","diffLines","a","b","aLines","bLines","numLines","diff","i","isWindows","CANCEL_SYMBOL","isCancel","setRawMode","input","getColumns","output","getRows","wrapTextWithPrefix","text","prefix","startPrefix","lineFormatter","columns","stdout","wrapAnsi","line","index","lineString","g$1","options","trackValue","input","stdin","render","signal","opts","event","params","cb","data","cbs","cleanup","subscriber","resolve","CANCEL_SYMBOL","readline","setRawMode","cursor","char","_key","_char","value","write","key","settings","problem","isActionKey","lines","frame","diff","diffLines","rows","diffOffsetAfter","diffOffsetBefore","diffLine","erase","adjustedDiffLine","newLines","ConfirmPrompt","Prompt","opts","confirm","cursor","GroupMultiSelectPrompt","Prompt","#selectableGroups","group","o","items","value","i","item","groupedItems","v","selected","opts","options","key","option","opt","currentIsGroup","Prompt","option","enabledOptions","allSelected","v","value","notSelected","selected","opts","cursor","findCursor","char","key","SelectPrompt","Prompt","opts","initialCursor","value","cursor","findCursor","key","isUnicodeSupported","process","unicode","unicodeOr","c","fallback","unicode","S_STEP_ACTIVE","S_STEP_CANCEL","S_STEP_ERROR","S_STEP_SUBMIT","S_BAR_START","S_BAR","S_BAR_END","S_BAR_START_RIGHT","S_BAR_END_RIGHT","S_RADIO_ACTIVE","S_RADIO_INACTIVE","S_CHECKBOX_ACTIVE","S_CHECKBOX_SELECTED","S_CHECKBOX_INACTIVE","S_PASSWORD_MASK","S_BAR_H","S_CORNER_TOP_RIGHT","S_CONNECT_LEFT","S_CORNER_BOTTOM_RIGHT","S_CORNER_BOTTOM_LEFT","S_CORNER_TOP_LEFT","S_INFO","S_SUCCESS","S_WARN","S_ERROR","symbol","state","styleText","symbolBar","trimLines","groups","initialLineCount","startIndex","endIndex","maxLines","lineCount","removals","i","group","limitOptions","cursor","options","style","output","maxItems","columnPadding","rowPadding","maxWidth","getColumns","rows","getRows","overflowFormat","outputMaxItems","computedMaxItems","slidingWindowLocation","shouldRenderTopEllipsis","shouldRenderBottomEllipsis","slidingWindowLocationEnd","lineGroups","slidingWindowLocationWithEllipsis","slidingWindowLocationEndWithEllipsis","wrappedLines","wrapAnsi","precedingRemovals","followingRemovals","newLineCount","cursorGroupIndex","trimLinesLocal","result","lineGroup","line","confirm","opts","active","inactive","ConfirmPrompt","hasGuide","settings","titlePrefix","symbol","titlePrefixBar","styleText","S_BAR","messageLines","wrapTextWithPrefix","title","value","submitPrefix","cancelPrefix","defaultPrefix","defaultPrefixEnd","S_BAR_END","S_RADIO_ACTIVE","S_RADIO_INACTIVE","groupMultiselect","opts","selectableGroups","groupSpacing","opt","option","state","options","label","isItem","next","isLast","prefix","S_BAR_END","S_BAR","spacingPrefix","spacingPrefixText","styleText","S_CHECKBOX_ACTIVE","S_CHECKBOX_SELECTED","selectedCheckbox","unselectedCheckbox","S_CHECKBOX_INACTIVE","required","GroupMultiSelectPrompt","selected","hasGuide","settings","title","symbol","value","selectedOptions","optionValue","optionsText","footer","ln","i","active","groupActive","optionText","optionsPrefix","cancel","message","opts","output","prefix","settings","styleText","S_BAR_END","intro","title","S_BAR_START","outro","S_BAR","computeLabel","label","format","line","multiselect","opts","opt","option","state","styleText","S_CHECKBOX_INACTIVE","str","S_CHECKBOX_ACTIVE","S_CHECKBOX_SELECTED","text","required","MultiSelectPrompt","selected","hasGuide","settings","wrappedMessage","wrapTextWithPrefix","symbolBar","symbol","title","S_BAR","value","styleOption","active","submitText","optionValue","wrappedSubmitText","wrappedLabel","prefix","footer","ln","i","S_BAR_END","titleLineCount","footerLineCount","limitOptions","S_PROGRESS_CHAR","unicodeOr","computeLabel","label","format","line","select","opts","opt","option","state","styleText","S_RADIO_INACTIVE","text","S_RADIO_ACTIVE","str","SelectPrompt","hasGuide","settings","titlePrefix","symbol","titlePrefixBar","symbolBar","messageLines","wrapTextWithPrefix","title","S_BAR","submitPrefix","wrappedLines","cancelPrefix","prefix","prefixEnd","S_BAR_END","titleLineCount","footerLineCount","limitOptions","item","active","prefix","styleText","S_BAR","ok","defaultSpawn","resolve","e","existsSync","join","readFileSync","h","spawnSync","cli","v","d","b","it","c","existsSync","readFileSync","join","join","existsSync","tracks","readFileSync","cli","b","k","e","cli"]}
|
|
1
|
+
{"version":3,"sources":["../node_modules/sisteransi/src/index.js","../src/index.ts","../src/cli.ts","../node_modules/cac/dist/index.js","../package.json","../src/commands/install.ts","../src/cli-targets.ts","../src/design.ts","../src/installer.ts","../src/antigravity/transform.ts","../src/codex/agents-md.ts","../src/codex/skills.ts","../src/fs-ops.ts","../src/project-claude-merge.ts","../src/ci-scaffold.ts","../src/codex/opt-in.ts","../src/codex/trust-entry.ts","../src/codex/transform.ts","../src/codex/config-toml.ts","../src/env-files.ts","../src/external-installer.ts","../src/install-log.ts","../src/mcp-merge.ts","../src/opencode/transform.ts","../src/opencode/agents-md.ts","../src/opencode/commands.ts","../src/opencode/opencode-json.ts","../src/settings-merge.ts","../src/update-mode.ts","../src/commands/install-render.ts","../src/preset-recommend.ts","../src/commands/list.ts","../src/commands/uninstall.ts","../src/uninstall-interactive.ts","../node_modules/fast-wrap-ansi/src/main.ts","../node_modules/fast-string-width/dist/index.js","../node_modules/fast-string-truncated-width/dist/index.js","../node_modules/fast-string-truncated-width/dist/utils.js","../node_modules/@clack/core/src/utils/cursor.ts","../node_modules/@clack/core/src/utils/settings.ts","../node_modules/@clack/core/src/utils/string.ts","../node_modules/@clack/core/src/utils/index.ts","../node_modules/@clack/core/src/prompts/prompt.ts","../node_modules/@clack/core/src/prompts/autocomplete.ts","../node_modules/@clack/core/src/prompts/confirm.ts","../node_modules/@clack/core/src/prompts/date.ts","../node_modules/@clack/core/src/prompts/group-multiselect.ts","../node_modules/@clack/core/src/prompts/multi-line.ts","../node_modules/@clack/core/src/prompts/multi-select.ts","../node_modules/@clack/core/src/prompts/password.ts","../node_modules/@clack/core/src/prompts/select.ts","../node_modules/@clack/core/src/prompts/select-key.ts","../node_modules/@clack/core/src/prompts/text.ts","../node_modules/node_modules/.pnpm/is-unicode-supported@1.3.0/node_modules/is-unicode-supported/index.js","../node_modules/@clack/prompts/src/common.ts","../node_modules/@clack/prompts/src/limit-options.ts","../node_modules/@clack/prompts/src/autocomplete.ts","../node_modules/@clack/prompts/src/box.ts","../node_modules/@clack/prompts/src/confirm.ts","../node_modules/@clack/prompts/src/date.ts","../node_modules/@clack/prompts/src/group.ts","../node_modules/@clack/prompts/src/group-multi-select.ts","../node_modules/@clack/prompts/src/log.ts","../node_modules/@clack/prompts/src/messages.ts","../node_modules/@clack/prompts/src/multi-line.ts","../node_modules/@clack/prompts/src/multi-select.ts","../node_modules/@clack/prompts/src/note.ts","../node_modules/@clack/prompts/src/password.ts","../node_modules/@clack/prompts/src/path.ts","../node_modules/@clack/prompts/src/spinner.ts","../node_modules/@clack/prompts/src/progress-bar.ts","../node_modules/@clack/prompts/src/select.ts","../node_modules/@clack/prompts/src/select-key.ts","../node_modules/@clack/prompts/src/stream.ts","../node_modules/@clack/prompts/src/task.ts","../node_modules/@clack/prompts/src/task-log.ts","../node_modules/@clack/prompts/src/text.ts","../src/commands/update.ts","../src/state.ts","../src/interactive.ts","../src/prompts.ts","../src/router.ts","../src/wizard-steps.ts"],"sourcesContent":["'use strict';\n\nconst ESC = '\\x1B';\nconst CSI = `${ESC}[`;\nconst beep = '\\u0007';\n\nconst cursor = {\n to(x, y) {\n if (!y) return `${CSI}${x + 1}G`;\n return `${CSI}${y + 1};${x + 1}H`;\n },\n move(x, y) {\n let ret = '';\n\n if (x < 0) ret += `${CSI}${-x}D`;\n else if (x > 0) ret += `${CSI}${x}C`;\n\n if (y < 0) ret += `${CSI}${-y}A`;\n else if (y > 0) ret += `${CSI}${y}B`;\n\n return ret;\n },\n up: (count = 1) => `${CSI}${count}A`,\n down: (count = 1) => `${CSI}${count}B`,\n forward: (count = 1) => `${CSI}${count}C`,\n backward: (count = 1) => `${CSI}${count}D`,\n nextLine: (count = 1) => `${CSI}E`.repeat(count),\n prevLine: (count = 1) => `${CSI}F`.repeat(count),\n left: `${CSI}G`,\n hide: `${CSI}?25l`,\n show: `${CSI}?25h`,\n save: `${ESC}7`,\n restore: `${ESC}8`\n}\n\nconst scroll = {\n up: (count = 1) => `${CSI}S`.repeat(count),\n down: (count = 1) => `${CSI}T`.repeat(count)\n}\n\nconst erase = {\n screen: `${CSI}2J`,\n up: (count = 1) => `${CSI}1J`.repeat(count),\n down: (count = 1) => `${CSI}J`.repeat(count),\n line: `${CSI}2K`,\n lineEnd: `${CSI}K`,\n lineStart: `${CSI}1K`,\n lines(count) {\n let clear = '';\n for (let i = 0; i < count; i++)\n clear += this.line + (i < count - 1 ? cursor.up() : '');\n if (count)\n clear += cursor.left;\n return clear;\n }\n}\n\nmodule.exports = { cursor, scroll, erase, beep };\n","import { buildCli } from \"./cli.js\";\n\nconst cli = buildCli();\ncli.parse(process.argv);\n","import { cac } from \"cac\";\nimport packageJson from \"../package.json\";\nimport { type ExecuteSpecDeps, executeSpec, registerInstallCommand } from \"./commands/install.js\";\nimport { registerListCommand } from \"./commands/list.js\";\nimport { registerUninstallCommand } from \"./commands/uninstall.js\";\nimport { registerUpdateCommand } from \"./commands/update.js\";\nimport { type InteractiveResult, runInteractive } from \"./interactive.js\";\n\n// v26.72.1 — CalVer 정합 (cli --version / package.json / git tag 단일 버전).\n// v26.82.1 — 하드코딩 → package.json derive. v26.82.0 ship 때 package.json 만 bump 되고\n// 본 상수(26.81.0)가 남아 npm 게시 패키지가 --version 을 거짓 보고 (수동 동기화 주석은\n// 못 막는다는 본 repo 3번째 증명) → 빌드 시 esbuild 가 값 인라인, 동기화 자체를 소멸.\nexport const VERSION: string = packageJson.version;\n\nexport type Cli = ReturnType<typeof cac>;\n\nexport interface DefaultActionDeps {\n log?: (msg: string) => void;\n err?: (msg: string) => void;\n exit?: (code: number) => never;\n run?: (cwd: string) => Promise<InteractiveResult>;\n /** Override the install pipeline + report renderer (used by tests). */\n execute?: (spec: NonNullable<InteractiveResult[\"spec\"]>, deps: ExecuteSpecDeps) => void;\n}\n\n/**\n * Default action — runs the interactive flow, then executes the install\n * pipeline with the captured spec. Mirrors the `install` flag-mode command's\n * post-install report.\n */\nexport async function defaultAction(deps: DefaultActionDeps = {}): Promise<void> {\n const log = deps.log ?? console.log;\n const err = deps.err ?? console.error;\n /* v8 ignore next — process.exit default. tests 는 exit 주입. */\n const exit = deps.exit ?? ((code: number) => process.exit(code) as never);\n const run = deps.run ?? ((cwd: string) => runInteractive(cwd));\n const execute = deps.execute ?? executeSpec;\n\n const result = await run(process.cwd());\n if (!result.ok) {\n if (result.message) {\n err(result.message);\n }\n // exit-code mapping: no-tty=2; cancelled/exit/disabled/declined=0\n exit(result.reason === \"no-tty\" ? 2 : 0);\n return;\n }\n if (!result.spec) {\n err(\"Internal error: interactive returned ok=true without a spec.\");\n exit(1);\n return;\n }\n // v26.63.0 — wizard 모드 표시. install header (TARGET 등) 출력 skip → Step 5 sub-section 으로 자연 흐름.\n const execDeps: import(\"./commands/install.js\").ExecuteSpecDeps = {\n log,\n err,\n exit,\n fromWizard: true,\n };\n if (result.mode) execDeps.mode = result.mode;\n execute(result.spec, execDeps);\n}\n\nexport function buildCli(): Cli {\n const cli = cac(\"agent-harness\");\n\n cli.help();\n cli.version(VERSION);\n\n registerInstallCommand(cli);\n registerUpdateCommand(cli);\n registerListCommand(cli);\n registerUninstallCommand(cli);\n\n cli\n .command(\"\", \"Interactive installer (state detection + prompts)\")\n /* v8 ignore next — cac action callback. defaultAction 자체는 별도 tests 로 검증. */\n .action(() => defaultAction());\n\n return cli;\n}\n","//#region node_modules/.pnpm/mri@1.2.0/node_modules/mri/lib/index.mjs\nfunction toArr(any) {\n\treturn any == null ? [] : Array.isArray(any) ? any : [any];\n}\nfunction toVal(out, key, val, opts) {\n\tvar x, old = out[key], nxt = !!~opts.string.indexOf(key) ? val == null || val === true ? \"\" : String(val) : typeof val === \"boolean\" ? val : !!~opts.boolean.indexOf(key) ? val === \"false\" ? false : val === \"true\" || (out._.push((x = +val, x * 0 === 0) ? x : val), !!val) : (x = +val, x * 0 === 0) ? x : val;\n\tout[key] = old == null ? nxt : Array.isArray(old) ? old.concat(nxt) : [old, nxt];\n}\nfunction lib_default(args, opts) {\n\targs = args || [];\n\topts = opts || {};\n\tvar k, arr, arg, name, val, out = { _: [] };\n\tvar i = 0, j = 0, idx = 0, len = args.length;\n\tconst alibi = opts.alias !== void 0;\n\tconst strict = opts.unknown !== void 0;\n\tconst defaults = opts.default !== void 0;\n\topts.alias = opts.alias || {};\n\topts.string = toArr(opts.string);\n\topts.boolean = toArr(opts.boolean);\n\tif (alibi) for (k in opts.alias) {\n\t\tarr = opts.alias[k] = toArr(opts.alias[k]);\n\t\tfor (i = 0; i < arr.length; i++) (opts.alias[arr[i]] = arr.concat(k)).splice(i, 1);\n\t}\n\tfor (i = opts.boolean.length; i-- > 0;) {\n\t\tarr = opts.alias[opts.boolean[i]] || [];\n\t\tfor (j = arr.length; j-- > 0;) opts.boolean.push(arr[j]);\n\t}\n\tfor (i = opts.string.length; i-- > 0;) {\n\t\tarr = opts.alias[opts.string[i]] || [];\n\t\tfor (j = arr.length; j-- > 0;) opts.string.push(arr[j]);\n\t}\n\tif (defaults) for (k in opts.default) {\n\t\tname = typeof opts.default[k];\n\t\tarr = opts.alias[k] = opts.alias[k] || [];\n\t\tif (opts[name] !== void 0) {\n\t\t\topts[name].push(k);\n\t\t\tfor (i = 0; i < arr.length; i++) opts[name].push(arr[i]);\n\t\t}\n\t}\n\tconst keys = strict ? Object.keys(opts.alias) : [];\n\tfor (i = 0; i < len; i++) {\n\t\targ = args[i];\n\t\tif (arg === \"--\") {\n\t\t\tout._ = out._.concat(args.slice(++i));\n\t\t\tbreak;\n\t\t}\n\t\tfor (j = 0; j < arg.length; j++) if (arg.charCodeAt(j) !== 45) break;\n\t\tif (j === 0) out._.push(arg);\n\t\telse if (arg.substring(j, j + 3) === \"no-\") {\n\t\t\tname = arg.substring(j + 3);\n\t\t\tif (strict && !~keys.indexOf(name)) return opts.unknown(arg);\n\t\t\tout[name] = false;\n\t\t} else {\n\t\t\tfor (idx = j + 1; idx < arg.length; idx++) if (arg.charCodeAt(idx) === 61) break;\n\t\t\tname = arg.substring(j, idx);\n\t\t\tval = arg.substring(++idx) || i + 1 === len || (\"\" + args[i + 1]).charCodeAt(0) === 45 || args[++i];\n\t\t\tarr = j === 2 ? [name] : name;\n\t\t\tfor (idx = 0; idx < arr.length; idx++) {\n\t\t\t\tname = arr[idx];\n\t\t\t\tif (strict && !~keys.indexOf(name)) return opts.unknown(\"-\".repeat(j) + name);\n\t\t\t\ttoVal(out, name, idx + 1 < arr.length || val, opts);\n\t\t\t}\n\t\t}\n\t}\n\tif (defaults) {\n\t\tfor (k in opts.default) if (out[k] === void 0) out[k] = opts.default[k];\n\t}\n\tif (alibi) for (k in out) {\n\t\tarr = opts.alias[k] || [];\n\t\twhile (arr.length > 0) out[arr.shift()] = out[k];\n\t}\n\treturn out;\n}\n\n//#endregion\n//#region src/utils.ts\nfunction removeBrackets(v) {\n\treturn v.replace(/[<[].+/, \"\").trim();\n}\nfunction findAllBrackets(v) {\n\tconst ANGLED_BRACKET_RE_GLOBAL = /<([^>]+)>/g;\n\tconst SQUARE_BRACKET_RE_GLOBAL = /\\[([^\\]]+)\\]/g;\n\tconst res = [];\n\tconst parse = (match) => {\n\t\tlet variadic = false;\n\t\tlet value = match[1];\n\t\tif (value.startsWith(\"...\")) {\n\t\t\tvalue = value.slice(3);\n\t\t\tvariadic = true;\n\t\t}\n\t\treturn {\n\t\t\trequired: match[0].startsWith(\"<\"),\n\t\t\tvalue,\n\t\t\tvariadic\n\t\t};\n\t};\n\tlet angledMatch;\n\twhile (angledMatch = ANGLED_BRACKET_RE_GLOBAL.exec(v)) res.push(parse(angledMatch));\n\tlet squareMatch;\n\twhile (squareMatch = SQUARE_BRACKET_RE_GLOBAL.exec(v)) res.push(parse(squareMatch));\n\treturn res;\n}\nfunction getMriOptions(options) {\n\tconst result = {\n\t\talias: {},\n\t\tboolean: []\n\t};\n\tfor (const [index, option] of options.entries()) {\n\t\tif (option.names.length > 1) result.alias[option.names[0]] = option.names.slice(1);\n\t\tif (option.isBoolean) if (option.negated) {\n\t\t\tif (!options.some((o, i) => {\n\t\t\t\treturn i !== index && o.names.some((name) => option.names.includes(name)) && typeof o.required === \"boolean\";\n\t\t\t})) result.boolean.push(option.names[0]);\n\t\t} else result.boolean.push(option.names[0]);\n\t}\n\treturn result;\n}\nfunction findLongest(arr) {\n\treturn arr.sort((a, b) => {\n\t\treturn a.length > b.length ? -1 : 1;\n\t})[0];\n}\nfunction padRight(str, length) {\n\treturn str.length >= length ? str : `${str}${\" \".repeat(length - str.length)}`;\n}\nfunction camelcase(input) {\n\treturn input.replaceAll(/([a-z])-([a-z])/g, (_, p1, p2) => {\n\t\treturn p1 + p2.toUpperCase();\n\t});\n}\nfunction setDotProp(obj, keys, val) {\n\tlet current = obj;\n\tfor (let i = 0; i < keys.length; i++) {\n\t\tconst key = keys[i];\n\t\tif (i === keys.length - 1) {\n\t\t\tcurrent[key] = val;\n\t\t\treturn;\n\t\t}\n\t\tif (current[key] == null) {\n\t\t\tconst nextKeyIsArrayIndex = +keys[i + 1] > -1;\n\t\t\tcurrent[key] = nextKeyIsArrayIndex ? [] : {};\n\t\t}\n\t\tcurrent = current[key];\n\t}\n}\nfunction setByType(obj, transforms) {\n\tfor (const key of Object.keys(transforms)) {\n\t\tconst transform = transforms[key];\n\t\tif (transform.shouldTransform) {\n\t\t\tobj[key] = [obj[key]].flat();\n\t\t\tif (typeof transform.transformFunction === \"function\") obj[key] = obj[key].map(transform.transformFunction);\n\t\t}\n\t}\n}\nfunction getFileName(input) {\n\tconst m = /([^\\\\/]+)$/.exec(input);\n\treturn m ? m[1] : \"\";\n}\nfunction camelcaseOptionName(name) {\n\treturn name.split(\".\").map((v, i) => {\n\t\treturn i === 0 ? camelcase(v) : v;\n\t}).join(\".\");\n}\nvar CACError = class extends Error {\n\tconstructor(message) {\n\t\tsuper(message);\n\t\tthis.name = \"CACError\";\n\t\tif (typeof Error.captureStackTrace !== \"function\") this.stack = new Error(message).stack;\n\t}\n};\n\n//#endregion\n//#region src/option.ts\nvar Option = class {\n\trawName;\n\tdescription;\n\t/** Option name */\n\tname;\n\t/** Option name and aliases */\n\tnames;\n\tisBoolean;\n\trequired;\n\tconfig;\n\tnegated;\n\tconstructor(rawName, description, config) {\n\t\tthis.rawName = rawName;\n\t\tthis.description = description;\n\t\tthis.config = Object.assign({}, config);\n\t\trawName = rawName.replaceAll(\".*\", \"\");\n\t\tthis.negated = false;\n\t\tthis.names = removeBrackets(rawName).split(\",\").map((v) => {\n\t\t\tlet name = v.trim().replace(/^-{1,2}/, \"\");\n\t\t\tif (name.startsWith(\"no-\")) {\n\t\t\t\tthis.negated = true;\n\t\t\t\tname = name.replace(/^no-/, \"\");\n\t\t\t}\n\t\t\treturn camelcaseOptionName(name);\n\t\t}).sort((a, b) => a.length > b.length ? 1 : -1);\n\t\tthis.name = this.names.at(-1);\n\t\tif (this.negated && this.config.default == null) this.config.default = true;\n\t\tif (rawName.includes(\"<\")) this.required = true;\n\t\telse if (rawName.includes(\"[\")) this.required = false;\n\t\telse this.isBoolean = true;\n\t}\n};\n\n//#endregion\n//#region src/runtime.ts\nlet runtimeProcessArgs;\nlet runtimeInfo;\nif (typeof process !== \"undefined\") {\n\tlet runtimeName;\n\tif (typeof Deno !== \"undefined\" && typeof Deno.version?.deno === \"string\") runtimeName = \"deno\";\n\telse if (typeof Bun !== \"undefined\" && typeof Bun.version === \"string\") runtimeName = \"bun\";\n\telse runtimeName = \"node\";\n\truntimeInfo = `${process.platform}-${process.arch} ${runtimeName}-${process.version}`;\n\truntimeProcessArgs = process.argv;\n} else if (typeof navigator === \"undefined\") runtimeInfo = `unknown`;\nelse runtimeInfo = `${navigator.platform} ${navigator.userAgent}`;\n\n//#endregion\n//#region src/command.ts\nvar Command = class {\n\trawName;\n\tdescription;\n\tconfig;\n\tcli;\n\toptions;\n\taliasNames;\n\tname;\n\targs;\n\tcommandAction;\n\tusageText;\n\tversionNumber;\n\texamples;\n\thelpCallback;\n\tglobalCommand;\n\tconstructor(rawName, description, config = {}, cli) {\n\t\tthis.rawName = rawName;\n\t\tthis.description = description;\n\t\tthis.config = config;\n\t\tthis.cli = cli;\n\t\tthis.options = [];\n\t\tthis.aliasNames = [];\n\t\tthis.name = removeBrackets(rawName);\n\t\tthis.args = findAllBrackets(rawName);\n\t\tthis.examples = [];\n\t}\n\tusage(text) {\n\t\tthis.usageText = text;\n\t\treturn this;\n\t}\n\tallowUnknownOptions() {\n\t\tthis.config.allowUnknownOptions = true;\n\t\treturn this;\n\t}\n\tignoreOptionDefaultValue() {\n\t\tthis.config.ignoreOptionDefaultValue = true;\n\t\treturn this;\n\t}\n\tversion(version, customFlags = \"-v, --version\") {\n\t\tthis.versionNumber = version;\n\t\tthis.option(customFlags, \"Display version number\");\n\t\treturn this;\n\t}\n\texample(example) {\n\t\tthis.examples.push(example);\n\t\treturn this;\n\t}\n\t/**\n\t* Add a option for this command\n\t* @param rawName Raw option name(s)\n\t* @param description Option description\n\t* @param config Option config\n\t*/\n\toption(rawName, description, config) {\n\t\tconst option = new Option(rawName, description, config);\n\t\tthis.options.push(option);\n\t\treturn this;\n\t}\n\talias(name) {\n\t\tthis.aliasNames.push(name);\n\t\treturn this;\n\t}\n\taction(callback) {\n\t\tthis.commandAction = callback;\n\t\treturn this;\n\t}\n\t/**\n\t* Check if a command name is matched by this command\n\t* @param name Command name\n\t*/\n\tisMatched(name) {\n\t\treturn this.name === name || this.aliasNames.includes(name);\n\t}\n\tget isDefaultCommand() {\n\t\treturn this.name === \"\" || this.aliasNames.includes(\"!\");\n\t}\n\tget isGlobalCommand() {\n\t\treturn this instanceof GlobalCommand;\n\t}\n\t/**\n\t* Check if an option is registered in this command\n\t* @param name Option name\n\t*/\n\thasOption(name) {\n\t\tname = name.split(\".\")[0];\n\t\treturn this.options.find((option) => {\n\t\t\treturn option.names.includes(name);\n\t\t});\n\t}\n\toutputHelp() {\n\t\tconst { name, commands } = this.cli;\n\t\tconst { versionNumber, options: globalOptions, helpCallback } = this.cli.globalCommand;\n\t\tlet sections = [{ body: `${name}${versionNumber ? `/${versionNumber}` : \"\"}` }];\n\t\tsections.push({\n\t\t\ttitle: \"Usage\",\n\t\t\tbody: ` $ ${name} ${this.usageText || this.rawName}`\n\t\t});\n\t\tif ((this.isGlobalCommand || this.isDefaultCommand) && commands.length > 0) {\n\t\t\tconst longestCommandName = findLongest(commands.map((command) => command.rawName));\n\t\t\tsections.push({\n\t\t\t\ttitle: \"Commands\",\n\t\t\t\tbody: commands.map((command) => {\n\t\t\t\t\treturn ` ${padRight(command.rawName, longestCommandName.length)} ${command.description}`;\n\t\t\t\t}).join(\"\\n\")\n\t\t\t}, {\n\t\t\t\ttitle: `For more info, run any command with the \\`--help\\` flag`,\n\t\t\t\tbody: commands.map((command) => ` $ ${name}${command.name === \"\" ? \"\" : ` ${command.name}`} --help`).join(\"\\n\")\n\t\t\t});\n\t\t}\n\t\tlet options = this.isGlobalCommand ? globalOptions : [...this.options, ...globalOptions || []];\n\t\tif (!this.isGlobalCommand && !this.isDefaultCommand) options = options.filter((option) => option.name !== \"version\");\n\t\tif (options.length > 0) {\n\t\t\tconst longestOptionName = findLongest(options.map((option) => option.rawName));\n\t\t\tsections.push({\n\t\t\t\ttitle: \"Options\",\n\t\t\t\tbody: options.map((option) => {\n\t\t\t\t\treturn ` ${padRight(option.rawName, longestOptionName.length)} ${option.description} ${option.config.default === void 0 ? \"\" : `(default: ${option.config.default})`}`;\n\t\t\t\t}).join(\"\\n\")\n\t\t\t});\n\t\t}\n\t\tif (this.examples.length > 0) sections.push({\n\t\t\ttitle: \"Examples\",\n\t\t\tbody: this.examples.map((example) => {\n\t\t\t\tif (typeof example === \"function\") return example(name);\n\t\t\t\treturn example;\n\t\t\t}).join(\"\\n\")\n\t\t});\n\t\tif (helpCallback) sections = helpCallback(sections) || sections;\n\t\tconsole.info(sections.map((section) => {\n\t\t\treturn section.title ? `${section.title}:\\n${section.body}` : section.body;\n\t\t}).join(\"\\n\\n\"));\n\t}\n\toutputVersion() {\n\t\tconst { name } = this.cli;\n\t\tconst { versionNumber } = this.cli.globalCommand;\n\t\tif (versionNumber) console.info(`${name}/${versionNumber} ${runtimeInfo}`);\n\t}\n\tcheckRequiredArgs() {\n\t\tconst minimalArgsCount = this.args.filter((arg) => arg.required).length;\n\t\tif (this.cli.args.length < minimalArgsCount) throw new CACError(`missing required args for command \\`${this.rawName}\\``);\n\t}\n\t/**\n\t* Check if the parsed options contain any unknown options\n\t*\n\t* Exit and output error when true\n\t*/\n\tcheckUnknownOptions() {\n\t\tconst { options, globalCommand } = this.cli;\n\t\tif (!this.config.allowUnknownOptions) {\n\t\t\tfor (const name of Object.keys(options)) if (name !== \"--\" && !this.hasOption(name) && !globalCommand.hasOption(name)) throw new CACError(`Unknown option \\`${name.length > 1 ? `--${name}` : `-${name}`}\\``);\n\t\t}\n\t}\n\t/**\n\t* Check if the required string-type options exist\n\t*/\n\tcheckOptionValue() {\n\t\tconst { options: parsedOptions, globalCommand } = this.cli;\n\t\tconst options = [...globalCommand.options, ...this.options];\n\t\tfor (const option of options) {\n\t\t\tconst value = parsedOptions[option.name.split(\".\")[0]];\n\t\t\tif (option.required) {\n\t\t\t\tconst hasNegated = options.some((o) => o.negated && o.names.includes(option.name));\n\t\t\t\tif (value === true || value === false && !hasNegated) throw new CACError(`option \\`${option.rawName}\\` value is missing`);\n\t\t\t}\n\t\t}\n\t}\n\t/**\n\t* Check if the number of args is more than expected\n\t*/\n\tcheckUnusedArgs() {\n\t\tconst maximumArgsCount = this.args.some((arg) => arg.variadic) ? Infinity : this.args.length;\n\t\tif (maximumArgsCount < this.cli.args.length) throw new CACError(`Unused args: ${this.cli.args.slice(maximumArgsCount).map((arg) => `\\`${arg}\\``).join(\", \")}`);\n\t}\n};\nvar GlobalCommand = class extends Command {\n\tconstructor(cli) {\n\t\tsuper(\"@@global@@\", \"\", {}, cli);\n\t}\n};\n\n//#endregion\n//#region src/cac.ts\nvar CAC = class extends EventTarget {\n\t/** The program name to display in help and version message */\n\tname;\n\tcommands;\n\tglobalCommand;\n\tmatchedCommand;\n\tmatchedCommandName;\n\t/**\n\t* Raw CLI arguments\n\t*/\n\trawArgs;\n\t/**\n\t* Parsed CLI arguments\n\t*/\n\targs;\n\t/**\n\t* Parsed CLI options, camelCased\n\t*/\n\toptions;\n\tshowHelpOnExit;\n\tshowVersionOnExit;\n\t/**\n\t* @param name The program name to display in help and version message\n\t*/\n\tconstructor(name = \"\") {\n\t\tsuper();\n\t\tthis.name = name;\n\t\tthis.commands = [];\n\t\tthis.rawArgs = [];\n\t\tthis.args = [];\n\t\tthis.options = {};\n\t\tthis.globalCommand = new GlobalCommand(this);\n\t\tthis.globalCommand.usage(\"<command> [options]\");\n\t}\n\t/**\n\t* Add a global usage text.\n\t*\n\t* This is not used by sub-commands.\n\t*/\n\tusage(text) {\n\t\tthis.globalCommand.usage(text);\n\t\treturn this;\n\t}\n\t/**\n\t* Add a sub-command\n\t*/\n\tcommand(rawName, description, config) {\n\t\tconst command = new Command(rawName, description || \"\", config, this);\n\t\tcommand.globalCommand = this.globalCommand;\n\t\tthis.commands.push(command);\n\t\treturn command;\n\t}\n\t/**\n\t* Add a global CLI option.\n\t*\n\t* Which is also applied to sub-commands.\n\t*/\n\toption(rawName, description, config) {\n\t\tthis.globalCommand.option(rawName, description, config);\n\t\treturn this;\n\t}\n\t/**\n\t* Show help message when `-h, --help` flags appear.\n\t*\n\t*/\n\thelp(callback) {\n\t\tthis.globalCommand.option(\"-h, --help\", \"Display this message\");\n\t\tthis.globalCommand.helpCallback = callback;\n\t\tthis.showHelpOnExit = true;\n\t\treturn this;\n\t}\n\t/**\n\t* Show version number when `-v, --version` flags appear.\n\t*\n\t*/\n\tversion(version, customFlags = \"-v, --version\") {\n\t\tthis.globalCommand.version(version, customFlags);\n\t\tthis.showVersionOnExit = true;\n\t\treturn this;\n\t}\n\t/**\n\t* Add a global example.\n\t*\n\t* This example added here will not be used by sub-commands.\n\t*/\n\texample(example) {\n\t\tthis.globalCommand.example(example);\n\t\treturn this;\n\t}\n\t/**\n\t* Output the corresponding help message\n\t* When a sub-command is matched, output the help message for the command\n\t* Otherwise output the global one.\n\t*\n\t*/\n\toutputHelp() {\n\t\tif (this.matchedCommand) this.matchedCommand.outputHelp();\n\t\telse this.globalCommand.outputHelp();\n\t}\n\t/**\n\t* Output the version number.\n\t*\n\t*/\n\toutputVersion() {\n\t\tthis.globalCommand.outputVersion();\n\t}\n\tsetParsedInfo({ args, options }, matchedCommand, matchedCommandName) {\n\t\tthis.args = args;\n\t\tthis.options = options;\n\t\tif (matchedCommand) this.matchedCommand = matchedCommand;\n\t\tif (matchedCommandName) this.matchedCommandName = matchedCommandName;\n\t\treturn this;\n\t}\n\tunsetMatchedCommand() {\n\t\tthis.matchedCommand = void 0;\n\t\tthis.matchedCommandName = void 0;\n\t}\n\t/**\n\t* Parse argv\n\t*/\n\tparse(argv, { run = true } = {}) {\n\t\tif (!argv) {\n\t\t\tif (!runtimeProcessArgs) throw new Error(\"No argv provided and runtime process argv is not available.\");\n\t\t\targv = runtimeProcessArgs;\n\t\t}\n\t\tthis.rawArgs = argv;\n\t\tif (!this.name) this.name = argv[1] ? getFileName(argv[1]) : \"cli\";\n\t\tlet shouldParse = true;\n\t\tfor (const command of this.commands) {\n\t\t\tconst parsed = this.mri(argv.slice(2), command);\n\t\t\tconst commandName = parsed.args[0];\n\t\t\tif (command.isMatched(commandName)) {\n\t\t\t\tshouldParse = false;\n\t\t\t\tconst parsedInfo = {\n\t\t\t\t\t...parsed,\n\t\t\t\t\targs: parsed.args.slice(1)\n\t\t\t\t};\n\t\t\t\tthis.setParsedInfo(parsedInfo, command, commandName);\n\t\t\t\tthis.dispatchEvent(new CustomEvent(`command:${commandName}`, { detail: command }));\n\t\t\t}\n\t\t}\n\t\tif (shouldParse) {\n\t\t\tfor (const command of this.commands) if (command.isDefaultCommand) {\n\t\t\t\tshouldParse = false;\n\t\t\t\tconst parsed = this.mri(argv.slice(2), command);\n\t\t\t\tthis.setParsedInfo(parsed, command);\n\t\t\t\tthis.dispatchEvent(new CustomEvent(\"command:!\", { detail: command }));\n\t\t\t}\n\t\t}\n\t\tif (shouldParse) {\n\t\t\tconst parsed = this.mri(argv.slice(2));\n\t\t\tthis.setParsedInfo(parsed);\n\t\t}\n\t\tif (this.options.help && this.showHelpOnExit) {\n\t\t\tthis.outputHelp();\n\t\t\trun = false;\n\t\t\tthis.unsetMatchedCommand();\n\t\t}\n\t\tif (this.options.version && this.showVersionOnExit && this.matchedCommandName == null) {\n\t\t\tthis.outputVersion();\n\t\t\trun = false;\n\t\t\tthis.unsetMatchedCommand();\n\t\t}\n\t\tconst parsedArgv = {\n\t\t\targs: this.args,\n\t\t\toptions: this.options\n\t\t};\n\t\tif (run) this.runMatchedCommand();\n\t\tif (!this.matchedCommand && this.args[0]) this.dispatchEvent(new CustomEvent(\"command:*\", { detail: this.args[0] }));\n\t\treturn parsedArgv;\n\t}\n\tmri(argv, command) {\n\t\tconst cliOptions = [...this.globalCommand.options, ...command ? command.options : []];\n\t\tconst mriOptions = getMriOptions(cliOptions);\n\t\tlet argsAfterDoubleDashes = [];\n\t\tconst doubleDashesIndex = argv.indexOf(\"--\");\n\t\tif (doubleDashesIndex !== -1) {\n\t\t\targsAfterDoubleDashes = argv.slice(doubleDashesIndex + 1);\n\t\t\targv = argv.slice(0, doubleDashesIndex);\n\t\t}\n\t\tlet parsed = lib_default(argv, mriOptions);\n\t\tparsed = Object.keys(parsed).reduce((res, name) => {\n\t\t\treturn {\n\t\t\t\t...res,\n\t\t\t\t[camelcaseOptionName(name)]: parsed[name]\n\t\t\t};\n\t\t}, { _: [] });\n\t\tconst args = parsed._;\n\t\tconst options = { \"--\": argsAfterDoubleDashes };\n\t\tconst ignoreDefault = command && command.config.ignoreOptionDefaultValue ? command.config.ignoreOptionDefaultValue : this.globalCommand.config.ignoreOptionDefaultValue;\n\t\tconst transforms = Object.create(null);\n\t\tfor (const cliOption of cliOptions) {\n\t\t\tif (!ignoreDefault && cliOption.config.default !== void 0) for (const name of cliOption.names) options[name] = cliOption.config.default;\n\t\t\tif (Array.isArray(cliOption.config.type) && transforms[cliOption.name] === void 0) {\n\t\t\t\ttransforms[cliOption.name] = Object.create(null);\n\t\t\t\ttransforms[cliOption.name].shouldTransform = true;\n\t\t\t\ttransforms[cliOption.name].transformFunction = cliOption.config.type[0];\n\t\t\t}\n\t\t}\n\t\tfor (const key of Object.keys(parsed)) if (key !== \"_\") {\n\t\t\tsetDotProp(options, key.split(\".\"), parsed[key]);\n\t\t\tsetByType(options, transforms);\n\t\t}\n\t\treturn {\n\t\t\targs,\n\t\t\toptions\n\t\t};\n\t}\n\trunMatchedCommand() {\n\t\tconst { args, options, matchedCommand: command } = this;\n\t\tif (!command || !command.commandAction) return;\n\t\tcommand.checkUnknownOptions();\n\t\tcommand.checkOptionValue();\n\t\tcommand.checkRequiredArgs();\n\t\tcommand.checkUnusedArgs();\n\t\tconst actionArgs = [];\n\t\tcommand.args.forEach((arg, index) => {\n\t\t\tif (arg.variadic) actionArgs.push(args.slice(index));\n\t\t\telse actionArgs.push(args[index]);\n\t\t});\n\t\tactionArgs.push(options);\n\t\treturn command.commandAction.apply(this, actionArgs);\n\t}\n};\n\n//#endregion\n//#region src/index.ts\n/**\n* @param name The program name to display in help and version message\n*/\nconst cac = (name = \"\") => new CAC(name);\n\n//#endregion\nexport { CAC, Command, cac, cac as default };","{\n \"name\": \"@uzysjung/agent-harness\",\n \"version\": \"26.131.0\",\n \"description\": \"Curate vetted AI-coding skills & plugins by your tech stack — install only what you need, across Claude Code, Codex, OpenCode & Antigravity\",\n \"type\": \"module\",\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"engines\": {\n \"node\": \">=20.0.0\"\n },\n \"bin\": {\n \"agent-harness\": \"./dist/index.js\"\n },\n \"files\": [\n \"dist\",\n \"templates\",\n \"scripts/prune-ecc.sh\",\n \"README.md\",\n \"LICENSE\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"gen:compat\": \"npm run build && node scripts/gen-compatibility.mjs\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"test:coverage\": \"vitest run --coverage\",\n \"typecheck\": \"tsc --noEmit\",\n \"lint\": \"biome check src tests\",\n \"lint:fix\": \"biome check --write src tests\",\n \"format\": \"biome format --write src tests\",\n \"ci\": \"npm run typecheck && npm run lint && npm run test:coverage && npm run build\",\n \"prepare\": \"[ -d dist ] || npm run build\",\n \"cost:report\": \"npm run build && node scripts/context-cost-report.mjs\"\n },\n \"dependencies\": {\n \"@clack/prompts\": \"^1.3.0\",\n \"cac\": \"^7.0.0\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"^2.4.13\",\n \"@types/node\": \"^25.6.0\",\n \"@vitest/coverage-v8\": \"^2.1.0\",\n \"tsup\": \"^8.3.0\",\n \"typescript\": \"^5.6.0\",\n \"vitest\": \"^2.1.0\"\n },\n \"license\": \"MIT\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/uzysjung/uzys-agent-harness.git\"\n }\n}\n","/**\n * `install` subcommand — spec 검증 + 파이프라인 오케스트레이션 (v26.82.0, Phase R).\n * 화면 출력(헤더/Phase rows/산출물/Summary)은 `install-render.ts` 로 분리.\n */\n\nimport { resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { Cli } from \"../cli.js\";\nimport { parseCliTargets } from \"../cli-targets.js\";\nimport { c, status, unifiedSection } from \"../design.js\";\nimport { EXTERNAL_ASSETS } from \"../external-assets.js\";\nimport { type InstallReport, runInstall as runInstallPipeline } from \"../installer.js\";\nimport {\n type CliTargets,\n type InstallScope,\n type InstallSpec,\n isInstallScope,\n isTrack,\n type Track,\n} from \"../types.js\";\nimport {\n createInstallRenderer,\n type PipelineCallbacks,\n renderCliArtifacts,\n renderFinalSummary,\n renderInstallHeader,\n renderUpdateSummary,\n} from \"./install-render.js\";\n\nexport interface InstallOptions {\n track?: string[];\n /** v0.7.0 — repeatable. cac type: [String]. v0.8.0 — legacy alias 'both'/'all' 제거됨. */\n cli?: string | string[];\n /** v26.63.0 — Phase 1 templates 의 files 라인 표시 (default: counts only). */\n verbose?: boolean;\n projectDir?: string;\n // v26.81.0 (ADR-022, BREAKING) — 자산 1:1 플래그 13종(withTauri/withGsd/withEcc/withTob/\n // withAddyAgentSkills/withUzysHarness/withSuperpowers/withWshobsonAgents/withOpenspec/\n // withBmad/withClaudeVideo/withUnderstandAnything/withAgentmemory) 완전 삭제.\n // 자산 선택 = generic `--with <id>` / `--without <id>` 만. 아래는 동작 옵션.\n withPrune?: boolean;\n withCodexTrust?: boolean;\n withKarpathyHook?: boolean;\n /**\n * v26.47.0 (Phase C full) — External Asset 직접 추가 (preset condition 무관 강제 포함).\n * cac repeatable. 예: `--with railway-skills --with impeccable`.\n * 옵션-키 동작 flag (예: `--with-prune`) 와 별개 — External Asset id 만.\n */\n with?: string | string[];\n /**\n * v26.47.0 (Phase C full) — External Asset 직접 제외 (preset 추천에서 unchecked).\n * cac repeatable. 예: `--without netlify-cli`.\n */\n without?: string | string[];\n /**\n * v26.64.0 (ADR-020) — Installation scope. `project` (default) | `global`.\n * 명시 안 하면 wizard 의 scope prompt → 비대화형은 \"project\".\n */\n scope?: string;\n}\n\nexport interface RunInstallResult {\n ok: boolean;\n cli: CliTargets;\n /** Deprecation warnings (alias 사용 시 emit). caller가 stderr로 출력. */\n warnings: ReadonlyArray<string>;\n message: string;\n report?: InstallReport;\n}\n\n/**\n * Lift raw flag options to a typed InstallSpec.\n * Returns a Result-shaped value so callers can render errors uniformly.\n */\nexport function specFromOptions(options: InstallOptions): RunInstallResult {\n const parsed = parseCliTargets(options.cli);\n if (!parsed.ok) {\n return {\n ok: false,\n cli: [\"claude\"],\n warnings: parsed.warnings,\n message: parsed.error ?? \"Invalid --cli value\",\n };\n }\n const trackInputs = options.track ?? [];\n if (trackInputs.length === 0) {\n return {\n ok: false,\n cli: parsed.targets,\n warnings: parsed.warnings,\n // v26.56.0 (F6) — wizard 진입 안내. `install` subcommand 는 non-interactive.\n message:\n \"At least one --track is required (e.g. --track tooling)\\n Interactive wizard: run without subcommand → `agent-harness` (drop the `install` word)\",\n };\n }\n for (const t of trackInputs) {\n if (!isTrack(t)) {\n return {\n ok: false,\n cli: parsed.targets,\n warnings: parsed.warnings,\n message: `Unknown track: ${t}`,\n };\n }\n }\n return {\n ok: true,\n cli: parsed.targets,\n warnings: parsed.warnings,\n message: \"spec valid\",\n };\n}\n\nexport interface InstallActionDeps {\n log?: (msg: string) => void;\n err?: (msg: string) => void;\n exit?: (code: number) => never;\n /** Override the install pipeline (used by tests to avoid real fs side effects). */\n runPipeline?: (\n spec: InstallSpec,\n harnessRoot: string,\n mode?: import(\"../installer.js\").InstallMode,\n callbacks?: PipelineCallbacks,\n ) => InstallReport;\n /** Override the harness root resolver (defaults to a path relative to this file). */\n resolveHarnessRoot?: () => string;\n}\n\nexport function installAction(options: InstallOptions, deps: InstallActionDeps = {}): void {\n const log = deps.log ?? console.log;\n const err = deps.err ?? console.error;\n const exit = deps.exit ?? ((code: number) => process.exit(code) as never);\n const runPipeline = deps.runPipeline ?? defaultRunPipeline;\n const resolveHarnessRoot = deps.resolveHarnessRoot ?? defaultHarnessRoot;\n\n const validated = specFromOptions(options);\n // Deprecation warnings to stderr (alias 사용 시), regardless of ok/fail.\n for (const w of validated.warnings) {\n err(c.yellow(`[WARN] ${w}`));\n }\n if (!validated.ok) {\n err(status.failure(c.red(`ERROR: ${validated.message}`)));\n exit(1);\n return;\n }\n\n // v26.47.0 — Phase C full: --with/--without repeatable → userOverride.\n const forceInclude = normalizeRepeatable(options.with);\n const forceExclude = normalizeRepeatable(options.without);\n // v26.49.0 — unknown asset id validation (silent ignore 방지).\n const validIds = new Set(EXTERNAL_ASSETS.map((a) => a.id));\n for (const id of [...forceInclude, ...forceExclude]) {\n if (!validIds.has(id)) {\n err(\n c.yellow(\n `[WARN] Unknown asset id '${id}' (--with/--without). Skipping. Use one of: ${[...validIds].sort().join(\", \")}`,\n ),\n );\n }\n }\n const filteredInclude = forceInclude.filter((id) => validIds.has(id));\n const filteredExclude = forceExclude.filter((id) => validIds.has(id));\n const userOverride =\n filteredInclude.length > 0 || filteredExclude.length > 0\n ? { forceInclude: filteredInclude, forceExclude: filteredExclude }\n : undefined;\n\n const spec: InstallSpec = {\n tracks: (options.track as Track[]) ?? [],\n ...(userOverride ? { userOverride } : {}),\n // v26.81.0 (ADR-022, BREAKING) — 자산 1:1 boolean 13종 삭제. 자산 선택은 위\n // userOverride(--with <id>)로 일원화. 잔존 = 설치 동작 옵션만.\n options: {\n withPrune: options.withPrune === true,\n withCodexTrust: options.withCodexTrust === true,\n withKarpathyHook: options.withKarpathyHook === true,\n },\n cli: validated.cli,\n projectDir: resolve(options.projectDir ?? process.cwd()),\n scope: resolveScopeOption(options.scope, err),\n };\n\n executeSpec(spec, {\n log,\n err,\n exit,\n runPipeline,\n resolveHarnessRoot,\n verbose: options.verbose === true,\n });\n}\n\nexport interface ExecuteSpecDeps {\n log?: (msg: string) => void;\n err?: (msg: string) => void;\n exit?: (code: number) => never;\n runPipeline?: (\n spec: InstallSpec,\n harnessRoot: string,\n mode?: import(\"../installer.js\").InstallMode,\n callbacks?: PipelineCallbacks,\n ) => InstallReport;\n resolveHarnessRoot?: () => string;\n /** Router action mode (forwarded to runInstall). Default \"fresh\". */\n mode?: import(\"../installer.js\").InstallMode;\n /**\n * v26.63.0 — wizard 모드 (Step 1~4 통과 후 호출) 식별. true 시:\n * - install header (TARGET / TRACKS / CLI / OPTIONS / ASSETS) 출력 skip\n * (Step 3 review + Step 4 confirm 에서 이미 표시)\n * - \"Step 5/5 — Installing\" 흐름에 자연 연결\n */\n fromWizard?: boolean;\n /**\n * v26.63.0 — verbose 출력 (Phase 1 templates 의 files 라인 표시).\n * Default false — 카운트 + use 만 표시 (cognitive load 감소).\n */\n verbose?: boolean;\n}\n\n/**\n * Run the install pipeline for a fully-validated InstallSpec and render the\n * report. Shared by the `install` flag-mode command and the default\n * (interactive) action so both have identical post-install output.\n */\nexport function executeSpec(spec: InstallSpec, deps: ExecuteSpecDeps = {}): void {\n const log = deps.log ?? console.log;\n const err = deps.err ?? console.error;\n const exit = deps.exit ?? ((code: number) => process.exit(code) as never);\n const runPipeline = deps.runPipeline ?? defaultRunPipeline;\n const resolveHarnessRoot = deps.resolveHarnessRoot ?? defaultHarnessRoot;\n\n // v26.63.0 — wizard 모드는 header (TARGET ~ ASSETS) 출력 skip — Step 3/4 에서 이미 표시.\n // non-interactive (--track ...) 모드는 기존 header 유지 — 사용자 spec 확인 cue 필요.\n if (!deps.fromWizard) {\n renderInstallHeader(log, spec, deps.mode);\n }\n\n // v26.63.0 — phaseHeader → unifiedSection. Phase 카운터 (1/2/3) 제거 — 5-step 통합 시\n // wizard step 5/5 안 sub-section 으로 자연 흐름. Update mode 도 동일.\n log(unifiedSection(deps.mode === \"update\" ? \"Update Mode\" : \"Templates\"));\n log(\"\");\n\n // Streaming progress: baseline 완료 시 즉시 Phase 1 rows 출력, external은 per-asset 스트리밍.\n const renderer = createInstallRenderer(log, spec, deps.verbose === true);\n\n let report: InstallReport;\n try {\n report = runPipeline(spec, resolveHarnessRoot(), deps.mode, renderer.callbacks);\n } catch (e: unknown) {\n const detail = e instanceof Error ? e.message : String(e);\n log(\"\");\n err(status.failure(c.red(`install failed — ${detail}`)));\n exit(1);\n return;\n }\n\n // Update mode 단축 출력 — manifest copy / external 모두 skip\n if (report.updateMode) {\n renderUpdateSummary(log, report);\n return;\n }\n\n // Phase 2 trailing newline (if header was printed)\n if (renderer.phase2HeaderPrinted()) {\n log(\"\");\n }\n\n renderCliArtifacts(log, spec, report);\n renderFinalSummary(log, spec, report, deps.fromWizard === true);\n}\n\n/**\n * v26.64.0 (ADR-020) — `--scope` flag 해석. invalid 값은 warn + \"project\" default.\n * 비대화형 (--track 명시) 진입에서만 호출. wizard 는 별도 prompt.\n */\nfunction resolveScopeOption(value: string | undefined, err: (msg: string) => void): InstallScope {\n if (value === undefined) return \"project\";\n if (isInstallScope(value)) return value;\n err(\n c.yellow(`[WARN] Unknown --scope value '${value}' (expected: project, global). Using project.`),\n );\n return \"project\";\n}\n\n/**\n * v26.47.0 — Normalize cac repeatable flag (string | string[] | undefined) → string[].\n * Trim 빈 문자열 + dedup.\n */\nfunction normalizeRepeatable(value: string | string[] | undefined): string[] {\n if (!value) return [];\n const arr = Array.isArray(value) ? value : [value];\n return [...new Set(arr.map((s) => s.trim()).filter((s) => s.length > 0))];\n}\n\n/* v8 ignore start — thin dep-inject defaults. tests 는 항상 runPipeline / resolveHarnessRoot 주입. */\nfunction defaultRunPipeline(\n spec: InstallSpec,\n harnessRoot: string,\n mode?: import(\"../installer.js\").InstallMode,\n callbacks?: PipelineCallbacks,\n): InstallReport {\n const ctx: import(\"../installer.js\").InstallContext = {\n harnessRoot,\n projectDir: spec.projectDir,\n spec,\n };\n if (mode) ctx.mode = mode;\n if (callbacks?.onProgress) ctx.onProgress = callbacks.onProgress;\n if (callbacks?.externalDeps) ctx.externalDeps = callbacks.externalDeps;\n return runInstallPipeline(ctx);\n}\n\nfunction defaultHarnessRoot(): string {\n // The bundled CLI lives at <root>/dist/index.js. import.meta.url + ../ resolves to <root>.\n // fileURLToPath 필수 — `.pathname` 은 공백/비ASCII 경로를 percent-encoded 로 남겨\n // \"Templates dir not found\" 로 install 이 실패한다 (v26.103.0 SOD 리뷰 2기 독립 수렴).\n return resolve(fileURLToPath(new URL(\".\", import.meta.url)), \"..\");\n}\n\n/* v8 ignore stop */\n\nexport { defaultHarnessRoot };\n\nexport function registerInstallCommand(cli: Cli): void {\n cli\n .command(\"install\", \"Install harness assets into a project\")\n // === Track / CLI / Project ===\n .option(\"--track <name>\", \"[Track] Track to install (repeatable)\", { type: [String] })\n .option(\n \"--cli <target>\",\n \"[CLI] Target CLI (repeatable): claude | codex | opencode | antigravity\",\n {\n type: [String],\n default: \"claude\",\n },\n )\n .option(\"--project-dir <path>\", \"[Project] Target project directory\", {\n default: process.cwd(),\n })\n .option(\"--scope <scope>\", \"[Scope] Installation scope: project (default) | global\", {\n default: \"project\",\n })\n // === Asset selection (Phase C full, v26.47.0+) ===\n .option(\n \"--with <asset-id>\",\n \"[Asset] Force-include External Asset id (regardless of preset). Repeatable. v26.47.0+\",\n )\n .option(\n \"--without <asset-id>\",\n \"[Asset] Force-exclude External Asset id (drop from preset recommendation). Repeatable. v26.47.0+\",\n )\n // === Codex global (v26.46.0+) ===\n .option(\n \"--with-codex-trust\",\n \"[Codex] Codex global opt-in: register trust entry in ~/.codex/config.toml\",\n )\n // v26.81.0 (ADR-022, BREAKING) — 자산 1:1 플래그 13종 삭제. 자산 opt-in 은 전부\n // generic `--with <asset-id>` (위) — 자산 id 목록은 docs/COMPATIBILITY.md 표 참조.\n // 아래는 자산이 아닌 설치 동작 옵션만.\n .option(\n \"--with-prune\",\n \"[Behavior] Prune ECC items beyond curated 89 (use with --with ecc-plugin)\",\n )\n .option(\n \"--with-karpathy-hook\",\n \"[Behavior] karpathy-coder pre-commit hook (.claude/settings.json PreToolUse Write|Edit)\",\n )\n // === Misc ===\n .option(\"--verbose\", \"[Misc] Show installed file lists per category (default: counts only)\")\n // === Examples (v26.50.0+) ===\n .example(\"install --track tooling --with karpathy-coder\")\n .example(\"install --track csr-supabase --cli claude --cli codex\")\n .example(\"install --track csr-supabase --without netlify-cli --with railway-skills\")\n /* v8 ignore next — cac action callback. installAction 자체는 별도 tests 로 검증. */\n .action((options: InstallOptions) => installAction(options));\n}\n","/**\n * CLI targets parser — v0.7.0 multi-select.\n *\n * SPEC: docs/specs/cli-multi-select.md F2 (parseCliTargets).\n *\n * Input shapes:\n * - undefined / null / \"\" / [] → [\"claude\"] (default)\n * - \"claude\" / \"codex\" / \"opencode\" / \"antigravity\" → single-element array\n * - [\"claude\", \"codex\"] (cac repeatable) → sorted array\n * - \"both\" / \"all\" (v0.8.0 제거된 legacy alias) → ok=false + 마이그레이션 안내 (throw 아님)\n * - \"invalid\" → ok=false + error (throw 아님)\n *\n * Output:\n * - ok: 유효하면 true, reject 시 false (+ error 메시지, targets=[\"claude\"] default)\n * - targets: sorted ReadonlyArray<CliBase> (claude → codex → opencode → antigravity 순)\n * - warnings: 메시지 배열 (현재 reject-only 정책이라 비어 있음)\n */\n\nimport { CLI_BASES, type CliBase, type CliTargets, isCliBase } from \"./types.js\";\n\n/** SSOT — claude → codex → opencode → antigravity 정렬 순서. prompts.ts에서 import. */\nexport const CLI_BASE_SORT_ORDER: Record<CliBase, number> = {\n claude: 0,\n codex: 1,\n opencode: 2,\n antigravity: 3,\n};\n\nexport interface ParseCliTargetsResult {\n ok: boolean;\n targets: CliTargets;\n warnings: ReadonlyArray<string>;\n /** ok=false 시 reject 사유. */\n error?: string;\n}\n\n/**\n * `--cli` 입력을 sorted CliTargets로 정규화.\n *\n * Default `[\"claude\"]` (비어있거나 undefined일 때).\n * Invalid 모드는 reject (ok=false).\n *\n * v0.8.0 — `both`/`all` legacy alias 제거 (v0.7.0에서 1 release deprecation 거침).\n * `both`/`all` 입력 시 invalid reject + 마이그레이션 안내.\n */\nexport function parseCliTargets(input: string | string[] | undefined): ParseCliTargetsResult {\n const items = normalizeInput(input);\n if (items.length === 0) {\n return { ok: true, targets: [\"claude\"], warnings: [] };\n }\n\n const collected = new Set<CliBase>();\n const warnings: string[] = [];\n\n for (const item of items) {\n if (!isCliBase(item)) {\n // v0.8.0 — alias 제거 마이그레이션 힌트\n let hint = \"\";\n if (item === \"both\") {\n hint = \"\\n v0.8.0 removed 'both' alias. Use --cli claude --cli codex.\";\n } else if (item === \"all\") {\n hint =\n \"\\n v0.8.0 removed 'all' alias. Use --cli claude --cli codex --cli opencode.\";\n } else if (item.includes(\",\")) {\n // v0.7.1 — comma-separated input hint\n hint = \"\\n Tip: comma-separated not supported. Use --cli A --cli B for multiple.\";\n }\n return {\n ok: false,\n targets: [\"claude\"],\n warnings,\n error: `Invalid --cli value: ${item}. Must be one of: ${CLI_BASES.join(\" | \")}${hint}`,\n };\n }\n collected.add(item);\n }\n\n const targets = [...collected].sort((a, b) => CLI_BASE_SORT_ORDER[a] - CLI_BASE_SORT_ORDER[b]);\n return { ok: true, targets, warnings };\n}\n\nfunction normalizeInput(input: string | string[] | undefined): string[] {\n if (input === undefined || input === null) return [];\n if (typeof input === \"string\") {\n const trimmed = input.trim();\n return trimmed === \"\" ? [] : [trimmed];\n }\n return input.filter((s) => typeof s === \"string\" && s.trim() !== \"\").map((s) => s.trim());\n}\n\n/** Targets에 특정 base 포함 여부. has() 패턴. */\nexport function targetsInclude(targets: CliTargets, base: CliBase): boolean {\n return targets.includes(base);\n}\n","/**\n * design.ts — CLI visual design tokens (color, symbols, layout helpers).\n *\n * Aesthetic direction: **refined ops-report**. Mission control feel without\n * decoration noise. Phase markers + aligned 2-column rows + structured summary.\n *\n * Goals:\n * 1. Make input-wait points visually obvious (handled by @clack/prompts).\n * 2. Make the install pipeline output legible:\n * - phase-segmented progress (━━━ Phase N · Title ━━━)\n * - aligned per-asset rows (✓/⊘/✗ + id + meta)\n * - explicit skipped/failed reporting (no silent skips)\n * - terminal-width responsive (default 78)\n * 3. Zero runtime dependencies — emit raw ANSI escapes.\n *\n * `NO_COLOR` is honored per https://no-color.org.\n */\n\nconst isColorEnabled = (() => {\n if (process.env.NO_COLOR && process.env.NO_COLOR !== \"\") {\n return false;\n }\n // stdout may be missing in some test contexts\n return Boolean(process.stdout?.isTTY);\n})();\n\nfunction wrap(open: number, close: number) {\n return (s: string): string => {\n if (!isColorEnabled) {\n return s;\n }\n return `\\x1b[${open}m${s}\\x1b[${close}m`;\n };\n}\n\nexport const c = {\n bold: wrap(1, 22),\n dim: wrap(2, 22),\n red: wrap(31, 39),\n green: wrap(32, 39),\n yellow: wrap(33, 39),\n cyan: wrap(36, 39),\n gray: wrap(90, 39),\n};\n\nexport const symbol = {\n success: \"✓\",\n failure: \"✗\",\n skip: \"⊘\",\n arrow: \"›\",\n pointer: \"▸\",\n bullet: \"•\",\n warn: \"⚠\",\n /** Heavy horizontal box-drawing — phase dividers. */\n rule: \"━\",\n /** Middle dot — section separator. */\n mid: \"·\",\n};\n\n/** Default width for phase headers / dividers. Terminal default ≥ 78. */\nexport const DEFAULT_WIDTH = 78;\n\n/** Render a legacy section header. Bold cyan with a leading arrow. (kept for backward compat) */\nexport function header(title: string): string {\n return c.bold(c.cyan(`${symbol.arrow} ${title}`));\n}\n\n/**\n * Render a phase header — `━━━ Phase N · Title ━━━━━━━...` (full-width).\n * v26.63.0 (deprecated): kept for non-interactive mode + backward compat.\n * wizard 모드는 unifiedSection() 사용 (5-step 통합 — phase 카운터 무관).\n */\nexport function phaseHeader(n: number | string, title: string, width = DEFAULT_WIDTH): string {\n const label = `${symbol.rule}${symbol.rule}${symbol.rule} Phase ${n} ${symbol.mid} ${title} `;\n const fill = symbol.rule.repeat(Math.max(0, width - visibleLength(label)));\n return c.bold(c.cyan(`${label}${fill}`));\n}\n\n/**\n * v26.63.0 — Step 5 (Installing) 안의 sub-section 헤더.\n * `━━ Templates ━━` / `━━ External assets (n) ━━` / `━━ Codex artifacts ━━`.\n * phaseHeader (3 rule + Phase N + ·) 대비 단순 — 2 rule + title.\n */\nexport function unifiedSection(title: string, width = DEFAULT_WIDTH): string {\n const label = `${symbol.rule}${symbol.rule} ${title} `;\n const fill = symbol.rule.repeat(Math.max(0, width - visibleLength(label)));\n return c.bold(c.cyan(`${label}${fill}`));\n}\n\n/**\n * Render a section header (non-phase) — `━━━ Title ━━━━━━━...`.\n * Used for TARGET / SUMMARY / NEXT etc.\n */\nexport function sectionHeader(title: string, width = DEFAULT_WIDTH): string {\n const label = `${symbol.rule}${symbol.rule}${symbol.rule} ${title} `;\n const fill = symbol.rule.repeat(Math.max(0, width - visibleLength(label)));\n return c.bold(c.cyan(`${label}${fill}`));\n}\n\n/** Plain horizontal divider — `━━━...━━━` (no label). */\nexport function divider(width = DEFAULT_WIDTH): string {\n return c.dim(symbol.rule.repeat(width));\n}\n\n/**\n * Render a `key: value` row with a fixed-width left column for alignment.\n * Used in pre-flight / summary blocks (▸ TRACKS executive, tooling).\n */\nexport function infoRow(key: string, value: string, width = 12): string {\n const label = `${symbol.pointer} ${key}`.padEnd(width + 2, \" \");\n return ` ${c.dim(label)} ${value}`;\n}\n\n/** Backward-compat — `keyValue` (used by older install report). */\nexport function keyValue(key: string, value: string, width = 16): string {\n const padded = `${key}:`.padEnd(width, \" \");\n return ` ${c.dim(padded)} ${value}`;\n}\n\n/**\n * Render an asset row — ` ✓ asset-id meta`.\n * symbol = success/skip/failure. label = stable id (left-pad). meta = dim right column.\n */\nexport function assetRow(\n kind: \"success\" | \"skip\" | \"failure\",\n label: string,\n meta = \"\",\n labelWidth = 40,\n): string {\n const sym = renderSymbol(kind);\n const labelPadded = label.padEnd(labelWidth, \" \");\n const metaText = meta ? c.dim(meta) : \"\";\n return ` ${sym} ${labelPadded} ${metaText}`.trimEnd();\n}\n\nfunction renderSymbol(kind: \"success\" | \"skip\" | \"failure\"): string {\n switch (kind) {\n case \"success\":\n return c.green(symbol.success);\n case \"skip\":\n return c.yellow(symbol.skip);\n case \"failure\":\n return c.red(symbol.failure);\n }\n}\n\nexport const status = {\n success: (msg: string): string => `${c.green(symbol.success)} ${msg}`,\n failure: (msg: string): string => `${c.red(symbol.failure)} ${msg}`,\n warn: (msg: string): string => `${c.yellow(symbol.warn)} ${msg}`,\n info: (msg: string): string => `${c.cyan(symbol.bullet)} ${msg}`,\n};\n\n/**\n * Strip ANSI escape sequences so visible width can be measured (for header padding).\n */\nfunction visibleLength(s: string): number {\n // biome-ignore lint/suspicious/noControlCharactersInRegex: ANSI escape stripping requires \\x1b\n return s.replace(/\\x1b\\[[0-9;]*m/g, \"\").length;\n}\n\n/**\n * v26.63.2 — Pad to fixed display width (ANSI-aware). spacing scale 정렬 용.\n */\nexport function padDisplay(s: string, width: number): string {\n const visible = visibleLength(s);\n return visible >= width ? s : s + \" \".repeat(width - visible);\n}\n","import {\n chmodSync,\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n writeFileSync,\n} from \"node:fs\";\nimport { basename, dirname, join, resolve } from \"node:path\";\nimport {\n type AntigravityTransformReport,\n runAntigravityTransform,\n} from \"./antigravity/transform.js\";\nimport { type CiScaffoldReport, installCiScaffold } from \"./ci-scaffold.js\";\nimport { type CodexOptInReport, runCodexOptIn } from \"./codex/opt-in.js\";\nimport { type CodexTransformReport, runCodexTransform } from \"./codex/transform.js\";\nimport {\n addGitignoreEnv,\n addGitignoreNpxSkillsAgents,\n writeEnvExample,\n writeMcpAllowlist,\n} from \"./env-files.js\";\nimport { EXTERNAL_ASSETS, INTERNAL_BUNDLED_SKILL_IDS, isAssetSelected } from \"./external-assets.js\";\nimport {\n type ExternalInstallerDeps,\n type ExternalInstallReport,\n runExternalInstall,\n selectExternalTargets,\n} from \"./external-installer.js\";\nimport {\n backupDir,\n backupFileIfChanged,\n copyBackupDir,\n copyDir,\n copyFile,\n ensureProjectSkeleton,\n} from \"./fs-ops.js\";\nimport {\n buildInstallLog,\n collectSkillHashes,\n hashContent,\n type InstallLog,\n type InstallLogRootFile,\n readInstallLog,\n writeInstallLog,\n} from \"./install-log.js\";\nimport { type AssetSpec, buildManifest } from \"./manifest.js\";\nimport { composeMcpJson, writeMcpJson } from \"./mcp-merge.js\";\nimport { type OpencodeTransformReport, runOpencodeTransform } from \"./opencode/transform.js\";\nimport { mergeProjectClaude } from \"./project-claude-merge.js\";\nimport { addPreToolUseHook, type ClaudeSettings } from \"./settings-merge.js\";\nimport { type InstallSpec, type OptionFlags, resolveScope, type Track } from \"./types.js\";\nimport { runUpdateMode, type UpdateModeReport } from \"./update-mode.js\";\n\n/**\n * karpathy-coder hook 상수 — install 이 쓰고 uninstall 의 수기 안내가 읽는다.\n * v26.123.0 — 두 곳이 같은 값을 봐야 해서 export. 파일명이 바뀌면 안내가 조용히 멈추므로\n * 경로도 여기서 파생시킨다 (`no-false-ship`: 같은 값이 2곳에 하드코딩되면 derive 로 단일화).\n */\nexport const KARPATHY_HOOK_RELPATH = \".claude/hooks/karpathy-gate.sh\";\nexport const KARPATHY_HOOK_COMMAND = `bash \"$CLAUDE_PROJECT_DIR/${KARPATHY_HOOK_RELPATH}\"`;\n\n/**\n * Install mode — Router action 매핑.\n * - \"fresh\" : 첫 설치 (기본값)\n * - \"add\" : 기존 위에 Track union 추가 (backup 없음)\n * - \"update\" : 정책 파일만 templates로 갱신 (backup + orphan prune + stale hook)\n * - \"reinstall\" : 기존 .claude/ backup 후 처음부터 (backup 강제)\n */\nexport type InstallMode = \"fresh\" | \"add\" | \"update\" | \"reinstall\";\n\n/**\n * 각 mode 를 **비대화형으로 도달하는 CLI 명령** (없으면 null = 위저드 전용).\n *\n * 왜 코드로 두나: `install` 은 플래그로 되는데 `update` 는 위저드로만 되던 상태가 오래\n * 방치됐다. \"CI 로 깔 수는 있는데 갱신할 수는 없다\"는 수요 문제가 아니라 계열 비대칭이고,\n * 사람이 매번 계열 전체를 기억해서 대조해야 하면 그 규약은 이미 실패한 것이다.\n *\n * `Record<InstallMode, ...>` 라서 **mode 를 추가하면 여기 분류하기 전에는 컴파일이 안 된다.**\n * null 을 고르는 건 허용하지만 그 순간 \"위저드 전용\"이 명시적 선언이 되고, 아래 테스트가\n * 그 목록을 화면에 내보낸다 — 침묵으로 빠지는 경로가 없다.\n */\nexport const MODE_ENTRY_POINT: Record<InstallMode, string | null> = {\n fresh: \"install\",\n // 기존 설치 위에 `install --track <new>` = add. mode 는 헤더 라벨만 다르고 동작은 fresh 와 같다\n // (backup 없음 · manifest copy 동일) — 별도 명령이 필요 없다.\n add: \"install\",\n update: \"update\",\n // 미제공 — `.claude/` 를 통째로 backup 으로 **옮기는** 파괴적 경로다. 비대화형 진입점을\n // 붙일지는 별도 판단 사항이라 열어둔다 (열어둔 것 자체가 이 표에 보인다).\n reinstall: null,\n};\n\nexport interface InstallContext {\n /** Path to the harness repo (where `templates/` lives). */\n harnessRoot: string;\n /** Target project directory. */\n projectDir: string;\n spec: InstallSpec;\n /**\n * Router action mode. Defaults to \"fresh\".\n * - \"add\"/\"update\"/\"reinstall\" trigger different install paths.\n * - reinstall + update force backup=true.\n */\n mode?: InstallMode;\n /**\n * When true, an existing .claude/ is renamed to a timestamped backup before install.\n * Auto-true when mode ∈ {update, reinstall}.\n */\n backup?: boolean;\n /**\n * External install (claude plugin / npm -g / npx skills) injection point.\n * Default: real `runExternalInstall`. Tests inject mock to avoid real spawn.\n * Pass `null` to disable external install entirely.\n */\n runExternal?:\n | ((\n // v26.77.0 — projectDir: 외부 설치기 spawn cwd (자산 착지 위치). Bug B fix.\n // v26.81.0 (ADR-022) — userOverride: 자산 opt-in(--with <id>) 전파 (flag 13종 대체).\n ctx: {\n tracks: ReadonlyArray<Track>;\n options: OptionFlags;\n projectDir?: string;\n userOverride?: {\n forceInclude: ReadonlyArray<string>;\n forceExclude: ReadonlyArray<string>;\n };\n },\n deps: ExternalInstallerDeps,\n ) => ExternalInstallReport)\n | null;\n /**\n * Progress callback fired between stages so renderers can stream output\n * (avoids \"Phase 1 header → 5 minutes silence\" UX problem).\n */\n onProgress?: (event: ProgressEvent) => void;\n /** External installer streaming hooks (forwarded to runExternalInstall). */\n externalDeps?: Pick<ExternalInstallerDeps, \"onAssetStart\" | \"onAssetResult\">;\n}\n\n/** Progress event types fired during runInstall. */\nexport type ProgressEvent =\n /** Baseline (manifest copy + mcp + envFiles + Codex/OpenCode transforms) finished. External not yet started. */\n | { type: \"baseline-complete\"; baseline: BaselineReport }\n /** External install phase about to begin. */\n | { type: \"external-start\"; assetCount: number }\n /** External install phase finished (with report). */\n | { type: \"external-complete\"; report: ExternalInstallReport }\n /** v26.64.0 — install log write 실패 (non-fatal). */\n | { type: \"install-log-error\"; message: string };\n\n/** karpathy-coder hook auto-wire 결과 (v0.6.0). */\nexport interface KarpathyHookReport {\n /** withKarpathyHook=true && karpathy-coder install 성공 시 true. */\n wired: boolean;\n /** wired=false 시 사유. */\n reason?:\n | \"opt-out\"\n | \"plugin-install-failed\"\n | \"external-skipped\"\n | \"settings-parse-error\"\n | \"claude-not-selected\";\n /** wired=true 시 settings.json 갱신 여부 (idempotent skip 시 false). */\n settingsUpdated?: boolean;\n /** wired=true 시 hook script 복사 여부. */\n hookScriptCopied?: boolean;\n}\n\n/** karpathy-coder asset ID — SSOT (external-assets.ts entry id와 일치 강제). */\nexport const KARPATHY_ASSET_ID = \"karpathy-coder\";\n\n/**\n * v0.6.1 — Phase 1 output 카테고리별 분류. install renderer가 각 카테고리별로 row를 출력한다.\n * Names는 description용 (display only); 빈 배열이면 row 출력 skip.\n */\nexport interface BaselineCategoryCounts {\n /** rule 파일 names (확장자 제외) — git-policy, change-management 등 */\n rules: string[];\n /** agent 파일 names */\n agents: string[];\n /** hook 파일 names (확장자 제외) */\n hooks: string[];\n /** commands 디렉토리 카운트 (uzys + ecc) — names는 디렉토리라 무의미 */\n commands: number;\n /** skill 디렉토리 names */\n skills: string[];\n}\n\n/** Baseline phase result (everything except external assets). */\nexport interface BaselineReport {\n filesCopied: number;\n dirsCopied: number;\n skipped: number;\n backup: string | null;\n installedTracks: string[];\n mcpServers: string[];\n codex: CodexTransformReport | null;\n codexOptIn: CodexOptInReport | null;\n opencode: OpencodeTransformReport | null;\n /** v26.66.0 — Present when spec.cli includes \"antigravity\". */\n antigravity: AntigravityTransformReport | null;\n updateMode: UpdateModeReport | null;\n mode: InstallMode;\n envFiles: {\n envExampleCreated: boolean;\n gitignoreEnvAdded: boolean;\n mcpAllowlist: string[] | null;\n /** v0.8.0 — `.gitignore`에 추가된 npx skills agent 디렉토리 패턴 (`.factory/`, `.goose/`). */\n gitignoreNpxSkillsAdded: string[];\n };\n /**\n * v26.108.0 (ADR-037) — CI 스캐폴드 결과. opt-in 미선택 시 null. `.github/workflows/`\n * 는 CLI-agnostic 이라 claude baseline 밖의 전용 단계 (ci-scaffold.ts) 가 설치 주체.\n */\n ciScaffold: CiScaffoldReport | null;\n /** v0.6.1 — Phase 1 카테고리별 카운트 + names. Update mode에서는 빈 객체. */\n categories?: BaselineCategoryCounts;\n /** Root CLAUDE.md fill-in scaffold (project name + active-track note + FILL sections). null when claude baseline disabled. */\n rootClaudeMd: { tracks: ReadonlyArray<Track> } | null;\n /** 덮어쓰기 전 보존한 사용자 파일 백업 경로 (settings.json·CLAUDE.md, fresh/add 모드). audit SEC-1/CODE-2. */\n backups?: string[];\n}\n\nexport interface InstallReport {\n filesCopied: number;\n dirsCopied: number;\n skipped: number;\n backup: string | null;\n installedTracks: string[];\n mcpServers: string[];\n /** Present when spec.cli includes \"codex\". */\n codex: CodexTransformReport | null;\n /** Present when Codex transform ran AND user opted-in to global skills/trust/prompts. null otherwise. */\n codexOptIn: CodexOptInReport | null;\n /** Present when spec.cli includes \"opencode\". */\n opencode: OpencodeTransformReport | null;\n /** v26.66.0 — Present when spec.cli includes \"antigravity\". */\n antigravity: AntigravityTransformReport | null;\n /** v26.108.0 (ADR-037) — CI 스캐폴드 결과 (opt-in 미선택 시 null). */\n ciScaffold: CiScaffoldReport | null;\n /** External install report (claude plugin / npm -g / npx skills). null when disabled or empty. */\n external: ExternalInstallReport | null;\n /** Update-mode report (rules/agents/commands/hooks/skills 갱신 + orphan prune + stale hook). null when not update mode. */\n updateMode: UpdateModeReport | null;\n /** karpathy-coder hook auto-wire 결과 (v0.6.0). null when withKarpathyHook=false. */\n karpathyHook: KarpathyHookReport | null;\n /** Install mode dispatched (echo of ctx.mode, default \"fresh\"). */\n mode: InstallMode;\n /** Environment file generation results (always present). */\n envFiles: {\n /** true if .env.example was created (csr-supabase/full only). */\n envExampleCreated: boolean;\n /** true if .gitignore got `.env` line appended. */\n gitignoreEnvAdded: boolean;\n /** Server names written to .mcp-allowlist; null if skipped. */\n mcpAllowlist: string[] | null;\n /** v0.8.0 — `.gitignore`에 추가된 npx skills agent 디렉토리 패턴 (`.factory/`, `.goose/`). */\n gitignoreNpxSkillsAdded: string[];\n };\n}\n\n/**\n * Run the installation pipeline. Pure function modulo filesystem side effects.\n * v26.82.0 (Phase R) — 276줄 단일 함수를 단계별 블록 함수로 분해 (동작 변경 0):\n * update 단축 / claude baseline / CLI transforms / external / install log.\n */\nexport function runInstall(ctx: InstallContext): InstallReport {\n const { harnessRoot, projectDir, spec } = ctx;\n const mode: InstallMode = ctx.mode ?? \"fresh\";\n const templatesDir = join(harnessRoot, \"templates\");\n\n if (!existsSync(templatesDir)) {\n throw new Error(`Templates dir not found: ${templatesDir}`);\n }\n\n const claudeDir = join(projectDir, \".claude\");\n\n // Update mode pre-flight: existing .claude/ 필수. backup 전에 검증.\n if (mode === \"update\" && !existsSync(claudeDir)) {\n throw new Error(`Update mode requires existing .claude/ at ${claudeDir}`);\n }\n\n // v26.123.0 (F-1a) — 추가 설치가 이전 설치 기록을 지우지 않도록 기존 로그를 먼저 읽는다.\n // reinstall 은 바로 아래에서 `.claude/` 를 통째로 backup 으로 옮기므로 그 뒤엔 읽을 수 없다.\n const previousLog = readInstallLog(projectDir);\n\n const backupPath = resolveBackupPath(ctx, mode, claudeDir);\n\n // Update mode 단축 — 정책 파일만 갱신하고 종료 (manifest copy / external 모두 skip)\n if (mode === \"update\") {\n return runUpdateInstall(ctx, templatesDir, backupPath);\n }\n\n const manifestSpec = buildManifestSpec(spec);\n\n // v0.8.0 — `.claude/` baseline은 spec.cli에 \"claude\" 포함 시에만 생성.\n // Codex/OpenCode 단독 사용자는 dead weight 회피.\n const base = spec.cli.includes(\"claude\")\n ? installClaudeBaseline(manifestSpec, projectDir, templatesDir)\n : emptyClaudeBaseline();\n\n // Compose .mcp.json from template + track-mcp-map.tsv (Codex/OpenCode도 사용 — claude 무관)\n const mcpResult = composeAndWriteMcp(harnessRoot, projectDir, spec);\n\n // v26.108.0 (ADR-037) — CI 스캐폴드 (opt-in 전용). `.github/` 은 CLI-agnostic 이라\n // claude baseline 조건 밖에서 설치. 기존 워크플로 파일은 절대 덮어쓰지 않는다.\n const ciScaffold = isAssetSelected(\"ci-scaffold\", {\n tracks: spec.tracks,\n options: spec.options,\n ...(spec.userOverride ? { userOverride: spec.userOverride } : {}),\n })\n ? installCiScaffold({ harnessRoot, projectDir, tracks: spec.tracks })\n : null;\n\n const baseline: BaselineReport = {\n filesCopied: base.filesCopied,\n dirsCopied: base.dirsCopied,\n skipped: base.skipped,\n backup: backupPath,\n installedTracks: [...spec.tracks].sort(),\n mcpServers: Object.keys(mcpResult.mcpServers).sort(),\n ...runCliTransforms(spec, harnessRoot, projectDir, manifestSpec.selectedInternalSkills),\n ciScaffold,\n updateMode: null,\n mode,\n envFiles: writeEnvironmentFiles(projectDir, spec.tracks),\n categories: base.categories,\n rootClaudeMd: base.rootClaudeMd,\n backups: base.backups,\n };\n\n // ━━━ Baseline complete — emit progress event so renderer can show Phase 1 rows ━━━\n ctx.onProgress?.({ type: \"baseline-complete\", baseline });\n\n // ━━━ External assets (claude plugin / npm -g / npx skills) ━━━\n const external = runExternalPhase(ctx);\n\n // ━━━ karpathy-coder hook auto-wire (v0.6.0) ━━━\n // SPEC: docs/specs/karpathy-hook-autowire.md AC2 — opt-in 강제 + install 성공 후에만.\n // v0.8.0 — `.claude/settings.json` PreToolUse 의존이라 spec.cli에 \"claude\" 포함 시에만 와이어 가능.\n const karpathyHook = wireKarpathyHook(spec, external, harnessRoot, projectDir);\n\n // ━━━ v26.64.0 (ADR-020) — Install log write ━━━\n // backupPath 가 있으면 `.claude/` 를 rename 으로 밀어냈다는 뜻 — 그 안에 살던 이전 자산은\n // 실제로 사라졌으므로 누적에서 빠져야 한다 (fresh/add 는 backupPath=null → 전부 유지).\n writeInstallLogSafe(\n ctx,\n external,\n base.rootClaudeMdLog,\n previousLog,\n backupPath !== null,\n collectRootFiles(baseline.envFiles, ciScaffold, mcpResult.created),\n );\n\n return { ...baseline, external, karpathyHook };\n}\n\n/**\n * Backup auto-on for update + reinstall (sourced from router action).\n * Update: copy backup (preserve original .claude/ for in-place update).\n * Reinstall + others: rename backup (move .claude/ aside, then full install).\n */\nfunction resolveBackupPath(\n ctx: InstallContext,\n mode: InstallMode,\n claudeDir: string,\n): string | null {\n const wantBackup = ctx.backup ?? (mode === \"update\" || mode === \"reinstall\");\n if (!wantBackup) return null;\n return mode === \"update\" ? copyBackupDir(claudeDir) : backupDir(claudeDir);\n}\n\n/** Update mode 단축 경로 — 정책 파일만 갱신 (manifest copy / external 모두 skip). */\nfunction runUpdateInstall(\n ctx: InstallContext,\n templatesDir: string,\n backupPath: string | null,\n): InstallReport {\n const updateReport = runUpdateMode(ctx.projectDir, templatesDir);\n const baseline: BaselineReport = {\n filesCopied: 0,\n dirsCopied: 0,\n skipped: 0,\n backup: backupPath,\n installedTracks: [...ctx.spec.tracks].sort(),\n mcpServers: [],\n codex: null,\n codexOptIn: null,\n opencode: null,\n antigravity: null,\n ciScaffold: null,\n updateMode: updateReport,\n mode: \"update\",\n envFiles: {\n envExampleCreated: false,\n gitignoreEnvAdded: false,\n mcpAllowlist: null,\n gitignoreNpxSkillsAdded: [],\n },\n rootClaudeMd: null,\n };\n ctx.onProgress?.({ type: \"baseline-complete\", baseline });\n return { ...baseline, external: null, karpathyHook: null };\n}\n\n/**\n * v26.81.0 (ADR-022) — manifest 게이팅 입력. 내부 자산 선택 판정 — 이전\n * OptionFlags.withTauri/withUzysHarness/withEcc boolean 자리를 카탈로그 선택\n * (wizard 체크 / --with <id> → forceInclude)으로 대체 (manifest 필드명은 유지).\n */\nfunction buildManifestSpec(spec: InstallSpec): Required<AssetSpec> {\n const selectionCtx = {\n tracks: spec.tracks,\n options: spec.options,\n ...(spec.userOverride ? { userOverride: spec.userOverride } : {}),\n };\n return {\n tracks: spec.tracks,\n withTauri: isAssetSelected(\"tauri-desktop\", selectionCtx),\n // v26.55.0 — withEcc gating (ADR-016). ECC cherry-pick (agents/skills/commands) 항목 토글.\n // withPrune 은 ecc-plugin 사용을 전제 (이전 applyOptionRules `withEcc ||= withPrune` 의미 보존).\n withEcc: isAssetSelected(\"ecc-plugin\", selectionCtx) || spec.options.withPrune,\n // v26.87.0 — internal bundled skills (dev-method + opt-in advisors, v26.95.0). Each id's\n // condition (has-dev-track vs opt-in) is applied by isAssetSelected — manifest copy + the 3\n // non-Claude CLI transforms gate on this filtered list, so opt-in ones install only when\n // wizard-checked / `--with <id>`, and any uncheck / `--without <id>` (forceExclude) drops it.\n selectedInternalSkills: INTERNAL_BUNDLED_SKILL_IDS.filter((id) =>\n isAssetSelected(id, selectionCtx),\n ),\n };\n}\n\n/** `.claude/` baseline (manifest copy) 결과. claude 미선택 시 emptyClaudeBaseline(). */\ninterface ClaudeBaselineResult {\n filesCopied: number;\n dirsCopied: number;\n skipped: number;\n categories: BaselineCategoryCounts;\n rootClaudeMd: { tracks: ReadonlyArray<Track> } | null;\n /** root CLAUDE.md 무결성 기록 — uninstall 시 사용자 수정 여부 판별 (install 원본과 sha 비교). */\n rootClaudeMdLog: { path: string; sha256: string } | null;\n /** 덮어쓰기 전 보존한 사용자 파일 백업 경로 (settings.json·CLAUDE.md). audit SEC-1/CODE-2. */\n backups: string[];\n}\n\nfunction emptyClaudeBaseline(): ClaudeBaselineResult {\n return {\n filesCopied: 0,\n dirsCopied: 0,\n skipped: 0,\n categories: { rules: [], agents: [], hooks: [], commands: 0, skills: [] },\n rootClaudeMd: null,\n rootClaudeMdLog: null,\n backups: [],\n };\n}\n\n/** `.claude/` baseline — manifest copy + hook chmod + .installed-tracks + root CLAUDE.md merge. */\nfunction installClaudeBaseline(\n manifestSpec: Required<AssetSpec>,\n projectDir: string,\n templatesDir: string,\n): ClaudeBaselineResult {\n ensureProjectSkeleton(projectDir);\n\n const result = emptyClaudeBaseline();\n const manifest = buildManifest(manifestSpec);\n\n for (const entry of manifest) {\n if (!entry.applies(manifestSpec)) {\n continue;\n }\n const source = join(templatesDir, entry.source);\n const target = join(projectDir, entry.target);\n if (!existsSync(source)) {\n result.skipped += 1;\n continue;\n }\n if (entry.type === \"file\") {\n // 사용자 편집 가능 파일은 덮어쓰기 전 백업 (audit SEC-1 — settings.json hook/statusLine 소실 방지).\n if (entry.target === \".claude/settings.json\") {\n const backup = backupFileIfChanged(target, readFileSync(source, \"utf-8\"));\n if (backup) {\n result.backups.push(backup);\n }\n }\n copyFile(source, target);\n result.filesCopied += 1;\n } else {\n copyDir(source, target);\n result.dirsCopied += 1;\n }\n accumulateCategory(result.categories, entry);\n }\n\n // chmod +x on hook scripts (cp does not preserve exec bit when source is non-exec)\n const hookDir = join(projectDir, \".claude/hooks\");\n if (existsSync(hookDir)) {\n chmodHooksSync(hookDir);\n }\n\n // Write metadata file used by detect_install_state on next run (.claude/.installed-tracks)\n writeInstalledTracks(projectDir, manifestSpec.tracks);\n\n // Project root CLAUDE.md — an honest fill-in scaffold (project name + active tracks + FILL sections).\n // Note: overwrites any user customization on re-install. Documented behavior.\n const rootClaudeMd = writeRootClaudeMd(projectDir, manifestSpec.tracks);\n result.rootClaudeMd = { tracks: manifestSpec.tracks };\n result.rootClaudeMdLog = { path: \"CLAUDE.md\", sha256: hashContent(rootClaudeMd.content) };\n if (rootClaudeMd.backup) {\n result.backups.push(rootClaudeMd.backup);\n }\n return result;\n}\n\n/** Environment files (F7/F8 — bash setup-harness.sh L880~890 + L954~996 등가). */\nfunction writeEnvironmentFiles(\n projectDir: string,\n tracks: ReadonlyArray<Track>,\n): BaselineReport[\"envFiles\"] {\n return {\n envExampleCreated: writeEnvExample(projectDir, tracks),\n gitignoreEnvAdded: addGitignoreEnv(projectDir),\n mcpAllowlist: writeMcpAllowlist(projectDir),\n // v0.8.0 — `.factory/`, `.goose/` ignore (npx skills universal install 사용자 #3)\n gitignoreNpxSkillsAdded: addGitignoreNpxSkillsAgents(projectDir),\n };\n}\n\n/** Codex / OpenCode / Antigravity per-CLI transforms (+ scope=global opt-in) 결과. */\ninterface CliTransformResults {\n codex: CodexTransformReport | null;\n codexOptIn: CodexOptInReport | null;\n opencode: OpencodeTransformReport | null;\n antigravity: AntigravityTransformReport | null;\n}\n\nfunction runCliTransforms(\n spec: InstallSpec,\n harnessRoot: string,\n projectDir: string,\n selectedInternalSkills: ReadonlyArray<string>,\n): CliTransformResults {\n // Codex transform when spec.cli includes \"codex\"\n let codex: CodexTransformReport | null = null;\n let codexOptIn: CodexOptInReport | null = null;\n if (spec.cli.includes(\"codex\")) {\n // v26.87.0 — dev-method skills 는 selectedInternalSkills 로 게이팅.\n codex = runCodexTransform({\n harnessRoot,\n projectDir,\n selectedInternalSkills,\n });\n // v26.64.0 (ADR-020) — Codex global trust opt-in 은 scope=global 일 때만 의미.\n // scope=project (default) 시 ~/.codex/ write skip (config.toml trust entry 만).\n const installScope = spec.scope ?? \"project\";\n if (installScope === \"global\" && spec.options.withCodexTrust) {\n codexOptIn = runCodexOptIn({ projectDir });\n }\n }\n\n // OpenCode transform when spec.cli includes \"opencode\"\n let opencode: OpencodeTransformReport | null = null;\n if (spec.cli.includes(\"opencode\")) {\n opencode = runOpencodeTransform({ harnessRoot, projectDir, selectedInternalSkills });\n }\n\n // v26.66.0 — Antigravity transform when spec.cli includes \"antigravity\".\n // `.agents/rules/uzys-harness.md` (project context) + dev-method skills.\n let antigravity: AntigravityTransformReport | null = null;\n if (spec.cli.includes(\"antigravity\")) {\n antigravity = runAntigravityTransform({\n harnessRoot,\n projectDir,\n selectedInternalSkills,\n });\n }\n\n return { codex, codexOptIn, opencode, antigravity };\n}\n\n/**\n * External assets (claude plugin / npm -g / npx skills) 설치 단계.\n * Default = real runExternalInstall. Tests inject mock or `null` to skip.\n * log/warn은 silent (renderer가 onAssetStart/Result로 스트리밍).\n */\nfunction runExternalPhase(ctx: InstallContext): ExternalInstallReport | null {\n if (ctx.runExternal === null) {\n return null;\n }\n const { harnessRoot, projectDir, spec } = ctx;\n const runExt = ctx.runExternal ?? runExternalInstall;\n const externalDeps: ExternalInstallerDeps = {\n harnessRoot,\n log: () => {},\n warn: () => {},\n };\n if (ctx.externalDeps?.onAssetStart) {\n externalDeps.onAssetStart = ctx.externalDeps.onAssetStart;\n }\n if (ctx.externalDeps?.onAssetResult) {\n externalDeps.onAssetResult = ctx.externalDeps.onAssetResult;\n }\n const filterCtx = {\n tracks: spec.tracks,\n options: spec.options,\n ...(spec.userOverride ? { userOverride: spec.userOverride } : {}),\n };\n // v26.102.0 (ADR-031) — 헤더 카운트 = 실제 시도될 자산 수. runExternalInstall 과 **같은\n // selector** 를 호출해 \"External assets (N)\" 의 N 이 시도 목록과 구조적으로 일치\n // (이전엔 internal 8종을 포함해 dev 트랙 전부에서 헤더가 과대였다 — SOD 리뷰 F1 실측).\n const applicableCount = selectExternalTargets(EXTERNAL_ASSETS, {\n ...filterCtx,\n cli: spec.cli,\n }).targets.length;\n ctx.onProgress?.({ type: \"external-start\", assetCount: applicableCount });\n const external = runExt(\n { ...filterCtx, cli: spec.cli, projectDir, ...(spec.scope ? { scope: spec.scope } : {}) },\n externalDeps,\n );\n ctx.onProgress?.({ type: \"external-complete\", report: external });\n return external;\n}\n\n/**\n * Install log write — `.claude/.harness-install.json` (자산 list + scope + timestamp,\n * uninstall command 의 source). 실패는 install 자체를 fail 시키지 않음 (D16 — install 성공 우선).\n */\nfunction writeInstallLogSafe(\n ctx: InstallContext,\n external: ExternalInstallReport | null,\n rootClaudeMdLog: { path: string; sha256: string } | null,\n previousLog: InstallLog | null,\n claudeDirMovedAside: boolean,\n rootFiles: ReadonlyArray<InstallLogRootFile>,\n): void {\n try {\n const log = buildInstallLog(\n ctx.spec,\n external,\n resolveScope(ctx.spec.scope),\n rootClaudeMdLog,\n previousLog,\n claudeDirMovedAside,\n rootFiles,\n );\n // v26.126.0 (ADR-046) — 스킬 기준선은 **이력이 아니라 스냅샷**이라 buildInstallLog 의 누적\n // 경로를 타지 않는다. manifest copy 가 끝난 뒤 디스크를 읽어야 값이 맞다.\n const skillFiles = collectSkillHashes(ctx.projectDir);\n writeInstallLog(ctx.projectDir, skillFiles.length > 0 ? { ...log, skillFiles } : log);\n } catch (e) {\n ctx.onProgress?.({\n type: \"install-log-error\",\n message: e instanceof Error ? e.message : String(e),\n });\n }\n}\n\n/**\n * karpathy-coder pre-commit hook auto-wire (v0.6.0).\n *\n * 활성화 조건 (AND):\n * 1. spec.options.withKarpathyHook === true (opt-in 강제)\n * 2. spec.cli 에 \"claude\" 포함 (v0.8.0 — `.claude/settings.json` 미생성 시 와이어 불가)\n * 3. external.attempted에 karpathy-coder ok=true (plugin install 성공)\n *\n * 동작:\n * - templates/hooks/karpathy-gate.sh → <projectDir>/.claude/hooks/karpathy-gate.sh 복사\n * - .claude/settings.json PreToolUse Write|Edit matcher에 hook entry 추가 (idempotent)\n */\nfunction wireKarpathyHook(\n spec: InstallSpec,\n external: ExternalInstallReport | null,\n harnessRoot: string,\n projectDir: string,\n): KarpathyHookReport | null {\n if (!spec.options.withKarpathyHook) {\n return null;\n }\n // v0.8.0 가드 — `.claude/` baseline 미생성 시 hook 와이어 불가 (silent partial state 방지).\n if (!spec.cli.includes(\"claude\")) {\n return { wired: false, reason: \"claude-not-selected\" };\n }\n if (external === null) {\n return { wired: false, reason: \"external-skipped\" };\n }\n const karpathyResult = external.attempted.find((r) => r.asset.id === KARPATHY_ASSET_ID);\n if (!karpathyResult?.ok) {\n return { wired: false, reason: \"plugin-install-failed\" };\n }\n\n // Hook script 복사 (manifest에 없는 v0.6.0 신규 — opt-in 시에만)\n const sourceHook = join(harnessRoot, \"templates/hooks/karpathy-gate.sh\");\n const targetHook = join(projectDir, KARPATHY_HOOK_RELPATH);\n let hookScriptCopied = false;\n if (existsSync(sourceHook)) {\n copyFile(sourceHook, targetHook);\n try {\n chmodSync(targetHook, 0o755);\n } catch {\n // best-effort\n }\n hookScriptCopied = true;\n }\n\n // settings.json PreToolUse Write|Edit entry 추가 (idempotent)\n // HIGH-2 fix: JSON.parse try/catch — add mode에서 사용자 손상 settings.json 시 install 중단 방지\n const settingsPath = join(projectDir, \".claude/settings.json\");\n let settingsUpdated = false;\n if (existsSync(settingsPath)) {\n const raw = readFileSync(settingsPath, \"utf8\");\n let before: ClaudeSettings;\n try {\n before = JSON.parse(raw);\n } catch {\n return { wired: false, reason: \"settings-parse-error\", hookScriptCopied };\n }\n const after = addPreToolUseHook(before, \"Write|Edit\", KARPATHY_HOOK_COMMAND);\n const beforeStr = JSON.stringify(before);\n const afterStr = JSON.stringify(after);\n if (beforeStr !== afterStr) {\n writeFileSync(settingsPath, `${JSON.stringify(after, null, 2)}\\n`);\n settingsUpdated = true;\n }\n }\n\n return { wired: true, settingsUpdated, hookScriptCopied };\n}\n\nfunction composeAndWriteMcp(\n harnessRoot: string,\n projectDir: string,\n spec: InstallSpec,\n): { mcpServers: Record<string, unknown>; created: boolean } {\n const mcpPath = join(projectDir, \".mcp.json\");\n // 쓰기 전에 본다 — 쓰고 나면 \"우리가 만든 것\"과 \"사용자 것에 병합한 것\"을 구분할 수 없다.\n const created = !existsSync(mcpPath);\n const composed = composeMcpJson({\n templateMcpPath: join(harnessRoot, \"templates/mcp.json\"),\n trackMapPath: join(harnessRoot, \"templates/track-mcp-map.tsv\"),\n existingPath: mcpPath,\n tracks: spec.tracks,\n });\n writeMcpJson(mcpPath, composed);\n return { ...composed, created };\n}\n\n/**\n * v26.124.0 (F-1f) — 이번 설치가 `.claude/` **밖**에 만들거나 고친 루트 파일 목록.\n *\n * uninstall 은 이걸 지우지 않고 **안내만** 한다 (사용자 내용이 섞임). 그러려면 무엇을 건드렸는지\n * 기록이 있어야 하는데 v26.123.0 까지 아무 기록이 없어서 안내조차 못 했다.\n *\n * **이번 설치가 실제로 바꾼 것만 넣는다** — idempotent skip(이미 있어서 안 건드림)은 넣지 않는다.\n * 이전 설치분은 install-log 의 누적(mergeRootFiles)이 살려 준다.\n */\nfunction collectRootFiles(\n envFiles: BaselineReport[\"envFiles\"],\n ciScaffold: CiScaffoldReport | null,\n mcpCreated: boolean,\n): InstallLogRootFile[] {\n const files: InstallLogRootFile[] = [\n {\n path: \".mcp.json\",\n change: mcpCreated ? \"created\" : \"modified\",\n notes: [mcpCreated ? \"MCP 서버 정의 생성\" : \"MCP 서버 정의 병합 (기존 항목 보존)\"],\n },\n ];\n if (envFiles.envExampleCreated) {\n files.push({ path: \".env.example\", change: \"created\", notes: [\"Supabase 토큰 가이드\"] });\n }\n // `mcpAllowlist` 는 세 값이 다 다르다: null=skip · []=**서버가 없어 안 씀** · 비어있지 않음=씀.\n // 길이를 안 보면 안 만든 파일을 만들었다고 기록한다 (env-files.ts writeMcpAllowlist).\n if (envFiles.mcpAllowlist && envFiles.mcpAllowlist.length > 0) {\n files.push({\n path: \".mcp-allowlist\",\n change: \"created\",\n notes: [`MCP allowlist (${envFiles.mcpAllowlist.length} server)`],\n });\n }\n const gitignoreAdded = [\n ...(envFiles.gitignoreEnvAdded ? [\".env\"] : []),\n ...envFiles.gitignoreNpxSkillsAdded,\n ];\n if (gitignoreAdded.length > 0) {\n files.push({\n path: \".gitignore\",\n change: \"modified\",\n notes: [`추가된 줄: ${gitignoreAdded.join(\", \")}`],\n });\n }\n for (const workflow of ciScaffold?.written ?? []) {\n files.push({ path: workflow, change: \"created\", notes: [\"CI 워크플로 스캐폴드\"] });\n }\n return files;\n}\n\n/**\n * v0.6.1 — manifest entry를 카테고리별로 누적. install renderer Phase 1 row 출력에 사용.\n * `entry.target` prefix로 분류. file은 basename(.확장자 제거), dir은 dir name.\n */\nfunction accumulateCategory(\n cats: BaselineCategoryCounts,\n entry: import(\"./manifest.js\").AssetEntry,\n): void {\n const target = entry.target;\n if (target.startsWith(\".claude/rules/\") && target.endsWith(\".md\")) {\n const name = target.replace(/^\\.claude\\/rules\\//, \"\").replace(/\\.md$/, \"\");\n cats.rules.push(name);\n } else if (target.startsWith(\".claude/agents/\") && target.endsWith(\".md\")) {\n const name = target.replace(/^\\.claude\\/agents\\//, \"\").replace(/\\.md$/, \"\");\n cats.agents.push(name);\n } else if (target.startsWith(\".claude/hooks/\") && target.endsWith(\".sh\")) {\n const name = target.replace(/^\\.claude\\/hooks\\//, \"\").replace(/\\.sh$/, \"\");\n cats.hooks.push(name);\n } else if (target.startsWith(\".claude/commands/\")) {\n cats.commands += 1;\n } else if (target.startsWith(\".claude/skills/\") && entry.type === \"dir\") {\n const name = target.replace(/^\\.claude\\/skills\\//, \"\").replace(/\\/?$/, \"\");\n cats.skills.push(name);\n }\n}\n\nfunction writeInstalledTracks(projectDir: string, tracks: ReadonlyArray<string>): void {\n const path = join(projectDir, \".claude/.installed-tracks\");\n mkdirSync(dirname(path), { recursive: true });\n const sorted = [...new Set(tracks)].sort().join(\"\\n\");\n writeFileSync(path, `${sorted}\\n`);\n}\n\nfunction writeRootClaudeMd(\n projectDir: string,\n tracks: ReadonlyArray<Track>,\n): { content: string; backup: string | null } {\n const content = mergeProjectClaude(tracks, { projectName: basename(projectDir) });\n const target = join(projectDir, \"CLAUDE.md\");\n // 기존 사용자 CLAUDE.md 는 덮어쓰기 전 백업 (audit CODE-2 — 무백업 덮어쓰기 데이터 손실 방지).\n const backup = backupFileIfChanged(target, content);\n writeFileSync(target, content);\n return { content, backup };\n}\n\nfunction chmodHooksSync(hookDir: string): void {\n for (const file of listHookFiles(hookDir)) {\n try {\n chmodSync(file, 0o755);\n } catch {\n // Best-effort; many platforms (Windows in particular) ignore mode bits.\n }\n }\n}\n\nfunction listHookFiles(hookDir: string): string[] {\n // Hooks are flat shell scripts — avoid pulling glob deps.\n return readdirSync(hookDir, { withFileTypes: true })\n .filter((e) => e.isFile() && e.name.endsWith(\".sh\"))\n .map((e) => resolve(hookDir, e.name));\n}\n","/**\n * Antigravity transform — v26.66.0 (skills/workflows) + v26.69.0 (rules).\n *\n * Google Antigravity 2.0 (I/O 2026-05-19) 공식 spec (codelabs):\n * - Workspace skills: .agents/skills/<name>/SKILL.md (Anthropic skill format — codex 와 공유)\n * - Workspace workflows: .agents/workflows/<name>.md (`/<name>` 슬래시로 호출)\n * - Workspace rules: .agents/rules/<name>.md (디렉토리, plain markdown)\n * - Global rules: ~/.gemini/GEMINI.md (사용자 글로벌 — harness 미터치)\n * - Global skills: ~/.gemini/antigravity/skills/ (Phase C opt-in — antigravity/opt-in.ts)\n *\n * 본 transform 의 책임 (모두 project-scope):\n * 1. `.agents/rules/uzys-harness.md` — project context (CLAUDE.md → Antigravity rule).\n * foundational context (CLAUDE.md/AGENTS.md 처럼 항상 작성).\n * cli=antigravity 단독 선택 시 이게 없으면 Antigravity 가 프로젝트 컨벤션을 모름.\n * 2. `.agents/skills/<id>/SKILL.md` — dev-method skills (frontmatter 보존, codex 와 공유).\n *\n * SAFETY: `~/.gemini/` 글로벌 write 없음.\n */\n\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { basename, join } from \"node:path\";\nimport { renderAgentsMd } from \"../codex/agents-md.js\";\nimport { renderBundledSkill } from \"../codex/skills.js\";\nimport { backupFileIfChanged, ensureDir } from \"../fs-ops.js\";\nimport { renderFillScaffold } from \"../project-claude-merge.js\";\n\nexport interface AntigravityTransformParams {\n /** harness root (templates/CLAUDE.md source 위치). */\n harnessRoot: string;\n /** 사용자 프로젝트 root. `.agents/` 가 만들어질 위치. */\n projectDir: string;\n /**\n * v26.87.0 — dev-method skill ids 선택 목록. 각 id 의 `templates/skills/<id>/SKILL.md` 를\n * Antigravity native `.agents/skills/<id>/SKILL.md` 로 (frontmatter 보존) 출력.\n */\n selectedInternalSkills?: ReadonlyArray<string>;\n}\n\nexport interface AntigravityTransformReport {\n /** v26.69.0 — 작성된 rules 파일 경로 (.agents/rules/uzys-harness.md). null = template 부재. */\n rulesFile: string | null;\n /** 작성된 SKILL.md 경로 list (.agents/skills/<id>/SKILL.md). */\n skillFiles: ReadonlyArray<string>;\n}\n\n/**\n * Antigravity 용 project-scope 자산 생성 (rules + dev-method skills).\n */\nexport function runAntigravityTransform(\n params: AntigravityTransformParams,\n): AntigravityTransformReport {\n const { harnessRoot, projectDir, selectedInternalSkills = [] } = params;\n\n // 1. .agents/rules/uzys-harness.md — project context (CLAUDE.md → Antigravity rule, 항상).\n const rulesFile = writeRules(harnessRoot, projectDir);\n\n const skillFiles: string[] = [];\n\n // 1b. v26.87.0 — dev-method skills → .agents/skills/<id>/SKILL.md (frontmatter 보존).\n // renderBundledSkill 이 source frontmatter(name: <id>)를 보존.\n for (const id of selectedInternalSkills) {\n const src = join(harnessRoot, \"templates/skills\", id, \"SKILL.md\");\n if (!existsSync(src)) {\n continue;\n }\n const skillDir = join(projectDir, \".agents\", \"skills\", id);\n ensureDir(skillDir);\n const target = join(skillDir, \"SKILL.md\");\n writeFileSync(target, renderBundledSkill(readFileSync(src, \"utf8\")));\n skillFiles.push(target);\n }\n\n return { rulesFile, skillFiles };\n}\n\n/**\n * v26.69.0 — `.agents/rules/uzys-harness.md` 작성. CLAUDE.md → Antigravity workspace rule.\n *\n * Source: templates/CLAUDE.md (전문) + templates/antigravity/AGENTS.md.template.\n * v26.70.0 — renderAgentsMd 재사용 (codex/opencode 와 동일 전문 embed). `{PROJECT_RULES}` 에\n * CLAUDE.md 본문 전체 삽입 + `/uzys:` → `/uzys-` rename.\n *\n * template 또는 CLAUDE.md 부재 시 null (graceful — install 진행).\n */\nfunction writeRules(harnessRoot: string, projectDir: string): string | null {\n const claudeMdPath = join(harnessRoot, \"templates/CLAUDE.md\");\n const templatePath = join(harnessRoot, \"templates/antigravity/AGENTS.md.template\");\n if (!existsSync(claudeMdPath) || !existsSync(templatePath)) {\n return null;\n }\n const claudeMd = readFileSync(claudeMdPath, \"utf8\");\n const template = readFileSync(templatePath, \"utf8\");\n const rulesDir = join(projectDir, \".agents\", \"rules\");\n ensureDir(rulesDir);\n const target = join(rulesDir, \"uzys-harness.md\");\n const rulesOut = renderAgentsMd({\n template,\n claudeMd,\n projectName: basename(projectDir),\n projectContext: renderFillScaffold(),\n });\n // 사용자가 채운 rules 파일을 재설치(add 모드) 덮어쓰기 전 보존 — 루트 CLAUDE.md 와 대칭.\n backupFileIfChanged(target, rulesOut);\n writeFileSync(target, rulesOut);\n return target;\n}\n","/**\n * AGENTS.md transform — CLAUDE.md → AGENTS.md.\n *\n * v26.70.0 — section 추출(Identity/Direction/Principles) → CLAUDE.md **전문 embed**.\n * 실 `templates/CLAUDE.md` 가 Rule 1~12 구조라 Identity/Direction/Principles 헤딩이 없어\n * extractSection 이 빈 결과 → AGENTS.md 가 빈 섹션으로 shipping 되던 버그 fix.\n * `{PROJECT_RULES}` placeholder 에 CLAUDE.md 본문 전체를 삽입 (heading 구조 의존 0).\n */\n\n/** Rename Claude slash conventions (`/uzys:foo`) to Codex (`/uzys-foo`). */\nexport function renameSlashes(text: string): string {\n return text.replaceAll(\"/uzys:\", \"/uzys-\");\n}\n\nexport interface AgentsMdParams {\n template: string;\n claudeMd: string;\n projectName: string;\n /** Project-context fill scaffold — the same body shipped to the Claude Code CLAUDE.md. */\n projectContext: string;\n}\n\n/**\n * Render AGENTS.md by embedding the full CLAUDE.md body into the template.\n *\n * Placeholders:\n * - {PROJECT_NAME} — basename of project dir\n * - {PROJECT_RULES} — full CLAUDE.md body (first h1 stripped; template provides its own h1)\n * - {PROJECT_CONTEXT} — project-specific fill scaffold (renderFillScaffold())\n *\n * 마지막에 `/uzys:` → `/uzys-` rename (Codex/Antigravity 는 slash namespace 미지원).\n */\nexport function renderAgentsMd(params: AgentsMdParams): string {\n // CLAUDE.md 의 첫 h1 (# title) 제거 — 템플릿이 자체 h1 보유.\n const body = params.claudeMd.replace(/^#\\s+.*\\r?\\n/, \"\").trim();\n const replaced = params.template\n .replaceAll(\"{PROJECT_NAME}\", params.projectName)\n .replaceAll(\"{PROJECT_RULES}\", body)\n .replaceAll(\"{PROJECT_CONTEXT}\", params.projectContext);\n return renameSlashes(replaced);\n}\n","/**\n * Bundled SKILL.md → non-Claude CLI native skill transform (dev-method skills).\n */\nimport { renameSlashes } from \"./agents-md.js\";\n\n/**\n * v26.87.0 — render a bundled, already-complete SKILL.md (dev-method skills) for a\n * non-Claude CLI (Codex / Antigravity native `.agents/skills/<id>/SKILL.md`).\n *\n * These sources are full Anthropic skills with their OWN frontmatter (`name: <id>`,\n * full description). We MUST preserve that frontmatter verbatim — only the BODY is\n * ported: `/uzys:` → `/uzys-` slash rename + `CLAUDE_PROJECT_DIR` → `CODEX_PROJECT_DIR`\n * env-var rename (Codex/Antigravity share the `.agents/` format + `CODEX_PROJECT_DIR`).\n */\nexport function renderBundledSkill(source: string): string {\n const trimmed = source.trimEnd();\n const lines = trimmed.split(/\\r?\\n/);\n // No frontmatter → emit body as-is (port slashes/env only). Defensive: bundled\n // dev-method skills always have frontmatter, but never silently drop content.\n if (lines[0] !== \"---\") {\n return `${portBody(trimmed)}\\n`;\n }\n let secondDelimAt = -1;\n for (let i = 1; i < lines.length; i++) {\n if (lines[i] === \"---\") {\n secondDelimAt = i;\n break;\n }\n }\n if (secondDelimAt < 0) {\n // Malformed frontmatter (no closing ---) → port whole thing as body.\n return `${portBody(trimmed)}\\n`;\n }\n const frontmatter = lines.slice(0, secondDelimAt + 1).join(\"\\n\");\n const body = lines.slice(secondDelimAt + 1).join(\"\\n\");\n return `${frontmatter}\\n${portBody(body)}\\n`;\n}\n\n/** Port a skill body for Codex/Antigravity: slash + project-dir env-var rename. */\nfunction portBody(body: string): string {\n return renameSlashes(body)\n .replace(/CLAUDE_PROJECT_DIR/g, \"CODEX_PROJECT_DIR\")\n .trimEnd();\n}\n","import {\n copyFileSync,\n cpSync,\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n renameSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\n\n/** Ensure a directory exists, creating parents as needed. Idempotent. */\nexport function ensureDir(path: string): void {\n mkdirSync(path, { recursive: true });\n}\n\nexport interface CopyResult {\n copied: number;\n skipped: number;\n}\n\n/** Copy a single file, creating parent dirs as needed. Idempotent. */\nexport function copyFile(source: string, target: string): void {\n if (!existsSync(source)) {\n throw new Error(`Source not found: ${source}`);\n }\n mkdirSync(dirname(target), { recursive: true });\n copyFileSync(source, target);\n}\n\n/** Copy a directory recursively. Creates target if missing. */\nexport function copyDir(source: string, target: string): void {\n if (!existsSync(source)) {\n throw new Error(`Source dir not found: ${source}`);\n }\n mkdirSync(target, { recursive: true });\n cpSync(source, target, { recursive: true, force: true });\n}\n\n/**\n * Move an existing directory to a timestamped backup sibling.\n * Returns the backup path, or null when nothing to back up.\n */\nexport function backupDir(target: string, now: Date = new Date()): string | null {\n if (!existsSync(target)) {\n return null;\n }\n const backup = `${target}.backup-${formatStamp(now)}`;\n renameSync(target, backup);\n return backup;\n}\n\n/**\n * Copy backup — original target preserved (for in-place update mode).\n * bash setup-harness.sh L477 `cp -R .claude \"$BACKUP_DIR\"` 등가.\n */\nexport function copyBackupDir(target: string, now: Date = new Date()): string | null {\n if (!existsSync(target)) {\n return null;\n }\n const backup = `${target}.backup-${formatStamp(now)}`;\n cpSync(target, backup, { recursive: true });\n return backup;\n}\n\n/**\n * 사용자 편집 가능 파일(settings.json·CLAUDE.md)을 덮어쓰기 전 보호.\n * 기존 파일이 있고 새 내용과 다르면 timestamp 백업본을 만들고 그 경로를 반환한다.\n * 부재하거나 내용이 동일하면(idempotent 재설치) null — 불필요한 백업을 만들지 않는다.\n * audit SEC-1/CODE-2 — add 모드(.claude/ backup 없음)에서 통째 덮어쓰기로 인한 데이터 손실 방지.\n */\nexport function backupFileIfChanged(\n target: string,\n newContent: string,\n now: Date = new Date(),\n): string | null {\n if (!existsSync(target)) {\n return null;\n }\n if (readFileSync(target, \"utf-8\") === newContent) {\n return null;\n }\n return backupFile(target, now);\n}\n\n/**\n * 기존 파일을 timestamp 백업본으로 복사하고 그 경로를 반환한다. **판정은 호출자 몫.**\n *\n * `backupFileIfChanged` 와 나뉜 이유는 술어가 다르기 때문이다: 저쪽은 \"새 내용과 다른가\",\n * update 의 스킬 갱신(ADR-046)은 \"**설치 시점**과 다른가\"로 판정한다. 하네스가 개선해서\n * 달라진 파일은 사용자가 안 건드렸으므로 백업 없이 덮어써야 하고, 내용 비교만으로는 그\n * 둘을 구분할 수 없다.\n */\nexport function backupFile(target: string, now: Date = new Date()): string {\n const backup = `${target}.backup-${formatStamp(now)}`;\n copyFileSync(target, backup);\n return backup;\n}\n\n/**\n * `dir` 아래 모든 파일의 상대 경로 (디렉터리 자체는 제외). 순서는 readdir 순.\n *\n * `readdirSync(dir, { recursive: true })` 를 안 쓰는 이유: 그 옵션은 Node 20.1.0 에 들어왔는데\n * `engines` 는 `>=20.0.0` 이다. 20.0.x 에서 조용히 `undefined` 를 흘리는 대신 직접 순회한다.\n */\nexport function listFilesRecursive(dir: string, prefix = \"\"): string[] {\n if (!existsSync(dir)) return [];\n const out: string[] = [];\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const rel = prefix ? `${prefix}/${entry.name}` : entry.name;\n if (entry.isDirectory()) {\n out.push(...listFilesRecursive(join(dir, entry.name), rel));\n } else if (entry.isFile()) {\n out.push(rel);\n }\n }\n return out;\n}\n\nfunction formatStamp(now: Date): string {\n return now\n .toISOString()\n .replace(/[-:]/g, \"\")\n .replace(/\\.\\d+Z$/, \"Z\")\n .slice(0, 15);\n}\n\n/** Create a project skeleton: <project>/.claude/{commands/{uzys,ecc},rules,skills,agents,hooks}. */\nexport function ensureProjectSkeleton(projectDir: string): void {\n const dirs = [\n \".claude/commands/uzys\",\n \".claude/commands/ecc\",\n \".claude/rules\",\n \".claude/skills\",\n \".claude/agents\",\n \".claude/hooks\",\n \"docs/decisions\",\n ];\n for (const d of dirs) {\n mkdirSync(join(projectDir, d), { recursive: true });\n }\n}\n","import { TRACKS, type Track } from \"./types.js\";\n\n/**\n * Project-context scaffold for the delivered CLAUDE.md / AGENTS.md.\n *\n * The installer is a pure Node CLI and CANNOT run an LLM, so it cannot fill a\n * project-specific context file at install time. Shipping generic per-track prose\n * instead produced \"meaningless\" files (a literal `# [Project Name]` title, a Bash\n * stack advertised to every project, phantom rule names). This module ships an\n * honest fill-in SCAFFOLD instead: each section carries an embedded `<!-- FILL: -->`\n * instruction the user runs in their own coding agent post-install (or by hand).\n * The same scaffold body feeds BOTH the Claude Code root CLAUDE.md and the\n * `{PROJECT_CONTEXT}` block of every AGENTS.md — one source, byte-identical across\n * all 4 CLIs, with no disk read-back coupling.\n */\n\nexport const TRACK_DISPLAY_NAMES: Record<Track, string> = {\n tooling: \"Tooling\",\n \"csr-supabase\": \"CSR Supabase\",\n \"csr-fastify\": \"CSR Fastify\",\n \"csr-fastapi\": \"CSR FastAPI\",\n \"ssr-htmx\": \"SSR HTMX\",\n \"ssr-nextjs\": \"SSR Next.js\",\n data: \"Data\",\n executive: \"Executive\",\n full: \"Full\",\n \"project-management\": \"Project Management\",\n \"growth-marketing\": \"Growth Marketing\",\n};\n\n/** Tracks expanded when 'full' is selected — every track except 'full' itself.\n * Derived from TRACKS so a future track can't be silently omitted from a 'full' install. */\nconst FULL_EXPANSION: ReadonlyArray<Track> = TRACKS.filter((t) => t !== \"full\");\n\n/**\n * The MUST-HAVE project-context sections, from a harness perspective: the context\n * an agent needs to work on ANY project with few round-trips. Order is intentional\n * (identity → stack → architecture → assets → boundaries → verify).\n */\nexport const FILL_SECTIONS = [\n \"identity\",\n \"stack\",\n \"architecture\",\n \"installed-assets\",\n \"boundaries\",\n \"verify\",\n] as const;\nexport type FillSection = (typeof FILL_SECTIONS)[number];\n\ninterface FillSpec {\n /** Rendered `## <title>` header. */\n title: string;\n /** Body of the `<!-- FILL:<id> — … -->` comment: what to inspect and write. */\n prompt: string;\n /** Honest `_(not filled yet — …)_` line so an unfilled section never states a false fact. */\n placeholder: string;\n}\n\nconst FILL_SPECS: Record<FillSection, FillSpec> = {\n identity: {\n title: \"Identity & Purpose\",\n prompt:\n 'Replace the H1 title above with this project\\'s real name, then state in 1-2 plain sentences what it does, who uses it, and why it exists. Sources: README.md, the package.json / pyproject.toml \"description\", docs/. Do NOT describe the harness itself. Delete this comment when done.',\n placeholder: \"what this project is, who it is for, and why it exists\",\n },\n stack: {\n title: \"Stack & Commands\",\n prompt:\n \"Replace the list below with this project's REAL stack. Inspect package.json / pyproject.toml / go.mod / Cargo.toml / Gemfile + lockfiles and any Makefile/justfile/package scripts. List the language(s)+versions, framework(s), package manager, and the exact install/build/test/run commands. Verify each command exists before writing it — never guess. Delete lines that do not apply, then delete this comment.\",\n placeholder: \"languages, runtimes, package manager, and the install/build/test/run commands\",\n },\n architecture: {\n title: \"Architecture & Layout\",\n prompt:\n \"Map this repository. List each top-level source directory and what it holds, the entry point(s), the 3-5 files a newcomer reads first, and how data/requests flow between the main layers. View the real tree (e.g. `git ls-files | sed 's#/.*##' | sort -u`) — do not assume a framework's conventional layout. Flag any generated/vendored directories that must never be hand-edited. If this is a single small module, say so in one line. Delete this comment when done.\",\n placeholder: \"where things live, the entry points, and how data flows between layers\",\n },\n \"installed-assets\": {\n title: \"Installed Harness Assets\",\n prompt:\n \"List the harness assets installed in this project (rules / skills / agents / commands) and add one line each on when to reach for it here. Verify against .claude/rules/*.md, .claude/skills/, .claude/agents/, .claude/commands/ (or this CLI's equivalent) and list ONLY assets whose file exists on disk — do not invent any. Do NOT restate the universal Rule 1-12 (they live in the rules layer) — cross-reference them instead. Delete this comment when done.\",\n placeholder: \"the installed rules/skills/agents/commands and when to use each\",\n },\n boundaries: {\n title: \"Boundaries — Always / Ask First / Never\",\n prompt:\n 'Fill the Always / Ask First / Never lists with this repo\\'s real red lines. Read the CI config, CODEOWNERS, .gitignore, and release/deploy scripts. Never must include secrets, generated files, force-push, and direct commits to the default branch, plus any repo-specific \"do not touch\" directories. Every entry must be specific and enforceable here. Delete this comment when done.',\n placeholder: \"what to always do, ask before doing, and never do in this repo\",\n },\n verify: {\n title: \"Verification Gate\",\n prompt:\n 'State the single command (or short sequence) that PROVES a change is safe here — the test/lint/typecheck/build gate you run before committing — plus the coverage/CI threshold and what \"done\" means. Sources: package scripts, CI workflow files, CONTRIBUTING. An agent must be able to self-verify without guessing. Delete this comment when done.',\n placeholder: \"the single command that proves a change is safe, and the done bar\",\n },\n};\n\n/** Visible (rendered-markdown) banner — HTML FILL comments are invisible in a preview, so this\n * blockquote is what stops the scaffold from reading as verified project fact for a human. */\nexport const SCAFFOLD_BANNER = [\n \"> ⚙️ **SCAFFOLD — not filled in yet.** The sections below are a fill-in template for THIS project, not verified facts.\",\n \"> To fill: open this file and paste each `<!-- FILL: … -->` comment's instruction into your coding agent (e.g. Claude Code) — it will inspect the real repo and write the section. You can also fill them by hand; the comments are the instructions.\",\n \"> The universal harness rules (Rule 1–12) live in the separate rules layer. This file is **project-specific context only**.\",\n].join(\"\\n\");\n\n/**\n * Shared project-context scaffold body: the visible banner followed by the six MUST-HAVE\n * sections, each a `## Title` + a self-contained `<!-- FILL:id — … -->` comment + an honest\n * `_(not filled yet — …)_` placeholder. Pure and track-agnostic, so the Claude Code CLAUDE.md\n * and every AGENTS.md `{PROJECT_CONTEXT}` block get byte-identical prompts from one source.\n */\nexport function renderFillScaffold(): string {\n const blocks = FILL_SECTIONS.map((id) => {\n const spec = FILL_SPECS[id];\n return `## ${spec.title}\\n\\n<!-- FILL:${id} — ${spec.prompt} -->\\n\\n_(not filled yet — ${spec.placeholder})_`;\n });\n return `${SCAFFOLD_BANNER}\\n\\n${blocks.join(\"\\n\\n\")}`;\n}\n\nexport interface MergeOptions {\n /** Project directory basename → the H1 title (fixes the shipped `# [Project Name]` literal). */\n projectName: string;\n}\n\n/**\n * Build the project-root CLAUDE.md: a real H1 project name + the active-track note (genuine\n * install metadata) + the shared fill scaffold. The scaffold is track-agnostic — the selected\n * tracks are recorded in the note; the installed-assets section is filled from real files at\n * fill time rather than from static per-track prose.\n */\nexport function mergeProjectClaude(tracks: ReadonlyArray<Track>, opts: MergeOptions): string {\n const expanded = expandTracks(tracks);\n const trackList = expanded.map((t) => TRACK_DISPLAY_NAMES[t]).join(\", \");\n const header = `# ${opts.projectName}\\n\\n> Active track(s): ${trackList}`;\n return `${header}\\n\\n${renderFillScaffold()}\\n`;\n}\n\nfunction expandTracks(tracks: ReadonlyArray<Track>): ReadonlyArray<Track> {\n if (tracks.includes(\"full\")) {\n return FULL_EXPANSION;\n }\n return tracks;\n}\n","/**\n * CI scaffold (v26.108.0, 라이프사이클 자산화 ② — ADR-037) — `.github/workflows/` fill-in\n * 워크플로 템플릿 설치. 실무 CI 패턴(실DB 서비스 컨테이너 · tag-only 트리거 +\n * 로컬 검증 1차 게이트 · Playwright E2E · coverage 게이트)의 도메인 중립 일반화\n * (docs/plans/lifecycle-codification-2026-07-18.md ② — CI 0 인 실프로젝트가 갭의 존재 증명).\n *\n * 본 하네스가 `.claude/` 밖에 쓰는 첫 자산 — 안전 계약 2가지:\n * 1. opt-in 전용 (`--with ci-scaffold` / wizard 체크) — 무인지 설치 없음.\n * 2. **기존 파일 절대 덮어쓰지 않음** — 이미 존재하는 워크플로 파일은 skip 하고\n * `skippedExisting` 으로 정직 보고 (manifest copyFile 의 무조건 overwrite 와 다른 이유).\n * uninstall 도 `.github/` 를 건드리지 않는다 (install-log 미기록 — 설치 후 사용자 소유물).\n */\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { copyFile } from \"./fs-ops.js\";\nimport { anyTrack, hasUiTrack } from \"./track-match.js\";\nimport type { Track } from \"./types.js\";\n\nexport interface CiScaffoldReport {\n /** 새로 쓴 워크플로 파일 (project-relative). */\n written: string[];\n /** 이미 존재해 보존한 파일 (project-relative) — no-clobber 정직 보고용. */\n skippedExisting: string[];\n}\n\ninterface WorkflowVariant {\n /** `templates/github-workflows/` 안의 소스 파일명. */\n source: string;\n /** `.github/workflows/` 안의 타깃 파일명. */\n target: string;\n applies: (tracks: ReadonlyArray<Track>) => boolean;\n}\n\nconst PYTHON_TRACKS = \"data|csr-fastapi|full\";\n\n/**\n * Track → 변형 매핑 (결정론 — Rule 5, 사용자가 받는 파일을 사전에 알 수 있어야 한다):\n * - node CI: node 계열 트랙, 또는 python 계열이 전혀 없을 때의 fallback — 명시 opt-in 이\n * 트랙 매핑 밖(예: PM 단독)이라고 무설치가 되면 silent no-op (no-false-ship 위반).\n * - python CI: python 계열 트랙. csr-fastapi·full 은 polyglot — node 와 양쪽 설치.\n * - e2e(Playwright): UI 트랙만 (playwright-launch 룰과 동일 게이팅).\n */\nconst VARIANTS: ReadonlyArray<WorkflowVariant> = [\n {\n source: \"ci-node.yml\",\n target: \"ci.yml\",\n applies: (tracks) =>\n anyTrack(tracks, \"csr-*|ssr-*|tooling|full\") || !anyTrack(tracks, PYTHON_TRACKS),\n },\n {\n source: \"ci-python.yml\",\n target: \"ci-python.yml\",\n applies: (tracks) => anyTrack(tracks, PYTHON_TRACKS),\n },\n {\n source: \"e2e.yml\",\n target: \"e2e.yml\",\n applies: (tracks) => hasUiTrack(tracks),\n },\n];\n\nexport function installCiScaffold(ctx: {\n harnessRoot: string;\n projectDir: string;\n tracks: ReadonlyArray<Track>;\n}): CiScaffoldReport {\n const report: CiScaffoldReport = { written: [], skippedExisting: [] };\n for (const v of VARIANTS) {\n if (!v.applies(ctx.tracks)) continue;\n const relTarget = `.github/workflows/${v.target}`;\n const target = join(ctx.projectDir, relTarget);\n if (existsSync(target)) {\n report.skippedExisting.push(relTarget);\n continue;\n }\n copyFile(join(ctx.harnessRoot, \"templates/github-workflows\", v.source), target);\n report.written.push(relTarget);\n }\n return report;\n}\n","/**\n * Codex global opt-in — ~/.codex/config.toml trust entry 등록.\n *\n * SPEC: docs/specs/cli-rewrite-completeness.md F11 (Reviewer HIGH-4)\n * Source: bash setup-harness.sh@911c246~1 L1389~1429\n *\n * SAFETY: 사용자 명시 opt-in 없이 ~/.codex/ 글로벌 수정 금지 (D16 / ADR-002 v2 D4).\n * 호출자(installer)는 OptionFlags.withCodexTrust 가 true 일 때만 호출.\n */\n\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { registerTrustEntry } from \"./trust-entry.js\";\n\nexport interface CodexOptInReport {\n /** ~/.codex/config.toml trust entry 등록 결과 */\n trustEntry: {\n enabled: boolean;\n status: \"registered\" | \"already-present\" | \"error\" | \"skipped\";\n message?: string;\n };\n}\n\nexport interface CodexOptInContext {\n /** 사용자 프로젝트 root (trust entry 경로). */\n projectDir: string;\n /** 글로벌 ~/.codex/ 경로 (테스트 override 가능). */\n codexHome?: string;\n}\n\n/** ~/.codex/config.toml 에 프로젝트 trust entry 등록. */\nexport function runCodexOptIn(ctx: CodexOptInContext): CodexOptInReport {\n const codexHome = ctx.codexHome ?? join(homedir(), \".codex\");\n const configPath = join(codexHome, \"config.toml\");\n const result = registerTrustEntry({ configPath, projectDir: ctx.projectDir });\n return {\n trustEntry: {\n enabled: true,\n status: result.status,\n ...(result.message ? { message: result.message } : {}),\n },\n };\n}\n","/**\n * Codex trust entry — `~/.codex/config.toml [projects.\"<dir>\"]` (parity with\n * setup-harness.sh L1404-1422).\n *\n * SAFETY: never modify the global `~/.codex/config.toml` without an explicit\n * opt-in (D16 / ADR-002 v2 D4). Callers must verify user consent first.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\n\nexport interface RegisterTrustResult {\n status: \"registered\" | \"already-present\" | \"error\";\n message?: string;\n}\n\nconst TRUST_BLOCK_REGEX = /\\[projects\\.\"([^\"]+)\"\\]/g;\n\n/** Append a `[projects.\"<projectDir>\"]` block to the user `config.toml` (idempotent). */\nexport function registerTrustEntry(opts: {\n configPath: string;\n projectDir: string;\n}): RegisterTrustResult {\n const { configPath, projectDir } = opts;\n try {\n mkdirSync(dirname(configPath), { recursive: true });\n const existing = existsSync(configPath) ? readFileSync(configPath, \"utf8\") : \"\";\n if (hasTrustEntry(existing, projectDir)) {\n return { status: \"already-present\" };\n }\n const block = `\\n[projects.\"${projectDir}\"]\\ntrust_level = \"trusted\"\\n`;\n writeFileSync(configPath, existing + block);\n return { status: \"registered\" };\n } catch (e: unknown) {\n return {\n status: \"error\",\n message: e instanceof Error ? e.message : String(e),\n };\n }\n}\n\nexport function hasTrustEntry(configContent: string, projectDir: string): boolean {\n const matches = [...configContent.matchAll(TRUST_BLOCK_REGEX)].map((m) => m[1]);\n return matches.includes(projectDir);\n}\n","/**\n * Codex transform orchestrator — wraps the 5-step pipeline.\n *\n * Replaces `scripts/claude-to-codex.sh` (Phase D, OQ4 = TS port).\n *\n * Inputs:\n * - harnessRoot: repository root (templates/ + .mcp.json)\n * - projectDir: target project to receive AGENTS.md + .codex/ + .agents/skills/\n *\n * Outputs (under projectDir):\n * - AGENTS.md\n * - .codex/config.toml\n * - .codex/hooks/*.sh (hooks ported from templates/hooks/)\n * - .agents/skills/<id>/SKILL.md (dev-method skills, frontmatter 보존)\n *\n * v0.6.4 — skill 출력 경로는 Codex 공식 표준 `.agents/skills/<name>/SKILL.md` (repo-level scope).\n * 참조: https://developers.openai.com/codex/skills\n */\n\nimport { chmodSync, existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { basename, join } from \"node:path\";\nimport { backupFileIfChanged, ensureDir } from \"../fs-ops.js\";\nimport type { McpJson } from \"../mcp-merge.js\";\nimport { renderFillScaffold } from \"../project-claude-merge.js\";\nimport { renderAgentsMd } from \"./agents-md.js\";\nimport { renderConfigToml } from \"./config-toml.js\";\nimport { renderBundledSkill } from \"./skills.js\";\n\nexport interface CodexTransformParams {\n harnessRoot: string;\n projectDir: string;\n /**\n * v26.87.0 — dev-method skill ids 선택 목록 (installer 가 `DEV_METHOD_SKILL_IDS` 를\n * `isAssetSelected` 로 필터). 각 id 의 `templates/skills/<id>/SKILL.md` 를 Codex native\n * `.agents/skills/<id>/SKILL.md` 로 (frontmatter 보존) 출력.\n */\n selectedInternalSkills?: ReadonlyArray<string>;\n}\n\nexport interface CodexTransformReport {\n agentsMdPath: string;\n configTomlPath: string;\n hookFiles: string[];\n skillFiles: string[];\n}\n\nconst HOOK_NAMES = [\"session-start\"];\n\nconst ENV_VAR_RENAME = /CLAUDE_PROJECT_DIR/g;\n\nexport function runCodexTransform(params: CodexTransformParams): CodexTransformReport {\n const { harnessRoot, projectDir, selectedInternalSkills = [] } = params;\n\n const claudeMd = readRequired(join(harnessRoot, \"templates/CLAUDE.md\"));\n const agentsTemplate = readRequired(join(harnessRoot, \"templates/codex/AGENTS.md.template\"));\n const configTemplate = readRequired(join(harnessRoot, \"templates/codex/config.toml.template\"));\n const projectName = basename(projectDir);\n const mcp = readOptionalJson(join(harnessRoot, \".mcp.json\"));\n\n // 1. AGENTS.md\n const agentsMdPath = join(projectDir, \"AGENTS.md\");\n ensureDir(projectDir);\n const agentsMdOut = renderAgentsMd({\n template: agentsTemplate,\n claudeMd,\n projectName,\n projectContext: renderFillScaffold(),\n });\n // 사용자가 채운 AGENTS.md 를 재설치(add 모드) 덮어쓰기 전 보존 — 루트 CLAUDE.md 와 대칭.\n backupFileIfChanged(agentsMdPath, agentsMdOut);\n writeFileSync(agentsMdPath, agentsMdOut);\n\n // 2. .codex/config.toml\n const configTomlPath = join(projectDir, \".codex/config.toml\");\n ensureDir(join(projectDir, \".codex\"));\n writeFileSync(\n configTomlPath,\n renderConfigToml({\n template: configTemplate,\n projectName,\n projectDir,\n mcp,\n }),\n );\n\n // 3. .codex/hooks/session-start.sh\n const hookDir = join(projectDir, \".codex/hooks\");\n ensureDir(hookDir);\n const hookFiles: string[] = [];\n for (const hook of HOOK_NAMES) {\n const src = join(harnessRoot, \"templates/hooks\", `${hook}.sh`);\n if (!existsSync(src)) {\n continue;\n }\n const ported = readFileSync(src, \"utf8\").replace(ENV_VAR_RENAME, \"CODEX_PROJECT_DIR\");\n const target = join(hookDir, `${hook}.sh`);\n writeFileSync(target, ported);\n chmodSync(target, 0o755);\n hookFiles.push(target);\n }\n\n // 4. v26.87.0 — dev-method skills → .agents/skills/<id>/SKILL.md (frontmatter 보존).\n // renderBundledSkill 이 source frontmatter(name: <id>)를 그대로 보존하고 body 만 포팅.\n const skillFiles: string[] = [];\n for (const id of selectedInternalSkills) {\n const src = join(harnessRoot, \"templates/skills\", id, \"SKILL.md\");\n if (!existsSync(src)) {\n continue;\n }\n const skillDir = join(projectDir, \".agents\", \"skills\", id);\n ensureDir(skillDir);\n const target = join(skillDir, \"SKILL.md\");\n writeFileSync(target, renderBundledSkill(readFileSync(src, \"utf8\")));\n skillFiles.push(target);\n }\n\n return { agentsMdPath, configTomlPath, hookFiles, skillFiles };\n}\n\nfunction readRequired(path: string): string {\n if (!existsSync(path)) {\n throw new Error(`Codex transform: required source missing: ${path}`);\n }\n return readFileSync(path, \"utf8\");\n}\n\nfunction readOptionalJson(path: string): McpJson | null {\n if (!existsSync(path)) {\n return null;\n }\n try {\n return JSON.parse(readFileSync(path, \"utf8\")) as McpJson;\n } catch {\n return null;\n }\n}\n","/**\n * config.toml transform — fill placeholders + append [mcp_servers.X] from .mcp.json.\n * Mirrors `claude-to-codex.sh` steps 2 + 5.\n */\n\nimport type { McpJson } from \"../mcp-merge.js\";\n\nexport interface RenderConfigTomlParams {\n template: string;\n projectName: string;\n projectDir: string;\n /** Source `.mcp.json` (parsed). When provided, [mcp_servers.X] blocks replace defaults. */\n mcp?: McpJson | null;\n}\n\nconst DEFAULT_MCP_BLOCK_RE = /\\n# =+\\n# MCP Servers — .*?\\n# =+[\\s\\S]*$/;\n\n/**\n * Substitute placeholders + replace the MCP servers section with blocks\n * derived from the supplied `.mcp.json` (or leave the template default).\n */\nexport function renderConfigToml(params: RenderConfigTomlParams): string {\n const substituted = params.template\n .replaceAll(\"{PROJECT_NAME}\", params.projectName)\n .replaceAll(\"{PROJECT_DIR}\", params.projectDir)\n .replaceAll(\"{GITHUB_TOKEN}\", \"${GITHUB_TOKEN}\");\n\n if (!params.mcp) {\n return substituted;\n }\n\n const stripped = stripExistingMcpSection(substituted);\n const fresh = renderMcpServers(params.mcp);\n return `${stripped.trimEnd()}\\n${fresh}\\n`;\n}\n\nfunction stripExistingMcpSection(toml: string): string {\n // Drop default [mcp_servers.X] blocks shipped in the template (we replace from .mcp.json)\n const lines = toml.split(/\\r?\\n/);\n const out: string[] = [];\n let skipping = false;\n for (const line of lines) {\n if (line.startsWith(\"[mcp_servers.\")) {\n skipping = true;\n continue;\n }\n if (skipping && line.startsWith(\"[\") && !line.startsWith(\"[mcp_servers.\")) {\n skipping = false;\n }\n if (skipping) {\n continue;\n }\n if (\n /^# .*MCP Servers/.test(line) ||\n /^# Railway MCP/.test(line) ||\n /^# github MCP/.test(line)\n ) {\n continue;\n }\n out.push(line);\n }\n return out.join(\"\\n\").replace(DEFAULT_MCP_BLOCK_RE, \"\");\n}\n\nfunction renderMcpServers(mcp: McpJson): string {\n const stamp = new Date().toISOString().slice(0, 10);\n const header = [\n \"# ============================================================\",\n `# MCP Servers — generated from .mcp.json (${stamp})`,\n \"# ============================================================\",\n ].join(\"\\n\");\n\n const blocks = Object.entries(mcp.mcpServers).map(([name, cfg]) => {\n const lines = [`[mcp_servers.${quoteIfNeeded(name)}]`];\n lines.push(`command = ${jsonString(cfg.command)}`);\n lines.push(`args = ${JSON.stringify(cfg.args)}`);\n if (cfg.env && Object.keys(cfg.env).length > 0) {\n const envBody = Object.entries(cfg.env)\n .map(([k, v]) => `${k} = ${jsonString(v)}`)\n .join(\", \");\n lines.push(`env = { ${envBody} }`);\n }\n return lines.join(\"\\n\");\n });\n\n return [header, \"\", ...blocks].join(\"\\n\");\n}\n\nfunction jsonString(s: string): string {\n return JSON.stringify(s);\n}\n\nfunction quoteIfNeeded(name: string): string {\n return /^[A-Za-z0-9_-]+$/.test(name) ? name : `\"${name}\"`;\n}\n","/**\n * env-files.ts — 환경 파일 자동 생성.\n *\n * SPEC: docs/specs/cli-rewrite-completeness.md F7, F8\n * Source: bash setup-harness.sh@911c246~1 L880~890 + L954~996.\n *\n * 3 종 산출:\n * 1. .env.example (csr-supabase / full Track) — Supabase 토큰 가이드\n * 2. .gitignore .env 라인 추가 (없을 때만)\n * 3. .mcp-allowlist (모든 dev Track) — D35 opt-in security gate\n *\n * 모두 idempotent — 이미 있으면 skip.\n */\n\nimport { appendFileSync, existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { Track } from \"./types.js\";\n\nconst ENV_EXAMPLE_BODY = `# .env.example — csr-supabase Track\n# Copy to .env (gitignored) and fill in values: cp .env.example .env\n\n# ===== Supabase Management API (MCP server용) =====\n# Personal Access Token — @supabase/mcp-server가 프로젝트 생성/마이그레이션/Edge Functions 배포에 사용\n# 발급: https://supabase.com/dashboard/account/tokens\nSUPABASE_ACCESS_TOKEN=\n\n# 프로젝트 참조 ID (예: \"abcdefghijklmnop\")\n# 위치: Supabase Dashboard → Project Settings → General\nSUPABASE_PROJECT_REF=\n\n# DB 패스워드 (supabase db push 등 직접 DB 접근용)\n# 위치: Supabase Dashboard → Project Settings → Database\nSUPABASE_DB_PASSWORD=\n\n# ===== Frontend (public, 클라이언트 노출 OK) =====\n# 위치: Supabase Dashboard → Project Settings → API\nNEXT_PUBLIC_SUPABASE_URL=\nNEXT_PUBLIC_SUPABASE_ANON_KEY=\n\n# ===== Optional — 앱 측 AI 기능용 =====\n# OPENAI_API_KEY=\n# ANTHROPIC_API_KEY=\n\n# ===== Note =====\n# - Vercel/Netlify는 별도 CLI login 사용 (env 불필요): vercel login / netlify login\n# - Supabase CLI(supabase login)는 OAuth로 ~/.config/supabase/에 토큰 저장 — env 별개\n# - .env는 .gitignore됨 (자동 추가). 절대 commit 금지.\n`;\n\nconst ENV_EXAMPLE_TRACKS: ReadonlyArray<Track> = [\"csr-supabase\", \"full\"];\n\nconst GITIGNORE_ENV_PATTERN = /^\\.env$|^\\.env\\s/m;\n\n/**\n * .env.example 생성 (csr-supabase/full Track 한정, idempotent).\n * @returns true if created, false if skipped (already exists or non-applicable track)\n */\nexport function writeEnvExample(projectDir: string, tracks: ReadonlyArray<Track>): boolean {\n if (!tracks.some((t) => ENV_EXAMPLE_TRACKS.includes(t))) {\n return false;\n }\n const path = join(projectDir, \".env.example\");\n if (existsSync(path)) {\n return false;\n }\n writeFileSync(path, ENV_EXAMPLE_BODY);\n return true;\n}\n\n/**\n * .gitignore에 `.env` 라인 추가. 이미 있으면 skip.\n * @returns true if appended, false if skipped (no .gitignore or .env already listed)\n */\nexport function addGitignoreEnv(projectDir: string): boolean {\n const path = join(projectDir, \".gitignore\");\n if (!existsSync(path)) {\n return false;\n }\n const content = readFileSync(path, \"utf8\");\n if (GITIGNORE_ENV_PATTERN.test(content)) {\n return false;\n }\n // append with separator (avoid double newlines)\n const sep = content.endsWith(\"\\n\") ? \"\" : \"\\n\";\n appendFileSync(path, `${sep}\\n# Secret env (auto-added by agent-harness install)\\n.env\\n`);\n return true;\n}\n\nconst NPX_SKILLS_AGENT_DIRS = [\".factory/\", \".goose/\"];\nconst GITIGNORE_NPX_SKILLS_HEADER =\n \"# npx skills add multi-CLI cache (auto-added by agent-harness)\";\n\n/**\n * v0.8.0 — `.gitignore`에 `.factory/`, `.goose/` 패턴 추가 (사용자 보고 #3).\n *\n * `npx skills add`가 multi-CLI universal install 동작 — Codex 사용자 환경에서\n * `.factory/skills/`, `.goose/skills/` 자동 생성. 사용자 git noise 회피용 ignore.\n *\n * idempotent — 이미 있으면 skip.\n * @returns added pattern list (empty if all already present or no .gitignore)\n */\nexport function addGitignoreNpxSkillsAgents(projectDir: string): string[] {\n const path = join(projectDir, \".gitignore\");\n if (!existsSync(path)) {\n return [];\n }\n const content = readFileSync(path, \"utf8\");\n const missing = NPX_SKILLS_AGENT_DIRS.filter((pattern) => {\n // exact line match (이스케이프 후 줄 단위 비교 — 단순화: 문자열 포함)\n const lineRegex = new RegExp(`^${pattern.replace(/\\./g, \"\\\\.\").replace(/\\//g, \"/\")}\\\\s*$`, \"m\");\n return !lineRegex.test(content);\n });\n if (missing.length === 0) {\n return [];\n }\n const sep = content.endsWith(\"\\n\") ? \"\" : \"\\n\";\n const block = [GITIGNORE_NPX_SKILLS_HEADER, ...missing].join(\"\\n\");\n appendFileSync(path, `${sep}\\n${block}\\n`);\n return [...missing];\n}\n\n/**\n * .mcp-allowlist 생성 from .mcp.json mcpServers keys (D35 opt-in security gate).\n * mcp-pre-exec.sh hook이 참조. 파일 부재 시 gate disabled.\n * @returns server name list written, or null if skipped (already exists or .mcp.json missing)\n */\nexport function writeMcpAllowlist(projectDir: string): string[] | null {\n const allowlistPath = join(projectDir, \".mcp-allowlist\");\n if (existsSync(allowlistPath)) {\n return null;\n }\n const mcpPath = join(projectDir, \".mcp.json\");\n if (!existsSync(mcpPath)) {\n return null;\n }\n let names: string[] = [];\n try {\n const parsed = JSON.parse(readFileSync(mcpPath, \"utf8\")) as {\n mcpServers?: Record<string, unknown>;\n };\n names = Object.keys(parsed.mcpServers ?? {}).sort();\n } catch {\n return null;\n }\n if (names.length === 0) {\n return [];\n }\n const body = [\n \"# MCP Server Allowlist — auto-generated by agent-harness install\",\n \"# Referenced by mcp-pre-exec.sh hook. Remove or '#' comment any server you want to block.\",\n \"# Deleting this file disables the gate (allows all MCP calls).\",\n \"\",\n ...names,\n \"\",\n ].join(\"\\n\");\n writeFileSync(allowlistPath, body);\n return names;\n}\n","/**\n * External installer — `EXTERNAL_ASSETS` 매트릭스를 실제 호출로 변환.\n *\n * SPEC: docs/specs/cli-rewrite-completeness.md F1\n *\n * Decision (OQ1): 실패는 warn-skip. 종료 시 누락 자산 목록 보고.\n * abort는 첫 실행 신뢰성을 깨뜨리므로 채택 안 함 (vibe killer).\n *\n * Spawning은 `child_process.spawnSync` 사용. command/args 분리로 shell injection 차단.\n * stdout/stderr는 captured — 사용자에게 한 줄 요약만 노출 (verbose-log는 별도 옵션 후속).\n */\n\nimport { type SpawnSyncReturns, spawnSync } from \"node:child_process\";\nimport { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { CATEGORIES as CATEGORY_ORDER } from \"./categories.js\";\nimport {\n assetReachesCli,\n EXTERNAL_ASSETS,\n type ExternalAsset,\n type ExternalAssetMethod,\n filterApplicableAssets,\n} from \"./external-assets.js\";\nimport {\n type CliTargets,\n type InstallScope,\n type OptionFlags,\n resolveScope,\n type Track,\n} from \"./types.js\";\n\nexport interface ExternalInstallerDeps {\n /** Override `spawnSync` for tests (mock으로 호출 횟수 + args 검증). */\n spawn?: (cmd: string, args: ReadonlyArray<string>, opts: SpawnOpts) => SpawnSyncReturns<string>;\n /** harness root (prune-ecc.sh script 위치 resolve용). */\n harnessRoot?: string;\n /** asset 매트릭스 override (테스트용, 기본 EXTERNAL_ASSETS 전체). */\n assets?: ReadonlyArray<ExternalAsset>;\n /** 진행 상황 로그 stream (기본 console.log). 일반 로그용. */\n log?: (msg: string) => void;\n /** 경고 메시지 stream (기본 console.error). */\n warn?: (msg: string) => void;\n /**\n * 자산 설치 시작 직전 호출 (streaming UI용).\n * Renderer가 \"→ asset (installing...)\" 라인 출력에 사용.\n */\n onAssetStart?: (asset: ExternalAsset) => void;\n /**\n * 자산 설치 완료 후 호출 (streaming UI용).\n * Renderer가 \"✓/⊘ asset meta\" 라인 출력에 사용.\n */\n onAssetResult?: (result: AssetInstallResult) => void;\n}\n\ninterface SpawnOpts {\n encoding: \"utf8\";\n stdio: (\"ignore\" | \"pipe\")[] | \"ignore\" | \"pipe\";\n timeout?: number;\n /** v26.77.0 — 작업 디렉토리. projectDir 로 고정해 자산이 올바른 프로젝트에 착지. */\n cwd?: string;\n}\n\nexport interface AssetInstallResult {\n asset: ExternalAsset;\n ok: boolean;\n /** ok=false 시 user-facing 메시지 */\n message?: string;\n /**\n * v26.59.0 — 설치된 자산 version. install 후 detectVersion 으로 path 기반 추출.\n * plugin: ~/.claude/plugins/cache/<marketplace>/<plugin>/<VERSION>/ 디렉토리명\n * npm-global: <npm root -g>/<pkg>/package.json 의 version\n * 그 외 method (skill, npx-run, shell-script): 표준 metadata 없음 → undefined.\n */\n version?: string;\n}\n\nexport interface ExternalInstallReport {\n /** 적용 시도된 자산 (조건 통과한 것만) */\n attempted: ReadonlyArray<AssetInstallResult>;\n /** 성공 갯수 */\n succeeded: number;\n /** warn-skip 된 갯수 */\n skipped: number;\n /**\n * v26.102.0 (ADR-031) — 조건은 통과했으나 선택 CLI 와 도달 범위(assetCliSupport)의\n * 교집합이 없어 **시도조차 하지 않은** 자산 (예: codex 단독 설치의 claude 전용 plugin).\n * 침묵 제외 금지 — render 가 이 목록을 사용자에게 고지한다 (no-false-ship).\n */\n excludedByCli: ReadonlyArray<ExternalAsset>;\n}\n\nconst DEFAULT_SPAWN_TIMEOUT_MS = 120_000;\n\n/**\n * v26.102.0 (ADR-031) — external 단계의 대상/배제 판정 **단일 지점**. 규칙 = 조건 통과 ∧\n * non-internal(Phase 1 담당) ∧ 선택 CLI 도달. runExternalInstall(시도 목록)과\n * runExternalPhase(헤더 카운트)가 이 함수만 호출한다 — 같은 규칙을 두 파일에 각각 기술하면\n * 3번째 조건이 생길 때 카운트만 조용히 어긋난다 (SOD 리뷰 Important-6, no-false-ship\n * \"동일 목록 2곳 하드코딩 금지\").\n */\nexport function selectExternalTargets(\n assets: ReadonlyArray<ExternalAsset>,\n ctx: {\n tracks: ReadonlyArray<Track>;\n options: OptionFlags;\n cli: CliTargets;\n userOverride?: { forceInclude: ReadonlyArray<string>; forceExclude: ReadonlyArray<string> };\n },\n): { targets: ExternalAsset[]; excludedByCli: ExternalAsset[] } {\n const conditionPassed = filterApplicableAssets(assets, ctx).filter(\n (a) => a.method.kind !== \"internal\",\n );\n return {\n targets: conditionPassed.filter((a) => assetReachesCli(a, ctx.cli)),\n excludedByCli: conditionPassed.filter((a) => !assetReachesCli(a, ctx.cli)),\n };\n}\n\n/**\n * spec에 적용 가능한 자산을 모두 시도. 실패는 warn-skip (기본).\n */\nexport function runExternalInstall(\n ctx: {\n tracks: ReadonlyArray<Track>;\n options: OptionFlags;\n cli: CliTargets;\n /** v26.47.0 — Phase C full user override (forceInclude/forceExclude). */\n userOverride?: { forceInclude: ReadonlyArray<string>; forceExclude: ReadonlyArray<string> };\n /** v26.64.0 (ADR-020) — Install scope. undefined → default \"project\". */\n scope?: InstallScope;\n /**\n * v26.77.0 — 외부 설치기 spawn 의 작업 디렉토리.\n * 미지정 시 process.cwd(). 핵심: npm(--save-dev)·npx-run(bmad --directory .)·\n * plugin(--scope project, claude 의 cwd 기반 project 탐지)·skill 이 모두 cwd 기준으로\n * 착지하므로, --project-dir 가 cwd 와 다르면 cwd 를 projectDir 로 맞춰야 자산이 올바른\n * 프로젝트에 떨어진다 (이 누락 = 2026-06-07 probe 가 repo 를 오염시킨 근본 원인).\n */\n projectDir?: string;\n },\n deps: ExternalInstallerDeps = {},\n): ExternalInstallReport {\n const log = deps.log ?? console.log;\n const warn = deps.warn ?? console.error;\n const spawn = deps.spawn ?? defaultSpawn;\n const assets = deps.assets ?? EXTERNAL_ASSETS;\n const harnessRoot = deps.harnessRoot ?? process.cwd();\n const projectDir = ctx.projectDir ?? process.cwd();\n\n // v26.81.0 (ADR-022) — internal 자산(tauri-desktop)은 Phase 1 의\n // manifest/transform 이 설치 주체 — external(spawn) 단계에서 제외. Phase 1 의\n // templates 행으로 사용자에게 이미 가시화됨 (중복 보고 방지).\n // v26.102.0 (ADR-031, Batch3) — CLI 도달 범위 필터. 선택 CLI 와 교집합 없는 자산은\n // spawn 자체를 배제한다: codex 단독 설치가 claude 전용 plugin 을 `claude plugin ...` 으로\n // spawn 해 ~/.claude/plugins 를 오염시키던 P0 [4cli-asymmetry-cluster] 의 구조적 fix.\n // 제외분은 excludedByCli 로 보고 — 침묵 제외 금지 (no-false-ship).\n const { targets: applicable, excludedByCli } = selectExternalTargets(assets, ctx);\n // v26.55.0 — Phase 2 grouped progress UX. 카테고리 순서로 정렬 → install.ts 의 onAssetStart\n // callback 이 category 변경 감지로 헤더 출력 가능. ADR-016.\n const sorted = [...applicable].sort((a, b) => {\n const ai = CATEGORY_ORDER.indexOf(a.category);\n const bi = CATEGORY_ORDER.indexOf(b.category);\n return ai - bi;\n });\n const attempted: AssetInstallResult[] = [];\n const cli = ctx.cli;\n const scope = resolveScope(ctx.scope);\n\n for (const asset of sorted) {\n deps.onAssetStart?.(asset);\n log(` → ${asset.description}`);\n const baseResult = installOne(asset, { spawn, harnessRoot, cli, scope, projectDir });\n let result: AssetInstallResult = baseResult;\n if (baseResult.ok) {\n const v = detectVersion(asset.method, spawn);\n if (v) result = { ...baseResult, version: v };\n }\n deps.onAssetResult?.(result);\n\n if (!result.ok) {\n // v26.79.0 — 모든 실패는 warn-skip (abort 는 vibe killer 라 미채택). 죽은\n // failureMode/aborted 메커니즘 제거 (사용 자산 0 + 렌더러 미참조).\n warn(` [warn-skip] ${asset.id}: ${result.message ?? \"failed\"}`);\n }\n\n attempted.push(result);\n }\n\n return {\n attempted,\n succeeded: attempted.filter((r) => r.ok).length,\n skipped: attempted.filter((r) => !r.ok).length,\n excludedByCli,\n };\n}\n\n/**\n * 자산 1개 설치. method.kind 별 적절한 명령 실행.\n */\nfunction installOne(\n asset: ExternalAsset,\n ctx: {\n spawn: NonNullable<ExternalInstallerDeps[\"spawn\"]>;\n harnessRoot: string;\n cli: CliTargets;\n scope: InstallScope;\n /** v26.77.0 — spawn cwd. 자산이 올바른 프로젝트에 착지하도록 projectDir 로 고정. */\n projectDir: string;\n },\n): AssetInstallResult {\n const { method } = asset;\n const cwd = ctx.projectDir;\n switch (method.kind) {\n case \"skill\":\n return runSpawn(asset, ctx.spawn, \"npx\", buildSkillArgs(method, ctx.cli, ctx.scope), cwd);\n case \"plugin\":\n return installPlugin(asset, ctx.spawn, method, ctx.scope, cwd);\n case \"npm\": {\n // v26.64.0 (ADR-020) — scope=project 시 devDep, scope=global 시 -g.\n // v26.68.0 — method.kind \"npm-global\" → \"npm\" rename (scope 분기와 무관 의미).\n // v26.80.0 — pinned 버전 설치 (`pkg@version`). vetting 시점의 코드만 실행 (보안 wedge).\n const pinned = `${method.pkg}@${method.version}`;\n return runSpawn(\n asset,\n ctx.spawn,\n \"npm\",\n ctx.scope === \"global\" ? [\"install\", \"-g\", pinned] : [\"install\", \"--save-dev\", pinned],\n cwd,\n );\n }\n case \"npx-run\":\n // v26.80.0 — pinned 버전 실행 (`cmd@version`). 이전 `cmd` 에 \"@latest\" 인라인이던 것을\n // 구조 필드로 분리 (cmd 는 bare 이름 — drift override/라벨이 이름 그대로 사용).\n return runSpawn(\n asset,\n ctx.spawn,\n \"npx\",\n [`${method.cmd}@${method.version}`, ...(method.args ?? [])],\n cwd,\n );\n case \"shell-script\": {\n const scriptPath = join(ctx.harnessRoot, method.script);\n if (!existsSync(scriptPath)) {\n return {\n asset,\n ok: false,\n message: `script not found: ${scriptPath}`,\n };\n }\n return runSpawn(asset, ctx.spawn, \"bash\", [scriptPath, ...method.args], cwd);\n }\n case \"internal\":\n // v26.81.0 (ADR-022) — 도달 불가 (runExternalInstall 이 사전 필터). exhaustive switch\n // + 방어: 도달해도 spawn 없이 ok (Phase 1 manifest 가 실 설치 주체).\n return { asset, ok: true, message: \"internal template (installed by Phase 1 manifest)\" };\n }\n}\n\n/**\n * v26.39.5 fix — `--agent <list>` 명시 추가 (사용자 보고 #3 진짜 fix).\n *\n * `npx skills add` default 동작은 `*` (all installed agents) → universal install →\n * `.factory/skills/`, `.goose/skills/` 자동 생성. v0.8.0 의 `.gitignore` 패턴 추가만으론\n * git noise 만 차단하고 disk 디렉토리 생성은 막지 못함.\n *\n * 본 fix: `spec.cli` 의 base CLI 만 콤마 구분 명시 → 의도된 agent 만 install.\n *\n * v26.39.6 fix — skills CLI agent name 매핑.\n * skills CLI 1.5.5 valid agent 이름은 `claude-code` 인데 우리 CliBase 는 `claude`.\n * 매핑 누락 시 `Invalid agents: claude` 로 exit 1 → 외부 사용자 (실사용 리포\n * reproduce 2026-05-06) 환경에서 7건 skill 자산 100% skip.\n */\nconst SKILLS_CLI_AGENT_MAP: Record<CliTargets[number], string> = {\n claude: \"claude-code\",\n codex: \"codex\",\n opencode: \"opencode\",\n // v26.66.0 — Antigravity (Google) skills agent. `.agents/skills/` 표준 공유 (codex transform 산출과 동일).\n antigravity: \"antigravity\",\n};\n\n/**\n * `npx skills` CLI 고정 버전 — unpinned 면 upstream breaking 이 설치·검증을 동시에 깬다\n * (1.5.5→1.5.7 multi-agent `--agent` 플래그 파손 전례). bump 시 Docker 시나리오 재검증 필수.\n * audit CODE-4/D-1. scripts/verify-catalog.mjs 와 동일 값 유지 (drift 테스트 가드).\n */\nexport const SKILLS_CLI_VERSION = \"1.5.11\";\n\n/** `npx skills <subcommand>` 의 첫 인자 — 항상 버전 고정. */\nexport function skillsCliSpec(): string {\n return `skills@${SKILLS_CLI_VERSION}`;\n}\n\nfunction buildSkillArgs(\n method: { kind: \"skill\"; source: string; skill?: string },\n cli: CliTargets,\n scope: InstallScope,\n): string[] {\n const args = [skillsCliSpec(), \"add\", method.source];\n if (method.skill) {\n args.push(\"--skill\", method.skill);\n }\n if (cli.length > 0) {\n // v26.55.1 — skills cli 1.5.7 부터 multi-agent 는 repeatable `--agent` 만 지원.\n for (const c of cli) {\n args.push(\"--agent\", SKILLS_CLI_AGENT_MAP[c] ?? c);\n }\n }\n // v26.64.0 (ADR-020) — global scope 시 -g. project 는 skills CLI default (project) 따름.\n if (scope === \"global\") {\n args.push(\"-g\");\n }\n args.push(\"--yes\");\n return args;\n}\n\n/**\n * Plugin 은 marketplace add → install 두 단계. marketplace add 실패는 무시 (이미 등록 케이스).\n *\n * v26.64.0 (ADR-020) — `--scope <project|user>` 분기. claude CLI native:\n * - project: --scope project (현재 projectPath 격리, installed_plugins.json 메타 매칭)\n * - global: --scope user (모든 projectPath 에서 활성)\n * fs 적으로는 양쪽 모두 ~/.claude/plugins/cache/ + ~/.claude/plugins/marketplaces/ 에 write\n * (claude CLI 자체 디자인). 격리는 메타데이터.\n */\nfunction installPlugin(\n asset: ExternalAsset,\n spawn: NonNullable<ExternalInstallerDeps[\"spawn\"]>,\n method: { kind: \"plugin\"; marketplace: string; pluginId: string },\n scope: InstallScope,\n cwd: string,\n): AssetInstallResult {\n const claudeScope = scope === \"global\" ? \"user\" : \"project\";\n // v26.77.0 — cwd=projectDir: --scope project 시 claude 가 cwd 기준으로 프로젝트를 탐지하므로\n // installed_plugins.json 의 projectPath 가 올바른 프로젝트로 기록된다.\n spawn(\n \"claude\",\n [\"plugin\", \"marketplace\", \"add\", \"--scope\", claudeScope, method.marketplace],\n spawnOpts(cwd),\n );\n return runSpawn(\n asset,\n spawn,\n \"claude\",\n [\"plugin\", \"install\", \"--scope\", claudeScope, method.pluginId],\n cwd,\n );\n}\n\nfunction runSpawn(\n asset: ExternalAsset,\n spawn: NonNullable<ExternalInstallerDeps[\"spawn\"]>,\n cmd: string,\n args: ReadonlyArray<string>,\n cwd?: string,\n): AssetInstallResult {\n const result = spawn(cmd, args, spawnOpts(cwd));\n if (result.error) {\n return { asset, ok: false, message: result.error.message };\n }\n if ((result.status ?? 1) !== 0) {\n const stderr = (result.stderr ?? \"\").trim();\n const tail = stderr.length > 200 ? `${stderr.slice(0, 200)}…` : stderr;\n return {\n asset,\n ok: false,\n message: `${cmd} exited ${result.status}${tail ? `: ${tail}` : \"\"}`,\n };\n }\n return { asset, ok: true };\n}\n\nfunction spawnOpts(cwd?: string): SpawnOpts {\n return {\n encoding: \"utf8\",\n stdio: \"pipe\",\n timeout: DEFAULT_SPAWN_TIMEOUT_MS,\n ...(cwd ? { cwd } : {}),\n };\n}\n\n/* v8 ignore next 7 — thin dep-inject default. tests 는 항상 spawn 주입. */\nfunction defaultSpawn(\n cmd: string,\n args: ReadonlyArray<string>,\n opts: SpawnOpts,\n): SpawnSyncReturns<string> {\n return spawnSync(cmd, [...args], opts);\n}\n\n/**\n * v26.59.0 — install 후 path 기반 version 추출.\n *\n * 안전 원칙: 실패 시 undefined 반환 (silent). install 성공 자체는 이미 검증됨.\n *\n * - plugin: ~/.claude/plugins/cache/<marketplace>/<plugin>/<VERSION>/ 디렉토리명 (semver-like 만)\n * - npm-global: <npm root -g>/<pkg>/package.json 의 version\n * - skill / npx-run / shell-script: 표준 metadata 위치 없음 → undefined\n */\nfunction detectVersion(\n method: ExternalAssetMethod,\n spawn: NonNullable<ExternalInstallerDeps[\"spawn\"]>,\n): string | undefined {\n try {\n switch (method.kind) {\n case \"plugin\": {\n // pluginId = \"<plugin>@<marketplace-short>\". cache path:\n // ~/.claude/plugins/cache/<marketplace-short>/<plugin>/<VERSION>/\n // method.marketplace 는 GH `<user>/<repo>` (다른 값) 이라 path 에 사용 X.\n const at = method.pluginId.lastIndexOf(\"@\");\n if (at <= 0) return undefined;\n const plugin = method.pluginId.slice(0, at);\n const marketplaceShort = method.pluginId.slice(at + 1);\n const cacheBase = join(homedir(), \".claude/plugins/cache\", marketplaceShort, plugin);\n if (!existsSync(cacheBase)) return undefined;\n const versions = readdirSync(cacheBase)\n .filter((v) => /^\\d/.test(v))\n .sort();\n return versions.at(-1);\n }\n case \"npm\": {\n const npmRoot = getNpmGlobalRoot(spawn);\n if (!npmRoot) return undefined;\n const pkgJson = join(npmRoot, method.pkg, \"package.json\");\n if (!existsSync(pkgJson)) return undefined;\n const parsed = JSON.parse(readFileSync(pkgJson, \"utf8\")) as { version?: string };\n return parsed.version;\n }\n default:\n return undefined;\n }\n } catch {\n return undefined;\n }\n}\n\nlet npmGlobalRootCache: string | undefined;\n\n/* v8 ignore start — npm CLI 실행 + cache. 실 시스템 의존. detectVersion (plugin 외 method) 가 본 함수 호출. */\nfunction getNpmGlobalRoot(spawn: NonNullable<ExternalInstallerDeps[\"spawn\"]>): string | undefined {\n if (npmGlobalRootCache !== undefined) return npmGlobalRootCache || undefined;\n try {\n const r = spawn(\"npm\", [\"root\", \"-g\"], spawnOpts());\n if ((r.status ?? 1) === 0) {\n npmGlobalRootCache = (r.stdout ?? \"\").trim();\n return npmGlobalRootCache || undefined;\n }\n } catch {\n // fallthrough\n }\n npmGlobalRootCache = \"\";\n return undefined;\n}\n/* v8 ignore stop */\n\n/**\n * 누락(skip) 자산 목록을 사용자 보고용 텍스트로 포맷.\n */\nexport function formatSkippedReport(report: ExternalInstallReport): string {\n const failed = report.attempted.filter((r) => !r.ok);\n if (failed.length === 0) return \"\";\n const lines = failed.map((r) => ` • ${r.asset.id} — ${r.message ?? \"failed\"}`);\n return [\n `${failed.length}개 외부 자산이 설치되지 않았습니다 (warn-skip):`,\n ...lines,\n \"\",\n \"Manual install or retry needed. See docs/REFERENCE.md or README.md for details.\",\n ].join(\"\\n\");\n}\n","/**\n * Install log — `.claude/.harness-install.json`.\n *\n * v26.64.0 (ADR-020) — install 종료 시 자산 list + scope + timestamp 기록.\n * uninstall command 가 본 log 를 읽어 정확한 reverse 수행.\n *\n * 글로벌 자산 (scope=global 또는 codexOptIn) 은 log 에 안내용으로만 기록 — uninstall 시 자동 삭제 X (D16).\n */\n\nimport { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { ExternalAsset, ExternalAssetMethod } from \"./external-assets.js\";\nimport type { ExternalInstallReport } from \"./external-installer.js\";\nimport { listFilesRecursive } from \"./fs-ops.js\";\nimport type { InstallScope, InstallSpec } from \"./types.js\";\n\nexport const INSTALL_LOG_FILENAME = \".harness-install.json\";\nexport const INSTALL_LOG_VERSION = 1;\n\nexport interface InstallLogAsset {\n id: string;\n category: string;\n /** External asset method.kind 그대로. uninstall reverse 시 분기 기준. */\n method: ExternalAssetMethod[\"kind\"];\n /** scope=global 자산은 uninstall 시 안내만 (D16 — 글로벌 자동 삭제 금지). */\n scope: InstallScope;\n /** method 별 추가 정보. plugin: marketplace + pluginId. skill: source. npm: pkg. */\n detail: Record<string, string>;\n /** installed 시점 version (detectVersion 결과, 없으면 undefined). */\n version?: string;\n}\n\n/**\n * v26.124.0 (F-1f) — install 이 `.claude/` **밖**에 만들거나 고친 프로젝트 루트 파일.\n *\n * uninstall 은 이 목록을 **안내만 하고 지우지 않는다**. `.mcp.json`/`.gitignore` 에는 사용자\n * 내용이 섞이고, `.github/workflows/` 는 설치 후 사용자 소유물이기 때문 (ci-scaffold.ts 안전\n * 계약 2 · F-1d 와 같은 방침). 기록이 없으면 안내도 없다 — 그래서 install 이 적어 둔다.\n */\nexport interface InstallLogRootFile {\n /** project-relative 경로 (예: `.mcp.json`, `.github/workflows/ci.yml`) */\n path: string;\n /**\n * created = 하네스가 없던 파일을 만들었다 (내용 전부 하네스 것 → 손 안 댔으면 지워도 안전).\n * modified = 이미 있던 사용자 파일에 병합/추가했다 (직접 확인이 필요하다).\n */\n change: \"created\" | \"modified\";\n /** 무엇을 했는지 — uninstall 안내에 그대로 나온다. 재설치 시 합집합으로 누적된다. */\n notes: string[];\n}\n\n/**\n * v26.126.0 (R-3a · ADR-046) — `.claude/skills/` 안 파일 하나의 **설치 시점 기준선**.\n *\n * update 는 이 해시로 \"사용자가 고쳤는가\"를 판정한다. 기록이 없으면 판정이 불가능하고,\n * 그때는 내용 비교로 폴백해 보수적으로 백업한다 (ADR-046 파생규칙 3).\n */\nexport interface InstallLogSkillFile {\n /** `.claude/skills/` 기준 상대 경로 (예: `multi-persona-review/SKILL.md`) */\n path: string;\n /** 하네스가 그 자리에 놓아둔 내용의 sha256. 지금 디스크가 이것과 다르면 = 사용자가 고쳤다. */\n sha256: string;\n}\n\nexport interface InstallLog {\n /** schema version — backward compat 검출용 */\n schemaVersion: number;\n /** harness 가 install 한 시점 ISO timestamp */\n installedAt: string;\n /** 전체 install scope. 자산 per-asset scope 와 동일 (현재는 single global scope) */\n scope: InstallScope;\n /** install 시 spec 요약 (tracks/cli — uninstall reasoning 용) */\n spec: {\n tracks: ReadonlyArray<string>;\n cli: ReadonlyArray<string>;\n };\n /** templates 출처 — uninstall 시 templates 제거 위치 */\n templates: {\n /** .claude/ project local */\n claudeDir: string;\n /** .codex/ project local (cli=codex 시) */\n codexDir?: string;\n /** .opencode/ project local (cli=opencode 시) */\n opencodeDir?: string;\n /**\n * project root CLAUDE.md (cli=claude 시 생성).\n * uninstall 시 sha256 이 install 시점과 동일할 때만 삭제 — 사용자가 수정했으면 보존.\n */\n rootClaudeMd?: { path: string; sha256: string };\n };\n /** external-installer 가 install 한 자산 (ok=true 만) */\n assets: ReadonlyArray<InstallLogAsset>;\n /**\n * v26.124.0 (F-1f) — `.claude/` 밖 루트 파일. 건드린 게 없으면 필드 자체가 없다\n * (v26.123.0 이하 로그도 이 상태 — 읽는 쪽은 부재를 정상으로 다뤄야 한다).\n */\n rootFiles?: ReadonlyArray<InstallLogRootFile>;\n /**\n * v26.126.0 (R-3a · ADR-046) — 스킬 파일 기준선 해시. 스킬을 안 깔았으면 필드 자체가 없다\n * (v26.125.0 이하 로그도 이 상태 — 읽는 쪽은 부재를 정상으로 다뤄야 한다).\n */\n skillFiles?: ReadonlyArray<InstallLogSkillFile>;\n}\n\n/**\n * external-installer 의 result 를 InstallLogAsset 으로 변환.\n * ok=false 자산은 제외 (실제 install 안 됨 → uninstall 대상 아님).\n */\nexport function buildAssetEntries(\n report: ExternalInstallReport | null,\n scope: InstallScope,\n): InstallLogAsset[] {\n if (!report) return [];\n return report.attempted\n .filter((r) => r.ok)\n .map((r) => assetToLogEntry(r.asset, scope, r.version));\n}\n\nfunction assetToLogEntry(\n asset: ExternalAsset,\n scope: InstallScope,\n version: string | undefined,\n): InstallLogAsset {\n const detail = methodDetail(asset.method);\n const entry: InstallLogAsset = {\n id: asset.id,\n category: asset.category,\n method: asset.method.kind,\n scope,\n detail,\n };\n if (version) entry.version = version;\n return entry;\n}\n\nfunction methodDetail(method: ExternalAssetMethod): Record<string, string> {\n switch (method.kind) {\n case \"plugin\":\n return { marketplace: method.marketplace, pluginId: method.pluginId };\n case \"skill\":\n return { source: method.source, ...(method.skill ? { skill: method.skill } : {}) };\n case \"npm\":\n return { pkg: method.pkg };\n case \"npx-run\":\n return { cmd: method.cmd, args: (method.args ?? []).join(\" \") };\n case \"shell-script\":\n return { script: method.script, args: method.args.join(\" \") };\n case \"internal\":\n // v26.81.0 (ADR-022) — Phase 1 manifest 가 설치 주체. external 단계에선 미기록이 정상.\n return { key: method.key };\n }\n}\n\n/**\n * install log 생성. `previous` 가 있으면 **누적**한다 (v26.123.0 — F-1a).\n *\n * install 은 이전에 설치한 것을 지우지 않는다. 그런데 로그는 매번 새로 만들어 덮어썼으므로,\n * 나중에 `install --with <id>` 를 한 번만 해도 1회차 자산이 기록에서 사라지고 **uninstall 이\n * 그걸 못 찾아 남긴다**. 디스크에는 남아 있는데 기록에는 없는 = 로그가 거짓이 되는 상태.\n *\n * 누적 대상은 uninstall 이 실제로 읽는 두 필드뿐이다 (`assets` · `templates`). `spec`(tracks/cli)은\n * 누적하지 않는다: `.claude/` 가 backup 으로 밀리는 설치(reinstall)에선 이전 트랙 파일이 실제로\n * 사라져 합집합이 거짓이 된다. 게다가 uninstall 은 `spec` 을 읽지 않는다 (표시용).\n *\n * `claudeDirMovedAside` = 이번 설치가 `.claude/` 를 backup 으로 rename 했는가. 그 경우\n * **`.claude/` 안에 살던 이전 자산은 실제로 사라졌으므로 누적에서 뺀다** — 안 빼면 F-1a 를\n * 반대 방향으로 재현한다(있지도 않은 걸 있다고 기록). 해당: project scope 의 `skill`\n * (`npx skills add` 가 `.claude/skills/` 에 설치) 와 `shell-script`(ecc-prune →\n * `.claude/local-plugins/`). plugin/npm 은 프로젝트 밖에 살아 남으므로 유지한다.\n */\nexport function buildInstallLog(\n spec: InstallSpec,\n external: ExternalInstallReport | null,\n scope: InstallScope,\n rootClaudeMd?: { path: string; sha256: string } | null,\n previous?: InstallLog | null,\n claudeDirMovedAside = false,\n rootFiles: ReadonlyArray<InstallLogRootFile> = [],\n): InstallLog {\n const templates: InstallLog[\"templates\"] = {\n claudeDir: \".claude/\",\n ...(spec.cli.includes(\"codex\") ? { codexDir: \".codex/\" } : {}),\n ...(spec.cli.includes(\"opencode\") ? { opencodeDir: \".opencode/\" } : {}),\n ...(rootClaudeMd ? { rootClaudeMd } : {}),\n };\n const log: InstallLog = {\n schemaVersion: INSTALL_LOG_VERSION,\n installedAt: new Date().toISOString(),\n scope,\n spec: {\n tracks: spec.tracks,\n cli: spec.cli,\n },\n // 이번 설치가 만든 항목이 이기고, 이번에 안 만든 항목은 이전 값을 그대로 둔다.\n // (예: claude 로 깔고 나중에 codex 만 추가 설치해도 root CLAUDE.md 기록이 살아남는다)\n templates: { ...previous?.templates, ...templates },\n assets: mergeAssets(\n claudeDirMovedAside ? previous?.assets?.filter(survivesClaudeDirRename) : previous?.assets,\n buildAssetEntries(external, scope),\n ),\n };\n // 루트 파일은 `.claude/` 밖이라 backup rename 과 무관하게 살아남는다 → 무조건 누적.\n const mergedRootFiles = mergeRootFiles(previous?.rootFiles, rootFiles);\n if (mergedRootFiles.length > 0) log.rootFiles = mergedRootFiles;\n return log;\n}\n\n/**\n * 경로 기준 합집합. 자산과 달리 **이번 설치분이 이전 것을 덮지 않고 합친다** — `.gitignore` 에\n * 1회차는 `.env`, 2회차는 `.factory/` 를 추가하면 둘 다 디스크에 남아 있으므로 둘 다 알려야 한다.\n * `change` 는 한 번이라도 created 면 created — 하네스가 만든 파일에 나중에 병합한 것뿐이고,\n * 사용자에게는 \"전부 하네스 것\"이 여전히 참이다 (modified 로 낮추면 지워도 될 것을 못 지운다).\n */\nfunction mergeRootFiles(\n previous: ReadonlyArray<InstallLogRootFile> | undefined,\n current: ReadonlyArray<InstallLogRootFile>,\n): InstallLogRootFile[] {\n const byPath = new Map<string, InstallLogRootFile>();\n for (const file of [...(previous ?? []), ...current]) {\n const prior = byPath.get(file.path);\n byPath.set(\n file.path,\n prior\n ? {\n path: file.path,\n change: prior.change === \"created\" ? \"created\" : file.change,\n notes: [...new Set([...prior.notes, ...file.notes])],\n }\n : file,\n );\n }\n return [...byPath.values()];\n}\n\n/**\n * `.claude/` 가 backup 으로 밀려도 살아남는 자산인가 — 산출물이 프로젝트 `.claude/` 밖인가.\n *\n * **exhaustive switch 로 쓴다(default 없음).** method 종류가 늘면 빌드가 깨져서 이 판단을\n * 강제로 하게 만든다 — `!==` 목록이면 새 method 가 조용히 \"살아남음\"으로 분류되고, 그건\n * 곧 없는 걸 있다고 기록하는 것이다 (`no-false-ship` §Drift 구조 차단: 하드코딩 목록에는\n * exhaustiveness 가드 없이 머지 금지, 기본값은 면제가 아니라 검사).\n */\nfunction survivesClaudeDirRename(asset: InstallLogAsset): boolean {\n if (asset.scope === \"global\") return true; // 글로벌 영역은 install 이 건드리지 않는다\n switch (asset.method) {\n case \"plugin\":\n return true; // `~/.claude/plugins/cache` — 프로젝트 밖\n case \"npm\":\n return true; // `node_modules/`\n case \"skill\":\n return false; // `npx skills add` project scope → `.claude/skills/`\n case \"shell-script\":\n return false; // ecc-prune → `.claude/local-plugins/`\n case \"npx-run\":\n // bmad-method 는 `--tools claude-code` 로 `.claude/` 안에 agent command 를 만든다\n // (external-assets.ts 의 cliSupportOverride 주석 + Docker 실증 realcli-workflows-2026-06-06).\n // `_bmad/` 는 루트에 남지만, `.claude/` 산출물이 사라진 이상 \"그대로 설치됨\"이 아니다.\n return false;\n case \"internal\":\n // 실제로는 로그에 실리지 않는다(external-installer 가 사전 제외). 그래도 기본값은 검사.\n return false;\n }\n}\n\n/** id 기준 합집합 — 같은 id 는 이번 설치분이 이긴다 (version/scope 가 최신). 순서는 안정적. */\nfunction mergeAssets(\n previous: ReadonlyArray<InstallLogAsset> | undefined,\n current: ReadonlyArray<InstallLogAsset>,\n): InstallLogAsset[] {\n if (!previous || previous.length === 0) return [...current];\n const currentById = new Map(current.map((a) => [a.id, a]));\n const previousIds = new Set(previous.map((a) => a.id));\n return [\n ...previous.map((a) => currentById.get(a.id) ?? a),\n ...current.filter((a) => !previousIds.has(a.id)),\n ];\n}\n\n/** install log + root CLAUDE.md 등 자산 무결성 비교용 sha256 (hex). */\nexport function hashContent(content: string): string {\n return createHash(\"sha256\").update(content, \"utf8\").digest(\"hex\");\n}\n\n/**\n * `.claude/skills/` 전체를 훑어 파일별 sha256 스냅샷을 만든다 (v26.126.0 · ADR-046).\n *\n * **복사가 끝난 뒤에 호출해야 한다.** 이 값이 \"하네스가 놓아둔 내용\"의 기준선이 되고, 다음\n * update 는 디스크가 이것과 다른지로 사용자 편집을 판정한다. 복사 **전에** 부르면 옛 내용이\n * 기준선이 돼 다음 update 가 멀쩡한 파일을 전부 \"사용자가 고쳤다\"로 오판한다.\n *\n * 누적하지 않고 **매번 통째로 교체**한다 (`rootFiles` 와 반대다) — 이건 이력이 아니라 현재\n * 디스크 상태의 스냅샷이고, 지워진 파일의 해시가 남으면 그 자체로 거짓 기록이 된다.\n */\nexport function collectSkillHashes(projectDir: string): InstallLogSkillFile[] {\n const skillsDir = join(projectDir, \".claude/skills\");\n return listFilesRecursive(skillsDir).map((rel) => ({\n path: rel,\n sha256: hashContent(readFileSync(join(skillsDir, rel), \"utf8\")),\n }));\n}\n\n/**\n * install log write. 위치: `<projectDir>/.claude/.harness-install.json`.\n *\n * `.claude/` 는 cli=claude 일 때 baseline phase 에서 생성되지만, codex/opencode/antigravity\n * 단독(claude 미포함) 설치 시엔 생성되지 않는다. 그 경우에도 uninstall 이 본 log 를 읽을 수 있도록\n * write 직전 디렉토리를 보장한다 (없으면 install log 누락 → uninstall 불가).\n */\nexport function writeInstallLog(projectDir: string, log: InstallLog): string {\n const path = join(projectDir, \".claude\", INSTALL_LOG_FILENAME);\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, `${JSON.stringify(log, null, 2)}\\n`, \"utf8\");\n return path;\n}\n\nexport function readInstallLog(projectDir: string): InstallLog | null {\n const path = join(projectDir, \".claude\", INSTALL_LOG_FILENAME);\n if (!existsSync(path)) return null;\n try {\n const parsed = JSON.parse(readFileSync(path, \"utf8\")) as InstallLog;\n // v26.68.0 — backward compat: method.kind \"npm-global\" → \"npm\" rename.\n // v26.64.0 ~ v26.67.0 시점 install log 가 새 uninstall 에서 작동하도록 normalize.\n if (Array.isArray(parsed.assets)) {\n parsed.assets = parsed.assets.map((a) =>\n (a.method as string) === \"npm-global\" ? { ...a, method: \"npm\" } : a,\n );\n }\n return parsed;\n } catch {\n return null;\n }\n}\n\nexport function installLogPath(projectDir: string): string {\n return join(projectDir, \".claude\", INSTALL_LOG_FILENAME);\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { anyTrack } from \"./track-match.js\";\nimport type { Track } from \"./types.js\";\n\nexport interface McpServerConfig {\n type?: \"stdio\" | \"http\";\n command: string;\n args: string[];\n env?: Record<string, string>;\n}\n\nexport interface McpJson {\n mcpServers: Record<string, McpServerConfig>;\n _comment?: string;\n}\n\nexport interface TrackMcpRow {\n name: string;\n pattern: string;\n command: string;\n args: string[];\n}\n\n/** Parse `templates/track-mcp-map.tsv` (tab-separated, comment-aware). */\nexport function parseTrackMcpMap(raw: string): TrackMcpRow[] {\n const rows: TrackMcpRow[] = [];\n for (const line of raw.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith(\"#\")) {\n continue;\n }\n const parts = line.split(\"\\t\");\n if (parts.length < 4) {\n continue;\n }\n const [name, pattern, command, argsJson] = parts;\n if (!name || !pattern || !command) {\n continue;\n }\n let args: unknown;\n try {\n args = JSON.parse(argsJson ?? \"[]\");\n } catch {\n continue;\n }\n if (!Array.isArray(args) || !args.every((a) => typeof a === \"string\")) {\n continue;\n }\n rows.push({ name, pattern, command, args: args as string[] });\n }\n return rows;\n}\n\n/**\n * Apply track-aware MCP rows to a base `.mcp.json` object.\n * Existing entries (including user customizations) are preserved.\n */\nexport function mergeMcpServers(\n base: McpJson,\n rows: ReadonlyArray<TrackMcpRow>,\n tracks: ReadonlyArray<Track>,\n): McpJson {\n const out: McpJson = {\n ...base,\n mcpServers: { ...base.mcpServers },\n };\n for (const row of rows) {\n if (!anyTrack(tracks, row.pattern)) {\n continue;\n }\n if (out.mcpServers[row.name]) {\n // Preserve existing — do not overwrite user customizations.\n continue;\n }\n out.mcpServers[row.name] = {\n type: \"stdio\",\n command: row.command,\n args: row.args,\n };\n }\n // Strip _comment marker (parity with the bash `jq 'del(._comment)'`).\n delete out._comment;\n return out;\n}\n\n/**\n * Compose the final `.mcp.json` for a project install.\n * Read base template + track map, merge with optional existing user file (additive).\n */\nexport function composeMcpJson(opts: {\n templateMcpPath: string;\n trackMapPath: string;\n existingPath?: string;\n tracks: ReadonlyArray<Track>;\n}): McpJson {\n const base = JSON.parse(readFileSync(opts.templateMcpPath, \"utf8\")) as McpJson;\n const merged =\n opts.existingPath && existsSync(opts.existingPath)\n ? mergeUserBase(base, opts.existingPath)\n : base;\n const mapRaw = existsSync(opts.trackMapPath) ? readFileSync(opts.trackMapPath, \"utf8\") : \"\";\n const rows = parseTrackMcpMap(mapRaw);\n return mergeMcpServers(merged, rows, opts.tracks);\n}\n\nfunction mergeUserBase(base: McpJson, existingPath: string): McpJson {\n try {\n const existing = JSON.parse(readFileSync(existingPath, \"utf8\")) as McpJson;\n return {\n ...base,\n mcpServers: { ...base.mcpServers, ...existing.mcpServers },\n };\n } catch {\n return base;\n }\n}\n\n/** Write the composed `.mcp.json` to disk (2-space pretty). */\nexport function writeMcpJson(path: string, mcp: McpJson): void {\n writeFileSync(path, `${JSON.stringify(mcp, null, 2)}\\n`);\n}\n","/**\n * OpenCode transform orchestrator — SSOT (templates/CLAUDE.md, .mcp.json) →\n * OpenCode 자산.\n *\n * Inputs:\n * - harnessRoot: repository root (templates/ + .mcp.json)\n * - projectDir: target project to receive AGENTS.md + opencode.json + .opencode/\n *\n * Outputs (under projectDir):\n * - AGENTS.md\n * - opencode.json\n * - .opencode/commands/<id>.md (dev-method skills as command fallback)\n *\n * SPEC: docs/specs/opencode-compat.md\n * Phase: C1 (transform orchestrator)\n */\n\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { basename, join } from \"node:path\";\nimport { backupFileIfChanged, ensureDir } from \"../fs-ops.js\";\nimport type { McpJson } from \"../mcp-merge.js\";\nimport { renderFillScaffold } from \"../project-claude-merge.js\";\nimport { renderAgentsMd } from \"./agents-md.js\";\nimport { renderCommandFromSkill } from \"./commands.js\";\nimport { renderOpencodeJson } from \"./opencode-json.js\";\n\nexport interface OpencodeTransformParams {\n harnessRoot: string;\n projectDir: string;\n /**\n * v26.87.0 — dev-method skill ids 선택 목록. OpenCode 는 native skill 개념이 없어 각 skill 을\n * `.opencode/commands/<id>.md` 커맨드 fallback 으로 surface (description = skill frontmatter,\n * body = skill 본문). installer 가 `DEV_METHOD_SKILL_IDS` 필터로 채움.\n */\n selectedInternalSkills?: ReadonlyArray<string>;\n}\n\nexport interface OpencodeTransformReport {\n agentsMdPath: string;\n opencodeJsonPath: string;\n commandFiles: string[];\n}\n\nexport function runOpencodeTransform(params: OpencodeTransformParams): OpencodeTransformReport {\n const { harnessRoot, projectDir, selectedInternalSkills = [] } = params;\n\n const claudeMd = readRequired(join(harnessRoot, \"templates/CLAUDE.md\"));\n const agentsTemplate = readRequired(join(harnessRoot, \"templates/opencode/AGENTS.md.template\"));\n const opencodeTemplate = readRequired(\n join(harnessRoot, \"templates/opencode/opencode.json.template\"),\n );\n const projectName = basename(projectDir);\n const mcp = readOptionalJson(join(harnessRoot, \".mcp.json\"));\n\n // 1. AGENTS.md\n ensureDir(projectDir);\n const agentsMdPath = join(projectDir, \"AGENTS.md\");\n const agentsMdOut = renderAgentsMd({\n template: agentsTemplate,\n claudeMd,\n projectName,\n projectContext: renderFillScaffold(),\n });\n // 사용자가 채운 AGENTS.md 를 재설치(add 모드) 덮어쓰기 전 보존 — 루트 CLAUDE.md 와 대칭.\n backupFileIfChanged(agentsMdPath, agentsMdOut);\n writeFileSync(agentsMdPath, agentsMdOut);\n\n // 2. opencode.json\n const opencodeJsonPath = join(projectDir, \"opencode.json\");\n writeFileSync(opencodeJsonPath, renderOpencodeJson({ template: opencodeTemplate, mcp }));\n\n // 3. v26.87.0 — dev-method skills → .opencode/commands/<id>.md (command fallback).\n // OpenCode 는 native skill 개념이 없어 skill 을 커맨드로 surface.\n const cmdDir = join(projectDir, \".opencode/commands\");\n ensureDir(cmdDir);\n const commandFiles: string[] = [];\n for (const id of selectedInternalSkills) {\n const src = join(harnessRoot, \"templates/skills\", id, \"SKILL.md\");\n if (!existsSync(src)) {\n continue;\n }\n const target = join(cmdDir, `${id}.md`);\n // scripts/ sidecar = the skill shells out to an external CLI → needs a\n // bash-capable agent; plan (bash denied) made such commands a no-op.\n const shellDependent = existsSync(join(harnessRoot, \"templates/skills\", id, \"scripts\"));\n writeFileSync(\n target,\n renderCommandFromSkill(readFileSync(src, \"utf8\"), id, { shellDependent }),\n );\n commandFiles.push(target);\n }\n\n return { agentsMdPath, opencodeJsonPath, commandFiles };\n}\n\nfunction readRequired(path: string): string {\n if (!existsSync(path)) {\n throw new Error(`OpenCode transform: required source missing: ${path}`);\n }\n return readFileSync(path, \"utf8\");\n}\n\nfunction readOptionalJson(path: string): McpJson | null {\n if (!existsSync(path)) {\n return null;\n }\n try {\n return JSON.parse(readFileSync(path, \"utf8\")) as McpJson;\n } catch {\n return null;\n }\n}\n","/**\n * AGENTS.md transform — CLAUDE.md → AGENTS.md (OpenCode flavor).\n *\n * Mirrors `src/codex/agents-md.ts` logic (Codex와 OpenCode 둘 다 콜론 namespace\n * 미사용으로 slash rename 동일). 별도 파일로 유지 — 모듈 독립성.\n *\n * v26.70.0 — section 추출 → CLAUDE.md 전문 embed (`{PROJECT_RULES}`). codex/agents-md 와 동일 fix.\n */\n\n/** Rename Claude slash conventions (`/uzys:foo`) to OpenCode (`/uzys-foo`). */\nexport function renameSlashes(text: string): string {\n return text.replaceAll(\"/uzys:\", \"/uzys-\");\n}\n\nexport interface AgentsMdParams {\n template: string;\n claudeMd: string;\n projectName: string;\n /** Project-context fill scaffold — the same body shipped to the Claude Code CLAUDE.md. */\n projectContext: string;\n}\n\n/**\n * Render the OpenCode AGENTS.md output by embedding the full CLAUDE.md body.\n *\n * Placeholders (matches templates/opencode/AGENTS.md.template):\n * - {PROJECT_NAME} — basename of project dir\n * - {PROJECT_RULES} — full CLAUDE.md body (first h1 stripped)\n * - {PROJECT_CONTEXT} — project-specific fill scaffold (renderFillScaffold())\n */\nexport function renderAgentsMd(params: AgentsMdParams): string {\n const body = params.claudeMd.replace(/^#\\s+.*\\r?\\n/, \"\").trim();\n const replaced = params.template\n .replaceAll(\"{PROJECT_NAME}\", params.projectName)\n .replaceAll(\"{PROJECT_RULES}\", body)\n .replaceAll(\"{PROJECT_CONTEXT}\", params.projectContext);\n return renameSlashes(replaced);\n}\n","/**\n * Bundled SKILL.md → OpenCode `.opencode/commands/<id>.md` command fallback (bundled skills).\n *\n * OpenCode 는 native skill 개념이 없어 각 skill 을 커맨드로 surface:\n * - 파일명 = 슬래시 커맨드명 → `<id>.md`\n * - Frontmatter: `description` (skill frontmatter 에서) + `agent: plan|build`, `name` 필드 없음\n */\nimport { renameSlashes } from \"./agents-md.js\";\n\n/**\n * v26.87.0 — render an OpenCode command from a bundled, already-complete SKILL.md.\n * OpenCode has NO native skill concept, so each selected skill is surfaced as a\n * `.opencode/commands/<id>.md` command fallback: command frontmatter (`description`\n * from the skill's own frontmatter, `agent: …`) + the skill body.\n *\n * Unlike a uzys phase command, there is no slash phase — the id IS the command name\n * (filename). Body slashes are renamed (`/uzys:` → `/uzys-`) for consistency with the\n * other ports.\n *\n * v26.100.0 — `agent` is no longer a blanket `plan`. Dev-method skills are read-heavy\n * (plan is right), but shell-dependent consult skills (gemini-consult / codex-consult —\n * they work ONLY by shelling out to an external CLI) were a no-op under plan, whose\n * profile in templates/opencode/opencode.json.template denies bash. The caller derives\n * `shellDependent` from the skill's bundled `scripts/` sidecar dir (structural signal,\n * no hardcoded id list to drift) and such skills render `agent: build` (bash-capable).\n */\nexport function renderCommandFromSkill(\n source: string,\n id: string,\n opts?: { shellDependent?: boolean },\n): string {\n const { description, body } = parseSkillFrontmatter(source);\n const finalDescription = description || `${id} (dev-method skill, OpenCode command fallback)`;\n const escapedDesc = finalDescription.replace(/\"/g, '\\\\\"');\n const renamedBody = renameSlashes(body).trimEnd();\n const agent = opts?.shellDependent ? \"build\" : \"plan\";\n\n return [\n \"---\",\n `description: \"${escapedDesc}\"`,\n `agent: ${agent}`,\n \"---\",\n \"\",\n renamedBody,\n \"\",\n ].join(\"\\n\");\n}\n\n/**\n * Parse a complete SKILL.md: split frontmatter from body, extracting the `description`\n * scalar. Handles folded/literal block scalars (`description: >-` or `|`) where the value\n * spans subsequent indented lines — the dev-method skills use `>-`. Single-line\n * `description: \"...\"` is also supported.\n */\nfunction parseSkillFrontmatter(source: string): ParsedSource {\n const lines = source.split(/\\r?\\n/);\n if (lines[0] !== \"---\") {\n const firstLine = lines[0] ?? \"\";\n return { description: firstLine.trim(), body: lines.slice(1).join(\"\\n\") };\n }\n let secondDelimAt = -1;\n let description = \"\";\n for (let i = 1; i < lines.length; i++) {\n const line = lines[i] ?? \"\";\n if (line === \"---\") {\n secondDelimAt = i;\n break;\n }\n const inline = line.match(/^description:\\s*(.+)$/);\n if (!inline) {\n continue;\n }\n const raw = (inline[1] ?? \"\").trim();\n if (raw === \">-\" || raw === \">\" || raw === \"|\" || raw === \"|-\") {\n // Folded/literal block scalar — collect following more-indented lines, join folded.\n const collected: string[] = [];\n for (let j = i + 1; j < lines.length; j++) {\n const next = lines[j] ?? \"\";\n if (next === \"---\") {\n break;\n }\n if (next.trim() === \"\" || /^\\s/.test(next)) {\n collected.push(next.trim());\n } else {\n break; // next top-level key\n }\n }\n description = collected.join(\" \").replace(/\\s+/g, \" \").trim();\n } else {\n description = stripQuotes(raw);\n }\n }\n const body =\n secondDelimAt >= 0\n ? lines\n .slice(secondDelimAt + 1)\n .join(\"\\n\")\n .replace(/^\\n+/, \"\")\n : source;\n return { description, body };\n}\n\ninterface ParsedSource {\n description: string;\n body: string;\n}\n\nfunction stripQuotes(raw: string): string {\n const trimmed = raw.trim();\n if (trimmed.startsWith('\"') && trimmed.endsWith('\"')) {\n return trimmed.slice(1, -1);\n }\n return trimmed;\n}\n","/**\n * opencode.json transform — fill template + merge mcp.<name> from .mcp.json.\n *\n * Output: opencode.json (top-level `mcp.<name>` map; OpenCode 1:1 매핑).\n *\n * Codex `[mcp_servers.X]` TOML과 다르게 OpenCode는 JSON이라 Object spread\n * 만으로 충분 (TOML 직렬화 없음).\n */\n\nimport type { McpJson, McpServerConfig } from \"../mcp-merge.js\";\n\nexport interface RenderOpencodeJsonParams {\n /** Template content (templates/opencode/opencode.json.template). */\n template: string;\n /** Source `.mcp.json` (parsed). When provided, top-level `mcp.<name>` is replaced. */\n mcp?: McpJson | null;\n}\n\ninterface OpencodeConfig {\n $schema?: string;\n instructions?: string[];\n mcp?: Record<string, McpServerConfig>;\n command?: Record<string, unknown>;\n agent?: Record<string, unknown>;\n plugin?: string[];\n permission?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n/**\n * Substitute `mcp` in the template with entries from `.mcp.json`.\n * Other keys (`agent`, `command`, `plugin`, `permission`, `instructions`,\n * `$schema`) are preserved from the template.\n */\nexport function renderOpencodeJson(params: RenderOpencodeJsonParams): string {\n const config = parseTemplate(params.template);\n\n if (params.mcp) {\n config.mcp = { ...params.mcp.mcpServers };\n }\n\n return `${JSON.stringify(config, null, 2)}\\n`;\n}\n\nfunction parseTemplate(template: string): OpencodeConfig {\n try {\n return JSON.parse(template) as OpencodeConfig;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`opencode.json template invalid JSON: ${message}`);\n }\n}\n","/**\n * settings.json 부분 머지 — `.claude/settings.json` PreToolUse hook entry 추가.\n *\n * SPEC: docs/specs/karpathy-hook-autowire.md AC2/AC4 — opt-in 시 idempotent 등록.\n *\n * 사용처: karpathy-coder hook auto-wire (v0.6.0). 기존 매처 entry 보존 + 동일 command 중복 X.\n */\n\nexport interface ClaudeHookCommand {\n type: \"command\";\n command: string;\n async?: boolean;\n timeout?: number;\n}\n\nexport interface ClaudeHookMatcher {\n matcher?: string;\n hooks: ClaudeHookCommand[];\n}\n\nexport interface ClaudeSettings {\n // 기타 키 (statusLine, _comment 등) 보존 — 알 필요 없음\n [key: string]: unknown;\n hooks?: {\n [event: string]: ClaudeHookMatcher[];\n };\n}\n\n/**\n * PreToolUse 배열에 hook entry 추가 (idempotent). 기존 settings 객체는 mutation 안 함 (deep clone).\n *\n * 동작:\n * - hooks.PreToolUse 없음 → 생성\n * - matcher 일치하는 entry 없음 → 새 entry 추가\n * - matcher 일치 + command 동일한 hook 있음 → idempotent (변경 없음)\n * - matcher 일치 + command 다름 → hooks 배열에 append\n */\nexport function addPreToolUseHook(\n settings: ClaudeSettings,\n matcher: string,\n command: string,\n): ClaudeSettings {\n const next: ClaudeSettings = JSON.parse(JSON.stringify(settings));\n if (!next.hooks) {\n next.hooks = {};\n }\n if (!next.hooks.PreToolUse) {\n next.hooks.PreToolUse = [];\n }\n const preToolUse = next.hooks.PreToolUse;\n const existing = preToolUse.find((m) => m.matcher === matcher);\n const newHook: ClaudeHookCommand = { type: \"command\", command };\n if (existing) {\n if (existing.hooks.some((h) => h.command === command)) {\n return next; // idempotent — 동일 command 중복 X\n }\n existing.hooks.push(newHook);\n } else {\n preToolUse.push({ matcher, hooks: [newHook] });\n }\n return next;\n}\n","/**\n * update-mode.ts — Update / Add / Reinstall router 액션 처리.\n *\n * SPEC: docs/specs/cli-rewrite-completeness.md F5, F6\n * Source: bash setup-harness.sh@911c246~1 L460~573 (update mode 113 LOC)\n *\n * Update 모드 동작:\n * 1. backup: .claude/ → .claude.backup-<timestamp>/\n * 2. update_dir: target에 이미 존재하는 파일만 templates로 덮어쓰기 (Track 혼입 방지)\n * 3. prune_orphans: templates에 없는데 target에 있는 파일 제거 (예: 폐기된 rule)\n * 4. clean_stale_hook_refs: settings.json hook 참조 중 실존 파일 없는 것 제거\n *\n * 보존: .mcp.json (사용자 추가 항목), docs/SPEC.md, settings.local.json\n */\n\nimport {\n copyFileSync,\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n unlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { backupFile, listFilesRecursive } from \"./fs-ops.js\";\nimport {\n collectSkillHashes,\n hashContent,\n type InstallLog,\n readInstallLog,\n writeInstallLog,\n} from \"./install-log.js\";\nimport { DEFAULT_OPTIONS, type InstallSpec, type Track } from \"./types.js\";\n\nexport interface UpdateModeReport {\n /** 덮어쓰기된 파일 갯수 (디렉토리별). */\n updated: Record<string, number>;\n /** 제거된 orphan 파일명 목록 (디렉토리별). */\n pruned: Record<string, string[]>;\n /** 제거된 stale hook ref 파일명 목록. */\n staleHookRefs: string[];\n /** 갱신된 CLAUDE.md (true if updated). */\n claudeMdUpdated: boolean;\n /**\n * v26.126.0 (R-3a) — 사용자가 고쳐서 백업본을 남긴 스킬 파일 (`.claude/skills/` 상대경로).\n * 화면에 그대로 노출한다. 안 보이면 사용자는 자기 편집분이 어디 갔는지 알 수 없다.\n */\n skillsBackedUp: string[];\n}\n\n/**\n * Update 진입점이 쓰는 InstallSpec — **위저드와 `update` 명령이 공유한다.**\n *\n * update 는 `.claude/` 만 건드리므로 spec 에서 실제로 소비되는 건 `projectDir` 와\n * (보고용) `tracks` 뿐이다. `cli`/`options` 는 타입을 채우기 위한 값이라 어느 진입점이든\n * 같아야 하고, 두 곳에서 각자 리터럴로 쓰면 한쪽만 바뀌었을 때 조용히 갈린다 — 이 repo 가\n * 반복해서 당한 실패 모드라 처음부터 한 곳에 둔다.\n */\nexport function buildUpdateSpec(projectDir: string, tracks: ReadonlyArray<Track>): InstallSpec {\n return {\n tracks: [...tracks],\n options: DEFAULT_OPTIONS,\n cli: [\"claude\"],\n projectDir,\n };\n}\n\n/**\n * Update mode 메인 — backup은 caller가 별도 처리.\n *\n * @param projectDir 대상 프로젝트 root\n * @param templatesDir templates/ 디렉토리 (sync source)\n */\nexport function runUpdateMode(projectDir: string, templatesDir: string): UpdateModeReport {\n const claudeDir = join(projectDir, \".claude\");\n const report: UpdateModeReport = {\n updated: {},\n pruned: {},\n staleHookRefs: [],\n claudeMdUpdated: false,\n skillsBackedUp: [],\n };\n\n // 1) update_dir × 4 (rules/agents/commands/uzys/hooks)\n const targets = [\n {\n target: join(claudeDir, \"rules\"),\n source: join(templatesDir, \"rules\"),\n pattern: \".md\",\n label: \".claude/rules\",\n },\n {\n target: join(claudeDir, \"agents\"),\n source: join(templatesDir, \"agents\"),\n pattern: \".md\",\n label: \".claude/agents\",\n },\n {\n target: join(claudeDir, \"commands/uzys\"),\n source: join(templatesDir, \"commands/uzys\"),\n pattern: \".md\",\n label: \".claude/commands/uzys\",\n },\n {\n target: join(claudeDir, \"hooks\"),\n source: join(templatesDir, \"hooks\"),\n pattern: \".sh\",\n label: \".claude/hooks\",\n },\n ];\n\n for (const t of targets) {\n report.updated[t.label] = updateDir(t.target, t.source, t.pattern);\n report.pruned[t.label] = pruneOrphans(t.target, t.source, t.pattern);\n }\n\n // 1.5) `.claude/skills/` — v26.126.0 (R-3a · ADR-046).\n // 위 4개와 달리 스킬은 디렉터리 단위라 재귀가 필요하고, 사용자 편집분 판정이 붙는다.\n const skillSync = syncSkills(\n join(claudeDir, \"skills\"),\n join(templatesDir, \"skills\"),\n skillBaseline(projectDir),\n );\n report.updated[\".claude/skills\"] = skillSync.updated;\n report.skillsBackedUp = skillSync.backedUp;\n refreshSkillBaseline(projectDir);\n\n // 2) .claude/CLAUDE.md\n const claudeMd = join(claudeDir, \"CLAUDE.md\");\n const templateMd = join(templatesDir, \"CLAUDE.md\");\n if (existsSync(claudeMd) && existsSync(templateMd)) {\n copyFileSync(templateMd, claudeMd);\n report.claudeMdUpdated = true;\n }\n\n // 3) settings.json stale hook ref cleanup\n const settingsPath = join(claudeDir, \"settings.json\");\n if (existsSync(settingsPath)) {\n report.staleHookRefs = cleanStaleHookRefs(settingsPath, join(claudeDir, \"hooks\"));\n }\n\n return report;\n}\n\n/**\n * `target`에 이미 존재하는 파일 중 `source`에 동일 이름 있는 것만 덮어쓰기.\n * Track 혼입 방지 (새 파일 추가 X) — bash update_dir 등가.\n */\nexport function updateDir(target: string, source: string, ext: string): number {\n if (!existsSync(target) || !existsSync(source)) return 0;\n let count = 0;\n for (const file of readdirSync(target)) {\n if (!file.endsWith(ext)) continue;\n const targetFile = join(target, file);\n const sourceFile = join(source, file);\n if (existsSync(sourceFile)) {\n copyFileSync(sourceFile, targetFile);\n count++;\n }\n }\n return count;\n}\n\n/**\n * `.claude/skills/` 를 templates 기준으로 갱신한다 (v26.126.0 · R-3a · ADR-046).\n *\n * **설치된 스킬만 손댄다** — templates 에 있어도 target 에 그 스킬 디렉터리가 없으면 건너뛴다.\n * 스킬은 트랙/opt-in 으로 게이팅돼 설치되므로(`installer.ts` selectedInternalSkills), 전부\n * 복사하면 사용자가 고르지 않은 스킬이 딸려 들어간다 (`updateDir` 의 \"Track 혼입 방지\"와 같은 취지).\n *\n * 파일 단위 판정:\n * | 디스크 vs 기준선 | 뜻 | 처리 |\n * |---|---|---|\n * | 같다 | 사용자가 안 고쳤다 | 조용히 덮어쓴다 |\n * | 다르다 | 사용자가 고쳤다 | `.backup-<stamp>` 남기고 덮어쓴다 |\n * | 기준선 기록 없음 | 판정 불가 | 보수적으로 백업 (레거시 설치의 첫 update 1회) |\n *\n * **orphan prune 은 하지 않는다** — 스킬 디렉터리 안에는 사용자가 자기 참고 파일을 넣을 수 있고,\n * templates 에 없다는 이유로 지우면 그게 곧 사용자 파일 삭제다 (ADR-046 \"지우지 않는다\").\n */\nexport function syncSkills(\n targetDir: string,\n sourceDir: string,\n baseline: ReadonlyMap<string, string>,\n now: Date = new Date(),\n): { updated: number; backedUp: string[] } {\n if (!existsSync(targetDir) || !existsSync(sourceDir)) return { updated: 0, backedUp: [] };\n let updated = 0;\n const backedUp: string[] = [];\n\n for (const skill of readdirSync(sourceDir, { withFileTypes: true })) {\n if (!skill.isDirectory()) continue;\n const targetSkill = join(targetDir, skill.name);\n if (!existsSync(targetSkill)) continue; // 사용자가 선택하지 않은 스킬 — 새로 깔지 않는다\n\n for (const rel of listFilesRecursive(join(sourceDir, skill.name))) {\n const targetFile = join(targetSkill, rel);\n const next = readFileSync(join(sourceDir, skill.name, rel), \"utf8\");\n\n if (!existsSync(targetFile)) {\n // 스킬 안에 새로 생긴 파일 (예: references/ 추가) — 스킬 자체는 이미 설치돼 있다.\n mkdirSync(dirname(targetFile), { recursive: true });\n writeFileSync(targetFile, next);\n updated++;\n continue;\n }\n\n const current = readFileSync(targetFile, \"utf8\");\n if (current === next) continue; // 이미 최신 — 백업도 갱신도 불필요\n\n const recorded = baseline.get(`${skill.name}/${rel}`);\n if (recorded === undefined || hashContent(current) !== recorded) {\n backupFile(targetFile, now);\n backedUp.push(`${skill.name}/${rel}`);\n }\n writeFileSync(targetFile, next);\n updated++;\n }\n }\n return { updated, backedUp };\n}\n\n/** 설치 시점 기준선을 Map 으로. 기록이 없으면 빈 Map — 그때는 보수적 백업으로 폴백한다. */\nfunction skillBaseline(projectDir: string): ReadonlyMap<string, string> {\n const log = readInstallLog(projectDir);\n return new Map((log?.skillFiles ?? []).map((f) => [f.path, f.sha256]));\n}\n\n/**\n * 갱신 직후 기준선을 다시 찍는다.\n *\n * 이걸 빼면 다음 update 가 **방금 자기가 덮어쓴 파일**을 전부 \"사용자가 고쳤다\"로 오판해\n * 백업본을 매번 새로 쌓는다. update 는 install log 를 안 쓰는 단축 경로라\n * (`installer.ts` runUpdateInstall) 여기서 안 하면 아무도 안 한다.\n *\n * 로그가 없으면 **만들지 않는다** — update 가 설치 기록을 날조하면 uninstall 이 그걸 믿는다.\n */\nfunction refreshSkillBaseline(projectDir: string): void {\n const log = readInstallLog(projectDir);\n if (!log) return;\n const skillFiles = collectSkillHashes(projectDir);\n const next: InstallLog = { ...log };\n if (skillFiles.length > 0) next.skillFiles = skillFiles;\n else delete next.skillFiles;\n try {\n writeInstallLog(projectDir, next);\n } catch {\n // 기록 실패가 update 자체를 실패시키지는 않는다 (D16 — 설치/갱신 성공 우선과 같은 방침).\n }\n}\n\n/**\n * Templates에 없는데 target에 있는 파일 제거 (orphan prune) — bash prune_orphans 등가.\n */\nexport function pruneOrphans(target: string, source: string, ext: string): string[] {\n if (!existsSync(target) || !existsSync(source)) return [];\n const removed: string[] = [];\n for (const file of readdirSync(target)) {\n if (!file.endsWith(ext)) continue;\n const sourceFile = join(source, file);\n if (!existsSync(sourceFile)) {\n const targetFile = join(target, file);\n try {\n unlinkSync(targetFile);\n removed.push(file);\n } catch {\n // best-effort — read-only? 다음 update 시 재시도\n }\n }\n }\n return removed;\n}\n\n/**\n * settings.json의 PreToolUse/PostToolUse hooks 중 실존 파일 없는 hook script 참조 제거.\n * bash clean_stale_hook_refs 등가 (jq 의존 없이 JSON 직접 파싱).\n *\n * @returns 제거된 hook script 파일명 목록\n */\nexport function cleanStaleHookRefs(settingsPath: string, hooksDir: string): string[] {\n let settings: SettingsJson;\n try {\n settings = JSON.parse(readFileSync(settingsPath, \"utf8\")) as SettingsJson;\n } catch {\n return [];\n }\n const hookEvents = settings.hooks ?? {};\n const removed: string[] = [];\n const cleanedHooks: Record<string, HookEntry[]> = {};\n\n for (const [eventName, eventEntries] of Object.entries(hookEvents)) {\n if (!Array.isArray(eventEntries)) {\n cleanedHooks[eventName] = eventEntries; // non-array event — 그대로 보존\n continue;\n }\n cleanedHooks[eventName] = eventEntries\n .filter((entry) => Array.isArray(entry?.hooks))\n .map((entry) => ({\n ...entry,\n hooks: entry.hooks.filter((hook) => keepHookRef(hook, hooksDir, removed)),\n }))\n .filter((entry) => entry.hooks.length > 0); // stale 제거 후 hooks 빈 entry 제거\n }\n\n if (removed.length > 0) {\n const next: SettingsJson = { ...settings, hooks: cleanedHooks };\n writeFileSync(settingsPath, `${JSON.stringify(next, null, 2)}\\n`);\n }\n return removed;\n}\n\n/** hook command 가 실존 `.sh` 참조면 true. stale(파일 부재) 이면 removed 에 fname 수집 후 false. */\nfunction keepHookRef(hook: HookCommand, hooksDir: string, removed: string[]): boolean {\n const refMatch = (hook?.command ?? \"\").match(/\\/\\.claude\\/hooks\\/([^\"\\s/]+\\.sh)/);\n if (!refMatch?.[1]) return true; // hook script 참조 아님 — 보존\n const fname = refMatch[1];\n const exists = existsSync(join(hooksDir, fname));\n if (!exists && !removed.includes(fname)) removed.push(fname);\n return exists;\n}\n\ninterface HookCommand {\n type?: string;\n command?: string;\n}\n\ninterface HookEntry {\n matcher?: string;\n hooks: HookCommand[];\n}\n\ninterface SettingsJson {\n hooks?: Record<string, HookEntry[]>;\n [key: string]: unknown;\n}\n","/**\n * Install 출력 렌더 레이어 (v26.82.0, Phase R).\n *\n * `commands/install.ts` 가 979줄(cap 800 초과 — repo 최대 위반)로 비대해진 원인이\n * 렌더 함수 누적이었음 → 본 파일로 추출. install.ts 는 spec 검증 + 파이프라인\n * 오케스트레이션만, 여기는 화면 출력만. 동작 변경 0 (순수 이동).\n */\n\nimport { CATEGORY_TITLES, type Category } from \"../categories.js\";\nimport { targetsInclude } from \"../cli-targets.js\";\nimport { formatResidentCostLine, residentCost, summarizeContextCost } from \"../context-cost.js\";\nimport { assetRow, c, infoRow, padDisplay, sectionHeader, unifiedSection } from \"../design.js\";\nimport {\n assetCliSupport,\n assetReachesCli,\n EXTERNAL_ASSETS,\n type ExternalAsset,\n experimentalOptInCandidates,\n isAssetSelected,\n} from \"../external-assets.js\";\nimport type { AssetInstallResult } from \"../external-installer.js\";\nimport type { BaselineReport, InstallMode, InstallReport, ProgressEvent } from \"../installer.js\";\nimport { buildManifest } from \"../manifest.js\";\nimport { finalSelectedAssets, groupAssetsByCategory } from \"../preset-recommend.js\";\nimport type { CliBase, CliTargets, InstallSpec, OptionFlags } from \"../types.js\";\n\n/**\n * v26.78.1 — Summary `CLI` 행 라벨 (SSOT). spec.cli 에서 derive → 헤더와 일관.\n * 이전 pairwise if-chain 은 codex/opencode 만 열거해 `--cli antigravity` 가 \"Claude\" 로\n * 잘못 출력 (R2). 4 base 전부 매핑.\n */\nconst CLI_SUMMARY_LABELS: Record<CliBase, string> = {\n claude: \"Claude\",\n codex: \"Codex\",\n opencode: \"OpenCode\",\n antigravity: \"Antigravity\",\n};\n\n/** Callbacks for progressive rendering during runInstall (avoids \"Phase 1 silence\" UX). */\nexport interface PipelineCallbacks {\n onProgress?: (event: ProgressEvent) => void;\n externalDeps?: {\n onAssetStart?: (asset: ExternalAsset) => void;\n onAssetResult?: (result: AssetInstallResult) => void;\n };\n}\n\n/** createInstallRenderer 반환 — 스트리밍 콜백 + 렌더 상태 조회. */\nexport interface InstallRenderer {\n callbacks: PipelineCallbacks;\n /** External assets 헤더 출력 여부 — Summary 직전 trailing newline 판단용. */\n phase2HeaderPrinted(): boolean;\n}\n\n/**\n * install header (TARGET / TRACKS / CLI / SCOPE / OPTIONS / ASSETS) 렌더.\n * wizard 모드는 Step 3 review + Step 4 confirm 에서 이미 표시하므로 호출 안 함.\n */\nexport function renderInstallHeader(\n log: (msg: string) => void,\n spec: InstallSpec,\n mode?: InstallMode,\n): void {\n const headerLabel =\n mode === \"update\"\n ? \"uzys-agent-harness · update\"\n : mode === \"add\"\n ? \"uzys-agent-harness · add\"\n : mode === \"reinstall\"\n ? \"uzys-agent-harness · reinstall\"\n : \"uzys-agent-harness · install\";\n log(\"\");\n log(sectionHeader(headerLabel));\n log(\"\");\n log(infoRow(\"TARGET\", shortenPath(spec.projectDir)));\n log(infoRow(\"TRACKS\", spec.tracks.join(\", \")));\n log(infoRow(\"CLI\", spec.cli.join(\" · \")));\n // v26.64.0 (ADR-020) — SCOPE row. 사용자가 매 install 시 어디에 write 되는지 인지 (D16).\n {\n const effectiveScope = spec.scope ?? \"project\";\n const scopeMsg =\n effectiveScope === \"global\"\n ? \"Global — writes to ~/.claude/, ~/.codex/, npm -g\"\n : \"Project — current directory only (no global write)\";\n log(infoRow(\"SCOPE\", scopeMsg));\n }\n log(infoRow(\"OPTIONS\", formatOptions(spec)));\n // v26.82.0 (Phase R, S6) — merge 는 preset-recommend.ts 단일 구현 (이전 computeFinalAssets 중복).\n const finalAssets = finalSelectedAssets(spec.tracks, spec.userOverride);\n if (finalAssets.length > 0) {\n // v26.102.0 (ADR-031) — 선택 수와 실제 설치 수의 어긋남을 약속 시점에 고지 (SOD 리뷰 F3:\n // executive/codex 가 \"4 selected\" 약속 후 0 설치이던 불일치). 숨김 없이 분해만 병기.\n // 미지 id(검증은 install.ts 담당)는 도달 가능으로 취급 — 여기서 이중 판정하지 않는다.\n const unreachable = finalAssets.filter((id) => {\n const asset = EXTERNAL_ASSETS.find((a) => a.id === id);\n return asset ? !assetReachesCli(asset, spec.cli) : false;\n });\n const label =\n unreachable.length > 0\n ? `${finalAssets.length} selected (${unreachable.length} outside [${spec.cli.join(\", \")}] reach — not installed)`\n : `${finalAssets.length} selected`;\n log(infoRow(\"ASSETS\", label));\n for (const [cat, ids] of groupAssetsByCategory(finalAssets)) {\n log(` ${c.dim(`· ${cat}:`)} ${ids.join(\", \")}`);\n }\n // v26.103.0 (ADR-032) — Session-Start Context Cost NSM. 번들 스킬 = frontmatter 실측(~),\n // 외부 자산 = unmeasured 명시 (추정치를 실측처럼 표기 금지).\n const cost = formatResidentCostLine(\n residentCost(buildManifest(spec).filter((e) => e.applies(spec))),\n summarizeContextCost(finalAssets).unmeasuredCount,\n );\n if (cost) log(` ${c.dim(`· ${cost}`)}`);\n }\n log(\"\");\n}\n\n/**\n * runInstall 스트리밍 렌더 콜백 생성 — baseline 완료 시 즉시 Phase 1 rows 출력,\n * external 은 per-asset 스트리밍 + 카테고리 헤더 (ADR-016 grouped progress UX).\n */\nexport function createInstallRenderer(\n log: (msg: string) => void,\n spec: InstallSpec,\n verbose: boolean,\n): InstallRenderer {\n let phase2HeaderPrinted = false;\n // v26.55.0 — Phase 2 grouped progress UX (ADR-016). category 변경 시 ━━ <Title> ━━ 헤더 출력.\n // external-installer 가 카테고리 순서로 정렬해 호출 → 첫 번째 호출이 category 1 의 첫 자산.\n let currentCategory: Category | null = null;\n const callbacks: PipelineCallbacks = {\n onProgress: (event) => {\n if (event.type === \"baseline-complete\") {\n // v26.81.0 (ADR-022) — withEcc boolean 삭제 → ecc-plugin 자산 선택으로 판정 (hint 게이팅).\n // v26.102.0 (ADR-031) — \"선택 = 설치됨\" 은 claude 도달 시에만 성립: codex 단독에선\n // ecc-plugin 이 배제되므로 fallback 힌트가 계속 진실이어야 한다 (SOD 리뷰 F2).\n const claudeSelected = targetsInclude(spec.cli, \"claude\");\n const eccWillInstall =\n claudeSelected &&\n (isAssetSelected(\"ecc-plugin\", spec) || spec.options.withPrune === true);\n renderPhase1Rows(log, event.baseline, verbose, eccWillInstall, claudeSelected);\n } else if (event.type === \"external-start\" && event.assetCount > 0) {\n // v26.63.0 — phaseHeader → unifiedSection. count 헤더에 inline 표시.\n log(unifiedSection(`External assets (${event.assetCount})`));\n log(\"\");\n phase2HeaderPrinted = true;\n } else if (event.type === \"external-complete\") {\n // v26.102.0 (ADR-031, Batch3) — CLI 도달 불가로 시도조차 안 한 자산 고지.\n // 침묵 제외는 \"4-CLI 지원\" 광고와 실동작의 어긋남을 숨긴다 (no-false-ship).\n // 어휘 주의: \"skipped\"(설치 실패)와 구분해 \"not installed\" 사용, 사유는 각 자산의\n // 실 도달 범위에서 derive — \"claude-only\" 하드코딩 금지 (SOD 리뷰 F4/F7/Nit-4).\n const excluded = event.report.excludedByCli;\n if (excluded.length > 0) {\n if (!phase2HeaderPrinted) {\n // attempted=0 인 트랙(executive 등)에서 고지가 헤더 없이 떠도는 것 방지 (F8).\n log(unifiedSection(\"External assets (0)\"));\n phase2HeaderPrinted = true;\n }\n const bySupport = new Map<string, string[]>();\n for (const a of excluded) {\n const key = assetCliSupport(a).join(\"/\");\n bySupport.set(key, [...(bySupport.get(key) ?? []), a.id]);\n }\n log(\"\");\n for (const [support, ids] of bySupport) {\n log(\n ` ${c.dim(`· ${ids.length} asset(s) not installed — requires ${support}, selected [${spec.cli.join(\", \")}]: ${ids.join(\", \")}`)}`,\n );\n }\n }\n }\n },\n externalDeps: {\n onAssetStart: (asset) => {\n // v26.57.0 (F2) — 카테고리 헤더만 출력. 자산 시작 라인 (→) 제거 — ✓ 결과 한 라인으로 1 단위 명확화.\n if (asset.category !== currentCategory) {\n if (currentCategory !== null) log(\"\");\n log(` ${c.bold(`━━ ${CATEGORY_TITLES[asset.category]} ━━`)}`);\n currentCategory = asset.category;\n }\n },\n onAssetResult: (result) => {\n const meta = result.ok\n ? formatAssetMeta(result.asset, result.version)\n : (result.message ?? \"failed\");\n log(` ${assetRow(result.ok ? \"success\" : \"skip\", result.asset.id, meta)}`);\n },\n },\n };\n return { callbacks, phase2HeaderPrinted: () => phase2HeaderPrinted };\n}\n\n/** Update mode 단축 Summary — manifest copy / external 모두 skip 된 경로. */\nexport function renderUpdateSummary(log: (msg: string) => void, report: InstallReport): void {\n log(\"\");\n // v26.63.2 — Summary 도 unifiedSection 으로 통일 (━━ marker). Step 5 안 sub-section 들과 일관.\n log(unifiedSection(\"Summary\"));\n log(\"\");\n log(infoRow(\"STATUS\", c.green(\"Update complete\")));\n log(infoRow(\"MODE\", \"update\"));\n if (report.backup) {\n log(infoRow(\"BACKUP\", shortenPath(report.backup)));\n log(infoRow(\"ROLLBACK\", `rm -rf .claude && mv ${shortenPath(report.backup)} .claude`));\n }\n log(\"\");\n}\n\n/**\n * Codex / OpenCode / Antigravity 산출물 sub-section.\n * v26.78.1 (R2): antigravity 추가 — `--cli antigravity` 시 산출물 invisible 이던 버그 fix.\n * 산출물 report 가 없거나 해당 CLI 미선택 시 출력 없음 (이전 executeSpec 의 게이트 if 이동).\n */\nexport function renderCliArtifacts(\n log: (msg: string) => void,\n spec: InstallSpec,\n report: InstallReport,\n): void {\n const hasArtifacts = Boolean(report.codex || report.opencode || report.antigravity);\n const cliSelected =\n targetsInclude(spec.cli, \"codex\") ||\n targetsInclude(spec.cli, \"opencode\") ||\n targetsInclude(spec.cli, \"antigravity\");\n if (!hasArtifacts || !cliSelected) {\n return;\n }\n log(unifiedSection(formatCliPhaseTitle(spec.cli)));\n log(\"\");\n // AGENTS.md is shared across Codex/OpenCode — render once with shared note\n if (report.codex && report.opencode) {\n log(assetRow(\"success\", \"AGENTS.md\", \"shared (Codex + OpenCode)\"));\n } else if (report.codex || report.opencode) {\n log(assetRow(\"success\", \"AGENTS.md\", \"from .claude/CLAUDE.md\"));\n }\n if (report.codex) {\n log(assetRow(\"success\", \".codex/config.toml\", \"settings + [mcp_servers.*]\"));\n log(assetRow(\"success\", \".codex/hooks/\", `${report.codex.hookFiles.length} files`));\n if (report.codex.skillFiles.length > 0) {\n log(\n assetRow(\n \"success\",\n \".agents/skills/<id>/SKILL.md\",\n `${report.codex.skillFiles.length} skills`,\n ),\n );\n }\n // Codex global opt-in (D16) — config.toml trust entry, only when explicitly enabled.\n if (report.codexOptIn?.trustEntry.enabled) {\n const trust = report.codexOptIn.trustEntry;\n const kind = trust.status === \"error\" ? \"skip\" : \"success\";\n const meta =\n trust.status === \"registered\"\n ? '[projects.\"<dir>\"] trust_level=\"trusted\"'\n : trust.status === \"already-present\"\n ? \"already present\"\n : (trust.message ?? \"error\");\n log(assetRow(kind, \"~/.codex/config.toml trust entry\", meta));\n }\n }\n if (report.opencode) {\n log(assetRow(\"success\", \"opencode.json\", \"$schema + 5 keys\"));\n log(assetRow(\"success\", \".opencode/commands/\", `${report.opencode.commandFiles.length} files`));\n }\n // v26.78.1 (R2) — Antigravity 산출물: rules (항상) + dev-method skills.\n if (report.antigravity) {\n if (report.antigravity.rulesFile) {\n log(assetRow(\"success\", \".agents/rules/uzys-harness.md\", \"from .claude/CLAUDE.md\"));\n }\n if (report.antigravity.skillFiles.length > 0) {\n log(\n assetRow(\n \"success\",\n \".agents/skills/<id>/SKILL.md\",\n `${report.antigravity.skillFiles.length} skills`,\n ),\n );\n }\n }\n log(\"\");\n}\n\n/** 최종 Summary (STATUS / TRACKS / CLI / HOOK / WARN / OPT-IN / NEXT). */\nexport function renderFinalSummary(\n log: (msg: string) => void,\n spec: InstallSpec,\n report: InstallReport,\n fromWizard: boolean,\n): void {\n // v26.63.2 — Summary 도 unifiedSection 으로 통일 (━━ marker).\n log(unifiedSection(\"Summary\"));\n log(\"\");\n log(infoRow(\"STATUS\", c.green(\"Install complete\")));\n log(infoRow(\"TRACKS\", report.installedTracks.join(\", \")));\n // v26.63.4 (P3): install header `CLI` 와 Summary `CLIs` 라벨 불일치 → `CLI` 로 통일.\n // v26.78.1 (R2): pairwise if-chain → spec.cli derive. antigravity 누락 + claude 무조건\n // prepend(claude 미선택 시에도 \"Claude\" 표기) 버그 fix. 헤더와 동일 SSOT.\n log(infoRow(\"CLI\", spec.cli.map((b) => CLI_SUMMARY_LABELS[b]).join(\" · \")));\n // v26.78.1 (R1) — karpathy hook opt-in 결과 렌더. null = 미opt-in(표시 안 함).\n // 이전엔 wired=false(plugin install 실패 등)여도 무음 → 사용자가 hook 안 깔린 걸\n // 모른 채 \"Install complete\" 만 봄 (Rule 12 fail-loud 위반).\n if (report.karpathyHook) {\n const kh = report.karpathyHook;\n if (kh.wired) {\n log(infoRow(\"HOOK\", c.green(\"karpathy-coder pre-commit hook wired\")));\n } else {\n log(infoRow(\"HOOK\", c.yellow(`karpathy hook skipped — ${kh.reason ?? \"unknown\"}`)));\n }\n }\n if (report.external && report.external.skipped > 0) {\n log(\"\");\n log(\n infoRow(\n \"WARN\",\n c.yellow(\n `${report.external.skipped} external asset${report.external.skipped > 1 ? \"s\" : \"\"} skipped (see Phase 2 above)`,\n ),\n ),\n );\n }\n // v26.102.0 (ADR-031) — v26.88.0 의 NOTE(plugin-kind 만 자체 재계산)를 대체: SSOT =\n // report.external.excludedByCli. 구 NOTE 는 ⊘ 고지와 다른 계산식(shell-script 누락)이라\n // 같은 화면에서 숫자가 어긋났고, claude 를 함께 골라 실제 설치된 경우에도 \"not installed\"\n // 를 찍었다 (SOD 리뷰 F4 — no-false-ship \"동일 목록 2곳 하드코딩 금지\").\n if (report.external && report.external.excludedByCli.length > 0) {\n const excluded = report.external.excludedByCli;\n log(\"\");\n log(\n infoRow(\n \"EXCLUDED\",\n c.dim(\n `${excluded.length} asset${excluded.length > 1 ? \"s\" : \"\"} not installed — outside [${spec.cli.join(\", \")}] reach: ${excluded.map((a) => a.id).join(\", \")}`,\n ),\n ),\n );\n }\n // v26.71.1 — experimental(T3) opt-in discoverability (Transparent Defaults — 숨김 0건).\n // 비대화형(--track) 에서 condition 은 맞지만 T3 라 default 제외된 자산을 --with 안내.\n // wizard 모드는 이미 ⚠ 배지로 노출하므로 skip.\n if (!fromWizard) {\n const optIn = experimentalOptInCandidates(spec);\n if (optIn.length > 0) {\n log(\"\");\n log(\n infoRow(\n \"OPT-IN\",\n c.dim(\n `${optIn.length} experimental available — add with --with <id>: ${optIn.map((a) => a.id).join(\", \")}`,\n ),\n ),\n );\n }\n }\n log(\"\");\n const primary = (spec.cli.includes(\"claude\") ? \"claude\" : spec.cli[0]) ?? \"claude\";\n const label = CLI_SUMMARY_LABELS[primary];\n log(infoRow(\"NEXT\", `Open ${c.bold(label)} — installed rules & skills are now active`));\n const scaffoldFiles = scaffoldFilesForCli(spec.cli);\n if (scaffoldFiles.length > 0) {\n log(\n infoRow(\n \"FILL\",\n `${scaffoldFiles.map((f) => c.bold(f)).join(\" · \")} — a fill-in scaffold. Open and paste each ${c.bold(\"<!-- FILL: … -->\")} prompt to your agent to tailor it to this project`,\n ),\n );\n }\n log(\"\");\n}\n\n/**\n * Which project-context scaffold files a given CLI selection actually writes:\n * `CLAUDE.md` only for a claude install, `AGENTS.md` only for a non-claude CLI.\n * The FILL hint must name only files that were written — advertising a file that\n * a given `--cli` never produced is the no-false-ship \"advertised ≠ real\" trap.\n */\nexport function scaffoldFilesForCli(cli: ReadonlyArray<CliBase>): string[] {\n const files: string[] = [];\n if (cli.includes(\"claude\")) {\n files.push(\"CLAUDE.md\");\n }\n if (cli.some((target) => target !== \"claude\")) {\n files.push(\"AGENTS.md\");\n }\n return files;\n}\n\nfunction formatAssetMeta(asset: ExternalAsset, version?: string): string {\n // v26.56.0 (F3) — description 제거. onAssetStart 의 → 라인이 이미 description 표시.\n // result row 는 method + source 만 간결하게 → terminal 120 char 안 wrap 방지.\n // v26.59.0 — plugin / npm-global 에 한해 version 표시 (path 기반 추출).\n const m = asset.method;\n const v = version ? ` ${c.dim(`v${version.replace(/^v/, \"\")}`)}` : \"\";\n switch (m.kind) {\n case \"skill\":\n // v26.63.3 (clarify M1): skill name 이 asset id 와 동일하면 중복 segment 생략.\n // \"skill · pbakaus/impeccable · impeccable\" → \"skill · pbakaus/impeccable\"\n if (m.skill && m.skill !== asset.id) return `skill · ${m.source} · ${m.skill}`;\n return `skill · ${m.source}`;\n case \"plugin\":\n return `plugin · ${m.pluginId}${v}`;\n case \"npm\":\n // A2 (Promise audit) — ADR-020 후 npm 자산 default 는 `--save-dev`(project), `-g` 는 global scope 만.\n // 라벨에 \"-g\" 고정은 scope 거짓 표기 → scope-중립 \"npm\" 으로 정정.\n // v26.80.0 — pinned 버전 표기 (Transparent Defaults: 실행되는 정확한 버전 노출).\n return `npm · ${m.pkg}@${m.version}`;\n case \"npx-run\":\n return `npx · ${m.cmd}@${m.version}`;\n case \"shell-script\":\n return `bash · ${m.script}`;\n case \"internal\":\n // v26.81.0 (ADR-022) — 내부 템플릿 자산 (Phase 1 manifest 가 설치 주체).\n return `internal · templates (${m.key})`;\n }\n}\n\n/**\n * Phase 1 rows 출력. baseline-complete progress event에서 호출 — 외부 자산 설치\n * 시작 전 즉시 화면에 표시되어야 한다 (멈춰 보임 방지).\n */\nfunction renderPhase1Rows(\n log: (msg: string) => void,\n baseline: BaselineReport,\n verbose = false,\n withEcc = false,\n // v26.102.0 (ADR-031) — ecc 힌트의 `--with ecc-plugin` 안내는 claude 도달 시에만 참\n // (plugin 은 claude 전용 — codex 단독에선 그 명령이 no-op, SOD 리뷰 F2).\n claudeSelected = true,\n): void {\n // Update mode rows\n if (baseline.updateMode) {\n if (baseline.backup) {\n log(assetRow(\"success\", \"backup\", shortenPath(baseline.backup)));\n }\n for (const [dir, count] of Object.entries(baseline.updateMode.updated)) {\n if (count > 0) log(assetRow(\"success\", dir, `${count} files updated`));\n }\n for (const [dir, removed] of Object.entries(baseline.updateMode.pruned)) {\n if (removed.length > 0) {\n log(assetRow(\"skip\", `${dir} orphan prune`, `${removed.length} removed`));\n }\n }\n if (baseline.updateMode.claudeMdUpdated) {\n log(assetRow(\"success\", \".claude/CLAUDE.md\", \"refreshed from template\"));\n }\n // v26.126.0 (R-3a) — 편집분을 백업했다는 사실은 **반드시 화면에 남긴다**. 갱신 건수만 보이면\n // 사용자는 자기가 고친 내용이 어디로 갔는지 알 수 없고, 그게 R-3a 를 만든 침묵과 같은 실패다.\n if (baseline.updateMode.skillsBackedUp.length > 0) {\n log(\n assetRow(\n \"skip\",\n \".claude/skills edited files\",\n `${baseline.updateMode.skillsBackedUp.length} backed up as *.backup-<time>`,\n ),\n );\n }\n if (baseline.updateMode.staleHookRefs.length > 0) {\n log(\n assetRow(\n \"skip\",\n \"settings.json stale hook refs\",\n `${baseline.updateMode.staleHookRefs.length} removed`,\n ),\n );\n }\n return;\n }\n\n // Fresh / add / reinstall — Phase 1 rows\n // audit SEC-1/CODE-2 — 기존 settings.json·CLAUDE.md 를 덮어쓰기 전 백업했으면 fail-loud 노출.\n if (baseline.backups) {\n for (const b of baseline.backups) {\n log(assetRow(\"success\", \"backup\", shortenPath(b)));\n }\n }\n // v26.57.1 (F2) — multi-line 구조 (header + use + files). visual hierarchy + width-safe.\n // 사용자 image 검증 (2026-05-17): 단일 라인 description 이 width 좁을 때 wrap → 들여쓰기 깨짐.\n const cats = baseline.categories;\n if (cats) {\n // v26.63.0 — files 라인은 verbose 옵션 시만. 기본은 카운트 + use 1 줄.\n // v26.63.2 — polish: label + count 칼럼 fixed-width 정렬 (28 char). spacing scale 일관.\n const phase1Row = (label: string, count: number, useText: string, files?: string[]) => {\n const labelCol = `${c.bold(label)} ${c.dim(`(${count})`)}`;\n const padded = padDisplay(labelCol, 28);\n log(` ${c.green(\"✓\")} ${padded} ${c.dim(useText)}`);\n if (verbose && files && files.length > 0) {\n log(` ${c.dim(\"└ files:\")} ${c.dim(files.join(\", \"))}`);\n }\n };\n\n if (cats.rules.length > 0) {\n phase1Row(\n \"rules\",\n cats.rules.length,\n \"coding · git/PR · tests · ship checklist · MCP policy\",\n cats.rules,\n );\n }\n if (cats.agents.length > 0) {\n // v26.63.3 (clarify H3): SOD jargon 보강 — independent verifier 명시.\n // v26.63.3 (distill H2): \"Without ECC plugin...\" 반복 제거 — section footer 통합.\n phase1Row(\n \"agents\",\n cats.agents.length,\n \"SOD reviewer (opus, independent verifier) + 3 base\",\n cats.agents,\n );\n }\n if (cats.hooks.length > 0) {\n phase1Row(\n \"hooks\",\n cats.hooks.length,\n \"session-start · spec-drift · checkpoint · mcp-pre-exec (security)\",\n cats.hooks,\n );\n }\n if (cats.commands > 0) {\n phase1Row(\"commands\", cats.commands, \"/ecc:* (ECC plugin OFF fallback)\");\n }\n if (cats.skills.length > 0) {\n phase1Row(\n \"skills\",\n cats.skills.length,\n \"north-star · gh-issue-workflow · ui-visual-review · cl-v2 (modified)\",\n cats.skills,\n );\n }\n } else {\n // v0.6.0 backwards compat — categories 없는 fakeReport 등\n log(assetRow(\"success\", \"rules + hooks + commands + agents\", `${baseline.filesCopied} files`));\n log(assetRow(\"success\", \"skeleton\", `${baseline.dirsCopied} dirs`));\n }\n // v26.63.4 (P3): Templates section 의 assetRow 호출 labelWidth=28 명시 → phase1Row 와 column 정렬.\n // default 40 은 External assets 의 긴 asset id (python-performance-optimization 등) 용 — 별개.\n const TEMPLATES_COL = 28;\n if (baseline.rootClaudeMd) {\n const n = baseline.rootClaudeMd.tracks.length;\n log(\n assetRow(\n \"success\",\n \"CLAUDE.md (root)\",\n `fill-in scaffold · ${n} track${n > 1 ? \"s\" : \"\"} noted`,\n TEMPLATES_COL,\n ),\n );\n }\n // v26.108.0 (ADR-037) — CI 스캐폴드 (opt-in). no-clobber: 기존 파일 보존은 skip 행으로\n // 정직 보고 (숨기면 \"설치됨\" 오인 — no-false-ship).\n if (baseline.ciScaffold) {\n for (const f of baseline.ciScaffold.written) {\n log(assetRow(\"success\", f, \"CI scaffold (fill-in template)\", TEMPLATES_COL));\n }\n for (const f of baseline.ciScaffold.skippedExisting) {\n log(assetRow(\"skip\", f, \"exists — preserved (no overwrite)\", TEMPLATES_COL));\n }\n }\n if (baseline.skipped > 0) {\n log(\n assetRow(\n \"skip\",\n \"manifest entries (applies → false)\",\n `${baseline.skipped} skipped`,\n TEMPLATES_COL,\n ),\n );\n }\n if (baseline.backup) {\n log(assetRow(\"success\", \"backup\", shortenPath(baseline.backup), TEMPLATES_COL));\n }\n const mcpList = baseline.mcpServers.join(\", \") || \"(none)\";\n log(assetRow(\"success\", \".mcp.json\", mcpList, TEMPLATES_COL));\n if (baseline.envFiles.mcpAllowlist) {\n log(\n assetRow(\n \"success\",\n \".mcp-allowlist\",\n `${baseline.envFiles.mcpAllowlist.length} servers (D35 opt-in gate)`,\n TEMPLATES_COL,\n ),\n );\n }\n // v26.63.3 (distill H2): ECC fallback hint — Templates section 마지막에 통합 표시.\n // withEcc=true (ECC plugin opt-in) 사용자에게는 hint 미표시.\n if (!withEcc && baseline.categories) {\n log(\"\");\n log(\n ` ${c.dim(\"·\")} ${c.dim(\"ECC plugin not selected — cherry-pick fallback active (up to 4 agents + 8 skills + 3 commands)\")}`,\n );\n if (claudeSelected) {\n log(` ${c.dim(\"·\")} ${c.dim(\"Use --with ecc-plugin to install ECC plugin instead\")}`);\n }\n }\n if (baseline.envFiles.envExampleCreated) {\n log(assetRow(\"success\", \".env.example\", \"Supabase token guide\"));\n }\n if (baseline.envFiles.gitignoreEnvAdded) {\n log(assetRow(\"success\", \".gitignore\", \"+ .env\"));\n }\n if (baseline.envFiles.gitignoreNpxSkillsAdded.length > 0) {\n log(\n assetRow(\n \"success\",\n \".gitignore\",\n `+ ${baseline.envFiles.gitignoreNpxSkillsAdded.join(\" \")} (npx skills universal install)`,\n ),\n );\n }\n log(\"\");\n}\n\nfunction formatOptions(spec: InstallSpec): string {\n // v26.81.0 (ADR-022) — 자산 플래그 13종 삭제 후 동작 옵션만. 키 순회로 enumeration drift 차단.\n const flags = (Object.keys(spec.options) as Array<keyof OptionFlags>)\n .filter((k) => spec.options[k])\n .map((k) =>\n k\n .replace(/^with/, \"\")\n .replace(/([a-z])([A-Z])/g, \"$1-$2\")\n .toLowerCase(),\n );\n // v26.63.3 (clarify H1): \"(defaults only)\" 모호 → \"(none added)\" 명료.\n return flags.length > 0 ? flags.join(\", \") : c.dim(\"(none added)\");\n}\n\n/**\n * Shorten an absolute path for display:\n * /Users/foo/bar → ~/bar (HOME relative)\n * /private/tmp/x.X → /tmp/x.X\n * /a/very/long/path → …/long/path (≥3 segs from end if > 50 chars)\n *\n * v26.48.0 — export for direct unit test (branch coverage 복구).\n */\nexport function shortenPath(p: string): string {\n if (p.length <= 50) return p;\n const home = process.env.HOME ?? \"\";\n if (home && p.startsWith(home)) {\n const rel = p.slice(home.length);\n return `~${rel.startsWith(\"/\") ? \"\" : \"/\"}${rel}`;\n }\n // private/tmp prefix on macOS — drop /private\n if (p.startsWith(\"/private/tmp/\")) {\n return p.slice(\"/private\".length);\n }\n // Last 3 segments\n const segs = p.split(\"/\").filter(Boolean);\n if (segs.length > 3) {\n return `…/${segs.slice(-3).join(\"/\")}`;\n }\n return p;\n}\n\n/**\n * v0.7.0 — CliTargets에서 codex/opencode 포함 여부에 따라 title 결정.\n * Phase 3는 codex 또는 opencode 1개 이상 포함 시 호출됨.\n * v26.48.0 — export for direct unit test (branch coverage 복구).\n */\nexport function formatCliPhaseTitle(targets: CliTargets): string {\n // v26.78.1 (R2) — antigravity 추가. 누락 시 `--cli antigravity` 산출물 헤더가\n // \"CLI artifacts\" generic 으로만 떠 antigravity 가 invisible 했음.\n const labels: string[] = [];\n if (targets.includes(\"codex\")) labels.push(\"Codex\");\n if (targets.includes(\"opencode\")) labels.push(\"OpenCode\");\n if (targets.includes(\"antigravity\")) labels.push(\"Antigravity\");\n return labels.length > 0 ? `${labels.join(\" + \")} artifacts` : \"CLI artifacts\";\n}\n","/**\n * Preset → Step 2 의 추천 ✓ 자산 매핑 (v26.44.0).\n *\n * Step 1 에서 선택된 preset 들의 condition 을 만족하는 외부 자산(plugin/skill/npm/npx)\n * 의 id 를 반환한다. Step 2 multiselect 의 초기 체크 상태에 사용.\n *\n * Option-gated 자산은 추천에 포함 X — 사용자가 의식적으로 토글해야 함\n * (superpowers, addy-agent-skills, ECC suite 등).\n */\n\nimport { assetTrustTier, EXTERNAL_ASSETS, filterApplicableAssets } from \"./external-assets.js\";\nimport { DEFAULT_OPTIONS, type InstallSpec, type Track } from \"./types.js\";\n\n/**\n * preset 1개 또는 N개 선택 시 추천 ✓ 자산 id 의 안정 정렬 배열.\n * - DEFAULT_OPTIONS 로 호출 → option-gated 자산은 모두 false → 추천에서 제외.\n * - v26.71.0 (PRD v26-71 R6) — experimental(T3) 자산은 pre-check 제외 (opt-in). official/vetted 만 추천.\n * - 결과는 자산 id 알파벳 정렬 (deterministic).\n */\nexport function recommendedExternalAssets(presets: ReadonlyArray<Track>): ReadonlyArray<string> {\n if (presets.length === 0) {\n return [];\n }\n const apps = filterApplicableAssets(EXTERNAL_ASSETS, {\n tracks: presets,\n options: DEFAULT_OPTIONS,\n });\n return apps\n .filter((a) => assetTrustTier(a.id) !== \"experimental\")\n .map((a) => a.id)\n .sort();\n}\n\n/**\n * v26.82.0 (Phase R, S6) — preset recommended + userOverride 적용 후 최종 선택 자산 id (정렬).\n * 이전엔 install.ts `computeFinalAssets` ↔ interactive.ts `formatSummary` 에 동일 merge 가\n * 중복 구현 (v26.62.4 주석이 본 위치를 통합 지점으로 지목). 우선순위: forceExclude > forceInclude.\n */\nexport function finalSelectedAssets(\n tracks: ReadonlyArray<Track>,\n userOverride?: InstallSpec[\"userOverride\"],\n): string[] {\n const selected = new Set(recommendedExternalAssets(tracks));\n if (userOverride) {\n for (const id of userOverride.forceExclude) selected.delete(id);\n for (const id of userOverride.forceInclude) selected.add(id);\n }\n return [...selected].sort();\n}\n\n/**\n * v26.82.0 (Phase R, S6) — 자산 id 를 카테고리별로 묶어 정렬된 entries 반환 (출력 hierarchy 용).\n * install header ASSETS row 와 wizard confirm summary 가 공유.\n */\nexport function groupAssetsByCategory(assetIds: ReadonlyArray<string>): Array<[string, string[]]> {\n const map = new Map<string, string[]>();\n for (const id of assetIds) {\n const asset = EXTERNAL_ASSETS.find((a) => a.id === id);\n const cat = asset?.category ?? \"other\";\n const list = map.get(cat) ?? [];\n list.push(id);\n map.set(cat, list);\n }\n return [...map.entries()];\n}\n","/**\n * List command — v26.123.0 (F-1b).\n *\n * `.claude/.harness-install.json` 을 사람이 읽는 표로 출력한다. 기록은 v26.64.0(ADR-020)부터\n * 있었지만 **사용자가 볼 수단이 없었다** — 무엇이 깔렸는지 알 수 없으면 항목별 제거(`--only`)의\n * 입력값도 알 수 없다. 본 커맨드가 그 입력값(자산 id)을 보여주는 곳이다.\n *\n * 읽기 전용 — 어떤 파일도 쓰지 않는다.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport { c, padDisplay, status } from \"../design.js\";\nimport {\n hashContent,\n type InstallLog,\n type InstallLogAsset,\n type InstallLogRootFile,\n installLogPath,\n readInstallLog,\n} from \"../install-log.js\";\n\nexport interface ListOptions {\n projectDir?: string;\n}\n\nexport interface ListActionDeps {\n log?: (msg: string) => void;\n err?: (msg: string) => void;\n exit?: (code: number) => never;\n}\n\nexport function listAction(options: ListOptions = {}, deps: ListActionDeps = {}): void {\n const log = deps.log ?? console.log;\n const err = deps.err ?? console.error;\n const exit = deps.exit ?? ((code: number) => process.exit(code) as never);\n\n const projectDir = resolve(options.projectDir ?? process.cwd());\n const installLog = readInstallLog(projectDir);\n if (!installLog) {\n err(status.failure(c.red(`ERROR: install log not found at ${installLogPath(projectDir)}`)));\n err(c.dim(\" Nothing installed here by agent-harness.\"));\n exit(1);\n return;\n }\n\n log(\"\");\n log(c.bold(\"uzys-agent-harness · installed\"));\n log(\"\");\n log(c.dim(` installed: ${installLog.installedAt}`));\n log(c.dim(` scope: ${installLog.scope}`));\n log(c.dim(` tracks: ${installLog.spec.tracks.join(\", \") || \"(none)\"}`));\n log(c.dim(` cli: ${installLog.spec.cli.join(\", \") || \"(none)\"}`));\n log(\"\");\n\n log(c.bold(` Assets (${installLog.assets.length})`));\n if (installLog.assets.length === 0) {\n log(c.dim(\" (none — 내부 템플릿만 설치됨)\"));\n }\n for (const line of formatAssetRows(installLog.assets)) {\n log(line);\n }\n\n log(\"\");\n log(c.bold(\" Templates\"));\n for (const line of formatTemplateRows(installLog, projectDir)) {\n log(line);\n }\n\n const rootRows = formatRootFileRows(installLog.rootFiles ?? [], projectDir);\n if (rootRows.length > 0) {\n log(\"\");\n log(c.bold(\" Root files\"));\n log(c.dim(\" (uninstall 이 지우지 않는다 — 사용자 내용이 섞인다)\"));\n for (const line of rootRows) log(line);\n }\n\n log(\"\");\n log(c.dim(\" remove one: agent-harness uninstall --only <id>\"));\n log(c.dim(\" remove all: agent-harness uninstall\"));\n log(\"\");\n exit(0);\n}\n\n/** 자산 행 — id / method / scope / version. global 은 uninstall 이 자동 삭제하지 않으므로 표시한다. */\nexport function formatAssetRows(assets: ReadonlyArray<InstallLogAsset>): string[] {\n const idWidth = Math.max(0, ...assets.map((a) => a.id.length));\n const methodWidth = Math.max(0, ...assets.map((a) => a.method.length));\n return assets.map((a) => {\n const marker = a.scope === \"global\" ? c.yellow(\"!\") : c.green(\"✓\");\n const version = a.version ? c.dim(` v${a.version}`) : \"\";\n const note = a.scope === \"global\" ? c.yellow(\" (manual removal — D16)\") : \"\";\n return ` ${marker} ${padDisplay(a.id, idWidth)} ${c.dim(padDisplay(a.method, methodWidth))} ${c.dim(a.scope)}${version}${note}`;\n });\n}\n\n/** templates 행 — 디렉토리 + root CLAUDE.md 수정 여부(uninstall 이 보존할지 여부와 같은 판정). */\nfunction formatTemplateRows(log: InstallLog, projectDir: string): string[] {\n const dirs = [log.templates.claudeDir, log.templates.codexDir, log.templates.opencodeDir].filter(\n (d): d is string => Boolean(d),\n );\n const rows = [` ${c.dim(dirs.join(\" \"))}`];\n const rootMd = log.templates.rootClaudeMd;\n if (rootMd) {\n const path = join(projectDir, rootMd.path);\n const modified = existsSync(path) && hashContent(readFileSync(path, \"utf8\")) !== rootMd.sha256;\n rows.push(\n modified\n ? ` ${c.dim(rootMd.path)} ${c.yellow(\"(수정됨 — uninstall 시 보존)\")}`\n : ` ${c.dim(rootMd.path)}`,\n );\n }\n return rows;\n}\n\n/**\n * v26.124.0 (F-1f) — `.claude/` 밖 루트 파일 행. uninstall 안내와 같은 규율로\n * **실재하는 것만** 낸다 (사용자가 이미 지운 파일을 인벤토리에 남기면 그게 거짓 기록이다).\n */\nfunction formatRootFileRows(\n rootFiles: ReadonlyArray<InstallLogRootFile>,\n projectDir: string,\n): string[] {\n const present = rootFiles.filter((f) => existsSync(join(projectDir, f.path)));\n const width = Math.max(0, ...present.map((f) => f.path.length));\n return present.map(\n (f) =>\n ` ${c.dim(padDisplay(f.path, width))} ${c.dim(f.change === \"created\" ? \"생성\" : \"병합\")} ${c.dim(f.notes.join(\" / \"))}`,\n );\n}\n\nexport function registerListCommand(cli: import(\"../cli.js\").Cli): void {\n cli\n .command(\"list\", \"Show what agent-harness installed in this project\")\n .option(\"--project-dir <path>\", \"[Project] Target project directory\", {\n default: process.cwd(),\n })\n /* v8 ignore next 3 — cac action callback. listAction 자체는 별도 tests 로 검증. */\n .action((options: ListOptions) => {\n listAction(options);\n });\n}\n","/**\n * Uninstall command — v26.64.0 (ADR-020).\n *\n * 동작:\n * 1. `.claude/.harness-install.json` 읽기.\n * 2. assets[] 별 reverse:\n * - scope=project: 실제 reverse (`claude plugin uninstall --scope project`, `npm uninstall`, fs rm).\n * - scope=global: 안내만 (D16 — 글로벌 영역 자동 삭제 금지). 사용자가 직접 명령 실행.\n * 3. templates 폴더 rm (`.claude/`, `.codex/`, `.opencode/`) — `--keep-templates` 시 보존.\n * 4. install log 자체도 함께 제거.\n *\n * 옵션:\n * --dry-run 실제 변경 없이 reverse list 만 출력.\n * --keep-templates `.claude/`, `.codex/`, `.opencode/` 보존.\n * --only <ids> v26.123.0 (F-1c) — 항목별 제거. templates 미변경 + 로그는 남은 자산으로 재기록.\n *\n * 안전:\n * - log 없으면 명확 에러 + early exit.\n * - scope=global 자산은 절대 자동 삭제 X (D16).\n * - 되돌리기에 성공한 것만 로그에서 뺀다. 자동 경로가 없거나 실패한 자산은 기록에 남기고,\n * 아무것도 못 되돌렸으면 성공으로 보고하지 않는다 (no-false-ship).\n */\n\nimport { type SpawnSyncReturns, spawnSync } from \"node:child_process\";\nimport { existsSync, readFileSync, rmSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport { c, status } from \"../design.js\";\nimport { skillsCliSpec } from \"../external-installer.js\";\nimport {\n hashContent,\n type InstallLog,\n type InstallLogAsset,\n type InstallLogRootFile,\n installLogPath,\n readInstallLog,\n writeInstallLog,\n} from \"../install-log.js\";\nimport { KARPATHY_ASSET_ID, KARPATHY_HOOK_COMMAND, KARPATHY_HOOK_RELPATH } from \"../installer.js\";\nimport type { ClaudeSettings } from \"../settings-merge.js\";\nimport { runInteractiveUninstall } from \"../uninstall-interactive.js\";\n\nexport interface UninstallOptions {\n projectDir?: string;\n dryRun?: boolean;\n keepTemplates?: boolean;\n /**\n * v26.123.0 (F-1c) — 항목별 제거. 쉼표 구분 자산 id.\n * 지정 시 templates(`.claude/` 등)는 건드리지 않고, 로그도 지우지 않고 **남은 자산으로 다시 쓴다**.\n */\n only?: string;\n /** v26.125.0 — 대화형 선택 화면을 건너뛰고 전량 제거 (비대화형 스크립트용). */\n yes?: boolean;\n}\n\nexport interface UninstallActionDeps {\n log?: (msg: string) => void;\n err?: (msg: string) => void;\n exit?: (code: number) => never;\n spawn?: (cmd: string, args: ReadonlyArray<string>) => SpawnSyncReturns<string>;\n rm?: (path: string) => void;\n /** `--only` 후 로그 재기록. 실패 경로를 테스트에서 재현하기 위해 주입 가능. */\n writeLog?: (projectDir: string, log: InstallLog) => void;\n}\n\ninterface ReverseStep {\n /** 어느 자산의 reverse 인지 — `--only` 성공분만 로그에서 빼기 위해 필요. */\n assetId: string;\n /** 사람이 읽는 라벨 (한 줄) */\n label: string;\n /** 실제 동작 — dry-run 일 때는 호출 안 함. */\n execute: () => { ok: boolean; message?: string };\n}\n\ninterface GlobalAdvisory {\n asset: InstallLogAsset;\n /** 사용자에게 안내할 reverse 명령 */\n command: string;\n}\n\n/**\n * 크기 예외 사유 (code-style 50줄 상한): 본 함수의 내용은 **단계의 순서와 전제조건 분기**이고,\n * 각 단계는 이미 이름 있는 함수로 빠져 있다 (`planReverse` → `headerLines` → `dryRunLines` |\n * `executeReverse` → `removeTemplates` → `settleLog` → `advisoryLines` → `summarize`).\n * 남은 것은 early return 3개(로그 없음 / 모르는 id / dry-run)와 호출 순서뿐 — 더 쪼개면\n * 그 순서가 흩어진다.\n */\nexport function uninstallAction(options: UninstallOptions, deps: UninstallActionDeps = {}): void {\n const log = deps.log ?? console.log;\n const err = deps.err ?? console.error;\n const exit = deps.exit ?? ((code: number) => process.exit(code) as never);\n const spawn = deps.spawn ?? defaultSpawn;\n const rm = deps.rm ?? defaultRm;\n const writeLog = deps.writeLog ?? writeInstallLog;\n\n const projectDir = resolve(options.projectDir ?? process.cwd());\n const installLog = readInstallLog(projectDir);\n if (!installLog) {\n err(status.failure(c.red(`ERROR: install log not found at ${installLogPath(projectDir)}`)));\n err(c.dim(\" Was this project installed by agent-harness? Nothing to uninstall.\"));\n exit(1);\n return;\n }\n\n const selectedIds = parseOnly(options.only);\n // `--only ,` 처럼 값이 있는데 id 가 하나도 안 나오면 **전량 제거로 흘려보내지 않는다** —\n // 하나만 빼려던 사용자가 templates 까지 잃는다. 무응답보다 명시적 거절이 안전하다.\n if (options.only !== undefined && selectedIds === null) {\n err(status.failure(c.red(\"ERROR: --only 에 자산 id 가 없다\")));\n err(c.dim(\" 예: --only code-review (id 는 `agent-harness list` 에서 확인)\"));\n exit(1);\n return;\n }\n const unknown = selectedIds ? unknownIds(installLog, selectedIds) : [];\n if (unknown.length > 0) {\n err(status.failure(c.red(`ERROR: not in install log: ${unknown.join(\", \")}`)));\n err(c.dim(` installed: ${installLog.assets.map((a) => a.id).join(\", \") || \"(none)\"}`));\n exit(1);\n return;\n }\n const targetAssets = selectedIds\n ? installLog.assets.filter((a) => selectedIds.includes(a.id))\n : installLog.assets;\n // `--only` 는 자산만 건드린다 — templates 를 지우면 \"하나만 빼기\"가 아니게 된다.\n const keepTemplates = options.keepTemplates || selectedIds !== null;\n\n // v26.124.0 (F-1f) — `.claude/` 밖 루트 파일 안내. `--only` 는 특정 자산만 건드리는 작업이라\n // 설치 전반이 만든 루트 파일은 대상이 아니다. 구 로그(rootFiles 부재)는 빈 배열 = 안내 없음.\n const rootFiles = selectedIds ? [] : (installLog.rootFiles ?? []);\n\n const plan = planReverse(targetAssets, spawn);\n for (const line of headerLines(installLog, selectedIds, targetAssets.length)) log(line);\n\n if (options.dryRun) {\n for (const line of dryRunLines(\n plan,\n installLog,\n projectDir,\n keepTemplates,\n targetAssets,\n rootFiles,\n )) {\n log(line);\n }\n exit(0);\n return;\n }\n\n // 두 사실을 분리해서 쓴다 — 셋을 하나로 묶다 리뷰 3라운드 내리 회귀가 났다.\n // `.claude/` 가 남는가 = keepTemplates (수기 안내 대상 여부)\n // install log 가 남는가 = `--only` 인가 (settleLog: --only 만 재기록, 나머지는 삭제)\n const logSurvives = selectedIds !== null;\n\n const { succeeded, failed, removedIds } = executeReverse(plan, log, logSurvives);\n\n if (!keepTemplates) {\n const { rootClaudeMdKept } = removeTemplates(installLog, projectDir, rm);\n log(` ${status.success(`templates removed: ${formatTemplateList(installLog)}`)}`);\n if (rootClaudeMdKept) {\n log(\n ` ${c.yellow(\"⊘\")} CLAUDE.md kept — modified since install. Remove manually if intended.`,\n );\n }\n }\n\n const logWriteFailed = settleLog(\n { installLog, projectDir, selectedIds, keepTemplates, removedIds },\n { log, err, rm, writeLog },\n );\n\n // 판정 기준은 \"`--only` 인가\"가 아니라 \"`.claude/` 가 남는가\"다 — `--keep-templates` 만 줘도\n // settings.json 은 살아남으므로 안내 대상이다. dry-run 과 같은 값을 넘겨야 미리보기가 맞는다.\n for (const line of advisoryLines(plan, targetAssets, projectDir, keepTemplates, rootFiles)) {\n log(line);\n }\n\n const outcome = summarize({\n succeeded,\n failed,\n logWriteFailed,\n // 제거된 것도 없고 templates 도 안 지웠는데, 사용자에게 줄 방법조차 없을 때만 실패다.\n // ① `--only` = \"이걸 빼라\"는 특정 요청 — 하나도 못 뺐으면 요청 불이행 (C1).\n // ② 자동 경로가 없는 자산이 남았으면 — 안내할 명령조차 없다 (R1).\n // ③ 반면 global 자산만 남은 경우는 **정확한 수기 명령을 출력했으므로** 성공이다.\n // D16 설계대로의 정상이고, 여기까지 묶으면 global scope 사용자는 exit 0 을 영원히\n // 못 받는다 (로그가 지워져 재시도하면 더 나빠진다).\n nothingDone: succeeded === 0 && keepTemplates && (logSurvives || plan.noReversePath.length > 0),\n });\n log(\"\");\n log(outcome.line);\n exit(outcome.code);\n}\n\n/**\n * 종료 보고 — **한 일이 없으면 성공이라 하지 않는다.** 이전 판본은 reverse step 이 0개일 때\n * `0 === 0` 이 성공 판정을 통과해 `✓ uninstall complete` + exit 0 을 찍었다 (SOD CRITICAL).\n */\nfunction summarize(r: {\n succeeded: number;\n failed: number;\n nothingDone: boolean;\n logWriteFailed: boolean;\n}): { line: string; code: number } {\n if (r.failed > 0)\n return {\n line: c.yellow(`uninstall finished with ${r.failed} skip(s) (${r.succeeded} ok)`),\n code: 1,\n };\n if (r.nothingDone)\n return {\n line: c.yellow(\"아무것도 자동 제거되지 않았다 — 위 안내를 따라 직접 처리해야 한다\"),\n code: 1,\n };\n if (r.logWriteFailed)\n return {\n line: c.yellow(\"자산은 제거됐으나 install log 를 갱신하지 못했다 (기록이 실제와 다르다)\"),\n code: 1,\n };\n return { line: status.success(c.green(`uninstall complete (${r.succeeded} asset(s))`)), code: 0 };\n}\n\nfunction headerLines(\n installLog: InstallLog,\n selectedIds: string[] | null,\n targetCount: number,\n): string[] {\n return [\n \"\",\n c.bold(\"uzys-agent-harness · uninstall\"),\n \"\",\n c.dim(` installed: ${installLog.installedAt}`),\n c.dim(` scope: ${installLog.scope}`),\n c.dim(\n selectedIds\n ? ` assets: ${targetCount} selected of ${installLog.assets.length} (--only)`\n : ` assets: ${installLog.assets.length}`,\n ),\n \"\",\n ];\n}\n\nfunction executeReverse(\n plan: ReversePlan,\n log: (msg: string) => void,\n logSurvives: boolean,\n): { succeeded: number; failed: number; removedIds: string[] } {\n let succeeded = 0;\n let failed = 0;\n const removedIds: string[] = [];\n for (const step of plan.reverseSteps) {\n const result = step.execute();\n if (result.ok) {\n log(` ${status.success(step.label)}`);\n removedIds.push(step.assetId);\n succeeded++;\n } else {\n log(` ${c.yellow(\"⊘\")} ${step.label} (${result.message ?? \"failed\"})`);\n failed++;\n }\n }\n // 자동 되돌리기 경로가 없는 자산은 **말한다.** 조용히 넘기면 `uninstall complete` 가\n // 아무것도 안 한 실행에 붙어 거짓 보고가 된다 (no-false-ship).\n // \"기록 유지\"는 **로그가 남을 때만** 참이다. `--keep-templates` 는 `.claude/` 를 남기면서도\n // 로그는 지우므로(settleLog), templates 보존 여부로 판단하면 지워질 기록을 유지한다고 말한다.\n const tail = logSurvives ? \"자동 되돌리기 경로 없음, 기록 유지\" : \"자동 되돌리기 경로 없음\";\n for (const asset of plan.noReversePath) {\n log(` ${c.yellow(\"⊘\")} ${asset.id} (${asset.method}) — ${tail}`);\n }\n return { succeeded, failed, removedIds };\n}\n\n/** 제거 후 로그 처리. @returns 재기록에 실패했는가 (실패해도 uninstall 을 죽이지 않는다). */\nfunction settleLog(\n ctx: {\n installLog: InstallLog;\n projectDir: string;\n selectedIds: string[] | null;\n keepTemplates: boolean;\n removedIds: string[];\n },\n io: {\n log: (msg: string) => void;\n err: (msg: string) => void;\n rm: (path: string) => void;\n writeLog: (projectDir: string, log: InstallLog) => void;\n },\n): boolean {\n const { installLog, projectDir, selectedIds, keepTemplates, removedIds } = ctx;\n if (selectedIds) {\n // v26.123.0 (F-1c) — 로그를 지우는 게 아니라 **되돌린 것만 빼고 다시 쓴다**.\n // 실패한 항목은 남긴다 — 실제로 안 지워진 걸 기록에서 지우면 그게 곧 거짓 기록이다.\n const remaining = installLog.assets.filter((a) => !removedIds.includes(a.id));\n try {\n io.writeLog(projectDir, { ...installLog, assets: remaining });\n io.log(` ${status.success(`install log updated (${remaining.length} asset(s) remain)`)}`);\n } catch (e) {\n // 되돌리기는 이미 끝난 뒤다 — 스택트레이스로 죽으면 무엇이 지워졌는지도 사라진다.\n io.err(status.failure(c.red(`ERROR: install log 갱신 실패 — ${installLogPath(projectDir)}`)));\n io.err(c.dim(` ${e instanceof Error ? e.message : String(e)}`));\n io.err(c.dim(` 실제로 제거된 자산: ${removedIds.join(\", \") || \"(없음)\"}`));\n return true;\n }\n } else if (keepTemplates) {\n // install log 자체도 함께 제거 (templates 제거 시 .claude/ 통째 사라짐 → log 도 자동 사라짐.\n // keepTemplates 시 .claude/ 유지 → log 만 명시 제거).\n io.rm(installLogPath(projectDir));\n io.log(` ${status.success(\"install log removed (templates kept)\")}`);\n }\n return false;\n}\n\n/** dry-run 미리보기 — 실행 경로와 같은 판정을 쓴다 (미리보기가 실제와 어긋나면 미리보기가 아니다). */\nfunction dryRunLines(\n plan: ReversePlan,\n installLog: InstallLog,\n projectDir: string,\n keepTemplates: boolean,\n targetAssets: ReadonlyArray<InstallLogAsset>,\n rootFiles: ReadonlyArray<InstallLogRootFile>,\n): string[] {\n const lines = [c.yellow(\"[DRY RUN] reverse list (실제 변경 없음):\"), \"\"];\n if (plan.reverseSteps.length === 0) {\n lines.push(c.dim(\" (no project-scope assets to reverse)\"));\n }\n lines.push(...plan.reverseSteps.map((s) => ` ○ ${s.label}`));\n lines.push(\n ...plan.noReversePath.map((a) =>\n c.dim(` ⊘ ${a.id} (${a.method}) — 자동 되돌리기 경로 없음, 기록 유지`),\n ),\n );\n if (!keepTemplates) {\n lines.push(` ○ remove templates: ${formatTemplateList(installLog)}`);\n if (installLog.templates.rootClaudeMd) {\n lines.push(\n rootClaudeMdModified(installLog, projectDir)\n ? \" ○ keep CLAUDE.md (modified since install — preserved)\"\n : \" ○ remove CLAUDE.md\",\n );\n }\n }\n // keepTemplates=false 면 실제 실행은 `.claude/` 를 통째로 지운다 → 수기 안내 대상 자체가\n // 사라지므로 미리보기에서도 안내하지 않는다. 안 그러면 곧 삭제될 파일을 손보라고 시킨다.\n lines.push(...advisoryLines(plan, targetAssets, projectDir, keepTemplates, rootFiles), \"\");\n return lines;\n}\n\n/** global(D16) + 수기 표면 + 루트 파일 안내. dry-run 과 실행 경로가 같은 함수를 쓴다. */\nfunction advisoryLines(\n plan: ReversePlan,\n targetAssets: ReadonlyArray<InstallLogAsset>,\n projectDir: string,\n templatesKept: boolean,\n rootFiles: ReadonlyArray<InstallLogRootFile>,\n): string[] {\n const lines: string[] = [];\n if (plan.globalAdvisories.length > 0) {\n lines.push(\n \"\",\n c.yellow(\n `[GLOBAL] ${plan.globalAdvisories.length} asset(s) at scope=global — manual removal required (D16):`,\n ),\n );\n for (const adv of plan.globalAdvisories) {\n lines.push(c.dim(` · ${adv.asset.id} (${adv.asset.method})`), c.dim(` ${adv.command}`));\n }\n }\n if (templatesKept) lines.push(...manualAdvisoryLines(targetAssets, projectDir));\n // templatesKept 와 무관하다 — `.claude/` 를 통째로 지우는 경로야말로 밖에 남는 것을\n // 사용자가 존재조차 모르게 되는 경우다. 그게 F-1f 가 잡는 구멍이다.\n lines.push(...rootFileAdvisoryLines(rootFiles, projectDir));\n return lines;\n}\n\n/**\n * v26.124.0 (F-1f) — `.claude/` 밖에 남는 것 안내. **지우지 않는다**:\n * `.mcp.json`/`.gitignore` 는 사용자 내용이 섞이고, `.github/workflows/` 는 설치 후 사용자\n * 소유물이다 (ci-scaffold.ts 안전 계약 2). 기계적 되돌리기는 손실 위험이라 안내로 넘긴다.\n *\n * manualAdvisoryLines 와 같은 규율 — **예측이 아니라 현재 파일 상태를 읽어** 실재하는 것만 낸다.\n */\nfunction rootFileAdvisoryLines(\n rootFiles: ReadonlyArray<InstallLogRootFile>,\n projectDir: string,\n): string[] {\n const present = rootFiles.filter((f) => existsSync(join(projectDir, f.path)));\n if (present.length === 0) return [];\n return [\n \"\",\n c.yellow(\"[ROOT] `.claude/` 밖에 남는 것 (자동으로 지우지 않는다):\"),\n ...present.flatMap((f) => [\n c.dim(\n ` · ${f.path} — ${\n f.change === \"created\"\n ? \"하네스가 생성 (수정한 적 없으면 삭제해도 안전)\"\n : \"기존 사용자 파일에 병합 (직접 확인 필요)\"\n }`,\n ),\n c.dim(` ${f.notes.join(\" / \")}`),\n ]),\n ];\n}\n\ninterface ReversePlan {\n reverseSteps: ReverseStep[];\n globalAdvisories: GlobalAdvisory[];\n /**\n * 자동 되돌리기 경로가 없는 자산 (npx-run / shell-script / internal). 전량 uninstall 에선\n * `.claude/` 통째 제거가 덮지만, `--only` 에선 **아무 일도 안 일어난다** — 그래서 따로 센다.\n */\n noReversePath: InstallLogAsset[];\n}\n\nfunction planReverse(\n assets: ReadonlyArray<InstallLogAsset>,\n spawn: (cmd: string, args: ReadonlyArray<string>) => SpawnSyncReturns<string>,\n): ReversePlan {\n const reverseSteps: ReverseStep[] = [];\n const globalAdvisories: GlobalAdvisory[] = [];\n const noReversePath: InstallLogAsset[] = [];\n\n for (const asset of assets) {\n if (asset.scope === \"global\") {\n globalAdvisories.push({ asset, command: buildGlobalAdvisoryCmd(asset) });\n continue;\n }\n const step = buildProjectReverseStep(asset, spawn);\n if (step) reverseSteps.push(step);\n else noReversePath.push(asset);\n }\n\n return { reverseSteps, globalAdvisories, noReversePath };\n}\n\nfunction buildProjectReverseStep(\n asset: InstallLogAsset,\n spawn: (cmd: string, args: ReadonlyArray<string>) => SpawnSyncReturns<string>,\n): ReverseStep | null {\n switch (asset.method) {\n case \"plugin\": {\n const pluginId = asset.detail.pluginId ?? asset.id;\n return {\n assetId: asset.id,\n label: `claude plugin uninstall --scope project ${pluginId}`,\n execute: () => {\n const r = spawn(\"claude\", [\"plugin\", \"uninstall\", \"--scope\", \"project\", pluginId]);\n return r.status === 0 ? { ok: true } : { ok: false, message: (r.stderr || \"\").trim() };\n },\n };\n }\n case \"skill\": {\n // skills CLI default 가 project — `skills remove <source>` (no -g).\n // 일부 source 는 폴더 경로/직접 id — npx skills remove 가 처리.\n const source = asset.detail.source ?? asset.id;\n return {\n assetId: asset.id,\n label: `npx skills remove ${source}`,\n execute: () => {\n const r = spawn(\"npx\", [skillsCliSpec(), \"remove\", source, \"--yes\"]);\n return r.status === 0 ? { ok: true } : { ok: false, message: (r.stderr || \"\").trim() };\n },\n };\n }\n case \"npm\": {\n const pkg = asset.detail.pkg ?? asset.id;\n return {\n assetId: asset.id,\n label: `npm uninstall --save-dev ${pkg}`,\n execute: () => {\n const r = spawn(\"npm\", [\"uninstall\", \"--save-dev\", pkg]);\n return r.status === 0 ? { ok: true } : { ok: false, message: (r.stderr || \"\").trim() };\n },\n };\n }\n case \"npx-run\":\n // fire-and-forget — reverse 없음 (예: GSD orchestrator).\n return null;\n case \"shell-script\":\n // 로컬 script 호출 — 일반 reverse 없음 (script 별 별도 cleanup 필요).\n return null;\n case \"internal\":\n // v26.81.0 (ADR-022) — 내부 템플릿 — removeTemplates 가 .claude/ 전체로 처리.\n return null;\n }\n}\n\n/**\n * `.claude/settings.json` 의 hook command 존재 여부. **파싱해서** 본다 — 원문 substring 매치는\n * JSON 이스케이프(`\\\"`) 때문에 실제로 등록된 훅을 놓친다 (도입 시 테스트가 잡은 실패).\n */\nfunction settingsHasHookCommand(projectDir: string, command: string): boolean {\n const path = join(projectDir, \".claude\", \"settings.json\");\n if (!existsSync(path)) return false;\n try {\n const parsed = JSON.parse(readFileSync(path, \"utf8\")) as ClaudeSettings;\n return Object.values(parsed.hooks ?? {}).some((matchers) =>\n matchers.some((m) => m.hooks?.some((h) => h.command === command)),\n );\n } catch {\n return false; // 깨진 settings.json — 안내를 못 만들 뿐, uninstall 을 막지는 않는다.\n }\n}\n\n/**\n * 로그에 없는 `--only` id — 오타로 엉뚱한 자산이 남지 않도록 **아무것도 실행하기 전에** 본다\n * (gates-taxonomy Pre-flight: 전제조건 미충족 시 차단, 부분 작업 없음).\n */\nfunction unknownIds(installLog: InstallLog, selectedIds: ReadonlyArray<string>): string[] {\n const known = new Set(installLog.assets.map((a) => a.id));\n return selectedIds.filter((id) => !known.has(id));\n}\n\n/** `--only <a,b>` → [\"a\",\"b\"]. 미지정이면 null (= 전량 제거, 기존 동작). */\nfunction parseOnly(only: string | undefined): string[] | null {\n if (!only) return null;\n const ids = only\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n return ids.length > 0 ? ids : null;\n}\n\n/**\n * v26.123.0 (F-1d) — 자산 제거로 **끊어진 참조가 남는 표면**을 알려준다. 자동으로 안 고치는 이유:\n * `.claude/settings.json` 과 hook 파일에는 사용자 편집이 섞이므로 기계적 되돌리기가 손실 위험이다\n * (사용자 방침 — 위험한 표면은 반자동 안내).\n *\n * 예측이 아니라 **현재 파일 상태를 읽어** 실제로 남아 있는 것만 출력한다.\n */\nfunction manualAdvisoryLines(\n targetAssets: ReadonlyArray<InstallLogAsset>,\n projectDir: string,\n): string[] {\n if (!targetAssets.some((a) => a.id === KARPATHY_ASSET_ID)) return [];\n\n const items: string[] = [];\n if (settingsHasHookCommand(projectDir, KARPATHY_HOOK_COMMAND))\n items.push(\n `.claude/settings.json — hooks.PreToolUse 에서 다음 command 항목 삭제:\\n ${KARPATHY_HOOK_COMMAND}`,\n );\n if (existsSync(join(projectDir, KARPATHY_HOOK_RELPATH)))\n items.push(`\\`${KARPATHY_HOOK_RELPATH}\\` — 삭제`);\n\n if (items.length === 0) return [];\n return [\n \"\",\n c.yellow(\"[MANUAL] 자동으로 되돌리지 않은 것 (사용자 편집이 섞이는 표면):\"),\n ...items.map((i) => c.dim(` · ${i}`)),\n ];\n}\n\nfunction buildGlobalAdvisoryCmd(asset: InstallLogAsset): string {\n switch (asset.method) {\n case \"plugin\": {\n const pid = asset.detail.pluginId ?? asset.id;\n return `claude plugin uninstall --scope user ${pid}`;\n }\n case \"skill\": {\n const s = asset.detail.source ?? asset.id;\n return `npx skills remove -g ${s}`;\n }\n case \"npm\": {\n const pkg = asset.detail.pkg ?? asset.id;\n return `npm uninstall -g ${pkg}`;\n }\n case \"npx-run\":\n case \"shell-script\":\n case \"internal\":\n return \"(no standard reverse — manual)\";\n }\n}\n\nfunction removeTemplates(\n log: InstallLog,\n projectDir: string,\n rm: (path: string) => void,\n): { rootClaudeMdKept: boolean } {\n rm(join(projectDir, log.templates.claudeDir));\n if (log.templates.codexDir) rm(join(projectDir, log.templates.codexDir));\n if (log.templates.opencodeDir) rm(join(projectDir, log.templates.opencodeDir));\n // root CLAUDE.md — install 원본 그대로일 때만 삭제. 사용자가 수정했으면 보존.\n const rootMd = log.templates.rootClaudeMd;\n if (rootMd) {\n if (rootClaudeMdModified(log, projectDir)) return { rootClaudeMdKept: true };\n rm(join(projectDir, rootMd.path));\n }\n return { rootClaudeMdKept: false };\n}\n\n/** root CLAUDE.md 가 install 이후 수정됐는지. log 에 없거나 파일 부재 시 false (= 삭제 대상). */\nfunction rootClaudeMdModified(log: InstallLog, projectDir: string): boolean {\n const rootMd = log.templates.rootClaudeMd;\n if (!rootMd) return false;\n const path = join(projectDir, rootMd.path);\n if (!existsSync(path)) return false;\n return hashContent(readFileSync(path, \"utf8\")) !== rootMd.sha256;\n}\n\nfunction formatTemplateList(log: InstallLog): string {\n const items: string[] = [log.templates.claudeDir];\n if (log.templates.codexDir) items.push(log.templates.codexDir);\n if (log.templates.opencodeDir) items.push(log.templates.opencodeDir);\n return items.join(\", \");\n}\n\n/* v8 ignore start — thin dep-inject defaults. tests 는 항상 mock 주입. */\nfunction defaultSpawn(cmd: string, args: ReadonlyArray<string>): SpawnSyncReturns<string> {\n return spawnSync(cmd, [...args], { encoding: \"utf8\", stdio: \"pipe\", timeout: 120_000 });\n}\n\nfunction defaultRm(path: string): void {\n if (existsSync(path)) {\n rmSync(path, { recursive: true, force: true });\n }\n}\n/* v8 ignore stop */\n\nexport function registerUninstallCommand(cli: import(\"../cli.js\").Cli): void {\n cli\n .command(\"uninstall\", \"Uninstall harness assets (log-based reverse)\")\n .option(\"--project-dir <path>\", \"[Project] Target project directory\", {\n default: process.cwd(),\n })\n .option(\"--dry-run\", \"[Mode] List reverse steps without executing\")\n .option(\n \"--keep-templates\",\n \"[Mode] Keep `.claude/`, `.codex/`, `.opencode/` templates (remove only external assets)\",\n )\n .option(\n \"--only <ids>\",\n \"[Scope] Remove only these assets (comma-separated ids from `agent-harness list`). Templates untouched\",\n )\n .option(\"--yes\", \"[Mode] Skip the interactive picker and remove everything (non-interactive)\")\n /* v8 ignore next 3 — cac action callback. 분기 판정은 shouldRunInteractive 가 갖고 tests 로 검증. */\n .action(async (options: UninstallOptions) => {\n await dispatchUninstall(options);\n });\n}\n\n/**\n * v26.125.0 — 대화형 선택 화면으로 들어갈 것인가.\n *\n * 들어가지 **않는** 조건은 전부 \"사용자가 이미 무엇을 원하는지 말한 경우\"다:\n * `--only` = 뺄 대상을 지정함 · `--dry-run` = 미리보기 · `--yes` = 묻지 말라는 명시.\n * 그 외 TTY 라면 화면으로 들어간다 — 플래그 없는 `uninstall` 이 즉시 전량 삭제하던 것이\n * 이 명령에서 가장 위험한 기본값이었다. TTY 가 아니면(CI·파이프) 기존 동작 그대로다.\n */\nexport function shouldRunInteractive(options: UninstallOptions, isTty: boolean): boolean {\n if (!isTty) return false;\n if (options.yes || options.dryRun) return false;\n return options.only === undefined;\n}\n\n/* v8 ignore start — 얇은 배선. 판정은 shouldRunInteractive, 선택은 uninstall-interactive, 실행은 uninstallAction 이 각각 tests 로 검증. */\nasync function dispatchUninstall(options: UninstallOptions): Promise<void> {\n if (!shouldRunInteractive(options, Boolean(process.stdin.isTTY))) {\n uninstallAction(options);\n return;\n }\n const projectDir = resolve(options.projectDir ?? process.cwd());\n const picked = await runInteractiveUninstall(projectDir);\n if (!picked.ok || !picked.options) {\n if (picked.reason === \"no-log\") {\n console.error(\n status.failure(c.red(`ERROR: install log not found at ${installLogPath(projectDir)}`)),\n );\n console.error(c.dim(\" Nothing installed here by agent-harness.\"));\n process.exit(1);\n }\n // no-tty 는 위 분기에서 이미 걸러졌고, 나머지(cancelled/nothing-selected)는 정상 종료다.\n return;\n }\n uninstallAction(picked.options);\n}\n/* v8 ignore stop */\n","/**\n * Interactive uninstall — v26.125.0 (사용자 요청 2026-07-19).\n *\n * `agent-harness uninstall` 을 TTY 에서 실행하면 **무엇을 뺄지 고르는 화면**으로 들어간다.\n *\n * 왜 install 위저드가 아니라 별도 명령인가 (사용자 결정): install 화면의 체크 해제는\n * \"이번에 설치하지 않음\"이지 제거가 아니다. 설치 화면 안에서 삭제가 일어나면 실수 한 번이\n * 되돌릴 수 없는 삭제가 되고, \"install 은 지우지 않는다\"는 불변식도 깨진다. 그래서 제거는\n * 이 명령으로만 들어온다.\n *\n * 본 모듈은 **선택만** 한다 — 실제 되돌리기는 기존 `uninstallAction` 이 그대로 수행한다.\n * 두 모드가 각각 기존 경로 하나에 1:1 로 대응하므로 새로운 파괴적 조합이 생기지 않는다:\n * 선택 제거 → `--only <ids>` (templates 유지, 로그는 남은 자산으로 재기록)\n * 전량 제거 → 플래그 없음 (templates 포함)\n */\n\nimport { cancel, confirm, intro, isCancel, multiselect, outro, select } from \"@clack/prompts\";\nimport { type InstallLog, type InstallLogAsset, readInstallLog } from \"./install-log.js\";\n\nexport interface RemovableRow {\n value: string;\n label: string;\n hint: string;\n}\n\nexport type UninstallMode = \"selected\" | \"all\";\n\nexport interface UninstallPrompts {\n intro: (msg: string) => void;\n outro: (msg: string) => void;\n cancel: (msg: string) => void;\n /** null = ESC/취소 */\n selectMode: (rowCount: number) => Promise<UninstallMode | null>;\n /** null = ESC/취소. 빈 배열 = 아무것도 안 고름 */\n selectAssets: (rows: ReadonlyArray<RemovableRow>) => Promise<ReadonlyArray<string> | null>;\n confirm: (summary: string) => Promise<boolean | null>;\n}\n\nexport interface InteractiveUninstallDeps {\n prompts?: UninstallPrompts;\n isTty?: () => boolean;\n readLog?: (projectDir: string) => InstallLog | null;\n}\n\nexport interface InteractiveUninstallResult {\n ok: boolean;\n /** ok=true 일 때 `uninstallAction` 에 그대로 넘길 옵션. */\n options?: { projectDir: string; only?: string };\n reason?: \"no-tty\" | \"no-log\" | \"cancelled\" | \"nothing-selected\";\n message?: string;\n}\n\n/**\n * 로그의 자산 → 선택 화면 행.\n *\n * hint 에 **고르면 실제로 무슨 일이 일어나는지**를 적는다. global(D16) 과 자동 되돌리기 경로가\n * 없는 method 는 골라도 자동 삭제되지 않으므로, 고르기 전에 말해야 한다 — 안 그러면 사용자가\n * 체크하고 Enter 를 눌렀는데 아무 일도 안 일어나는 것을 결과 화면에서야 알게 된다.\n */\nexport function buildRemovableRows(\n assets: ReadonlyArray<InstallLogAsset>,\n): ReadonlyArray<RemovableRow> {\n return assets.map((a) => ({\n value: a.id,\n label: `${a.id} [${a.method}]${a.version ? ` v${a.version}` : \"\"}`,\n hint: hintFor(a),\n }));\n}\n\nfunction hintFor(asset: InstallLogAsset): string {\n if (asset.scope === \"global\") return \"global scope — 자동 삭제 안 함, 수기 제거 명령을 출력한다\";\n switch (asset.method) {\n case \"plugin\":\n return \"claude plugin uninstall --scope project\";\n case \"skill\":\n return \"npx skills remove\";\n case \"npm\":\n return \"npm uninstall --save-dev\";\n case \"npx-run\":\n case \"shell-script\":\n case \"internal\":\n return \"자동 되돌리기 경로 없음 — 전량 제거(`.claude/` 삭제)로만 사라진다\";\n }\n}\n\nexport async function runInteractiveUninstall(\n projectDir: string,\n deps: InteractiveUninstallDeps = {},\n): Promise<InteractiveUninstallResult> {\n const prompts = deps.prompts ?? defaultUninstallPrompts();\n const isTty = deps.isTty ?? (() => Boolean(process.stdin.isTTY));\n const readLog = deps.readLog ?? readInstallLog;\n\n // CI/파이프에서 프롬프트가 뜨면 그대로 멈춘다 — install 위저드와 같은 게이트.\n if (!isTty()) return { ok: false, reason: \"no-tty\" };\n\n const log = readLog(projectDir);\n if (!log) return { ok: false, reason: \"no-log\" };\n\n prompts.intro(\"uzys-agent-harness · uninstall\");\n const rows = buildRemovableRows(log.assets);\n\n const mode = await prompts.selectMode(rows.length);\n if (mode === null) {\n prompts.cancel(\"Cancelled.\");\n return { ok: false, reason: \"cancelled\" };\n }\n\n if (mode === \"all\") {\n const ok = await prompts.confirm(\n [\n \"전량 제거 — 되돌릴 수 없다:\",\n ` · 자산 ${log.assets.length}개 (자동 경로가 있는 것만 실제 제거)`,\n \" · templates 삭제: `.claude/` 등 (설치 기록도 함께 사라진다)\",\n \" · `.claude/` 밖 파일(`.mcp.json` 등)은 삭제하지 않고 안내만 한다\",\n ].join(\"\\n\"),\n );\n if (!ok) {\n prompts.cancel(\"Cancelled.\");\n return { ok: false, reason: \"cancelled\" };\n }\n return { ok: true, options: { projectDir } };\n }\n\n const picked = await prompts.selectAssets(rows);\n if (picked === null) {\n prompts.cancel(\"Cancelled.\");\n return { ok: false, reason: \"cancelled\" };\n }\n // 빈 선택을 그대로 흘리면 `--only` 가 비어 **전량 제거로 떨어진다**. 하나만 빼려던 사용자가\n // templates 까지 잃는 경로라 여기서 끊는다 (uninstall.ts 의 `--only ,` 방어와 같은 이유).\n if (picked.length === 0) {\n prompts.outro(\"아무것도 선택하지 않았다 — 변경 없음.\");\n return { ok: false, reason: \"nothing-selected\" };\n }\n\n const ok = await prompts.confirm(\n [\n `선택 제거 (${picked.length}개):`,\n ...picked.map((id) => ` · ${id}`),\n \"\",\n \"templates 는 그대로 둔다.\",\n ].join(\"\\n\"),\n );\n if (!ok) {\n prompts.cancel(\"Cancelled.\");\n return { ok: false, reason: \"cancelled\" };\n }\n return { ok: true, options: { projectDir, only: picked.join(\",\") } };\n}\n\n/* v8 ignore start — @clack/prompts 어댑터. 선택 로직은 위 순수 함수들이 갖고 tests 로 검증. */\nfunction defaultUninstallPrompts(): UninstallPrompts {\n return {\n intro: (m) => intro(m),\n outro: (m) => outro(m),\n cancel: (m) => cancel(m),\n selectMode: async (rowCount) => {\n const r = await select({\n message: `무엇을 제거할까? (설치된 자산 ${rowCount}개)`,\n options: [\n {\n value: \"selected\",\n label: \"항목 선택해서 제거\",\n hint: \"templates(`.claude/` 등)는 그대로 둔다\",\n },\n {\n value: \"all\",\n label: \"전부 제거\",\n hint: \"자산 + templates. 설치 기록도 사라진다\",\n },\n ],\n });\n return isCancel(r) ? null : (r as UninstallMode);\n },\n selectAssets: async (rows) => {\n if (rows.length === 0) return [];\n const r = await multiselect({\n message: \"제거할 항목 (Space 토글 · Enter 확정 · ESC 취소)\",\n options: rows.map((x) => ({ value: x.value, label: x.label, hint: x.hint })),\n required: false,\n });\n return isCancel(r) ? null : (r as string[]);\n },\n confirm: async (summary) => {\n const r = await confirm({ message: `${summary}\\n\\n진행할까?`, initialValue: false });\n return isCancel(r) ? null : r;\n },\n };\n}\n/* v8 ignore stop */\n",null,"/* IMPORT */\nimport fastStringTruncatedWidth from 'fast-string-truncated-width';\n/* HELPERS */\nconst NO_TRUNCATION = {\n limit: Infinity,\n ellipsis: '',\n ellipsisWidth: 0,\n};\n/* MAIN */\nconst fastStringWidth = (input, options = {}) => {\n return fastStringTruncatedWidth(input, NO_TRUNCATION, options).width;\n};\n/* EXPORT */\nexport default fastStringWidth;\n","/* IMPORT */\nimport { getCodePointsLength, isFullWidth, isWideNotCJKTNotEmoji } from './utils.js';\n/* HELPERS */\nconst ANSI_RE = /[\\u001b\\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\\u001b\\]8;[^;]*;.*?(?:\\u0007|\\u001b\\u005c)/y;\nconst CONTROL_RE = /[\\x00-\\x08\\x0A-\\x1F\\x7F-\\x9F]{1,1000}/y;\nconst CJKT_WIDE_RE = /(?:(?![\\uFF61-\\uFF9F\\uFF00-\\uFFEF])[\\p{Script=Han}\\p{Script=Hiragana}\\p{Script=Katakana}\\p{Script=Hangul}\\p{Script=Tangut}]){1,1000}/yu;\nconst TAB_RE = /\\t{1,1000}/y;\nconst EMOJI_RE = /[\\u{1F1E6}-\\u{1F1FF}]{2}|\\u{1F3F4}[\\u{E0061}-\\u{E007A}]{2}[\\u{E0030}-\\u{E0039}\\u{E0061}-\\u{E007A}]{1,3}\\u{E007F}|(?:\\p{Emoji}\\uFE0F\\u20E3?|\\p{Emoji_Modifier_Base}\\p{Emoji_Modifier}?|\\p{Emoji_Presentation})(?:\\u200D(?:\\p{Emoji_Modifier_Base}\\p{Emoji_Modifier}?|\\p{Emoji_Presentation}|\\p{Emoji}\\uFE0F\\u20E3?))*/yu;\nconst LATIN_RE = /(?:[\\x20-\\x7E\\xA0-\\xFF](?!\\uFE0F)){1,1000}/y;\nconst MODIFIER_RE = /\\p{M}+/gu;\nconst NO_TRUNCATION = { limit: Infinity, ellipsis: '' };\n/* MAIN */\nconst getStringTruncatedWidth = (input, truncationOptions = {}, widthOptions = {}) => {\n /* CONSTANTS */\n const LIMIT = truncationOptions.limit ?? Infinity;\n const ELLIPSIS = truncationOptions.ellipsis ?? '';\n const ELLIPSIS_WIDTH = truncationOptions?.ellipsisWidth ?? (ELLIPSIS ? getStringTruncatedWidth(ELLIPSIS, NO_TRUNCATION, widthOptions).width : 0);\n const ANSI_WIDTH = 0;\n const CONTROL_WIDTH = widthOptions.controlWidth ?? 0;\n const TAB_WIDTH = widthOptions.tabWidth ?? 8;\n const EMOJI_WIDTH = widthOptions.emojiWidth ?? 2;\n const FULL_WIDTH_WIDTH = 2;\n const REGULAR_WIDTH = widthOptions.regularWidth ?? 1;\n const WIDE_WIDTH = widthOptions.wideWidth ?? FULL_WIDTH_WIDTH;\n const PARSE_BLOCKS = [\n [LATIN_RE, REGULAR_WIDTH],\n [ANSI_RE, ANSI_WIDTH],\n [CONTROL_RE, CONTROL_WIDTH],\n [TAB_RE, TAB_WIDTH],\n [EMOJI_RE, EMOJI_WIDTH],\n [CJKT_WIDE_RE, WIDE_WIDTH],\n ];\n /* STATE */\n let indexPrev = 0;\n let index = 0;\n let length = input.length;\n let lengthExtra = 0;\n let truncationEnabled = false;\n let truncationIndex = length;\n let truncationLimit = Math.max(0, LIMIT - ELLIPSIS_WIDTH);\n let unmatchedStart = 0;\n let unmatchedEnd = 0;\n let width = 0;\n let widthExtra = 0;\n /* PARSE LOOP */\n outer: while (true) {\n /* UNMATCHED */\n if ((unmatchedEnd > unmatchedStart) || (index >= length && index > indexPrev)) {\n const unmatched = input.slice(unmatchedStart, unmatchedEnd) || input.slice(indexPrev, index);\n lengthExtra = 0;\n for (const char of unmatched.replaceAll(MODIFIER_RE, '')) {\n const codePoint = char.codePointAt(0) || 0;\n if (isFullWidth(codePoint)) {\n widthExtra = FULL_WIDTH_WIDTH;\n }\n else if (isWideNotCJKTNotEmoji(codePoint)) {\n widthExtra = WIDE_WIDTH;\n }\n else {\n widthExtra = REGULAR_WIDTH;\n }\n if ((width + widthExtra) > truncationLimit) {\n truncationIndex = Math.min(truncationIndex, Math.max(unmatchedStart, indexPrev) + lengthExtra);\n }\n if ((width + widthExtra) > LIMIT) {\n truncationEnabled = true;\n break outer;\n }\n lengthExtra += char.length;\n width += widthExtra;\n }\n unmatchedStart = unmatchedEnd = 0;\n }\n /* EXITING */\n if (index >= length) {\n break outer;\n }\n /* PARSE BLOCKS */\n for (let i = 0, l = PARSE_BLOCKS.length; i < l; i++) {\n const [BLOCK_RE, BLOCK_WIDTH] = PARSE_BLOCKS[i];\n BLOCK_RE.lastIndex = index;\n if (BLOCK_RE.test(input)) {\n lengthExtra = BLOCK_RE === CJKT_WIDE_RE ? getCodePointsLength(input.slice(index, BLOCK_RE.lastIndex)) : BLOCK_RE === EMOJI_RE ? 1 : BLOCK_RE.lastIndex - index;\n widthExtra = lengthExtra * BLOCK_WIDTH;\n if ((width + widthExtra) > truncationLimit) {\n truncationIndex = Math.min(truncationIndex, index + Math.floor((truncationLimit - width) / BLOCK_WIDTH));\n }\n if ((width + widthExtra) > LIMIT) {\n truncationEnabled = true;\n break outer;\n }\n width += widthExtra;\n unmatchedStart = indexPrev;\n unmatchedEnd = index;\n index = indexPrev = BLOCK_RE.lastIndex;\n continue outer;\n }\n }\n /* UNMATCHED INDEX */\n index += 1;\n }\n /* RETURN */\n return {\n width: truncationEnabled ? truncationLimit : width,\n index: truncationEnabled ? truncationIndex : length,\n truncated: truncationEnabled,\n ellipsed: truncationEnabled && LIMIT >= ELLIPSIS_WIDTH\n };\n};\n/* EXPORT */\nexport default getStringTruncatedWidth;\n","/* MAIN */\nconst getCodePointsLength = (() => {\n const SURROGATE_PAIR_RE = /[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]/g;\n return (input) => {\n let surrogatePairsNr = 0;\n SURROGATE_PAIR_RE.lastIndex = 0;\n while (SURROGATE_PAIR_RE.test(input)) {\n surrogatePairsNr += 1;\n }\n return input.length - surrogatePairsNr;\n };\n})();\nconst isFullWidth = (x) => {\n return x === 0x3000 || x >= 0xFF01 && x <= 0xFF60 || x >= 0xFFE0 && x <= 0xFFE6;\n};\nconst isWideNotCJKTNotEmoji = (x) => {\n return x === 0x231B || x === 0x2329 || x >= 0x2FF0 && x <= 0x2FFF || x >= 0x3001 && x <= 0x303E || x >= 0x3099 && x <= 0x30FF || x >= 0x3105 && x <= 0x312F || x >= 0x3131 && x <= 0x318E || x >= 0x3190 && x <= 0x31E3 || x >= 0x31EF && x <= 0x321E || x >= 0x3220 && x <= 0x3247 || x >= 0x3250 && x <= 0x4DBF || x >= 0xFE10 && x <= 0xFE19 || x >= 0xFE30 && x <= 0xFE52 || x >= 0xFE54 && x <= 0xFE66 || x >= 0xFE68 && x <= 0xFE6B || x >= 0x1F200 && x <= 0x1F202 || x >= 0x1F210 && x <= 0x1F23B || x >= 0x1F240 && x <= 0x1F248 || x >= 0x20000 && x <= 0x2FFFD || x >= 0x30000 && x <= 0x3FFFD;\n};\n/* EXPORT */\nexport { getCodePointsLength, isFullWidth, isWideNotCJKTNotEmoji };\n","export function findCursor<T extends { disabled?: boolean }>(\n\tcursor: number,\n\tdelta: number,\n\toptions: T[]\n) {\n\tconst hasEnabledOptions = options.some((opt) => !opt.disabled);\n\tif (!hasEnabledOptions) {\n\t\treturn cursor;\n\t}\n\tconst newCursor = cursor + delta;\n\tconst maxCursor = Math.max(options.length - 1, 0);\n\tconst clampedCursor = newCursor < 0 ? maxCursor : newCursor > maxCursor ? 0 : newCursor;\n\tconst newOption = options[clampedCursor];\n\tif (newOption.disabled) {\n\t\treturn findCursor(clampedCursor, delta < 0 ? -1 : 1, options);\n\t}\n\treturn clampedCursor;\n}\n\nexport function findTextCursor(\n\tcursor: number,\n\tdeltaX: number,\n\tdeltaY: number,\n\tvalue: string\n): number {\n\tconst lines = value.split('\\n');\n\tlet cursorY = 0;\n\tlet cursorX = cursor;\n\n\tfor (const line of lines) {\n\t\tif (cursorX <= line.length) {\n\t\t\tbreak;\n\t\t}\n\t\tcursorX -= line.length + 1;\n\t\tcursorY++;\n\t}\n\n\tcursorY = Math.max(0, Math.min(lines.length - 1, cursorY + deltaY));\n\n\tcursorX = Math.min(cursorX, lines[cursorY].length) + deltaX;\n\twhile (cursorX < 0 && cursorY > 0) {\n\t\tcursorY--;\n\t\tcursorX += lines[cursorY].length + 1;\n\t}\n\twhile (cursorX > lines[cursorY].length && cursorY < lines.length - 1) {\n\t\tcursorX -= lines[cursorY].length + 1;\n\t\tcursorY++;\n\t}\n\tcursorX = Math.max(0, Math.min(lines[cursorY].length, cursorX));\n\n\tlet newCursor = 0;\n\tfor (let i = 0; i < cursorY; i++) {\n\t\tnewCursor += lines[i].length + 1;\n\t}\n\treturn newCursor + cursorX;\n}\n","const actions = ['up', 'down', 'left', 'right', 'space', 'enter', 'cancel'] as const;\nexport type Action = (typeof actions)[number];\n\nconst DEFAULT_MONTH_NAMES = [\n\t'January',\n\t'February',\n\t'March',\n\t'April',\n\t'May',\n\t'June',\n\t'July',\n\t'August',\n\t'September',\n\t'October',\n\t'November',\n\t'December',\n];\n\n/** Global settings for Clack programs, stored in memory */\ninterface InternalClackSettings {\n\tactions: Set<Action>;\n\taliases: Map<string, Action>;\n\tmessages: {\n\t\tcancel: string;\n\t\terror: string;\n\t};\n\twithGuide: boolean;\n\tdate: {\n\t\tmonthNames: string[];\n\t\tmessages: {\n\t\t\tinvalidMonth: string;\n\t\t\trequired: string;\n\t\t\tinvalidDay: (days: number, month: string) => string;\n\t\t\tafterMin: (min: Date) => string;\n\t\t\tbeforeMax: (max: Date) => string;\n\t\t};\n\t};\n}\n\nexport const settings: InternalClackSettings = {\n\tactions: new Set(actions),\n\taliases: new Map<string, Action>([\n\t\t// vim support\n\t\t['k', 'up'],\n\t\t['j', 'down'],\n\t\t['h', 'left'],\n\t\t['l', 'right'],\n\t\t['\\x03', 'cancel'],\n\t\t// opinionated defaults!\n\t\t['escape', 'cancel'],\n\t]),\n\tmessages: {\n\t\tcancel: 'Canceled',\n\t\terror: 'Something went wrong',\n\t},\n\twithGuide: true,\n\tdate: {\n\t\tmonthNames: [...DEFAULT_MONTH_NAMES],\n\t\tmessages: {\n\t\t\trequired: 'Please enter a valid date',\n\t\t\tinvalidMonth: 'There are only 12 months in a year',\n\t\t\tinvalidDay: (days, month) => `There are only ${days} days in ${month}`,\n\t\t\tafterMin: (min) => `Date must be on or after ${min.toISOString().slice(0, 10)}`,\n\t\t\tbeforeMax: (max) => `Date must be on or before ${max.toISOString().slice(0, 10)}`,\n\t\t},\n\t},\n};\n\nexport interface ClackSettings {\n\t/**\n\t * Set custom global aliases for the default actions.\n\t * This will not overwrite existing aliases, it will only add new ones!\n\t *\n\t * @param aliases - An object that maps aliases to actions\n\t * @default { k: 'up', j: 'down', h: 'left', l: 'right', '\\x03': 'cancel', 'escape': 'cancel' }\n\t */\n\taliases?: Record<string, Action>;\n\n\t/**\n\t * Custom messages for prompts\n\t */\n\tmessages?: {\n\t\t/**\n\t\t * Custom message to display when a spinner is cancelled\n\t\t * @default \"Canceled\"\n\t\t */\n\t\tcancel?: string;\n\t\t/**\n\t\t * Custom message to display when a spinner encounters an error\n\t\t * @default \"Something went wrong\"\n\t\t */\n\t\terror?: string;\n\t};\n\n\twithGuide?: boolean;\n\n\t/**\n\t * Date prompt localization\n\t */\n\tdate?: {\n\t\t/** Month names for validation messages (January, February, ...) */\n\t\tmonthNames?: string[];\n\t\tmessages?: {\n\t\t\t/** Shown when date is missing */\n\t\t\trequired?: string;\n\t\t\t/** Shown when month > 12 */\n\t\t\tinvalidMonth?: string;\n\t\t\t/** (days, monthName) => message for invalid day */\n\t\t\tinvalidDay?: (days: number, month: string) => string;\n\t\t\t/** (min) => message when date is before minDate */\n\t\t\tafterMin?: (min: Date) => string;\n\t\t\t/** (max) => message when date is after maxDate */\n\t\t\tbeforeMax?: (max: Date) => string;\n\t\t};\n\t};\n}\n\nexport function updateSettings(updates: ClackSettings) {\n\t// Handle each property in the updates\n\tif (updates.aliases !== undefined) {\n\t\tconst aliases = updates.aliases;\n\t\tfor (const alias in aliases) {\n\t\t\tif (!Object.hasOwn(aliases, alias)) continue;\n\n\t\t\tconst action = aliases[alias];\n\t\t\tif (!settings.actions.has(action)) continue;\n\n\t\t\tif (!settings.aliases.has(alias)) {\n\t\t\t\tsettings.aliases.set(alias, action);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (updates.messages !== undefined) {\n\t\tconst messages = updates.messages;\n\t\tif (messages.cancel !== undefined) {\n\t\t\tsettings.messages.cancel = messages.cancel;\n\t\t}\n\t\tif (messages.error !== undefined) {\n\t\t\tsettings.messages.error = messages.error;\n\t\t}\n\t}\n\n\tif (updates.withGuide !== undefined) {\n\t\tsettings.withGuide = updates.withGuide !== false;\n\t}\n\n\tif (updates.date !== undefined) {\n\t\tconst date = updates.date;\n\t\tif (date.monthNames !== undefined) {\n\t\t\tsettings.date.monthNames = [...date.monthNames];\n\t\t}\n\t\tif (date.messages !== undefined) {\n\t\t\tif (date.messages.required !== undefined) {\n\t\t\t\tsettings.date.messages.required = date.messages.required;\n\t\t\t}\n\t\t\tif (date.messages.invalidMonth !== undefined) {\n\t\t\t\tsettings.date.messages.invalidMonth = date.messages.invalidMonth;\n\t\t\t}\n\t\t\tif (date.messages.invalidDay !== undefined) {\n\t\t\t\tsettings.date.messages.invalidDay = date.messages.invalidDay;\n\t\t\t}\n\t\t\tif (date.messages.afterMin !== undefined) {\n\t\t\t\tsettings.date.messages.afterMin = date.messages.afterMin;\n\t\t\t}\n\t\t\tif (date.messages.beforeMax !== undefined) {\n\t\t\t\tsettings.date.messages.beforeMax = date.messages.beforeMax;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/**\n * Check if a key is an alias for a default action\n * @param key - The raw key which might match to an action\n * @param action - The action to match\n * @returns boolean\n */\nexport function isActionKey(key: string | Array<string | undefined>, action: Action) {\n\tif (typeof key === 'string') {\n\t\treturn settings.aliases.get(key) === action;\n\t}\n\n\tfor (const value of key) {\n\t\tif (value === undefined) continue;\n\t\tif (isActionKey(value, action)) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n","export function diffLines(a: string, b: string) {\n\tif (a === b) return;\n\n\tconst aLines = a.split('\\n');\n\tconst bLines = b.split('\\n');\n\tconst numLines = Math.max(aLines.length, bLines.length);\n\tconst diff: number[] = [];\n\n\tfor (let i = 0; i < numLines; i++) {\n\t\tif (aLines[i] !== bLines[i]) diff.push(i);\n\t}\n\n\treturn {\n\t\tlines: diff,\n\t\tnumLinesBefore: aLines.length,\n\t\tnumLinesAfter: bLines.length,\n\t\tnumLines,\n\t};\n}\n","import { stdin, stdout } from 'node:process';\nimport type { Key } from 'node:readline';\nimport * as readline from 'node:readline';\nimport type { Readable, Writable } from 'node:stream';\nimport { ReadStream } from 'node:tty';\nimport { wrapAnsi } from 'fast-wrap-ansi';\nimport { cursor } from 'sisteransi';\nimport { isActionKey } from './settings.js';\n\nexport * from './settings.js';\nexport * from './string.js';\n\nconst isWindows = globalThis.process.platform.startsWith('win');\n\nexport const CANCEL_SYMBOL = Symbol('clack:cancel');\n\nexport function isCancel(value: unknown): value is symbol {\n\treturn value === CANCEL_SYMBOL;\n}\n\nexport function setRawMode(input: Readable, value: boolean) {\n\tconst i = input as typeof stdin;\n\n\tif (i.isTTY) i.setRawMode(value);\n}\n\ninterface BlockOptions {\n\tinput?: Readable;\n\toutput?: Writable;\n\toverwrite?: boolean;\n\thideCursor?: boolean;\n}\n\nexport function block({\n\tinput = stdin,\n\toutput = stdout,\n\toverwrite = true,\n\thideCursor = true,\n}: BlockOptions = {}) {\n\tconst rl = readline.createInterface({\n\t\tinput,\n\t\toutput,\n\t\tprompt: '',\n\t\ttabSize: 1,\n\t});\n\treadline.emitKeypressEvents(input, rl);\n\n\tif (input instanceof ReadStream && input.isTTY) {\n\t\tinput.setRawMode(true);\n\t}\n\n\tconst clear = (data: Buffer, { name, sequence }: Key) => {\n\t\tconst str = String(data);\n\t\tif (isActionKey([str, name, sequence], 'cancel')) {\n\t\t\tif (hideCursor) output.write(cursor.show);\n\t\t\tprocess.exit(0);\n\t\t\treturn;\n\t\t}\n\t\tif (!overwrite) return;\n\t\tconst dx = name === 'return' ? 0 : -1;\n\t\tconst dy = name === 'return' ? -1 : 0;\n\n\t\treadline.moveCursor(output, dx, dy, () => {\n\t\t\treadline.clearLine(output, 1, () => {\n\t\t\t\tinput.once('keypress', clear);\n\t\t\t});\n\t\t});\n\t};\n\tif (hideCursor) output.write(cursor.hide);\n\tinput.once('keypress', clear);\n\n\treturn () => {\n\t\tinput.off('keypress', clear);\n\t\tif (hideCursor) output.write(cursor.show);\n\n\t\t// Prevent Windows specific issues: https://github.com/bombshell-dev/clack/issues/176\n\t\tif (input instanceof ReadStream && input.isTTY && !isWindows) {\n\t\t\tinput.setRawMode(false);\n\t\t}\n\n\t\t// @ts-expect-error fix for https://github.com/nodejs/node/issues/31762#issuecomment-1441223907\n\t\trl.terminal = false;\n\t\trl.close();\n\t};\n}\n\nexport const getColumns = (output: Writable): number => {\n\tif ('columns' in output && typeof output.columns === 'number') {\n\t\treturn output.columns;\n\t}\n\treturn 80;\n};\n\nexport const getRows = (output: Writable): number => {\n\tif ('rows' in output && typeof output.rows === 'number') {\n\t\treturn output.rows;\n\t}\n\treturn 20;\n};\n\nexport function wrapTextWithPrefix(\n\toutput: Writable | undefined,\n\ttext: string,\n\tprefix: string,\n\tstartPrefix: string = prefix,\n\tlineFormatter?: (line: string, index: number) => string\n): string {\n\tconst columns = getColumns(output ?? stdout);\n\tconst wrapped = wrapAnsi(text, columns - prefix.length, {\n\t\thard: true,\n\t\ttrim: false,\n\t});\n\tconst lines = wrapped\n\t\t.split('\\n')\n\t\t.map((line, index) => {\n\t\t\tconst lineString = lineFormatter ? lineFormatter(line, index) : line;\n\t\t\treturn `${index === 0 ? startPrefix : prefix}${lineString}`;\n\t\t})\n\t\t.join('\\n');\n\treturn lines;\n}\n","import { stdin, stdout } from 'node:process';\nimport readline, { type Key, type ReadLine } from 'node:readline';\nimport type { Readable, Writable } from 'node:stream';\nimport { wrapAnsi } from 'fast-wrap-ansi';\nimport { cursor, erase } from 'sisteransi';\nimport type { ClackEvents, ClackState } from '../types.js';\nimport type { Action } from '../utils/index.js';\nimport {\n\tCANCEL_SYMBOL,\n\tdiffLines,\n\tgetRows,\n\tisActionKey,\n\tsetRawMode,\n\tsettings,\n} from '../utils/index.js';\n\nexport interface PromptOptions<TValue, Self extends Prompt<TValue>> {\n\trender(this: Omit<Self, 'prompt'>): string | undefined;\n\tinitialValue?: any;\n\tinitialUserInput?: string;\n\tvalidate?: ((value: TValue | undefined) => string | Error | undefined) | undefined;\n\tinput?: Readable;\n\toutput?: Writable;\n\tsignal?: AbortSignal;\n}\n\nexport default class Prompt<TValue> {\n\tprotected input: Readable;\n\tprotected output: Writable;\n\tprivate _abortSignal?: AbortSignal;\n\n\tprivate rl: ReadLine | undefined;\n\tprivate opts: Omit<PromptOptions<TValue, Prompt<TValue>>, 'render' | 'input' | 'output'>;\n\tprivate _render: (context: Omit<Prompt<TValue>, 'prompt'>) => string | undefined;\n\tprivate _track = false;\n\tprivate _prevFrame = '';\n\tprivate _subscribers = new Map<string, { cb: (...args: any) => any; once?: boolean }[]>();\n\tprotected _cursor = 0;\n\n\tpublic state: ClackState = 'initial';\n\tpublic error = '';\n\tpublic value: TValue | undefined;\n\tpublic userInput = '';\n\n\tconstructor(options: PromptOptions<TValue, Prompt<TValue>>, trackValue = true) {\n\t\tconst { input = stdin, output = stdout, render, signal, ...opts } = options;\n\n\t\tthis.opts = opts;\n\t\tthis.onKeypress = this.onKeypress.bind(this);\n\t\tthis.close = this.close.bind(this);\n\t\tthis.render = this.render.bind(this);\n\t\tthis._render = render.bind(this);\n\t\tthis._track = trackValue;\n\t\tthis._abortSignal = signal;\n\n\t\tthis.input = input;\n\t\tthis.output = output;\n\t}\n\n\t/**\n\t * Unsubscribe all listeners\n\t */\n\tprotected unsubscribe() {\n\t\tthis._subscribers.clear();\n\t}\n\n\t/**\n\t * Set a subscriber with opts\n\t * @param event - The event name\n\t */\n\tprivate setSubscriber<T extends keyof ClackEvents<TValue>>(\n\t\tevent: T,\n\t\topts: { cb: ClackEvents<TValue>[T]; once?: boolean }\n\t) {\n\t\tconst params = this._subscribers.get(event) ?? [];\n\t\tparams.push(opts);\n\t\tthis._subscribers.set(event, params);\n\t}\n\n\t/**\n\t * Subscribe to an event\n\t * @param event - The event name\n\t * @param cb - The callback\n\t */\n\tpublic on<T extends keyof ClackEvents<TValue>>(event: T, cb: ClackEvents<TValue>[T]) {\n\t\tthis.setSubscriber(event, { cb });\n\t}\n\n\t/**\n\t * Subscribe to an event once\n\t * @param event - The event name\n\t * @param cb - The callback\n\t */\n\tpublic once<T extends keyof ClackEvents<TValue>>(event: T, cb: ClackEvents<TValue>[T]) {\n\t\tthis.setSubscriber(event, { cb, once: true });\n\t}\n\n\t/**\n\t * Emit an event with data\n\t * @param event - The event name\n\t * @param data - The data to pass to the callback\n\t */\n\tpublic emit<T extends keyof ClackEvents<TValue>>(\n\t\tevent: T,\n\t\t...data: Parameters<ClackEvents<TValue>[T]>\n\t) {\n\t\tconst cbs = this._subscribers.get(event) ?? [];\n\t\tconst cleanup: (() => void)[] = [];\n\n\t\tfor (const subscriber of cbs) {\n\t\t\tsubscriber.cb(...data);\n\n\t\t\tif (subscriber.once) {\n\t\t\t\tcleanup.push(() => cbs.splice(cbs.indexOf(subscriber), 1));\n\t\t\t}\n\t\t}\n\n\t\tfor (const cb of cleanup) {\n\t\t\tcb();\n\t\t}\n\t}\n\n\tpublic prompt() {\n\t\treturn new Promise<TValue | symbol | undefined>((resolve) => {\n\t\t\tif (this._abortSignal) {\n\t\t\t\tif (this._abortSignal.aborted) {\n\t\t\t\t\tthis.state = 'cancel';\n\n\t\t\t\t\tthis.close();\n\t\t\t\t\treturn resolve(CANCEL_SYMBOL);\n\t\t\t\t}\n\n\t\t\t\tthis._abortSignal.addEventListener(\n\t\t\t\t\t'abort',\n\t\t\t\t\t() => {\n\t\t\t\t\t\tthis.state = 'cancel';\n\t\t\t\t\t\tthis.close();\n\t\t\t\t\t},\n\t\t\t\t\t{ once: true }\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.rl = readline.createInterface({\n\t\t\t\tinput: this.input,\n\t\t\t\ttabSize: 2,\n\t\t\t\tprompt: '',\n\t\t\t\tescapeCodeTimeout: 50,\n\t\t\t\tterminal: true,\n\t\t\t});\n\t\t\tthis.rl.prompt();\n\n\t\t\tif (this.opts.initialUserInput !== undefined) {\n\t\t\t\tthis._setUserInput(this.opts.initialUserInput, true);\n\t\t\t}\n\n\t\t\tthis.input.on('keypress', this.onKeypress);\n\t\t\tsetRawMode(this.input, true);\n\t\t\tthis.output.on('resize', this.render);\n\n\t\t\tthis.render();\n\n\t\t\tthis.once('submit', () => {\n\t\t\t\tthis.output.write(cursor.show);\n\t\t\t\tthis.output.off('resize', this.render);\n\t\t\t\tsetRawMode(this.input, false);\n\t\t\t\tresolve(this.value);\n\t\t\t});\n\t\t\tthis.once('cancel', () => {\n\t\t\t\tthis.output.write(cursor.show);\n\t\t\t\tthis.output.off('resize', this.render);\n\t\t\t\tsetRawMode(this.input, false);\n\t\t\t\tresolve(CANCEL_SYMBOL);\n\t\t\t});\n\t\t});\n\t}\n\n\tprotected _isActionKey(char: string | undefined, _key: Key): boolean {\n\t\treturn char === '\\t';\n\t}\n\n\tprotected _shouldSubmit(_char: string | undefined, _key: Key): boolean {\n\t\treturn true;\n\t}\n\n\tprotected _setValue(value: TValue | undefined): void {\n\t\tthis.value = value;\n\t\tthis.emit('value', this.value);\n\t}\n\n\tprotected _setUserInput(value: string | undefined, write?: boolean): void {\n\t\tthis.userInput = value ?? '';\n\t\tthis.emit('userInput', this.userInput);\n\t\tif (write && this._track && this.rl) {\n\t\t\tthis.rl.write(this.userInput);\n\t\t\tthis._cursor = this.rl.cursor;\n\t\t}\n\t}\n\n\tprotected _clearUserInput(): void {\n\t\tthis.rl?.write(null, { ctrl: true, name: 'u' });\n\t\tthis._setUserInput('');\n\t}\n\n\tprivate onKeypress(char: string | undefined, key: Key) {\n\t\tif (this._track && key.name !== 'return') {\n\t\t\tif (key.name && this._isActionKey(char, key)) {\n\t\t\t\tthis.rl?.write(null, { ctrl: true, name: 'h' });\n\t\t\t}\n\t\t\tthis._cursor = this.rl?.cursor ?? 0;\n\t\t\tthis._setUserInput(this.rl?.line);\n\t\t}\n\n\t\tif (this.state === 'error') {\n\t\t\tthis.state = 'active';\n\t\t}\n\t\tif (key?.name) {\n\t\t\tif (!this._track && settings.aliases.has(key.name)) {\n\t\t\t\tthis.emit('cursor', settings.aliases.get(key.name));\n\t\t\t}\n\t\t\tif (settings.actions.has(key.name as Action)) {\n\t\t\t\tthis.emit('cursor', key.name as Action);\n\t\t\t}\n\t\t}\n\t\tif (char && (char.toLowerCase() === 'y' || char.toLowerCase() === 'n')) {\n\t\t\tthis.emit('confirm', char.toLowerCase() === 'y');\n\t\t}\n\n\t\t// Call the key event handler and emit the key event\n\t\tthis.emit('key', char?.toLowerCase(), key);\n\n\t\tif (key?.name === 'return' && this._shouldSubmit(char, key)) {\n\t\t\tif (this.opts.validate) {\n\t\t\t\tconst problem = this.opts.validate(this.value);\n\t\t\t\tif (problem) {\n\t\t\t\t\tthis.error = problem instanceof Error ? problem.message : problem;\n\t\t\t\t\tthis.state = 'error';\n\t\t\t\t\tthis.rl?.write(this.userInput);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (this.state !== 'error') {\n\t\t\t\tthis.state = 'submit';\n\t\t\t}\n\t\t}\n\n\t\tif (isActionKey([char, key?.name, key?.sequence], 'cancel')) {\n\t\t\tthis.state = 'cancel';\n\t\t}\n\n\t\tif (this.state === 'submit' || this.state === 'cancel') {\n\t\t\tthis.emit('finalize');\n\t\t}\n\t\tthis.render();\n\t\tif (this.state === 'submit' || this.state === 'cancel') {\n\t\t\tthis.close();\n\t\t}\n\t}\n\n\tprotected close() {\n\t\tthis.input.unpipe();\n\t\tthis.input.removeListener('keypress', this.onKeypress);\n\t\tthis.output.write('\\n');\n\t\tsetRawMode(this.input, false);\n\t\tthis.rl?.close();\n\t\tthis.rl = undefined;\n\t\tthis.emit(`${this.state}`, this.value);\n\t\tthis.unsubscribe();\n\t}\n\n\tprivate restoreCursor() {\n\t\tconst lines =\n\t\t\twrapAnsi(this._prevFrame, process.stdout.columns, { hard: true, trim: false }).split('\\n')\n\t\t\t\t.length - 1;\n\t\tthis.output.write(cursor.move(-999, lines * -1));\n\t}\n\n\tprivate render() {\n\t\tconst frame = wrapAnsi(this._render(this) ?? '', process.stdout.columns, {\n\t\t\thard: true,\n\t\t\ttrim: false,\n\t\t});\n\t\tif (frame === this._prevFrame) return;\n\n\t\tif (this.state === 'initial') {\n\t\t\tthis.output.write(cursor.hide);\n\t\t} else {\n\t\t\tconst diff = diffLines(this._prevFrame, frame);\n\t\t\tconst rows = getRows(this.output);\n\t\t\tthis.restoreCursor();\n\t\t\tif (diff) {\n\t\t\t\tconst diffOffsetAfter = Math.max(0, diff.numLinesAfter - rows);\n\t\t\t\tconst diffOffsetBefore = Math.max(0, diff.numLinesBefore - rows);\n\t\t\t\tlet diffLine = diff.lines.find((line) => line >= diffOffsetAfter);\n\n\t\t\t\tif (diffLine === undefined) {\n\t\t\t\t\tthis._prevFrame = frame;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\t// If a single line has changed, only update that line\n\t\t\t\tif (diff.lines.length === 1) {\n\t\t\t\t\tthis.output.write(cursor.move(0, diffLine - diffOffsetBefore));\n\t\t\t\t\tthis.output.write(erase.lines(1));\n\t\t\t\t\tconst lines = frame.split('\\n');\n\t\t\t\t\tthis.output.write(lines[diffLine]);\n\t\t\t\t\tthis._prevFrame = frame;\n\t\t\t\t\tthis.output.write(cursor.move(0, lines.length - diffLine - 1));\n\t\t\t\t\treturn;\n\t\t\t\t\t// If many lines have changed, rerender everything past the first line\n\t\t\t\t} else if (diff.lines.length > 1) {\n\t\t\t\t\tif (diffOffsetAfter < diffOffsetBefore) {\n\t\t\t\t\t\tdiffLine = diffOffsetAfter;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst adjustedDiffLine = diffLine - diffOffsetBefore;\n\t\t\t\t\t\tif (adjustedDiffLine > 0) {\n\t\t\t\t\t\t\tthis.output.write(cursor.move(0, adjustedDiffLine));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthis.output.write(erase.down());\n\t\t\t\t\tconst lines = frame.split('\\n');\n\t\t\t\t\tconst newLines = lines.slice(diffLine);\n\t\t\t\t\tthis.output.write(newLines.join('\\n'));\n\t\t\t\t\tthis._prevFrame = frame;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.output.write(erase.down());\n\t\t}\n\n\t\tthis.output.write(frame);\n\t\tif (this.state === 'initial') {\n\t\t\tthis.state = 'active';\n\t\t}\n\t\tthis._prevFrame = frame;\n\t}\n}\n","import type { Key } from 'node:readline';\nimport { styleText } from 'node:util';\nimport { findCursor } from '../utils/cursor.js';\nimport Prompt, { type PromptOptions } from './prompt.js';\n\ninterface OptionLike {\n\tvalue: unknown;\n\tlabel?: string;\n\tdisabled?: boolean;\n}\n\ntype FilterFunction<T extends OptionLike> = (search: string, opt: T) => boolean;\n\nfunction getCursorForValue<T extends OptionLike>(\n\tselected: T['value'] | undefined,\n\titems: T[]\n): number {\n\tif (selected === undefined) {\n\t\treturn 0;\n\t}\n\n\tconst currLength = items.length;\n\n\t// If filtering changed the available options, update cursor\n\tif (currLength === 0) {\n\t\treturn 0;\n\t}\n\n\t// Try to maintain the same selected item\n\tconst index = items.findIndex((item) => item.value === selected);\n\treturn index !== -1 ? index : 0;\n}\n\nfunction defaultFilter<T extends OptionLike>(input: string, option: T): boolean {\n\tconst label = option.label ?? String(option.value);\n\treturn label.toLowerCase().includes(input.toLowerCase());\n}\n\nfunction normalisedValue<T>(multiple: boolean, values: T[] | undefined): T | T[] | undefined {\n\tif (!values) {\n\t\treturn undefined;\n\t}\n\tif (multiple) {\n\t\treturn values;\n\t}\n\treturn values[0];\n}\n\nexport interface AutocompleteOptions<T extends OptionLike>\n\textends PromptOptions<T['value'] | T['value'][], AutocompletePrompt<T>> {\n\toptions: T[] | ((this: AutocompletePrompt<T>) => T[]);\n\tfilter?: FilterFunction<T>;\n\tmultiple?: boolean;\n\t/**\n\t * When set (non-empty), pressing Tab with no input fills the field with this value\n\t * and runs the normal filter/selection logic so the user can confirm with Enter.\n\t * Tab only fills the input when the placeholder matches at least one option under\n\t * the prompt's filter (so the value remains selectable).\n\t */\n\tplaceholder?: string;\n}\n\nexport default class AutocompletePrompt<T extends OptionLike> extends Prompt<\n\tT['value'] | T['value'][]\n> {\n\tfilteredOptions: T[];\n\tmultiple: boolean;\n\tisNavigating = false;\n\tselectedValues: Array<T['value']> = [];\n\n\tfocusedValue: T['value'] | undefined;\n\t#cursor = 0;\n\t#lastUserInput = '';\n\t#filterFn: FilterFunction<T> | undefined;\n\t#options: T[] | (() => T[]);\n\t#placeholder: string | undefined;\n\n\tget cursor(): number {\n\t\treturn this.#cursor;\n\t}\n\n\tget userInputWithCursor() {\n\t\tif (!this.userInput) {\n\t\t\treturn styleText(['inverse', 'hidden'], '_');\n\t\t}\n\t\tif (this._cursor >= this.userInput.length) {\n\t\t\treturn `${this.userInput}█`;\n\t\t}\n\t\tconst s1 = this.userInput.slice(0, this._cursor);\n\t\tconst [s2, ...s3] = this.userInput.slice(this._cursor);\n\t\treturn `${s1}${styleText('inverse', s2)}${s3.join('')}`;\n\t}\n\n\tget options(): T[] {\n\t\tif (typeof this.#options === 'function') {\n\t\t\treturn this.#options();\n\t\t}\n\t\treturn this.#options;\n\t}\n\n\tconstructor(opts: AutocompleteOptions<T>) {\n\t\tsuper(opts);\n\n\t\tthis.#options = opts.options;\n\t\tthis.#placeholder = opts.placeholder;\n\t\tconst options = this.options;\n\t\tthis.filteredOptions = [...options];\n\t\tthis.multiple = opts.multiple === true;\n\t\tthis.#filterFn =\n\t\t\ttypeof opts.options === 'function' ? opts.filter : (opts.filter ?? defaultFilter);\n\t\tlet initialValues: unknown[] | undefined;\n\t\tif (opts.initialValue && Array.isArray(opts.initialValue)) {\n\t\t\tif (this.multiple) {\n\t\t\t\tinitialValues = opts.initialValue;\n\t\t\t} else {\n\t\t\t\tinitialValues = opts.initialValue.slice(0, 1);\n\t\t\t}\n\t\t} else {\n\t\t\tif (!this.multiple && this.options.length > 0) {\n\t\t\t\tinitialValues = [this.options[0].value];\n\t\t\t}\n\t\t}\n\n\t\tif (initialValues) {\n\t\t\tfor (const selectedValue of initialValues) {\n\t\t\t\tconst selectedIndex = options.findIndex((opt) => opt.value === selectedValue);\n\t\t\t\tif (selectedIndex !== -1) {\n\t\t\t\t\tthis.toggleSelected(selectedValue);\n\t\t\t\t\tthis.#cursor = selectedIndex;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.focusedValue = this.options[this.#cursor]?.value;\n\n\t\tthis.on('key', (char, key) => this.#onKey(char, key));\n\t\tthis.on('userInput', (value) => this.#onUserInputChanged(value));\n\t}\n\n\tprotected override _isActionKey(char: string | undefined, key: Key): boolean {\n\t\treturn (\n\t\t\tchar === '\\t' ||\n\t\t\t(this.multiple &&\n\t\t\t\tthis.isNavigating &&\n\t\t\t\tkey.name === 'space' &&\n\t\t\t\tchar !== undefined &&\n\t\t\t\tchar !== '')\n\t\t);\n\t}\n\n\t#onKey(_char: string | undefined, key: Key): void {\n\t\tconst isUpKey = key.name === 'up';\n\t\tconst isDownKey = key.name === 'down';\n\t\tconst isReturnKey = key.name === 'return';\n\n\t\t// Tab with empty input and placeholder: fill input with placeholder to trigger autocomplete\n\t\t// Only when the placeholder matches at least one (non-disabled) option so the value remains selectable\n\t\tconst isEmptyOrOnlyTab = this.userInput === '' || this.userInput === '\\t';\n\t\tconst placeholder = this.#placeholder;\n\t\tconst options = this.options;\n\t\tconst placeholderMatchesOption =\n\t\t\tplaceholder !== undefined &&\n\t\t\tplaceholder !== '' &&\n\t\t\toptions.some(\n\t\t\t\t(opt) => !opt.disabled && (this.#filterFn ? this.#filterFn(placeholder, opt) : true)\n\t\t\t);\n\t\tif (key.name === 'tab' && isEmptyOrOnlyTab && placeholderMatchesOption) {\n\t\t\tif (this.userInput === '\\t') {\n\t\t\t\tthis._clearUserInput();\n\t\t\t}\n\t\t\tthis._setUserInput(placeholder, true);\n\t\t\tthis.isNavigating = false;\n\t\t\treturn;\n\t\t}\n\n\t\t// Start navigation mode with up/down arrows\n\t\tif (isUpKey || isDownKey) {\n\t\t\tthis.#cursor = findCursor(this.#cursor, isUpKey ? -1 : 1, this.filteredOptions);\n\t\t\tthis.focusedValue = this.filteredOptions[this.#cursor]?.value;\n\t\t\tif (!this.multiple) {\n\t\t\t\tthis.selectedValues = [this.focusedValue];\n\t\t\t}\n\t\t\tthis.isNavigating = true;\n\t\t} else if (isReturnKey) {\n\t\t\tthis.value = normalisedValue(this.multiple, this.selectedValues);\n\t\t} else {\n\t\t\tif (this.multiple) {\n\t\t\t\tif (\n\t\t\t\t\tthis.focusedValue !== undefined &&\n\t\t\t\t\t(key.name === 'tab' || (this.isNavigating && key.name === 'space'))\n\t\t\t\t) {\n\t\t\t\t\tthis.toggleSelected(this.focusedValue);\n\t\t\t\t} else {\n\t\t\t\t\tthis.isNavigating = false;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (this.focusedValue) {\n\t\t\t\t\tthis.selectedValues = [this.focusedValue];\n\t\t\t\t}\n\t\t\t\tthis.isNavigating = false;\n\t\t\t}\n\t\t}\n\t}\n\n\tdeselectAll() {\n\t\tthis.selectedValues = [];\n\t}\n\n\ttoggleSelected(value: T['value']) {\n\t\tif (this.filteredOptions.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.multiple) {\n\t\t\tif (this.selectedValues.includes(value)) {\n\t\t\t\tthis.selectedValues = this.selectedValues.filter((v) => v !== value);\n\t\t\t} else {\n\t\t\t\tthis.selectedValues = [...this.selectedValues, value];\n\t\t\t}\n\t\t} else {\n\t\t\tthis.selectedValues = [value];\n\t\t}\n\t}\n\n\t#onUserInputChanged(value: string): void {\n\t\tif (value !== this.#lastUserInput) {\n\t\t\tthis.#lastUserInput = value;\n\n\t\t\tconst options = this.options;\n\n\t\t\tif (value && this.#filterFn) {\n\t\t\t\tthis.filteredOptions = options.filter((opt) => this.#filterFn?.(value, opt));\n\t\t\t} else {\n\t\t\t\tthis.filteredOptions = [...options];\n\t\t\t}\n\t\t\tconst valueCursor = getCursorForValue(this.focusedValue, this.filteredOptions);\n\t\t\tthis.#cursor = findCursor(valueCursor, 0, this.filteredOptions);\n\t\t\tconst focusedOption = this.filteredOptions[this.#cursor];\n\t\t\tif (focusedOption && !focusedOption.disabled) {\n\t\t\t\tthis.focusedValue = focusedOption.value;\n\t\t\t} else {\n\t\t\t\tthis.focusedValue = undefined;\n\t\t\t}\n\t\t\tif (!this.multiple) {\n\t\t\t\tif (this.focusedValue !== undefined) {\n\t\t\t\t\tthis.toggleSelected(this.focusedValue);\n\t\t\t\t} else {\n\t\t\t\t\tthis.deselectAll();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n","import { cursor } from 'sisteransi';\nimport Prompt, { type PromptOptions } from './prompt.js';\n\nexport interface ConfirmOptions extends PromptOptions<boolean, ConfirmPrompt> {\n\tactive: string;\n\tinactive: string;\n\tinitialValue?: boolean;\n}\n\nexport default class ConfirmPrompt extends Prompt<boolean> {\n\tget cursor() {\n\t\treturn this.value ? 0 : 1;\n\t}\n\n\tprivate get _value() {\n\t\treturn this.cursor === 0;\n\t}\n\n\tconstructor(opts: ConfirmOptions) {\n\t\tsuper(opts, false);\n\t\tthis.value = !!opts.initialValue;\n\n\t\tthis.on('userInput', () => {\n\t\t\tthis.value = this._value;\n\t\t});\n\n\t\tthis.on('confirm', (confirm) => {\n\t\t\tthis.output.write(cursor.move(0, -1));\n\t\t\tthis.value = confirm;\n\t\t\tthis.state = 'submit';\n\t\t\tthis.close();\n\t\t});\n\n\t\tthis.on('cursor', () => {\n\t\t\tthis.value = !this.value;\n\t\t});\n\t}\n}\n","import type { Key } from 'node:readline';\nimport { settings } from '../utils/settings.js';\nimport Prompt, { type PromptOptions } from './prompt.js';\n\ninterface SegmentConfig {\n\ttype: 'year' | 'month' | 'day';\n\tlen: number;\n}\n\nexport interface DateParts {\n\tyear: string;\n\tmonth: string;\n\tday: string;\n}\n\nexport type DateFormat = 'YMD' | 'MDY' | 'DMY';\n\nconst SEGMENTS: Record<string, SegmentConfig> = {\n\tY: { type: 'year', len: 4 },\n\tM: { type: 'month', len: 2 },\n\tD: { type: 'day', len: 2 },\n} as const;\n\nfunction segmentsFor(fmt: DateFormat): SegmentConfig[] {\n\treturn [...fmt].map((c) => SEGMENTS[c as keyof typeof SEGMENTS]);\n}\n\nfunction detectLocaleFormat(locale?: string): { segments: SegmentConfig[]; separator: string } {\n\tconst fmt = new Intl.DateTimeFormat(locale, {\n\t\tyear: 'numeric',\n\t\tmonth: '2-digit',\n\t\tday: '2-digit',\n\t});\n\tconst parts = fmt.formatToParts(new Date(2000, 0, 15));\n\tconst segments: SegmentConfig[] = [];\n\tlet separator = '/';\n\tfor (const p of parts) {\n\t\tif (p.type === 'literal') {\n\t\t\tseparator = p.value.trim() || p.value;\n\t\t} else if (p.type === 'year' || p.type === 'month' || p.type === 'day') {\n\t\t\tsegments.push({ type: p.type, len: p.type === 'year' ? 4 : 2 });\n\t\t}\n\t}\n\treturn { segments, separator };\n}\n\n/** Parse string segment values to numbers, treating blanks as 0 */\nfunction parseSegmentToNum(s: string): number {\n\treturn Number.parseInt((s || '0').replace(/_/g, '0'), 10) || 0;\n}\n\nfunction parse(parts: DateParts): { year: number; month: number; day: number } {\n\treturn {\n\t\tyear: parseSegmentToNum(parts.year),\n\t\tmonth: parseSegmentToNum(parts.month),\n\t\tday: parseSegmentToNum(parts.day),\n\t};\n}\n\nfunction daysInMonth(year: number, month: number): number {\n\treturn new Date(year || 2001, month || 1, 0).getDate();\n}\n\n/** Validate and return calendar parts, or undefined if invalid */\nfunction validParts(parts: DateParts): { year: number; month: number; day: number } | undefined {\n\tconst { year, month, day } = parse(parts);\n\tif (!year || year < 0 || year > 9999) return undefined;\n\tif (!month || month < 1 || month > 12) return undefined;\n\tif (!day || day < 1) return undefined;\n\tconst d = new Date(Date.UTC(year, month - 1, day));\n\tif (d.getUTCFullYear() !== year || d.getUTCMonth() !== month - 1 || d.getUTCDate() !== day)\n\t\treturn undefined;\n\treturn { year, month, day };\n}\n\nfunction toDate(parts: DateParts): Date | undefined {\n\tconst p = validParts(parts);\n\treturn p ? new Date(Date.UTC(p.year, p.month - 1, p.day)) : undefined;\n}\n\nfunction segmentBounds(\n\ttype: 'year' | 'month' | 'day',\n\tctx: { year: number; month: number },\n\tminDate: Date | undefined,\n\tmaxDate: Date | undefined\n): { min: number; max: number } {\n\tconst minP = minDate\n\t\t? {\n\t\t\t\tyear: minDate.getUTCFullYear(),\n\t\t\t\tmonth: minDate.getUTCMonth() + 1,\n\t\t\t\tday: minDate.getUTCDate(),\n\t\t\t}\n\t\t: null;\n\tconst maxP = maxDate\n\t\t? {\n\t\t\t\tyear: maxDate.getUTCFullYear(),\n\t\t\t\tmonth: maxDate.getUTCMonth() + 1,\n\t\t\t\tday: maxDate.getUTCDate(),\n\t\t\t}\n\t\t: null;\n\n\tif (type === 'year') {\n\t\treturn { min: minP?.year ?? 1, max: maxP?.year ?? 9999 };\n\t}\n\tif (type === 'month') {\n\t\treturn {\n\t\t\tmin: minP && ctx.year === minP.year ? minP.month : 1,\n\t\t\tmax: maxP && ctx.year === maxP.year ? maxP.month : 12,\n\t\t};\n\t}\n\treturn {\n\t\tmin: minP && ctx.year === minP.year && ctx.month === minP.month ? minP.day : 1,\n\t\tmax:\n\t\t\tmaxP && ctx.year === maxP.year && ctx.month === maxP.month\n\t\t\t\t? maxP.day\n\t\t\t\t: daysInMonth(ctx.year, ctx.month),\n\t};\n}\n\nexport interface DateOptions extends PromptOptions<Date, DatePrompt> {\n\tformat?: DateFormat;\n\tlocale?: string;\n\tseparator?: string;\n\tdefaultValue?: Date;\n\tinitialValue?: Date;\n\tminDate?: Date;\n\tmaxDate?: Date;\n}\n\nexport default class DatePrompt extends Prompt<Date> {\n\t#segments: SegmentConfig[];\n\t#separator: string;\n\t#segmentValues: DateParts;\n\t#minDate: Date | undefined;\n\t#maxDate: Date | undefined;\n\t#cursor = { segmentIndex: 0, positionInSegment: 0 };\n\t#segmentSelected = true;\n\t#pendingTensDigit: string | null = null;\n\n\tinlineError = '';\n\n\tget segmentCursor() {\n\t\treturn { ...this.#cursor };\n\t}\n\n\tget segmentValues(): DateParts {\n\t\treturn { ...this.#segmentValues };\n\t}\n\n\tget segments(): readonly SegmentConfig[] {\n\t\treturn this.#segments;\n\t}\n\n\tget separator(): string {\n\t\treturn this.#separator;\n\t}\n\n\tget formattedValue(): string {\n\t\treturn this.#format(this.#segmentValues);\n\t}\n\n\t#format(parts: DateParts): string {\n\t\treturn this.#segments.map((s) => parts[s.type]).join(this.#separator);\n\t}\n\n\t#refresh() {\n\t\tthis._setUserInput(this.#format(this.#segmentValues));\n\t\tthis._setValue(toDate(this.#segmentValues) ?? undefined);\n\t}\n\n\tconstructor(opts: DateOptions) {\n\t\tconst detected = opts.format\n\t\t\t? { segments: segmentsFor(opts.format), separator: opts.separator ?? '/' }\n\t\t\t: detectLocaleFormat(opts.locale);\n\t\tconst sep = opts.separator ?? detected.separator;\n\t\tconst segments = opts.format ? segmentsFor(opts.format) : detected.segments;\n\n\t\tconst initialDate = opts.initialValue ?? opts.defaultValue;\n\t\tconst segmentValues: DateParts = initialDate\n\t\t\t? {\n\t\t\t\t\tyear: String(initialDate.getUTCFullYear()).padStart(4, '0'),\n\t\t\t\t\tmonth: String(initialDate.getUTCMonth() + 1).padStart(2, '0'),\n\t\t\t\t\tday: String(initialDate.getUTCDate()).padStart(2, '0'),\n\t\t\t\t}\n\t\t\t: { year: '____', month: '__', day: '__' };\n\n\t\tconst initialDisplay = segments.map((s) => segmentValues[s.type]).join(sep);\n\n\t\tsuper({ ...opts, initialUserInput: initialDisplay }, false);\n\t\tthis.#segments = segments;\n\t\tthis.#separator = sep;\n\t\tthis.#segmentValues = segmentValues;\n\t\tthis.#minDate = opts.minDate;\n\t\tthis.#maxDate = opts.maxDate;\n\t\tthis.#refresh();\n\n\t\tthis.on('cursor', (key) => this.#onCursor(key));\n\t\tthis.on('key', (char, key) => this.#onKey(char, key));\n\t\tthis.on('finalize', () => this.#onFinalize(opts));\n\t}\n\n\t#seg(): { segment: SegmentConfig; index: number } | undefined {\n\t\tconst index = Math.max(0, Math.min(this.#cursor.segmentIndex, this.#segments.length - 1));\n\t\tconst segment = this.#segments[index];\n\t\tif (!segment) return undefined;\n\t\tthis.#cursor.positionInSegment = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.#cursor.positionInSegment, segment.len - 1)\n\t\t);\n\t\treturn { segment, index };\n\t}\n\n\t#navigate(direction: 1 | -1) {\n\t\tthis.inlineError = '';\n\t\tthis.#pendingTensDigit = null;\n\t\tconst ctx = this.#seg();\n\t\tif (!ctx) return;\n\t\tthis.#cursor.segmentIndex = Math.max(\n\t\t\t0,\n\t\t\tMath.min(this.#segments.length - 1, ctx.index + direction)\n\t\t);\n\t\tthis.#cursor.positionInSegment = 0;\n\t\tthis.#segmentSelected = true;\n\t}\n\n\t#adjust(direction: 1 | -1) {\n\t\tconst ctx = this.#seg();\n\t\tif (!ctx) return;\n\t\tconst { segment } = ctx;\n\t\tconst raw = this.#segmentValues[segment.type];\n\t\tconst isBlank = !raw || raw.replace(/_/g, '') === '';\n\t\tconst num = Number.parseInt((raw || '0').replace(/_/g, '0'), 10) || 0;\n\t\tconst bounds = segmentBounds(\n\t\t\tsegment.type,\n\t\t\tparse(this.#segmentValues),\n\t\t\tthis.#minDate,\n\t\t\tthis.#maxDate\n\t\t);\n\n\t\tlet next: number;\n\t\tif (isBlank) {\n\t\t\tnext = direction === 1 ? bounds.min : bounds.max;\n\t\t} else {\n\t\t\tnext = Math.max(Math.min(bounds.max, num + direction), bounds.min);\n\t\t}\n\n\t\tthis.#segmentValues = {\n\t\t\t...this.#segmentValues,\n\t\t\t[segment.type]: next.toString().padStart(segment.len, '0'),\n\t\t};\n\t\tthis.#segmentSelected = true;\n\t\tthis.#pendingTensDigit = null;\n\t\tthis.#refresh();\n\t}\n\n\t#onCursor(key?: string) {\n\t\tif (!key) return;\n\t\tswitch (key) {\n\t\t\tcase 'right':\n\t\t\t\treturn this.#navigate(1);\n\t\t\tcase 'left':\n\t\t\t\treturn this.#navigate(-1);\n\t\t\tcase 'up':\n\t\t\t\treturn this.#adjust(1);\n\t\t\tcase 'down':\n\t\t\t\treturn this.#adjust(-1);\n\t\t}\n\t}\n\n\t#onKey(char: string | undefined, key: Key) {\n\t\t// Backspace\n\t\tconst isBackspace =\n\t\t\tkey?.name === 'backspace' ||\n\t\t\tkey?.sequence === '\\x7f' ||\n\t\t\tkey?.sequence === '\\b' ||\n\t\t\tchar === '\\x7f' ||\n\t\t\tchar === '\\b';\n\t\tif (isBackspace) {\n\t\t\tthis.inlineError = '';\n\t\t\tconst ctx = this.#seg();\n\t\t\tif (!ctx) return;\n\t\t\tif (!this.#segmentValues[ctx.segment.type].replace(/_/g, '')) {\n\t\t\t\tthis.#navigate(-1);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.#segmentValues[ctx.segment.type] = '_'.repeat(ctx.segment.len);\n\t\t\tthis.#segmentSelected = true;\n\t\t\tthis.#cursor.positionInSegment = 0;\n\t\t\tthis.#refresh();\n\t\t\treturn;\n\t\t}\n\n\t\t// Tab navigation\n\t\tif (key?.name === 'tab') {\n\t\t\tthis.inlineError = '';\n\t\t\tconst ctx = this.#seg();\n\t\t\tif (!ctx) return;\n\t\t\tconst dir = key.shift ? -1 : 1;\n\t\t\tconst next = ctx.index + dir;\n\t\t\tif (next >= 0 && next < this.#segments.length) {\n\t\t\t\tthis.#cursor.segmentIndex = next;\n\t\t\t\tthis.#cursor.positionInSegment = 0;\n\t\t\t\tthis.#segmentSelected = true;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Digit input\n\t\tif (char && /^[0-9]$/.test(char)) {\n\t\t\tconst ctx = this.#seg();\n\t\t\tif (!ctx) return;\n\t\t\tconst { segment } = ctx;\n\t\t\tconst isBlank = !this.#segmentValues[segment.type].replace(/_/g, '');\n\n\t\t\t// Pending tens digit: complete the two-digit entry\n\t\t\tif (this.#segmentSelected && this.#pendingTensDigit !== null && !isBlank) {\n\t\t\t\tconst newVal = this.#pendingTensDigit + char;\n\t\t\t\tconst newParts = { ...this.#segmentValues, [segment.type]: newVal };\n\t\t\t\tconst err = this.#validateSegment(newParts, segment);\n\t\t\t\tif (err) {\n\t\t\t\t\tthis.inlineError = err;\n\t\t\t\t\tthis.#pendingTensDigit = null;\n\t\t\t\t\tthis.#segmentSelected = false;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.inlineError = '';\n\t\t\t\tthis.#segmentValues[segment.type] = newVal;\n\t\t\t\tthis.#pendingTensDigit = null;\n\t\t\t\tthis.#segmentSelected = false;\n\t\t\t\tthis.#refresh();\n\t\t\t\tif (ctx.index < this.#segments.length - 1) {\n\t\t\t\t\tthis.#cursor.segmentIndex = ctx.index + 1;\n\t\t\t\t\tthis.#cursor.positionInSegment = 0;\n\t\t\t\t\tthis.#segmentSelected = true;\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Clear-on-type: typing into a selected filled segment clears it first\n\t\t\tif (this.#segmentSelected && !isBlank) {\n\t\t\t\tthis.#segmentValues[segment.type] = '_'.repeat(segment.len);\n\t\t\t\tthis.#cursor.positionInSegment = 0;\n\t\t\t}\n\t\t\tthis.#segmentSelected = false;\n\t\t\tthis.#pendingTensDigit = null;\n\n\t\t\tconst display = this.#segmentValues[segment.type];\n\t\t\tconst firstBlank = display.indexOf('_');\n\t\t\tconst pos =\n\t\t\t\tfirstBlank >= 0 ? firstBlank : Math.min(this.#cursor.positionInSegment, segment.len - 1);\n\t\t\tif (pos < 0 || pos >= segment.len) return;\n\n\t\t\tlet newVal = display.slice(0, pos) + char + display.slice(pos + 1);\n\n\t\t\t// Smart digit placement\n\t\t\tlet shouldStaySelected = false;\n\t\t\tif (pos === 0 && display === '__' && (segment.type === 'month' || segment.type === 'day')) {\n\t\t\t\tconst digit = Number.parseInt(char, 10);\n\t\t\t\tnewVal = `0${char}`;\n\t\t\t\tshouldStaySelected = digit <= (segment.type === 'month' ? 1 : 2);\n\t\t\t}\n\t\t\tif (segment.type === 'year') {\n\t\t\t\tconst digits = display.replace(/_/g, '');\n\t\t\t\tnewVal = (digits + char).padStart(segment.len, '_');\n\t\t\t}\n\n\t\t\tif (!newVal.includes('_')) {\n\t\t\t\tconst newParts = { ...this.#segmentValues, [segment.type]: newVal };\n\t\t\t\tconst err = this.#validateSegment(newParts, segment);\n\t\t\t\tif (err) {\n\t\t\t\t\tthis.inlineError = err;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.inlineError = '';\n\n\t\t\tthis.#segmentValues[segment.type] = newVal;\n\n\t\t\t// Clamp only when the current segment is fully entered\n\t\t\tconst parsed = !newVal.includes('_') ? validParts(this.#segmentValues) : undefined;\n\t\t\tif (parsed) {\n\t\t\t\tconst { year, month } = parsed;\n\t\t\t\tconst maxDay = daysInMonth(year, month);\n\t\t\t\tthis.#segmentValues = {\n\t\t\t\t\tyear: String(Math.max(0, Math.min(9999, year))).padStart(4, '0'),\n\t\t\t\t\tmonth: String(Math.max(1, Math.min(12, month))).padStart(2, '0'),\n\t\t\t\t\tday: String(Math.max(1, Math.min(maxDay, parsed.day))).padStart(2, '0'),\n\t\t\t\t};\n\t\t\t}\n\t\t\tthis.#refresh();\n\n\t\t\t// Advance cursor\n\t\t\tconst nextBlank = newVal.indexOf('_');\n\t\t\tif (shouldStaySelected) {\n\t\t\t\tthis.#segmentSelected = true;\n\t\t\t\tthis.#pendingTensDigit = char;\n\t\t\t} else if (nextBlank >= 0) {\n\t\t\t\tthis.#cursor.positionInSegment = nextBlank;\n\t\t\t} else if (firstBlank >= 0 && ctx.index < this.#segments.length - 1) {\n\t\t\t\tthis.#cursor.segmentIndex = ctx.index + 1;\n\t\t\t\tthis.#cursor.positionInSegment = 0;\n\t\t\t\tthis.#segmentSelected = true;\n\t\t\t} else {\n\t\t\t\tthis.#cursor.positionInSegment = Math.min(pos + 1, segment.len - 1);\n\t\t\t}\n\t\t}\n\t}\n\n\t#validateSegment(parts: DateParts, seg: SegmentConfig): string | undefined {\n\t\tconst { month, day } = parse(parts);\n\t\tif (seg.type === 'month' && (month < 0 || month > 12)) {\n\t\t\treturn settings.date.messages.invalidMonth;\n\t\t}\n\t\tif (seg.type === 'day' && (day < 0 || day > 31)) {\n\t\t\treturn settings.date.messages.invalidDay(31, 'any month');\n\t\t}\n\t\treturn undefined;\n\t}\n\n\t#onFinalize(opts: DateOptions) {\n\t\tconst { year, month, day } = parse(this.#segmentValues);\n\t\tif (year && month && day) {\n\t\t\tconst maxDay = daysInMonth(year, month);\n\t\t\tthis.#segmentValues = {\n\t\t\t\t...this.#segmentValues,\n\t\t\t\tday: String(Math.min(day, maxDay)).padStart(2, '0'),\n\t\t\t};\n\t\t}\n\t\tthis.value = toDate(this.#segmentValues) ?? opts.defaultValue ?? undefined;\n\t}\n}\n","import Prompt, { type PromptOptions } from './prompt.js';\n\nexport interface GroupMultiSelectOptions<T extends { value: any }>\n\textends PromptOptions<T['value'][], GroupMultiSelectPrompt<T>> {\n\toptions: Record<string, T[]>;\n\tinitialValues?: T['value'][];\n\trequired?: boolean;\n\tcursorAt?: T['value'];\n\tselectableGroups?: boolean;\n}\nexport default class GroupMultiSelectPrompt<T extends { value: any }> extends Prompt<T['value'][]> {\n\toptions: (T & { group: string | boolean })[];\n\tcursor = 0;\n\t#selectableGroups: boolean;\n\n\tgetGroupItems(group: string): T[] {\n\t\treturn this.options.filter((o) => o.group === group);\n\t}\n\n\tisGroupSelected(group: string) {\n\t\tconst items = this.getGroupItems(group);\n\t\tconst value = this.value;\n\t\tif (value === undefined) {\n\t\t\treturn false;\n\t\t}\n\t\treturn items.every((i) => value.includes(i.value));\n\t}\n\n\tprivate toggleValue() {\n\t\tconst item = this.options[this.cursor];\n\t\tif (this.value === undefined) {\n\t\t\tthis.value = [];\n\t\t}\n\t\tif (item.group === true) {\n\t\t\tconst group = item.value;\n\t\t\tconst groupedItems = this.getGroupItems(group);\n\t\t\tif (this.isGroupSelected(group)) {\n\t\t\t\tthis.value = this.value.filter(\n\t\t\t\t\t(v: string) => groupedItems.findIndex((i) => i.value === v) === -1\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\tthis.value = [...this.value, ...groupedItems.map((i) => i.value)];\n\t\t\t}\n\t\t\tthis.value = Array.from(new Set(this.value));\n\t\t} else {\n\t\t\tconst selected = this.value.includes(item.value);\n\t\t\tthis.value = selected\n\t\t\t\t? this.value.filter((v: T['value']) => v !== item.value)\n\t\t\t\t: [...this.value, item.value];\n\t\t}\n\t}\n\n\tconstructor(opts: GroupMultiSelectOptions<T>) {\n\t\tsuper(opts, false);\n\t\tconst { options } = opts;\n\t\tthis.#selectableGroups = opts.selectableGroups !== false;\n\t\tthis.options = Object.entries(options).flatMap(([key, option]) => [\n\t\t\t{ value: key, group: true, label: key },\n\t\t\t...option.map((opt) => ({ ...opt, group: key })),\n\t\t]) as any;\n\t\tthis.value = [...(opts.initialValues ?? [])];\n\t\tthis.cursor = Math.max(\n\t\t\tthis.options.findIndex(({ value }) => value === opts.cursorAt),\n\t\t\tthis.#selectableGroups ? 0 : 1\n\t\t);\n\n\t\tthis.on('cursor', (key) => {\n\t\t\tswitch (key) {\n\t\t\t\tcase 'left':\n\t\t\t\tcase 'up': {\n\t\t\t\t\tthis.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;\n\t\t\t\t\tconst currentIsGroup = this.options[this.cursor]?.group === true;\n\t\t\t\t\tif (!this.#selectableGroups && currentIsGroup) {\n\t\t\t\t\t\tthis.cursor = this.cursor === 0 ? this.options.length - 1 : this.cursor - 1;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'down':\n\t\t\t\tcase 'right': {\n\t\t\t\t\tthis.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;\n\t\t\t\t\tconst currentIsGroup = this.options[this.cursor]?.group === true;\n\t\t\t\t\tif (!this.#selectableGroups && currentIsGroup) {\n\t\t\t\t\t\tthis.cursor = this.cursor === this.options.length - 1 ? 0 : this.cursor + 1;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'space':\n\t\t\t\t\tthis.toggleValue();\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t});\n\t}\n}\n","import type { Key } from 'node:readline';\nimport { styleText } from 'node:util';\nimport { findTextCursor } from '../utils/cursor.js';\nimport { type Action, settings } from '../utils/index.js';\nimport Prompt, { type PromptOptions } from './prompt.js';\n\nexport interface MultiLineOptions extends PromptOptions<string, MultiLinePrompt> {\n\tplaceholder?: string;\n\tdefaultValue?: string;\n\tshowSubmit?: boolean;\n}\n\nexport default class MultiLinePrompt extends Prompt<string> {\n\t#lastKeyWasReturn = false;\n\t#showSubmit: boolean;\n\tpublic focused: 'editor' | 'submit' = 'editor';\n\n\tget userInputWithCursor() {\n\t\tif (this.state === 'submit') {\n\t\t\treturn this.userInput;\n\t\t}\n\t\tconst userInput = this.userInput;\n\t\tif (this.cursor >= userInput.length) {\n\t\t\treturn `${userInput}█`;\n\t\t}\n\t\tconst s1 = userInput.slice(0, this.cursor);\n\t\tconst s2 = userInput[this.cursor];\n\t\tconst s3 = userInput.slice(this.cursor + 1);\n\t\tif (s2 === '\\n') return `${s1}█\\n${s3}`;\n\t\treturn `${s1}${styleText('inverse', s2)}${s3}`;\n\t}\n\tget cursor() {\n\t\treturn this._cursor;\n\t}\n\t#insertAtCursor(char: string) {\n\t\tif (this.userInput.length === 0) {\n\t\t\tthis._setUserInput(char);\n\t\t\treturn;\n\t\t}\n\t\tthis._setUserInput(\n\t\t\tthis.userInput.slice(0, this.cursor) + char + this.userInput.slice(this.cursor)\n\t\t);\n\t}\n\t#handleCursor(key?: Action) {\n\t\tconst text = this.value ?? '';\n\t\tswitch (key) {\n\t\t\tcase 'up':\n\t\t\t\tthis._cursor = findTextCursor(this._cursor, 0, -1, text);\n\t\t\t\treturn;\n\t\t\tcase 'down':\n\t\t\t\tthis._cursor = findTextCursor(this._cursor, 0, 1, text);\n\t\t\t\treturn;\n\t\t\tcase 'left':\n\t\t\t\tthis._cursor = findTextCursor(this._cursor, -1, 0, text);\n\t\t\t\treturn;\n\t\t\tcase 'right':\n\t\t\t\tthis._cursor = findTextCursor(this._cursor, 1, 0, text);\n\t\t\t\treturn;\n\t\t}\n\t}\n\n\tprotected override _shouldSubmit(_char: string | undefined, _key: Key): boolean {\n\t\tif (this.#showSubmit) {\n\t\t\tif (this.focused === 'submit') {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tthis.#insertAtCursor('\\n');\n\t\t\tthis._cursor++;\n\t\t\treturn false;\n\t\t}\n\t\tconst wasReturn = this.#lastKeyWasReturn;\n\t\tthis.#lastKeyWasReturn = true;\n\t\tif (wasReturn) {\n\t\t\tif (this.userInput[this.cursor - 1] === '\\n') {\n\t\t\t\tthis._setUserInput(\n\t\t\t\t\tthis.userInput.slice(0, this.cursor - 1) + this.userInput.slice(this.cursor)\n\t\t\t\t);\n\t\t\t\tthis._cursor--;\n\t\t\t}\n\t\t\treturn true;\n\t\t}\n\t\tthis.#insertAtCursor('\\n');\n\t\tthis._cursor++;\n\t\treturn false;\n\t}\n\n\tconstructor(opts: MultiLineOptions) {\n\t\tsuper(opts, false);\n\t\tthis.#showSubmit = opts.showSubmit ?? false;\n\n\t\tthis.on('key', (char, key) => {\n\t\t\tif (key?.name && settings.actions.has(key.name as Action)) {\n\t\t\t\tthis.#handleCursor(key.name as Action);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (char === '\\t' && this.#showSubmit) {\n\t\t\t\tthis.focused = this.focused === 'editor' ? 'submit' : 'editor';\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (key?.name === 'return') {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.#lastKeyWasReturn = false;\n\t\t\tif (key?.name === 'backspace' && this.cursor > 0) {\n\t\t\t\tthis._setUserInput(\n\t\t\t\t\tthis.userInput.slice(0, this.cursor - 1) + this.userInput.slice(this.cursor)\n\t\t\t\t);\n\t\t\t\tthis._cursor--;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (key?.name === 'delete' && this.cursor < this.userInput.length) {\n\t\t\t\tthis._setUserInput(\n\t\t\t\t\tthis.userInput.slice(0, this.cursor) + this.userInput.slice(this.cursor + 1)\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (char) {\n\t\t\t\tif (this.#showSubmit && this.focused === 'submit') {\n\t\t\t\t\tthis.focused = 'editor';\n\t\t\t\t}\n\t\t\t\tthis.#insertAtCursor(char ?? '');\n\t\t\t\tthis._cursor++;\n\t\t\t}\n\t\t});\n\n\t\tthis.on('userInput', (input) => {\n\t\t\tthis._setValue(input);\n\t\t});\n\t\tthis.on('finalize', () => {\n\t\t\tif (!this.value) {\n\t\t\t\tthis.value = opts.defaultValue;\n\t\t\t}\n\t\t\tif (this.value === undefined) {\n\t\t\t\tthis.value = '';\n\t\t\t}\n\t\t});\n\t}\n}\n","import { findCursor } from '../utils/cursor.js';\nimport Prompt, { type PromptOptions } from './prompt.js';\n\ninterface OptionLike {\n\tvalue: any;\n\tdisabled?: boolean;\n}\n\nexport interface MultiSelectOptions<T extends OptionLike>\n\textends PromptOptions<T['value'][], MultiSelectPrompt<T>> {\n\toptions: T[];\n\tinitialValues?: T['value'][];\n\trequired?: boolean;\n\tcursorAt?: T['value'];\n}\nexport default class MultiSelectPrompt<T extends OptionLike> extends Prompt<T['value'][]> {\n\toptions: T[];\n\tcursor = 0;\n\n\tprivate get _value(): T['value'] {\n\t\treturn this.options[this.cursor].value;\n\t}\n\n\tprivate get _enabledOptions(): T[] {\n\t\treturn this.options.filter((option) => option.disabled !== true);\n\t}\n\n\tprivate toggleAll() {\n\t\tconst enabledOptions = this._enabledOptions;\n\t\tconst allSelected = this.value !== undefined && this.value.length === enabledOptions.length;\n\t\tthis.value = allSelected ? [] : enabledOptions.map((v) => v.value);\n\t}\n\n\tprivate toggleInvert() {\n\t\tconst value = this.value;\n\t\tif (!value) {\n\t\t\treturn;\n\t\t}\n\t\tconst notSelected = this._enabledOptions.filter((v) => !value.includes(v.value));\n\t\tthis.value = notSelected.map((v) => v.value);\n\t}\n\n\tprivate toggleValue() {\n\t\tif (this.value === undefined) {\n\t\t\tthis.value = [];\n\t\t}\n\t\tconst selected = this.value.includes(this._value);\n\t\tthis.value = selected\n\t\t\t? this.value.filter((value) => value !== this._value)\n\t\t\t: [...this.value, this._value];\n\t}\n\n\tconstructor(opts: MultiSelectOptions<T>) {\n\t\tsuper(opts, false);\n\n\t\tthis.options = opts.options;\n\t\tthis.value = [...(opts.initialValues ?? [])];\n\t\tconst cursor = Math.max(\n\t\t\tthis.options.findIndex(({ value }) => value === opts.cursorAt),\n\t\t\t0\n\t\t);\n\t\tthis.cursor = this.options[cursor].disabled ? findCursor<T>(cursor, 1, this.options) : cursor;\n\t\tthis.on('key', (char) => {\n\t\t\tif (char === 'a') {\n\t\t\t\tthis.toggleAll();\n\t\t\t}\n\t\t\tif (char === 'i') {\n\t\t\t\tthis.toggleInvert();\n\t\t\t}\n\t\t});\n\n\t\tthis.on('cursor', (key) => {\n\t\t\tswitch (key) {\n\t\t\t\tcase 'left':\n\t\t\t\tcase 'up':\n\t\t\t\t\tthis.cursor = findCursor<T>(this.cursor, -1, this.options);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'down':\n\t\t\t\tcase 'right':\n\t\t\t\t\tthis.cursor = findCursor<T>(this.cursor, 1, this.options);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'space':\n\t\t\t\t\tthis.toggleValue();\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t});\n\t}\n}\n","import { styleText } from 'node:util';\nimport Prompt, { type PromptOptions } from './prompt.js';\n\nexport interface PasswordOptions extends PromptOptions<string, PasswordPrompt> {\n\tmask?: string;\n}\nexport default class PasswordPrompt extends Prompt<string> {\n\tprivate _mask = '•';\n\tget cursor() {\n\t\treturn this._cursor;\n\t}\n\tget masked() {\n\t\treturn this.userInput.replaceAll(/./g, this._mask);\n\t}\n\tget userInputWithCursor() {\n\t\tif (this.state === 'submit' || this.state === 'cancel') {\n\t\t\treturn this.masked;\n\t\t}\n\t\tconst userInput = this.userInput;\n\t\tif (this.cursor >= userInput.length) {\n\t\t\treturn `${this.masked}${styleText(['inverse', 'hidden'], '_')}`;\n\t\t}\n\t\tconst masked = this.masked;\n\t\tconst s1 = masked.slice(0, this.cursor);\n\t\tconst s2 = masked.slice(this.cursor);\n\t\treturn `${s1}${styleText('inverse', s2[0])}${s2.slice(1)}`;\n\t}\n\tclear() {\n\t\tthis._clearUserInput();\n\t}\n\tconstructor({ mask, ...opts }: PasswordOptions) {\n\t\tsuper(opts);\n\t\tthis._mask = mask ?? '•';\n\t\tthis.on('userInput', (input) => {\n\t\t\tthis._setValue(input);\n\t\t});\n\t}\n}\n","import { findCursor } from '../utils/cursor.js';\nimport Prompt, { type PromptOptions } from './prompt.js';\n\nexport interface SelectOptions<T extends { value: any; disabled?: boolean }>\n\textends PromptOptions<T['value'], SelectPrompt<T>> {\n\toptions: T[];\n\tinitialValue?: T['value'];\n}\nexport default class SelectPrompt<T extends { value: any; disabled?: boolean }> extends Prompt<\n\tT['value']\n> {\n\toptions: T[];\n\tcursor = 0;\n\n\tprivate get _selectedValue() {\n\t\treturn this.options[this.cursor];\n\t}\n\n\tprivate changeValue() {\n\t\tthis.value = this._selectedValue.value;\n\t}\n\n\tconstructor(opts: SelectOptions<T>) {\n\t\tsuper(opts, false);\n\n\t\tthis.options = opts.options;\n\n\t\tconst initialCursor = this.options.findIndex(({ value }) => value === opts.initialValue);\n\t\tconst cursor = initialCursor === -1 ? 0 : initialCursor;\n\t\tthis.cursor = this.options[cursor].disabled ? findCursor<T>(cursor, 1, this.options) : cursor;\n\t\tthis.changeValue();\n\n\t\tthis.on('cursor', (key) => {\n\t\t\tswitch (key) {\n\t\t\t\tcase 'left':\n\t\t\t\tcase 'up':\n\t\t\t\t\tthis.cursor = findCursor<T>(this.cursor, -1, this.options);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'down':\n\t\t\t\tcase 'right':\n\t\t\t\t\tthis.cursor = findCursor<T>(this.cursor, 1, this.options);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tthis.changeValue();\n\t\t});\n\t}\n}\n","import Prompt, { type PromptOptions } from './prompt.js';\n\nexport interface SelectKeyOptions<T extends { value: string }>\n\textends PromptOptions<T['value'], SelectKeyPrompt<T>> {\n\toptions: T[];\n\tcaseSensitive?: boolean;\n}\nexport default class SelectKeyPrompt<T extends { value: string }> extends Prompt<T['value']> {\n\toptions: T[];\n\tcursor = 0;\n\n\tconstructor(opts: SelectKeyOptions<T>) {\n\t\tsuper(opts, false);\n\n\t\tthis.options = opts.options;\n\t\tconst caseSensitive = opts.caseSensitive === true;\n\t\tconst keys = this.options.map(({ value: [initial] }) => {\n\t\t\treturn caseSensitive ? initial : initial?.toLowerCase();\n\t\t});\n\t\tthis.cursor = Math.max(keys.indexOf(opts.initialValue), 0);\n\n\t\tthis.on('key', (key, keyInfo) => {\n\t\t\tif (!key) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst casedKey = caseSensitive && keyInfo.shift ? key.toUpperCase() : key;\n\t\t\tif (!keys.includes(casedKey)) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst value = this.options.find(({ value: [initial] }) => {\n\t\t\t\treturn caseSensitive ? initial === casedKey : initial?.toLowerCase() === key;\n\t\t\t});\n\t\t\tif (value) {\n\t\t\t\tthis.value = value.value;\n\t\t\t\tthis.state = 'submit';\n\t\t\t\tthis.emit('submit');\n\t\t\t}\n\t\t});\n\t}\n}\n","import { styleText } from 'node:util';\nimport Prompt, { type PromptOptions } from './prompt.js';\n\nexport interface TextOptions extends PromptOptions<string, TextPrompt> {\n\tplaceholder?: string;\n\tdefaultValue?: string;\n}\n\nexport default class TextPrompt extends Prompt<string> {\n\tget userInputWithCursor() {\n\t\tif (this.state === 'submit') {\n\t\t\treturn this.userInput;\n\t\t}\n\t\tconst userInput = this.userInput;\n\t\tif (this.cursor >= userInput.length) {\n\t\t\treturn `${this.userInput}█`;\n\t\t}\n\t\tconst s1 = userInput.slice(0, this.cursor);\n\t\tconst [s2, ...s3] = userInput.slice(this.cursor);\n\t\treturn `${s1}${styleText('inverse', s2)}${s3.join('')}`;\n\t}\n\tget cursor() {\n\t\treturn this._cursor;\n\t}\n\tconstructor(opts: TextOptions) {\n\t\tsuper({\n\t\t\t...opts,\n\t\t\tinitialUserInput: opts.initialUserInput ?? opts.initialValue,\n\t\t});\n\n\t\tthis.on('userInput', (input) => {\n\t\t\tthis._setValue(input);\n\t\t});\n\t\tthis.on('finalize', () => {\n\t\t\tif (!this.value) {\n\t\t\t\tthis.value = opts.defaultValue;\n\t\t\t}\n\t\t\tif (this.value === undefined) {\n\t\t\t\tthis.value = '';\n\t\t\t}\n\t\t});\n\t}\n}\n","import process from 'node:process';\n\nexport default function isUnicodeSupported() {\n\tif (process.platform !== 'win32') {\n\t\treturn process.env.TERM !== 'linux'; // Linux console (kernel)\n\t}\n\n\treturn Boolean(process.env.CI)\n\t\t|| Boolean(process.env.WT_SESSION) // Windows Terminal\n\t\t|| Boolean(process.env.TERMINUS_SUBLIME) // Terminus (<0.2.27)\n\t\t|| process.env.ConEmuTask === '{cmd::Cmder}' // ConEmu and cmder\n\t\t|| process.env.TERM_PROGRAM === 'Terminus-Sublime'\n\t\t|| process.env.TERM_PROGRAM === 'vscode'\n\t\t|| process.env.TERM === 'xterm-256color'\n\t\t|| process.env.TERM === 'alacritty'\n\t\t|| process.env.TERMINAL_EMULATOR === 'JetBrains-JediTerm';\n}\n","import type { Readable, Writable } from 'node:stream';\nimport { styleText } from 'node:util';\nimport type { State } from '@clack/core';\nimport isUnicodeSupported from 'is-unicode-supported';\n\nexport const unicode = isUnicodeSupported();\nexport const isCI = (): boolean => process.env.CI === 'true';\nexport const isTTY = (output: Writable): boolean => {\n\treturn (output as Writable & { isTTY?: boolean }).isTTY === true;\n};\nexport const unicodeOr = (c: string, fallback: string) => (unicode ? c : fallback);\nexport const S_STEP_ACTIVE = unicodeOr('◆', '*');\nexport const S_STEP_CANCEL = unicodeOr('■', 'x');\nexport const S_STEP_ERROR = unicodeOr('▲', 'x');\nexport const S_STEP_SUBMIT = unicodeOr('◇', 'o');\n\nexport const S_BAR_START = unicodeOr('┌', 'T');\nexport const S_BAR = unicodeOr('│', '|');\nexport const S_BAR_END = unicodeOr('└', '—');\nexport const S_BAR_START_RIGHT = unicodeOr('┐', 'T');\nexport const S_BAR_END_RIGHT = unicodeOr('┘', '—');\n\nexport const S_RADIO_ACTIVE = unicodeOr('●', '>');\nexport const S_RADIO_INACTIVE = unicodeOr('○', ' ');\nexport const S_CHECKBOX_ACTIVE = unicodeOr('◻', '[•]');\nexport const S_CHECKBOX_SELECTED = unicodeOr('◼', '[+]');\nexport const S_CHECKBOX_INACTIVE = unicodeOr('◻', '[ ]');\nexport const S_PASSWORD_MASK = unicodeOr('▪', '•');\n\nexport const S_BAR_H = unicodeOr('─', '-');\nexport const S_CORNER_TOP_RIGHT = unicodeOr('╮', '+');\nexport const S_CONNECT_LEFT = unicodeOr('├', '+');\nexport const S_CORNER_BOTTOM_RIGHT = unicodeOr('╯', '+');\nexport const S_CORNER_BOTTOM_LEFT = unicodeOr('╰', '+');\nexport const S_CORNER_TOP_LEFT = unicodeOr('╭', '+');\n\nexport const S_INFO = unicodeOr('●', '•');\nexport const S_SUCCESS = unicodeOr('◆', '*');\nexport const S_WARN = unicodeOr('▲', '!');\nexport const S_ERROR = unicodeOr('■', 'x');\n\nexport const symbol = (state: State) => {\n\tswitch (state) {\n\t\tcase 'initial':\n\t\tcase 'active':\n\t\t\treturn styleText('cyan', S_STEP_ACTIVE);\n\t\tcase 'cancel':\n\t\t\treturn styleText('red', S_STEP_CANCEL);\n\t\tcase 'error':\n\t\t\treturn styleText('yellow', S_STEP_ERROR);\n\t\tcase 'submit':\n\t\t\treturn styleText('green', S_STEP_SUBMIT);\n\t}\n};\n\nexport const symbolBar = (state: State) => {\n\tswitch (state) {\n\t\tcase 'initial':\n\t\tcase 'active':\n\t\t\treturn styleText('cyan', S_BAR);\n\t\tcase 'cancel':\n\t\t\treturn styleText('red', S_BAR);\n\t\tcase 'error':\n\t\t\treturn styleText('yellow', S_BAR);\n\t\tcase 'submit':\n\t\t\treturn styleText('green', S_BAR);\n\t}\n};\n\nexport interface CommonOptions {\n\tinput?: Readable;\n\toutput?: Writable;\n\tsignal?: AbortSignal;\n\twithGuide?: boolean;\n}\n","import { styleText } from 'node:util';\nimport { getColumns, getRows } from '@clack/core';\nimport { wrapAnsi } from 'fast-wrap-ansi';\nimport type { CommonOptions } from './common.js';\n\nexport interface LimitOptionsParams<TOption> extends CommonOptions {\n\toptions: TOption[];\n\tcursor: number;\n\tstyle: (option: TOption, active: boolean) => string;\n\tmaxItems?: number;\n\tcolumnPadding?: number;\n\trowPadding?: number;\n}\n\nconst trimLines = (\n\tgroups: Array<string[]>,\n\tinitialLineCount: number,\n\tstartIndex: number,\n\tendIndex: number,\n\tmaxLines: number\n) => {\n\tlet lineCount = initialLineCount;\n\tlet removals = 0;\n\tfor (let i = startIndex; i < endIndex; i++) {\n\t\tconst group = groups[i];\n\t\tlineCount = lineCount - group.length;\n\t\tremovals++;\n\t\tif (lineCount <= maxLines) {\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn { lineCount, removals };\n};\n\nexport const limitOptions = <TOption>({\n\tcursor,\n\toptions,\n\tstyle,\n\toutput = process.stdout,\n\tmaxItems = Number.POSITIVE_INFINITY,\n\tcolumnPadding = 0,\n\trowPadding = 4,\n}: LimitOptionsParams<TOption>): string[] => {\n\tconst columns = getColumns(output);\n\tconst maxWidth = columns - columnPadding;\n\tconst rows = getRows(output);\n\tconst overflowFormat = styleText('dim', '...');\n\n\tconst outputMaxItems = Math.max(rows - rowPadding, 0);\n\t// We clamp to minimum 5 because anything less doesn't make sense UX wise\n\tconst computedMaxItems = Math.max(Math.min(maxItems, outputMaxItems), 5);\n\tlet slidingWindowLocation = 0;\n\n\tif (cursor >= computedMaxItems - 3) {\n\t\tslidingWindowLocation = Math.max(\n\t\t\tMath.min(cursor - computedMaxItems + 3, options.length - computedMaxItems),\n\t\t\t0\n\t\t);\n\t}\n\n\tlet shouldRenderTopEllipsis = computedMaxItems < options.length && slidingWindowLocation > 0;\n\tlet shouldRenderBottomEllipsis =\n\t\tcomputedMaxItems < options.length && slidingWindowLocation + computedMaxItems < options.length;\n\n\tconst slidingWindowLocationEnd = Math.min(\n\t\tslidingWindowLocation + computedMaxItems,\n\t\toptions.length\n\t);\n\tconst lineGroups: Array<string[]> = [];\n\tlet lineCount = 0;\n\tif (shouldRenderTopEllipsis) {\n\t\tlineCount++;\n\t}\n\tif (shouldRenderBottomEllipsis) {\n\t\tlineCount++;\n\t}\n\n\tconst slidingWindowLocationWithEllipsis =\n\t\tslidingWindowLocation + (shouldRenderTopEllipsis ? 1 : 0);\n\tconst slidingWindowLocationEndWithEllipsis =\n\t\tslidingWindowLocationEnd - (shouldRenderBottomEllipsis ? 1 : 0);\n\n\tfor (let i = slidingWindowLocationWithEllipsis; i < slidingWindowLocationEndWithEllipsis; i++) {\n\t\tconst wrappedLines = wrapAnsi(style(options[i], i === cursor), maxWidth, {\n\t\t\thard: true,\n\t\t\ttrim: false,\n\t\t}).split('\\n');\n\t\tlineGroups.push(wrappedLines);\n\t\tlineCount += wrappedLines.length;\n\t}\n\n\tif (lineCount > outputMaxItems) {\n\t\tlet precedingRemovals = 0;\n\t\tlet followingRemovals = 0;\n\t\tlet newLineCount = lineCount;\n\t\tconst cursorGroupIndex = cursor - slidingWindowLocationWithEllipsis;\n\t\tconst trimLinesLocal = (startIndex: number, endIndex: number) =>\n\t\t\ttrimLines(lineGroups, newLineCount, startIndex, endIndex, outputMaxItems);\n\n\t\tif (shouldRenderTopEllipsis) {\n\t\t\t({ lineCount: newLineCount, removals: precedingRemovals } = trimLinesLocal(\n\t\t\t\t0,\n\t\t\t\tcursorGroupIndex\n\t\t\t));\n\t\t\tif (newLineCount > outputMaxItems) {\n\t\t\t\t({ lineCount: newLineCount, removals: followingRemovals } = trimLinesLocal(\n\t\t\t\t\tcursorGroupIndex + 1,\n\t\t\t\t\tlineGroups.length\n\t\t\t\t));\n\t\t\t}\n\t\t} else {\n\t\t\t({ lineCount: newLineCount, removals: followingRemovals } = trimLinesLocal(\n\t\t\t\tcursorGroupIndex + 1,\n\t\t\t\tlineGroups.length\n\t\t\t));\n\t\t\tif (newLineCount > outputMaxItems) {\n\t\t\t\t({ lineCount: newLineCount, removals: precedingRemovals } = trimLinesLocal(\n\t\t\t\t\t0,\n\t\t\t\t\tcursorGroupIndex\n\t\t\t\t));\n\t\t\t}\n\t\t}\n\n\t\tif (precedingRemovals > 0) {\n\t\t\tshouldRenderTopEllipsis = true;\n\t\t\tlineGroups.splice(0, precedingRemovals);\n\t\t}\n\t\tif (followingRemovals > 0) {\n\t\t\tshouldRenderBottomEllipsis = true;\n\t\t\tlineGroups.splice(lineGroups.length - followingRemovals, followingRemovals);\n\t\t}\n\t}\n\n\tconst result: string[] = [];\n\tif (shouldRenderTopEllipsis) {\n\t\tresult.push(overflowFormat);\n\t}\n\tfor (const lineGroup of lineGroups) {\n\t\tfor (const line of lineGroup) {\n\t\t\tresult.push(line);\n\t\t}\n\t}\n\tif (shouldRenderBottomEllipsis) {\n\t\tresult.push(overflowFormat);\n\t}\n\n\treturn result;\n};\n","import { styleText } from 'node:util';\nimport { AutocompletePrompt, settings } from '@clack/core';\nimport {\n\ttype CommonOptions,\n\tS_BAR,\n\tS_BAR_END,\n\tS_CHECKBOX_INACTIVE,\n\tS_CHECKBOX_SELECTED,\n\tS_RADIO_ACTIVE,\n\tS_RADIO_INACTIVE,\n\tsymbol,\n} from './common.js';\nimport { limitOptions } from './limit-options.js';\nimport type { Option } from './select.js';\n\nfunction getLabel<T>(option: Option<T>) {\n\treturn option.label ?? String(option.value ?? '');\n}\n\nfunction getFilteredOption<T>(searchText: string, option: Option<T>): boolean {\n\tif (!searchText) {\n\t\treturn true;\n\t}\n\tconst label = (option.label ?? String(option.value ?? '')).toLowerCase();\n\tconst hint = (option.hint ?? '').toLowerCase();\n\tconst value = String(option.value).toLowerCase();\n\tconst term = searchText.toLowerCase();\n\n\treturn label.includes(term) || hint.includes(term) || value.includes(term);\n}\n\nfunction getSelectedOptions<T>(values: T[], options: Option<T>[]): Option<T>[] {\n\tconst results: Option<T>[] = [];\n\n\tfor (const option of options) {\n\t\tif (values.includes(option.value)) {\n\t\t\tresults.push(option);\n\t\t}\n\t}\n\n\treturn results;\n}\n\ninterface AutocompleteSharedOptions<Value> extends CommonOptions {\n\t/**\n\t * The message to display to the user.\n\t */\n\tmessage: string;\n\t/**\n\t * Available options for the autocomplete prompt.\n\t */\n\toptions: Option<Value>[] | ((this: AutocompletePrompt<Option<Value>>) => Option<Value>[]);\n\t/**\n\t * Maximum number of items to display at once.\n\t */\n\tmaxItems?: number;\n\t/**\n\t * Placeholder text to display when no input is provided.\n\t */\n\tplaceholder?: string;\n\t/**\n\t * Validates the value\n\t */\n\tvalidate?: (value: Value | Value[] | undefined) => string | Error | undefined;\n\t/**\n\t * Custom filter function to match options against search input.\n\t * If not provided, a default filter that matches label, hint, and value is used.\n\t */\n\tfilter?: (search: string, option: Option<Value>) => boolean;\n}\n\nexport interface AutocompleteOptions<Value> extends AutocompleteSharedOptions<Value> {\n\t/**\n\t * The initial selected value.\n\t */\n\tinitialValue?: Value;\n\t/**\n\t * The initial user input\n\t */\n\tinitialUserInput?: string;\n}\n\nexport const autocomplete = <Value>(opts: AutocompleteOptions<Value>) => {\n\tconst prompt = new AutocompletePrompt({\n\t\toptions: opts.options,\n\t\tinitialValue: opts.initialValue ? [opts.initialValue] : undefined,\n\t\tinitialUserInput: opts.initialUserInput,\n\t\tplaceholder: opts.placeholder,\n\t\tfilter:\n\t\t\topts.filter ??\n\t\t\t((search: string, opt: Option<Value>) => {\n\t\t\t\treturn getFilteredOption(search, opt);\n\t\t\t}),\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\toutput: opts.output,\n\t\tvalidate: opts.validate,\n\t\trender() {\n\t\t\tconst hasGuide = opts.withGuide ?? settings.withGuide;\n\t\t\t// Title and message display\n\t\t\tconst headings = hasGuide\n\t\t\t\t? [`${styleText('gray', S_BAR)}`, `${symbol(this.state)} ${opts.message}`]\n\t\t\t\t: [`${symbol(this.state)} ${opts.message}`];\n\t\t\tconst userInput = this.userInput;\n\t\t\tconst options = this.options;\n\t\t\tconst placeholder = opts.placeholder;\n\t\t\tconst showPlaceholder = userInput === '' && placeholder !== undefined;\n\t\t\tconst opt = (option: Option<Value>, state: 'inactive' | 'active' | 'disabled') => {\n\t\t\t\tconst label = getLabel(option);\n\t\t\t\tconst hint =\n\t\t\t\t\toption.hint && option.value === this.focusedValue\n\t\t\t\t\t\t? styleText('dim', ` (${option.hint})`)\n\t\t\t\t\t\t: '';\n\t\t\t\tswitch (state) {\n\t\t\t\t\tcase 'active':\n\t\t\t\t\t\treturn `${styleText('green', S_RADIO_ACTIVE)} ${label}${hint}`;\n\t\t\t\t\tcase 'inactive':\n\t\t\t\t\t\treturn `${styleText('dim', S_RADIO_INACTIVE)} ${styleText('dim', label)}`;\n\t\t\t\t\tcase 'disabled':\n\t\t\t\t\t\treturn `${styleText('gray', S_RADIO_INACTIVE)} ${styleText(['strikethrough', 'gray'], label)}`;\n\t\t\t\t}\n\t\t\t};\n\n\t\t\t// Handle different states\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'submit': {\n\t\t\t\t\t// Show selected value\n\t\t\t\t\tconst selected = getSelectedOptions(this.selectedValues, options);\n\t\t\t\t\tconst label =\n\t\t\t\t\t\tselected.length > 0 ? ` ${styleText('dim', selected.map(getLabel).join(', '))}` : '';\n\t\t\t\t\tconst submitPrefix = hasGuide ? styleText('gray', S_BAR) : '';\n\t\t\t\t\treturn `${headings.join('\\n')}\\n${submitPrefix}${label}`;\n\t\t\t\t}\n\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst userInputText = userInput\n\t\t\t\t\t\t? ` ${styleText(['strikethrough', 'dim'], userInput)}`\n\t\t\t\t\t\t: '';\n\t\t\t\t\tconst cancelPrefix = hasGuide ? styleText('gray', S_BAR) : '';\n\t\t\t\t\treturn `${headings.join('\\n')}\\n${cancelPrefix}${userInputText}`;\n\t\t\t\t}\n\n\t\t\t\tdefault: {\n\t\t\t\t\tconst barStyle = this.state === 'error' ? 'yellow' : 'cyan';\n\t\t\t\t\tconst guidePrefix = hasGuide ? `${styleText(barStyle, S_BAR)} ` : '';\n\t\t\t\t\tconst guidePrefixEnd = hasGuide ? styleText(barStyle, S_BAR_END) : '';\n\t\t\t\t\t// Display cursor position - show plain text in navigation mode\n\t\t\t\t\tlet searchText = '';\n\t\t\t\t\tif (this.isNavigating || showPlaceholder) {\n\t\t\t\t\t\tconst searchTextValue = showPlaceholder ? placeholder : userInput;\n\t\t\t\t\t\tsearchText = searchTextValue !== '' ? ` ${styleText('dim', searchTextValue)}` : '';\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsearchText = ` ${this.userInputWithCursor}`;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Show match count if filtered\n\t\t\t\t\tconst matches =\n\t\t\t\t\t\tthis.filteredOptions.length !== options.length\n\t\t\t\t\t\t\t? styleText(\n\t\t\t\t\t\t\t\t\t'dim',\n\t\t\t\t\t\t\t\t\t` (${this.filteredOptions.length} match${this.filteredOptions.length === 1 ? '' : 'es'})`\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t: '';\n\n\t\t\t\t\t// No matches message\n\t\t\t\t\tconst noResults =\n\t\t\t\t\t\tthis.filteredOptions.length === 0 && userInput\n\t\t\t\t\t\t\t? [`${guidePrefix}${styleText('yellow', 'No matches found')}`]\n\t\t\t\t\t\t\t: [];\n\n\t\t\t\t\tconst validationError =\n\t\t\t\t\t\tthis.state === 'error' ? [`${guidePrefix}${styleText('yellow', this.error)}`] : [];\n\n\t\t\t\t\tif (hasGuide) {\n\t\t\t\t\t\theadings.push(`${guidePrefix.trimEnd()}`);\n\t\t\t\t\t}\n\t\t\t\t\theadings.push(\n\t\t\t\t\t\t`${guidePrefix}${styleText('dim', 'Search:')}${searchText}${matches}`,\n\t\t\t\t\t\t...noResults,\n\t\t\t\t\t\t...validationError\n\t\t\t\t\t);\n\n\t\t\t\t\t// Show instructions\n\t\t\t\t\tconst instructions = [\n\t\t\t\t\t\t`${styleText('dim', '↑/↓')} to select`,\n\t\t\t\t\t\t`${styleText('dim', 'Enter:')} confirm`,\n\t\t\t\t\t\t`${styleText('dim', 'Type:')} to search`,\n\t\t\t\t\t];\n\n\t\t\t\t\tconst footers = [`${guidePrefix}${instructions.join(' • ')}`, guidePrefixEnd];\n\n\t\t\t\t\t// Render options with selection\n\t\t\t\t\tconst displayOptions =\n\t\t\t\t\t\tthis.filteredOptions.length === 0\n\t\t\t\t\t\t\t? []\n\t\t\t\t\t\t\t: limitOptions({\n\t\t\t\t\t\t\t\t\tcursor: this.cursor,\n\t\t\t\t\t\t\t\t\toptions: this.filteredOptions,\n\t\t\t\t\t\t\t\t\tcolumnPadding: hasGuide ? 3 : 0, // for `| ` when guide is shown\n\t\t\t\t\t\t\t\t\trowPadding: headings.length + footers.length,\n\t\t\t\t\t\t\t\t\tstyle: (option, active) => {\n\t\t\t\t\t\t\t\t\t\treturn opt(\n\t\t\t\t\t\t\t\t\t\t\toption,\n\t\t\t\t\t\t\t\t\t\t\toption.disabled ? 'disabled' : active ? 'active' : 'inactive'\n\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tmaxItems: opts.maxItems,\n\t\t\t\t\t\t\t\t\toutput: opts.output,\n\t\t\t\t\t\t\t\t});\n\n\t\t\t\t\t// Return the formatted prompt\n\t\t\t\t\treturn [\n\t\t\t\t\t\t...headings,\n\t\t\t\t\t\t...displayOptions.map((option) => `${guidePrefix}${option}`),\n\t\t\t\t\t\t...footers,\n\t\t\t\t\t].join('\\n');\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t});\n\n\t// Return the result or cancel symbol\n\treturn prompt.prompt() as Promise<Value | symbol>;\n};\n\n// Type definition for the autocompleteMultiselect component\nexport interface AutocompleteMultiSelectOptions<Value> extends AutocompleteSharedOptions<Value> {\n\t/**\n\t * The initial selected values\n\t */\n\tinitialValues?: Value[];\n\t/**\n\t * If true, at least one option must be selected\n\t */\n\trequired?: boolean;\n}\n\n/**\n * Integrated autocomplete multiselect - combines type-ahead filtering with multiselect in one UI\n */\nexport const autocompleteMultiselect = <Value>(opts: AutocompleteMultiSelectOptions<Value>) => {\n\tconst formatOption = (\n\t\toption: Option<Value>,\n\t\tactive: boolean,\n\t\tselectedValues: Value[],\n\t\tfocusedValue: Value | undefined\n\t) => {\n\t\tconst isSelected = selectedValues.includes(option.value);\n\t\tconst label = option.label ?? String(option.value ?? '');\n\t\tconst hint =\n\t\t\toption.hint && focusedValue !== undefined && option.value === focusedValue\n\t\t\t\t? styleText('dim', ` (${option.hint})`)\n\t\t\t\t: '';\n\t\tconst checkbox = isSelected\n\t\t\t? styleText('green', S_CHECKBOX_SELECTED)\n\t\t\t: styleText('dim', S_CHECKBOX_INACTIVE);\n\n\t\tif (option.disabled) {\n\t\t\treturn `${styleText('gray', S_CHECKBOX_INACTIVE)} ${styleText(['strikethrough', 'gray'], label)}`;\n\t\t}\n\t\tif (active) {\n\t\t\treturn `${checkbox} ${label}${hint}`;\n\t\t}\n\t\treturn `${checkbox} ${styleText('dim', label)}`;\n\t};\n\n\t// Create text prompt which we'll use as foundation\n\tconst prompt = new AutocompletePrompt<Option<Value>>({\n\t\toptions: opts.options,\n\t\tmultiple: true,\n\t\tplaceholder: opts.placeholder,\n\t\tfilter:\n\t\t\topts.filter ??\n\t\t\t((search, opt) => {\n\t\t\t\treturn getFilteredOption(search, opt);\n\t\t\t}),\n\t\tvalidate: () => {\n\t\t\tif (opts.required && prompt.selectedValues.length === 0) {\n\t\t\t\treturn 'Please select at least one item';\n\t\t\t}\n\t\t\treturn undefined;\n\t\t},\n\t\tinitialValue: opts.initialValues,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\toutput: opts.output,\n\t\trender() {\n\t\t\tconst hasGuide = opts.withGuide ?? settings.withGuide;\n\t\t\t// Title and symbol\n\t\t\tconst title = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${symbol(this.state)} ${\n\t\t\t\topts.message\n\t\t\t}\\n`;\n\n\t\t\t// Selection counter\n\t\t\tconst userInput = this.userInput;\n\t\t\tconst placeholder = opts.placeholder;\n\t\t\tconst showPlaceholder = userInput === '' && placeholder !== undefined;\n\n\t\t\t// Search input display\n\t\t\tconst searchText =\n\t\t\t\tthis.isNavigating || showPlaceholder\n\t\t\t\t\t? styleText('dim', showPlaceholder ? placeholder : userInput) // Just show plain text when in navigation mode\n\t\t\t\t\t: this.userInputWithCursor;\n\n\t\t\tconst options = this.options;\n\n\t\t\tconst matches =\n\t\t\t\tthis.filteredOptions.length !== options.length\n\t\t\t\t\t? styleText(\n\t\t\t\t\t\t\t'dim',\n\t\t\t\t\t\t\t` (${this.filteredOptions.length} match${this.filteredOptions.length === 1 ? '' : 'es'})`\n\t\t\t\t\t\t)\n\t\t\t\t\t: '';\n\n\t\t\t// Render prompt state\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'submit': {\n\t\t\t\t\treturn `${title}${hasGuide ? `${styleText('gray', S_BAR)} ` : ''}${styleText(\n\t\t\t\t\t\t'dim',\n\t\t\t\t\t\t`${this.selectedValues.length} items selected`\n\t\t\t\t\t)}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\treturn `${title}${hasGuide ? `${styleText('gray', S_BAR)} ` : ''}${styleText(\n\t\t\t\t\t\t['strikethrough', 'dim'],\n\t\t\t\t\t\tuserInput\n\t\t\t\t\t)}`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst barStyle = this.state === 'error' ? 'yellow' : 'cyan';\n\t\t\t\t\tconst guidePrefix = hasGuide ? `${styleText(barStyle, S_BAR)} ` : '';\n\t\t\t\t\tconst guidePrefixEnd = hasGuide ? styleText(barStyle, S_BAR_END) : '';\n\t\t\t\t\t// Instructions\n\t\t\t\t\tconst instructions = [\n\t\t\t\t\t\t`${styleText('dim', '↑/↓')} to navigate`,\n\t\t\t\t\t\t`${styleText('dim', this.isNavigating ? 'Space/Tab:' : 'Tab:')} select`,\n\t\t\t\t\t\t`${styleText('dim', 'Enter:')} confirm`,\n\t\t\t\t\t\t`${styleText('dim', 'Type:')} to search`,\n\t\t\t\t\t];\n\n\t\t\t\t\t// No results message\n\t\t\t\t\tconst noResults =\n\t\t\t\t\t\tthis.filteredOptions.length === 0 && userInput\n\t\t\t\t\t\t\t? [`${guidePrefix}${styleText('yellow', 'No matches found')}`]\n\t\t\t\t\t\t\t: [];\n\n\t\t\t\t\tconst errorMessage =\n\t\t\t\t\t\tthis.state === 'error' ? [`${guidePrefix}${styleText('yellow', this.error)}`] : [];\n\n\t\t\t\t\t// Calculate header and footer line counts for rowPadding\n\t\t\t\t\tconst headerLines = [\n\t\t\t\t\t\t...`${title}${hasGuide ? styleText(barStyle, S_BAR) : ''}`.split('\\n'),\n\t\t\t\t\t\t`${guidePrefix}${styleText('dim', 'Search:')} ${searchText}${matches}`,\n\t\t\t\t\t\t...noResults,\n\t\t\t\t\t\t...errorMessage,\n\t\t\t\t\t];\n\t\t\t\t\tconst footerLines = [`${guidePrefix}${instructions.join(' • ')}`, guidePrefixEnd];\n\n\t\t\t\t\t// Get limited options for display\n\t\t\t\t\tconst displayOptions = limitOptions({\n\t\t\t\t\t\tcursor: this.cursor,\n\t\t\t\t\t\toptions: this.filteredOptions,\n\t\t\t\t\t\tstyle: (option, active) =>\n\t\t\t\t\t\t\tformatOption(option, active, this.selectedValues, this.focusedValue),\n\t\t\t\t\t\tmaxItems: opts.maxItems,\n\t\t\t\t\t\toutput: opts.output,\n\t\t\t\t\t\trowPadding: headerLines.length + footerLines.length,\n\t\t\t\t\t});\n\n\t\t\t\t\t// Build the prompt display\n\t\t\t\t\treturn [\n\t\t\t\t\t\t...headerLines,\n\t\t\t\t\t\t...displayOptions.map((option) => `${guidePrefix}${option}`),\n\t\t\t\t\t\t...footerLines,\n\t\t\t\t\t].join('\\n');\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t});\n\n\t// Return the result or cancel symbol\n\treturn prompt.prompt() as Promise<Value[] | symbol>;\n};\n","import type { Writable } from 'node:stream';\nimport { getColumns, settings } from '@clack/core';\nimport stringWidth from 'fast-string-width';\nimport { wrapAnsi } from 'fast-wrap-ansi';\nimport {\n\ttype CommonOptions,\n\tS_BAR,\n\tS_BAR_END,\n\tS_BAR_END_RIGHT,\n\tS_BAR_H,\n\tS_BAR_START,\n\tS_BAR_START_RIGHT,\n\tS_CORNER_BOTTOM_LEFT,\n\tS_CORNER_BOTTOM_RIGHT,\n\tS_CORNER_TOP_LEFT,\n\tS_CORNER_TOP_RIGHT,\n} from './common.js';\n\nexport type BoxAlignment = 'left' | 'center' | 'right';\n\ntype BoxSymbols = [topLeft: string, topRight: string, bottomLeft: string, bottomRight: string];\n\nconst roundedSymbols: BoxSymbols = [\n\tS_CORNER_TOP_LEFT,\n\tS_CORNER_TOP_RIGHT,\n\tS_CORNER_BOTTOM_LEFT,\n\tS_CORNER_BOTTOM_RIGHT,\n];\nconst squareSymbols: BoxSymbols = [S_BAR_START, S_BAR_START_RIGHT, S_BAR_END, S_BAR_END_RIGHT];\n\nexport interface BoxOptions extends CommonOptions {\n\tcontentAlign?: BoxAlignment;\n\ttitleAlign?: BoxAlignment;\n\twidth?: number | 'auto';\n\ttitlePadding?: number;\n\tcontentPadding?: number;\n\trounded?: boolean;\n\tformatBorder?: (text: string) => string;\n}\n\nfunction getPaddingForLine(\n\tlineLength: number,\n\tinnerWidth: number,\n\tpadding: number,\n\tcontentAlign: BoxAlignment | undefined\n): [number, number] {\n\tlet leftPadding = padding;\n\tlet rightPadding = padding;\n\tif (contentAlign === 'center') {\n\t\tleftPadding = Math.floor((innerWidth - lineLength) / 2);\n\t} else if (contentAlign === 'right') {\n\t\tleftPadding = innerWidth - lineLength - padding;\n\t}\n\n\trightPadding = innerWidth - leftPadding - lineLength;\n\n\treturn [leftPadding, rightPadding];\n}\n\nconst defaultFormatBorder = (text: string) => text;\n\nexport const box = (message = '', title = '', opts?: BoxOptions) => {\n\tconst output: Writable = opts?.output ?? process.stdout;\n\tconst columns = getColumns(output);\n\tconst borderWidth = 1;\n\tconst borderTotalWidth = borderWidth * 2;\n\tconst titlePadding = opts?.titlePadding ?? 1;\n\tconst contentPadding = opts?.contentPadding ?? 2;\n\tconst width = opts?.width === undefined || opts.width === 'auto' ? 1 : Math.min(1, opts.width);\n\tconst hasGuide = opts?.withGuide ?? settings.withGuide;\n\tconst linePrefix = !hasGuide ? '' : `${S_BAR} `;\n\tconst formatBorder = opts?.formatBorder ?? defaultFormatBorder;\n\tconst symbols = (opts?.rounded ? roundedSymbols : squareSymbols).map(formatBorder);\n\tconst hSymbol = formatBorder(S_BAR_H);\n\tconst vSymbol = formatBorder(S_BAR);\n\tconst linePrefixWidth = stringWidth(linePrefix);\n\tconst titleWidth = stringWidth(title);\n\tconst maxBoxWidth = columns - linePrefixWidth;\n\tlet boxWidth = Math.floor(columns * width) - linePrefixWidth;\n\tif (opts?.width === 'auto') {\n\t\tconst lines = message.split('\\n');\n\t\tlet longestLine = titleWidth + titlePadding * 2;\n\t\tfor (const line of lines) {\n\t\t\tconst lineWithPadding = stringWidth(line) + contentPadding * 2;\n\t\t\tif (lineWithPadding > longestLine) {\n\t\t\t\tlongestLine = lineWithPadding;\n\t\t\t}\n\t\t}\n\t\tconst longestLineWidth = longestLine + borderTotalWidth;\n\t\tif (longestLineWidth < boxWidth) {\n\t\t\tboxWidth = longestLineWidth;\n\t\t}\n\t}\n\tif (boxWidth % 2 !== 0) {\n\t\tif (boxWidth < maxBoxWidth) {\n\t\t\tboxWidth++;\n\t\t} else {\n\t\t\tboxWidth--;\n\t\t}\n\t}\n\tconst innerWidth = boxWidth - borderTotalWidth;\n\tconst maxTitleLength = innerWidth - titlePadding * 2;\n\tconst truncatedTitle =\n\t\ttitleWidth > maxTitleLength ? `${title.slice(0, maxTitleLength - 3)}...` : title;\n\tconst [titlePaddingLeft, titlePaddingRight] = getPaddingForLine(\n\t\tstringWidth(truncatedTitle),\n\t\tinnerWidth,\n\t\ttitlePadding,\n\t\topts?.titleAlign\n\t);\n\tconst wrappedMessage = wrapAnsi(message, innerWidth - contentPadding * 2, {\n\t\thard: true,\n\t\ttrim: false,\n\t});\n\toutput.write(\n\t\t`${linePrefix}${symbols[0]}${hSymbol.repeat(titlePaddingLeft)}${truncatedTitle}${hSymbol.repeat(titlePaddingRight)}${symbols[1]}\\n`\n\t);\n\tconst wrappedLines = wrappedMessage.split('\\n');\n\tfor (const line of wrappedLines) {\n\t\tconst [leftLinePadding, rightLinePadding] = getPaddingForLine(\n\t\t\tstringWidth(line),\n\t\t\tinnerWidth,\n\t\t\tcontentPadding,\n\t\t\topts?.contentAlign\n\t\t);\n\t\toutput.write(\n\t\t\t`${linePrefix}${vSymbol}${' '.repeat(leftLinePadding)}${line}${' '.repeat(rightLinePadding)}${vSymbol}\\n`\n\t\t);\n\t}\n\toutput.write(`${linePrefix}${symbols[2]}${hSymbol.repeat(innerWidth)}${symbols[3]}\\n`);\n};\n","import { styleText } from 'node:util';\nimport { ConfirmPrompt, settings, wrapTextWithPrefix } from '@clack/core';\nimport {\n\ttype CommonOptions,\n\tS_BAR,\n\tS_BAR_END,\n\tS_RADIO_ACTIVE,\n\tS_RADIO_INACTIVE,\n\tsymbol,\n} from './common.js';\n\nexport interface ConfirmOptions extends CommonOptions {\n\tmessage: string;\n\tactive?: string;\n\tinactive?: string;\n\tinitialValue?: boolean;\n\tvertical?: boolean;\n}\nexport const confirm = (opts: ConfirmOptions) => {\n\tconst active = opts.active ?? 'Yes';\n\tconst inactive = opts.inactive ?? 'No';\n\treturn new ConfirmPrompt({\n\t\tactive,\n\t\tinactive,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\toutput: opts.output,\n\t\tinitialValue: opts.initialValue ?? true,\n\t\trender() {\n\t\t\tconst hasGuide = opts.withGuide ?? settings.withGuide;\n\t\t\tconst titlePrefix = `${symbol(this.state)} `;\n\t\t\tconst titlePrefixBar = hasGuide ? `${styleText('gray', S_BAR)} ` : '';\n\t\t\tconst messageLines = wrapTextWithPrefix(\n\t\t\t\topts.output,\n\t\t\t\topts.message,\n\t\t\t\ttitlePrefixBar,\n\t\t\t\ttitlePrefix\n\t\t\t);\n\t\t\tconst title = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${messageLines}\\n`;\n\t\t\tconst value = this.value ? active : inactive;\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst submitPrefix = hasGuide ? `${styleText('gray', S_BAR)} ` : '';\n\t\t\t\t\treturn `${title}${submitPrefix}${styleText('dim', value)}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst cancelPrefix = hasGuide ? `${styleText('gray', S_BAR)} ` : '';\n\t\t\t\t\treturn `${title}${cancelPrefix}${styleText(['strikethrough', 'dim'], value)}${\n\t\t\t\t\t\thasGuide ? `\\n${styleText('gray', S_BAR)}` : ''\n\t\t\t\t\t}`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst defaultPrefix = hasGuide ? `${styleText('cyan', S_BAR)} ` : '';\n\t\t\t\t\tconst defaultPrefixEnd = hasGuide ? styleText('cyan', S_BAR_END) : '';\n\t\t\t\t\treturn `${title}${defaultPrefix}${\n\t\t\t\t\t\tthis.value\n\t\t\t\t\t\t\t? `${styleText('green', S_RADIO_ACTIVE)} ${active}`\n\t\t\t\t\t\t\t: `${styleText('dim', S_RADIO_INACTIVE)} ${styleText('dim', active)}`\n\t\t\t\t\t}${opts.vertical ? (hasGuide ? `\\n${styleText('cyan', S_BAR)} ` : '\\n') : ` ${styleText('dim', '/')} `}${\n\t\t\t\t\t\t!this.value\n\t\t\t\t\t\t\t? `${styleText('green', S_RADIO_ACTIVE)} ${inactive}`\n\t\t\t\t\t\t\t: `${styleText('dim', S_RADIO_INACTIVE)} ${styleText('dim', inactive)}`\n\t\t\t\t\t}\\n${defaultPrefixEnd}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<boolean | symbol>;\n};\n","import { styleText } from 'node:util';\nimport type { DateFormat, State } from '@clack/core';\nimport { DatePrompt, settings } from '@clack/core';\nimport { type CommonOptions, S_BAR, S_BAR_END, symbol } from './common.js';\n\nexport type { DateFormat };\n\nexport interface DateOptions extends CommonOptions {\n\tmessage: string;\n\tformat?: DateFormat;\n\tlocale?: string;\n\tdefaultValue?: Date;\n\tinitialValue?: Date;\n\tminDate?: Date;\n\tmaxDate?: Date;\n\tvalidate?: (value: Date | undefined) => string | Error | undefined;\n}\n\nexport const date = (opts: DateOptions) => {\n\tconst validate = opts.validate;\n\treturn new DatePrompt({\n\t\t...opts,\n\t\tvalidate(value: Date | undefined) {\n\t\t\tif (value === undefined) {\n\t\t\t\tif (opts.defaultValue !== undefined) return undefined;\n\t\t\t\tif (validate) return validate(value);\n\t\t\t\treturn settings.date.messages.required;\n\t\t\t}\n\t\t\tconst iso = (d: Date) => d.toISOString().slice(0, 10);\n\t\t\tif (opts.minDate && iso(value) < iso(opts.minDate)) {\n\t\t\t\treturn settings.date.messages.afterMin(opts.minDate);\n\t\t\t}\n\t\t\tif (opts.maxDate && iso(value) > iso(opts.maxDate)) {\n\t\t\t\treturn settings.date.messages.beforeMax(opts.maxDate);\n\t\t\t}\n\t\t\tif (validate) return validate(value);\n\t\t\treturn undefined;\n\t\t},\n\t\trender() {\n\t\t\tconst hasGuide = (opts?.withGuide ?? settings.withGuide) !== false;\n\t\t\tconst titlePrefix = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${symbol(this.state)} `;\n\t\t\tconst title = `${titlePrefix}${opts.message}\\n`;\n\n\t\t\tconst state = this.state !== 'initial' ? this.state : 'active';\n\n\t\t\tconst userInput = renderDate(this, state);\n\t\t\tconst value = this.value instanceof Date ? this.formattedValue : '';\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'error': {\n\t\t\t\t\tconst errorText = this.error ? ` ${styleText('yellow', this.error)}` : '';\n\t\t\t\t\tconst bar = hasGuide ? `${styleText('yellow', S_BAR)} ` : '';\n\t\t\t\t\tconst barEnd = hasGuide ? styleText('yellow', S_BAR_END) : '';\n\t\t\t\t\treturn `${title.trim()}\\n${bar}${userInput}\\n${barEnd}${errorText}\\n`;\n\t\t\t\t}\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst valueText = value ? ` ${styleText('dim', value)}` : '';\n\t\t\t\t\tconst bar = hasGuide ? styleText('gray', S_BAR) : '';\n\t\t\t\t\treturn `${title}${bar}${valueText}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst valueText = value ? ` ${styleText(['strikethrough', 'dim'], value)}` : '';\n\t\t\t\t\tconst bar = hasGuide ? styleText('gray', S_BAR) : '';\n\t\t\t\t\treturn `${title}${bar}${valueText}${value.trim() ? `\\n${bar}` : ''}`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst bar = hasGuide ? `${styleText('cyan', S_BAR)} ` : '';\n\t\t\t\t\tconst barEnd = hasGuide ? styleText('cyan', S_BAR_END) : '';\n\t\t\t\t\tconst inlineBar = hasGuide ? `${styleText('cyan', S_BAR)} ` : '';\n\t\t\t\t\tconst inlineError = this.inlineError\n\t\t\t\t\t\t? `\\n${inlineBar}${styleText('yellow', this.inlineError)}`\n\t\t\t\t\t\t: '';\n\t\t\t\t\treturn `${title}${bar}${userInput}${inlineError}\\n${barEnd}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<Date | symbol>;\n};\n\nfunction renderDate(prompt: Omit<InstanceType<typeof DatePrompt>, 'prompt'>, state: State): string {\n\tconst parts = prompt.segmentValues;\n\tconst cursor = prompt.segmentCursor;\n\n\tif (state === 'submit' || state === 'cancel') {\n\t\treturn prompt.formattedValue;\n\t}\n\n\tconst sep = styleText('gray', prompt.separator);\n\treturn prompt.segments\n\t\t.map((seg, i) => {\n\t\t\tconst isActive = i === cursor.segmentIndex && !['submit', 'cancel'].includes(state);\n\t\t\tconst label = DEFAULT_LABELS[seg.type];\n\t\t\treturn renderSegment(parts[seg.type], { isActive, label });\n\t\t})\n\t\t.join(sep);\n}\n\ninterface SegmentOptions {\n\tisActive: boolean;\n\tlabel: string;\n}\nfunction renderSegment(value: string, opts: SegmentOptions): string {\n\tconst isBlank = !value || value.replace(/_/g, '') === '';\n\tif (opts.isActive) return styleText('inverse', isBlank ? opts.label : value.replace(/_/g, ' '));\n\tif (isBlank) return styleText('dim', opts.label);\n\treturn value.replace(/_/g, styleText('dim', ' '));\n}\n\nconst DEFAULT_LABELS: Record<'year' | 'month' | 'day', string> = {\n\tyear: 'yyyy',\n\tmonth: 'mm',\n\tday: 'dd',\n};\n","import { isCancel } from '@clack/core';\n\ntype Prettify<T> = {\n\t[P in keyof T]: T[P];\n} & {};\n\nexport type PromptGroupAwaitedReturn<T> = {\n\t[P in keyof T]: Exclude<Awaited<T[P]>, symbol>;\n};\n\nexport interface PromptGroupOptions<T> {\n\t/**\n\t * Control how the group can be canceled\n\t * if one of the prompts is canceled.\n\t */\n\tonCancel?: (opts: { results: Prettify<Partial<PromptGroupAwaitedReturn<T>>> }) => void;\n}\n\nexport type PromptGroup<T> = {\n\t[P in keyof T]: (opts: {\n\t\tresults: Prettify<Partial<PromptGroupAwaitedReturn<Omit<T, P>>>>;\n\t}) => undefined | Promise<T[P] | undefined>;\n};\n\n/**\n * Define a group of prompts to be displayed\n * and return a results of objects within the group\n */\nexport const group = async <T>(\n\tprompts: PromptGroup<T>,\n\topts?: PromptGroupOptions<T>\n): Promise<Prettify<PromptGroupAwaitedReturn<T>>> => {\n\tconst results = {} as any;\n\tconst promptNames = Object.keys(prompts);\n\n\tfor (const name of promptNames) {\n\t\tconst prompt = prompts[name as keyof T];\n\t\tconst result = await prompt({ results })?.catch((e) => {\n\t\t\tthrow e;\n\t\t});\n\n\t\t// Pass the results to the onCancel function\n\t\t// so the user can decide what to do with the results\n\t\t// TODO: Switch to callback within core to avoid isCancel Fn\n\t\tif (typeof opts?.onCancel === 'function' && isCancel(result)) {\n\t\t\tresults[name] = 'canceled';\n\t\t\topts.onCancel({ results });\n\t\t\tcontinue;\n\t\t}\n\n\t\tresults[name] = result;\n\t}\n\n\treturn results;\n};\n","import { styleText } from 'node:util';\nimport { GroupMultiSelectPrompt, settings } from '@clack/core';\nimport {\n\ttype CommonOptions,\n\tS_BAR,\n\tS_BAR_END,\n\tS_CHECKBOX_ACTIVE,\n\tS_CHECKBOX_INACTIVE,\n\tS_CHECKBOX_SELECTED,\n\tsymbol,\n} from './common.js';\nimport type { Option } from './select.js';\n\nexport interface GroupMultiSelectOptions<Value> extends CommonOptions {\n\tmessage: string;\n\toptions: Record<string, Option<Value>[]>;\n\tinitialValues?: Value[];\n\trequired?: boolean;\n\tcursorAt?: Value;\n\tselectableGroups?: boolean;\n\tgroupSpacing?: number;\n}\nexport const groupMultiselect = <Value>(opts: GroupMultiSelectOptions<Value>) => {\n\tconst { selectableGroups = true, groupSpacing = 0 } = opts;\n\tconst opt = (\n\t\toption: Option<Value> & { group: string | boolean },\n\t\tstate:\n\t\t\t| 'inactive'\n\t\t\t| 'active'\n\t\t\t| 'selected'\n\t\t\t| 'active-selected'\n\t\t\t| 'group-active'\n\t\t\t| 'group-active-selected'\n\t\t\t| 'submitted'\n\t\t\t| 'cancelled',\n\t\toptions: (Option<Value> & { group: string | boolean })[] = []\n\t) => {\n\t\tconst label = option.label ?? String(option.value);\n\t\tconst isItem = typeof option.group === 'string';\n\t\tconst next = isItem && (options[options.indexOf(option) + 1] ?? { group: true });\n\t\tconst isLast = isItem && next && next.group === true;\n\t\tconst prefix = isItem ? (selectableGroups ? `${isLast ? S_BAR_END : S_BAR} ` : ' ') : '';\n\t\tlet spacingPrefix = '';\n\t\tif (groupSpacing > 0 && !isItem) {\n\t\t\tconst spacingPrefixText = `\\n${styleText('cyan', S_BAR)}`;\n\t\t\tspacingPrefix = `${spacingPrefixText.repeat(groupSpacing - 1)}${spacingPrefixText} `;\n\t\t}\n\n\t\tif (state === 'active') {\n\t\t\treturn `${spacingPrefix}${styleText('dim', prefix)}${styleText('cyan', S_CHECKBOX_ACTIVE)} ${label}${\n\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t\t}`;\n\t\t}\n\t\tif (state === 'group-active') {\n\t\t\treturn `${spacingPrefix}${prefix}${styleText('cyan', S_CHECKBOX_ACTIVE)} ${styleText('dim', label)}`;\n\t\t}\n\t\tif (state === 'group-active-selected') {\n\t\t\treturn `${spacingPrefix}${prefix}${styleText('green', S_CHECKBOX_SELECTED)} ${styleText('dim', label)}`;\n\t\t}\n\t\tif (state === 'selected') {\n\t\t\tconst selectedCheckbox =\n\t\t\t\tisItem || selectableGroups ? styleText('green', S_CHECKBOX_SELECTED) : '';\n\t\t\treturn `${spacingPrefix}${styleText('dim', prefix)}${selectedCheckbox} ${styleText('dim', label)}${\n\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t\t}`;\n\t\t}\n\t\tif (state === 'cancelled') {\n\t\t\treturn `${styleText(['strikethrough', 'dim'], label)}`;\n\t\t}\n\t\tif (state === 'active-selected') {\n\t\t\treturn `${spacingPrefix}${styleText('dim', prefix)}${styleText('green', S_CHECKBOX_SELECTED)} ${label}${\n\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t\t}`;\n\t\t}\n\t\tif (state === 'submitted') {\n\t\t\treturn `${styleText('dim', label)}`;\n\t\t}\n\t\tconst unselectedCheckbox =\n\t\t\tisItem || selectableGroups ? styleText('dim', S_CHECKBOX_INACTIVE) : '';\n\t\treturn `${spacingPrefix}${styleText('dim', prefix)}${unselectedCheckbox} ${styleText('dim', label)}`;\n\t};\n\tconst required = opts.required ?? true;\n\n\treturn new GroupMultiSelectPrompt({\n\t\toptions: opts.options,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\toutput: opts.output,\n\t\tinitialValues: opts.initialValues,\n\t\trequired,\n\t\tcursorAt: opts.cursorAt,\n\t\tselectableGroups,\n\t\tvalidate(selected: Value[] | undefined) {\n\t\t\tif (required && (selected === undefined || selected.length === 0))\n\t\t\t\treturn `Please select at least one option.\\n${styleText(\n\t\t\t\t\t'reset',\n\t\t\t\t\tstyleText(\n\t\t\t\t\t\t'dim',\n\t\t\t\t\t\t`Press ${styleText(['gray', 'bgWhite', 'inverse'], ' space ')} to select, ${styleText(\n\t\t\t\t\t\t\t'gray',\n\t\t\t\t\t\t\tstyleText(['bgWhite', 'inverse'], ' enter ')\n\t\t\t\t\t\t)} to submit`\n\t\t\t\t\t)\n\t\t\t\t)}`;\n\t\t},\n\t\trender() {\n\t\t\tconst hasGuide = opts.withGuide ?? settings.withGuide;\n\t\t\tconst title = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${symbol(this.state)} ${opts.message}\\n`;\n\t\t\tconst value = this.value ?? [];\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst selectedOptions = this.options\n\t\t\t\t\t\t.filter(({ value: optionValue }) => value.includes(optionValue))\n\t\t\t\t\t\t.map((option) => opt(option, 'submitted'));\n\t\t\t\t\tconst optionsText =\n\t\t\t\t\t\tselectedOptions.length === 0 ? '' : ` ${selectedOptions.join(styleText('dim', ', '))}`;\n\t\t\t\t\treturn `${title}${hasGuide ? styleText('gray', S_BAR) : ''}${optionsText}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst label = this.options\n\t\t\t\t\t\t.filter(({ value: optionValue }) => value.includes(optionValue))\n\t\t\t\t\t\t.map((option) => opt(option, 'cancelled'))\n\t\t\t\t\t\t.join(styleText('dim', ', '));\n\t\t\t\t\treturn `${title}${hasGuide ? `${styleText('gray', S_BAR)} ` : ''}${\n\t\t\t\t\t\tlabel.trim() ? `${label}${hasGuide ? `\\n${styleText('gray', S_BAR)}` : ''}` : ''\n\t\t\t\t\t}`;\n\t\t\t\t}\n\t\t\t\tcase 'error': {\n\t\t\t\t\tconst footer = this.error\n\t\t\t\t\t\t.split('\\n')\n\t\t\t\t\t\t.map((ln, i) =>\n\t\t\t\t\t\t\ti === 0\n\t\t\t\t\t\t\t\t? `${hasGuide ? `${styleText('yellow', S_BAR_END)} ` : ''}${styleText('yellow', ln)}`\n\t\t\t\t\t\t\t\t: ` ${ln}`\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.join('\\n');\n\t\t\t\t\treturn `${title}${hasGuide ? `${styleText('yellow', S_BAR)} ` : ''}${this.options\n\t\t\t\t\t\t.map((option, i, options) => {\n\t\t\t\t\t\t\tconst selected =\n\t\t\t\t\t\t\t\tvalue.includes(option.value) ||\n\t\t\t\t\t\t\t\t(option.group === true && this.isGroupSelected(`${option.value}`));\n\t\t\t\t\t\t\tconst active = i === this.cursor;\n\t\t\t\t\t\t\tconst groupActive =\n\t\t\t\t\t\t\t\t!active &&\n\t\t\t\t\t\t\t\ttypeof option.group === 'string' &&\n\t\t\t\t\t\t\t\tthis.options[this.cursor].value === option.group;\n\t\t\t\t\t\t\tif (groupActive) {\n\t\t\t\t\t\t\t\treturn opt(option, selected ? 'group-active-selected' : 'group-active', options);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (active && selected) {\n\t\t\t\t\t\t\t\treturn opt(option, 'active-selected', options);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (selected) {\n\t\t\t\t\t\t\t\treturn opt(option, 'selected', options);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn opt(option, active ? 'active' : 'inactive', options);\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.join(`\\n${hasGuide ? `${styleText('yellow', S_BAR)} ` : ''}`)}\\n${footer}\\n`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst optionsText = this.options\n\t\t\t\t\t\t.map((option, i, options) => {\n\t\t\t\t\t\t\tconst selected =\n\t\t\t\t\t\t\t\tvalue.includes(option.value) ||\n\t\t\t\t\t\t\t\t(option.group === true && this.isGroupSelected(`${option.value}`));\n\t\t\t\t\t\t\tconst active = i === this.cursor;\n\t\t\t\t\t\t\tconst groupActive =\n\t\t\t\t\t\t\t\t!active &&\n\t\t\t\t\t\t\t\ttypeof option.group === 'string' &&\n\t\t\t\t\t\t\t\tthis.options[this.cursor].value === option.group;\n\t\t\t\t\t\t\tlet optionText = '';\n\t\t\t\t\t\t\tif (groupActive) {\n\t\t\t\t\t\t\t\toptionText = opt(\n\t\t\t\t\t\t\t\t\toption,\n\t\t\t\t\t\t\t\t\tselected ? 'group-active-selected' : 'group-active',\n\t\t\t\t\t\t\t\t\toptions\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t} else if (active && selected) {\n\t\t\t\t\t\t\t\toptionText = opt(option, 'active-selected', options);\n\t\t\t\t\t\t\t} else if (selected) {\n\t\t\t\t\t\t\t\toptionText = opt(option, 'selected', options);\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\toptionText = opt(option, active ? 'active' : 'inactive', options);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tconst prefix = i !== 0 && !optionText.startsWith('\\n') ? ' ' : '';\n\t\t\t\t\t\t\treturn `${prefix}${optionText}`;\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.join(`\\n${hasGuide ? styleText('cyan', S_BAR) : ''}`);\n\t\t\t\t\tconst optionsPrefix = optionsText.startsWith('\\n') ? '' : ' ';\n\t\t\t\t\treturn `${title}${hasGuide ? styleText('cyan', S_BAR) : ''}${optionsPrefix}${optionsText}\\n${\n\t\t\t\t\t\thasGuide ? styleText('cyan', S_BAR_END) : ''\n\t\t\t\t\t}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<Value[] | symbol>;\n};\n","import { styleText } from 'node:util';\nimport { settings } from '@clack/core';\nimport {\n\ttype CommonOptions,\n\tS_BAR,\n\tS_ERROR,\n\tS_INFO,\n\tS_STEP_SUBMIT,\n\tS_SUCCESS,\n\tS_WARN,\n} from './common.js';\n\nexport interface LogMessageOptions extends CommonOptions {\n\tsymbol?: string;\n\tspacing?: number;\n\tsecondarySymbol?: string;\n}\n\nexport const log = {\n\tmessage: (\n\t\tmessage: string | string[] = [],\n\t\t{\n\t\t\tsymbol = styleText('gray', S_BAR),\n\t\t\tsecondarySymbol = styleText('gray', S_BAR),\n\t\t\toutput = process.stdout,\n\t\t\tspacing = 1,\n\t\t\twithGuide,\n\t\t}: LogMessageOptions = {}\n\t) => {\n\t\tconst parts: string[] = [];\n\t\tconst hasGuide = withGuide ?? settings.withGuide;\n\t\tconst spacingString = !hasGuide ? '' : secondarySymbol;\n\t\tconst prefix = !hasGuide ? '' : `${symbol} `;\n\t\tconst secondaryPrefix = !hasGuide ? '' : `${secondarySymbol} `;\n\n\t\tfor (let i = 0; i < spacing; i++) {\n\t\t\tparts.push(spacingString);\n\t\t}\n\n\t\tconst messageParts = Array.isArray(message) ? message : message.split('\\n');\n\t\tif (messageParts.length > 0) {\n\t\t\tconst [firstLine, ...lines] = messageParts;\n\t\t\tif (firstLine.length > 0) {\n\t\t\t\tparts.push(`${prefix}${firstLine}`);\n\t\t\t} else {\n\t\t\t\tparts.push(hasGuide ? symbol : '');\n\t\t\t}\n\t\t\tfor (const ln of lines) {\n\t\t\t\tif (ln.length > 0) {\n\t\t\t\t\tparts.push(`${secondaryPrefix}${ln}`);\n\t\t\t\t} else {\n\t\t\t\t\tparts.push(hasGuide ? secondarySymbol : '');\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\toutput.write(`${parts.join('\\n')}\\n`);\n\t},\n\tinfo: (message: string, opts?: LogMessageOptions) => {\n\t\tlog.message(message, { ...opts, symbol: styleText('blue', S_INFO) });\n\t},\n\tsuccess: (message: string, opts?: LogMessageOptions) => {\n\t\tlog.message(message, { ...opts, symbol: styleText('green', S_SUCCESS) });\n\t},\n\tstep: (message: string, opts?: LogMessageOptions) => {\n\t\tlog.message(message, { ...opts, symbol: styleText('green', S_STEP_SUBMIT) });\n\t},\n\twarn: (message: string, opts?: LogMessageOptions) => {\n\t\tlog.message(message, { ...opts, symbol: styleText('yellow', S_WARN) });\n\t},\n\t/** alias for `log.warn()`. */\n\twarning: (message: string, opts?: LogMessageOptions) => {\n\t\tlog.warn(message, opts);\n\t},\n\terror: (message: string, opts?: LogMessageOptions) => {\n\t\tlog.message(message, { ...opts, symbol: styleText('red', S_ERROR) });\n\t},\n};\n","import type { Writable } from 'node:stream';\nimport { styleText } from 'node:util';\nimport { settings } from '@clack/core';\nimport { type CommonOptions, S_BAR, S_BAR_END, S_BAR_START } from './common.js';\n\nexport const cancel = (message = '', opts?: CommonOptions) => {\n\tconst output: Writable = opts?.output ?? process.stdout;\n\tconst hasGuide = opts?.withGuide ?? settings.withGuide;\n\tconst prefix = hasGuide ? `${styleText('gray', S_BAR_END)} ` : '';\n\toutput.write(`${prefix}${styleText('red', message)}\\n\\n`);\n};\n\nexport const intro = (title = '', opts?: CommonOptions) => {\n\tconst output: Writable = opts?.output ?? process.stdout;\n\tconst hasGuide = opts?.withGuide ?? settings.withGuide;\n\tconst prefix = hasGuide ? `${styleText('gray', S_BAR_START)} ` : '';\n\toutput.write(`${prefix}${title}\\n`);\n};\n\nexport const outro = (message = '', opts?: CommonOptions) => {\n\tconst output: Writable = opts?.output ?? process.stdout;\n\tconst hasGuide = opts?.withGuide ?? settings.withGuide;\n\tconst prefix = hasGuide ? `${styleText('gray', S_BAR)}\\n${styleText('gray', S_BAR_END)} ` : '';\n\toutput.write(`${prefix}${message}\\n\\n`);\n};\n","import { styleText } from 'node:util';\nimport { MultiLinePrompt, settings, wrapTextWithPrefix } from '@clack/core';\nimport { S_BAR, S_BAR_END, symbol } from './common.js';\nimport type { TextOptions } from './text.js';\n\nexport interface MultiLineOptions extends TextOptions {\n\tshowSubmit?: boolean;\n}\n\nexport const multiline = (opts: MultiLineOptions) => {\n\treturn new MultiLinePrompt({\n\t\tvalidate: opts.validate,\n\t\tplaceholder: opts.placeholder,\n\t\tdefaultValue: opts.defaultValue,\n\t\tinitialValue: opts.initialValue,\n\t\tshowSubmit: opts.showSubmit,\n\t\toutput: opts.output,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\trender() {\n\t\t\tconst hasGuide = opts?.withGuide ?? settings.withGuide;\n\t\t\tconst titlePrefix = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${symbol(this.state)} `;\n\t\t\tconst title = `${titlePrefix}${opts.message}\\n`;\n\t\t\tconst placeholder = opts.placeholder\n\t\t\t\t? styleText('inverse', opts.placeholder[0]) + styleText('dim', opts.placeholder.slice(1))\n\t\t\t\t: styleText(['inverse', 'hidden'], '_');\n\t\t\tconst userInput = !this.userInput ? placeholder : this.userInputWithCursor;\n\t\t\tconst value = this.value ?? '';\n\t\t\tconst submitButton = opts.showSubmit\n\t\t\t\t? `\\n ${styleText(this.focused === 'submit' ? 'cyan' : 'dim', '[ submit ]')}`\n\t\t\t\t: '';\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'error': {\n\t\t\t\t\tconst errorPrefix = `${styleText('yellow', S_BAR)} `;\n\t\t\t\t\tconst lines = hasGuide\n\t\t\t\t\t\t? wrapTextWithPrefix(opts.output, userInput, errorPrefix, undefined)\n\t\t\t\t\t\t: userInput;\n\t\t\t\t\tconst errorPrefixEnd = styleText('yellow', S_BAR_END);\n\t\t\t\t\treturn `${title}${lines}\\n${errorPrefixEnd} ${styleText('yellow', this.error)}${submitButton}\\n`;\n\t\t\t\t}\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst submitPrefix = `${styleText('gray', S_BAR)} `;\n\t\t\t\t\tconst lines = hasGuide\n\t\t\t\t\t\t? wrapTextWithPrefix(opts.output, value, submitPrefix, undefined, (str) =>\n\t\t\t\t\t\t\t\tstyleText('dim', str)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t: value\n\t\t\t\t\t\t\t? styleText('dim', value)\n\t\t\t\t\t\t\t: '';\n\t\t\t\t\treturn `${title}${lines}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst cancelPrefix = `${styleText('gray', S_BAR)} `;\n\t\t\t\t\tconst lines = hasGuide\n\t\t\t\t\t\t? wrapTextWithPrefix(opts.output, value, cancelPrefix, undefined, (str) =>\n\t\t\t\t\t\t\t\tstyleText(['strikethrough', 'dim'], str)\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t: value\n\t\t\t\t\t\t\t? styleText(['strikethrough', 'dim'], value)\n\t\t\t\t\t\t\t: '';\n\t\t\t\t\treturn `${title}${lines}`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst defaultPrefix = hasGuide ? `${styleText('cyan', S_BAR)} ` : '';\n\t\t\t\t\tconst defaultPrefixEnd = hasGuide ? styleText('cyan', S_BAR_END) : '';\n\t\t\t\t\tconst lines = hasGuide\n\t\t\t\t\t\t? wrapTextWithPrefix(opts.output, userInput, defaultPrefix)\n\t\t\t\t\t\t: userInput;\n\t\t\t\t\treturn `${title}${lines}\\n${defaultPrefixEnd}${submitButton}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<string | symbol>;\n};\n","import { styleText } from 'node:util';\nimport { MultiSelectPrompt, settings, wrapTextWithPrefix } from '@clack/core';\nimport {\n\ttype CommonOptions,\n\tS_BAR,\n\tS_BAR_END,\n\tS_CHECKBOX_ACTIVE,\n\tS_CHECKBOX_INACTIVE,\n\tS_CHECKBOX_SELECTED,\n\tsymbol,\n\tsymbolBar,\n} from './common.js';\nimport { limitOptions } from './limit-options.js';\nimport type { Option } from './select.js';\n\nexport interface MultiSelectOptions<Value> extends CommonOptions {\n\tmessage: string;\n\toptions: Option<Value>[];\n\tinitialValues?: Value[];\n\tmaxItems?: number;\n\trequired?: boolean;\n\tcursorAt?: Value;\n}\nconst computeLabel = (label: string, format: (text: string) => string) => {\n\treturn label\n\t\t.split('\\n')\n\t\t.map((line) => format(line))\n\t\t.join('\\n');\n};\n\nexport const multiselect = <Value>(opts: MultiSelectOptions<Value>) => {\n\tconst opt = (\n\t\toption: Option<Value>,\n\t\tstate:\n\t\t\t| 'inactive'\n\t\t\t| 'active'\n\t\t\t| 'selected'\n\t\t\t| 'active-selected'\n\t\t\t| 'submitted'\n\t\t\t| 'cancelled'\n\t\t\t| 'disabled'\n\t) => {\n\t\tconst label = option.label ?? String(option.value);\n\t\tif (state === 'disabled') {\n\t\t\treturn `${styleText('gray', S_CHECKBOX_INACTIVE)} ${computeLabel(label, (str) => styleText(['strikethrough', 'gray'], str))}${\n\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint ?? 'disabled'})`)}` : ''\n\t\t\t}`;\n\t\t}\n\t\tif (state === 'active') {\n\t\t\treturn `${styleText('cyan', S_CHECKBOX_ACTIVE)} ${label}${\n\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t\t}`;\n\t\t}\n\t\tif (state === 'selected') {\n\t\t\treturn `${styleText('green', S_CHECKBOX_SELECTED)} ${computeLabel(label, (text) => styleText('dim', text))}${\n\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t\t}`;\n\t\t}\n\t\tif (state === 'cancelled') {\n\t\t\treturn `${computeLabel(label, (text) => styleText(['strikethrough', 'dim'], text))}`;\n\t\t}\n\t\tif (state === 'active-selected') {\n\t\t\treturn `${styleText('green', S_CHECKBOX_SELECTED)} ${label}${\n\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t\t}`;\n\t\t}\n\t\tif (state === 'submitted') {\n\t\t\treturn `${computeLabel(label, (text) => styleText('dim', text))}`;\n\t\t}\n\t\treturn `${styleText('dim', S_CHECKBOX_INACTIVE)} ${computeLabel(label, (text) => styleText('dim', text))}`;\n\t};\n\tconst required = opts.required ?? true;\n\n\treturn new MultiSelectPrompt({\n\t\toptions: opts.options,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\toutput: opts.output,\n\t\tinitialValues: opts.initialValues,\n\t\trequired,\n\t\tcursorAt: opts.cursorAt,\n\t\tvalidate(selected: Value[] | undefined) {\n\t\t\tif (required && (selected === undefined || selected.length === 0))\n\t\t\t\treturn `Please select at least one option.\\n${styleText(\n\t\t\t\t\t'reset',\n\t\t\t\t\tstyleText(\n\t\t\t\t\t\t'dim',\n\t\t\t\t\t\t`Press ${styleText(['gray', 'bgWhite', 'inverse'], ' space ')} to select, ${styleText(\n\t\t\t\t\t\t\t'gray',\n\t\t\t\t\t\t\tstyleText('bgWhite', styleText('inverse', ' enter '))\n\t\t\t\t\t\t)} to submit`\n\t\t\t\t\t)\n\t\t\t\t)}`;\n\t\t},\n\t\trender() {\n\t\t\tconst hasGuide = opts.withGuide ?? settings.withGuide;\n\t\t\tconst wrappedMessage = wrapTextWithPrefix(\n\t\t\t\topts.output,\n\t\t\t\topts.message,\n\t\t\t\thasGuide ? `${symbolBar(this.state)} ` : '',\n\t\t\t\t`${symbol(this.state)} `\n\t\t\t);\n\t\t\tconst title = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${wrappedMessage}\\n`;\n\t\t\tconst value = this.value ?? [];\n\n\t\t\tconst styleOption = (option: Option<Value>, active: boolean) => {\n\t\t\t\tif (option.disabled) {\n\t\t\t\t\treturn opt(option, 'disabled');\n\t\t\t\t}\n\t\t\t\tconst selected = value.includes(option.value);\n\t\t\t\tif (active && selected) {\n\t\t\t\t\treturn opt(option, 'active-selected');\n\t\t\t\t}\n\t\t\t\tif (selected) {\n\t\t\t\t\treturn opt(option, 'selected');\n\t\t\t\t}\n\t\t\t\treturn opt(option, active ? 'active' : 'inactive');\n\t\t\t};\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst submitText =\n\t\t\t\t\t\tthis.options\n\t\t\t\t\t\t\t.filter(({ value: optionValue }) => value.includes(optionValue))\n\t\t\t\t\t\t\t.map((option) => opt(option, 'submitted'))\n\t\t\t\t\t\t\t.join(styleText('dim', ', ')) || styleText('dim', 'none');\n\t\t\t\t\tconst wrappedSubmitText = wrapTextWithPrefix(\n\t\t\t\t\t\topts.output,\n\t\t\t\t\t\tsubmitText,\n\t\t\t\t\t\thasGuide ? `${styleText('gray', S_BAR)} ` : ''\n\t\t\t\t\t);\n\t\t\t\t\treturn `${title}${wrappedSubmitText}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst label = this.options\n\t\t\t\t\t\t.filter(({ value: optionValue }) => value.includes(optionValue))\n\t\t\t\t\t\t.map((option) => opt(option, 'cancelled'))\n\t\t\t\t\t\t.join(styleText('dim', ', '));\n\t\t\t\t\tif (label.trim() === '') {\n\t\t\t\t\t\treturn `${title}${styleText('gray', S_BAR)}`;\n\t\t\t\t\t}\n\t\t\t\t\tconst wrappedLabel = wrapTextWithPrefix(\n\t\t\t\t\t\topts.output,\n\t\t\t\t\t\tlabel,\n\t\t\t\t\t\thasGuide ? `${styleText('gray', S_BAR)} ` : ''\n\t\t\t\t\t);\n\t\t\t\t\treturn `${title}${wrappedLabel}${hasGuide ? `\\n${styleText('gray', S_BAR)}` : ''}`;\n\t\t\t\t}\n\t\t\t\tcase 'error': {\n\t\t\t\t\tconst prefix = hasGuide ? `${styleText('yellow', S_BAR)} ` : '';\n\t\t\t\t\tconst footer = this.error\n\t\t\t\t\t\t.split('\\n')\n\t\t\t\t\t\t.map((ln, i) =>\n\t\t\t\t\t\t\ti === 0\n\t\t\t\t\t\t\t\t? `${hasGuide ? `${styleText('yellow', S_BAR_END)} ` : ''}${styleText('yellow', ln)}`\n\t\t\t\t\t\t\t\t: ` ${ln}`\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.join('\\n');\n\t\t\t\t\t// Calculate rowPadding: title lines + footer lines (error message + trailing newline)\n\t\t\t\t\tconst titleLineCount = title.split('\\n').length;\n\t\t\t\t\tconst footerLineCount = footer.split('\\n').length + 1; // footer + trailing newline\n\t\t\t\t\treturn `${title}${prefix}${limitOptions({\n\t\t\t\t\t\toutput: opts.output,\n\t\t\t\t\t\toptions: this.options,\n\t\t\t\t\t\tcursor: this.cursor,\n\t\t\t\t\t\tmaxItems: opts.maxItems,\n\t\t\t\t\t\tcolumnPadding: prefix.length,\n\t\t\t\t\t\trowPadding: titleLineCount + footerLineCount,\n\t\t\t\t\t\tstyle: styleOption,\n\t\t\t\t\t}).join(`\\n${prefix}`)}\\n${footer}\\n`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst prefix = hasGuide ? `${styleText('cyan', S_BAR)} ` : '';\n\t\t\t\t\t// Calculate rowPadding: title lines + footer lines (S_BAR_END + trailing newline)\n\t\t\t\t\tconst titleLineCount = title.split('\\n').length;\n\t\t\t\t\tconst footerLineCount = hasGuide ? 2 : 1; // S_BAR_END + trailing newline\n\t\t\t\t\treturn `${title}${prefix}${limitOptions({\n\t\t\t\t\t\toutput: opts.output,\n\t\t\t\t\t\toptions: this.options,\n\t\t\t\t\t\tcursor: this.cursor,\n\t\t\t\t\t\tmaxItems: opts.maxItems,\n\t\t\t\t\t\tcolumnPadding: prefix.length,\n\t\t\t\t\t\trowPadding: titleLineCount + footerLineCount,\n\t\t\t\t\t\tstyle: styleOption,\n\t\t\t\t\t}).join(`\\n${prefix}`)}\\n${hasGuide ? styleText('cyan', S_BAR_END) : ''}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<Value[] | symbol>;\n};\n","import process from 'node:process';\nimport type { Writable } from 'node:stream';\nimport { styleText } from 'node:util';\nimport { getColumns, settings } from '@clack/core';\nimport stringWidth from 'fast-string-width';\nimport { type Options as WrapAnsiOptions, wrapAnsi } from 'fast-wrap-ansi';\nimport {\n\ttype CommonOptions,\n\tS_BAR,\n\tS_BAR_H,\n\tS_CONNECT_LEFT,\n\tS_CORNER_BOTTOM_LEFT,\n\tS_CORNER_BOTTOM_RIGHT,\n\tS_CORNER_TOP_RIGHT,\n\tS_STEP_SUBMIT,\n} from './common.js';\n\ntype FormatFn = (line: string) => string;\nexport interface NoteOptions extends CommonOptions {\n\tformat?: FormatFn;\n}\n\nconst defaultNoteFormatter = (line: string): string => styleText('dim', line);\n\nconst wrapWithFormat = (message: string, width: number, format: FormatFn): string => {\n\tconst opts: WrapAnsiOptions = {\n\t\thard: true,\n\t\ttrim: false,\n\t};\n\tconst wrapMsg = wrapAnsi(message, width, opts).split('\\n');\n\tconst maxWidthNormal = wrapMsg.reduce((sum, ln) => Math.max(stringWidth(ln), sum), 0);\n\tconst maxWidthFormat = wrapMsg.map(format).reduce((sum, ln) => Math.max(stringWidth(ln), sum), 0);\n\tconst wrapWidth = width - (maxWidthFormat - maxWidthNormal);\n\treturn wrapAnsi(message, wrapWidth, opts);\n};\n\nexport const note = (message = '', title = '', opts?: NoteOptions) => {\n\tconst output: Writable = opts?.output ?? process.stdout;\n\tconst hasGuide = opts?.withGuide ?? settings.withGuide;\n\tconst format = opts?.format ?? defaultNoteFormatter;\n\tconst wrapMsg = wrapWithFormat(message, getColumns(output) - 6, format);\n\tconst lines = ['', ...wrapMsg.split('\\n').map(format), ''];\n\tconst titleLen = stringWidth(title);\n\tconst len =\n\t\tMath.max(\n\t\t\tlines.reduce((sum, ln) => {\n\t\t\t\tconst width = stringWidth(ln);\n\t\t\t\treturn width > sum ? width : sum;\n\t\t\t}, 0),\n\t\t\ttitleLen\n\t\t) + 2;\n\tconst msg = lines\n\t\t.map(\n\t\t\t(ln) =>\n\t\t\t\t`${styleText('gray', S_BAR)} ${ln}${' '.repeat(len - stringWidth(ln))}${styleText('gray', S_BAR)}`\n\t\t)\n\t\t.join('\\n');\n\tconst leadingBorder = hasGuide ? `${styleText('gray', S_BAR)}\\n` : '';\n\tconst bottomLeft = hasGuide ? S_CONNECT_LEFT : S_CORNER_BOTTOM_LEFT;\n\toutput.write(\n\t\t`${leadingBorder}${styleText('green', S_STEP_SUBMIT)} ${styleText('reset', title)} ${styleText(\n\t\t\t'gray',\n\t\t\tS_BAR_H.repeat(Math.max(len - titleLen - 1, 1)) + S_CORNER_TOP_RIGHT\n\t\t)}\\n${msg}\\n${styleText('gray', bottomLeft + S_BAR_H.repeat(len + 2) + S_CORNER_BOTTOM_RIGHT)}\\n`\n\t);\n};\n","import { styleText } from 'node:util';\nimport { PasswordPrompt, settings } from '@clack/core';\nimport { type CommonOptions, S_BAR, S_BAR_END, S_PASSWORD_MASK, symbol } from './common.js';\n\nexport interface PasswordOptions extends CommonOptions {\n\tmessage: string;\n\tmask?: string;\n\tvalidate?: (value: string | undefined) => string | Error | undefined;\n\tclearOnError?: boolean;\n}\nexport const password = (opts: PasswordOptions) => {\n\treturn new PasswordPrompt({\n\t\tvalidate: opts.validate,\n\t\tmask: opts.mask ?? S_PASSWORD_MASK,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\toutput: opts.output,\n\t\trender() {\n\t\t\tconst hasGuide = opts.withGuide ?? settings.withGuide;\n\t\t\tconst title = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${symbol(this.state)} ${opts.message}\\n`;\n\t\t\tconst userInput = this.userInputWithCursor;\n\t\t\tconst masked = this.masked;\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'error': {\n\t\t\t\t\tconst errorPrefix = hasGuide ? `${styleText('yellow', S_BAR)} ` : '';\n\t\t\t\t\tconst errorPrefixEnd = hasGuide ? `${styleText('yellow', S_BAR_END)} ` : '';\n\t\t\t\t\tconst maskedText = masked ?? '';\n\t\t\t\t\tif (opts.clearOnError) {\n\t\t\t\t\t\tthis.clear();\n\t\t\t\t\t}\n\t\t\t\t\treturn `${title.trim()}\\n${errorPrefix}${maskedText}\\n${errorPrefixEnd}${styleText('yellow', this.error)}\\n`;\n\t\t\t\t}\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst submitPrefix = hasGuide ? `${styleText('gray', S_BAR)} ` : '';\n\t\t\t\t\tconst maskedText = masked ? styleText('dim', masked) : '';\n\t\t\t\t\treturn `${title}${submitPrefix}${maskedText}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst cancelPrefix = hasGuide ? `${styleText('gray', S_BAR)} ` : '';\n\t\t\t\t\tconst maskedText = masked ? styleText(['strikethrough', 'dim'], masked) : '';\n\t\t\t\t\treturn `${title}${cancelPrefix}${maskedText}${\n\t\t\t\t\t\tmasked && hasGuide ? `\\n${styleText('gray', S_BAR)}` : ''\n\t\t\t\t\t}`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst defaultPrefix = hasGuide ? `${styleText('cyan', S_BAR)} ` : '';\n\t\t\t\t\tconst defaultPrefixEnd = hasGuide ? styleText('cyan', S_BAR_END) : '';\n\t\t\t\t\treturn `${title}${defaultPrefix}${userInput}\\n${defaultPrefixEnd}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<string | symbol>;\n};\n","import { existsSync, lstatSync, readdirSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { autocomplete } from './autocomplete.js';\nimport type { CommonOptions } from './common.js';\n\nexport interface PathOptions extends CommonOptions {\n\troot?: string;\n\tdirectory?: boolean;\n\tinitialValue?: string;\n\tmessage: string;\n\tvalidate?: (value: string | undefined) => string | Error | undefined;\n}\n\nexport const path = (opts: PathOptions) => {\n\tconst validate = opts.validate;\n\n\treturn autocomplete({\n\t\t...opts,\n\t\tinitialUserInput: opts.initialValue ?? opts.root ?? process.cwd(),\n\t\tmaxItems: 5,\n\t\tvalidate(value) {\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\t// Shouldn't ever happen since we don't enable `multiple: true`\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tif (!value) {\n\t\t\t\treturn 'Please select a path';\n\t\t\t}\n\t\t\tif (validate) {\n\t\t\t\treturn validate(value);\n\t\t\t}\n\t\t\treturn undefined;\n\t\t},\n\t\toptions() {\n\t\t\tconst userInput = this.userInput;\n\t\t\tif (userInput === '') {\n\t\t\t\treturn [];\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tlet searchPath: string;\n\n\t\t\t\tif (!existsSync(userInput)) {\n\t\t\t\t\tsearchPath = dirname(userInput);\n\t\t\t\t} else {\n\t\t\t\t\tconst stat = lstatSync(userInput);\n\t\t\t\t\tif (stat.isDirectory() && (!opts.directory || userInput.endsWith('/'))) {\n\t\t\t\t\t\tsearchPath = userInput;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tsearchPath = dirname(userInput);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Strip trailing slash so startsWith matches the directory itself among its siblings\n\t\t\t\tconst prefix =\n\t\t\t\t\tuserInput.length > 1 && userInput.endsWith('/') ? userInput.slice(0, -1) : userInput;\n\n\t\t\t\tconst items = readdirSync(searchPath)\n\t\t\t\t\t.map((item) => {\n\t\t\t\t\t\tconst path = join(searchPath, item);\n\t\t\t\t\t\tconst stats = lstatSync(path);\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tname: item,\n\t\t\t\t\t\t\tpath,\n\t\t\t\t\t\t\tisDirectory: stats.isDirectory(),\n\t\t\t\t\t\t};\n\t\t\t\t\t})\n\t\t\t\t\t.filter(\n\t\t\t\t\t\t({ path, isDirectory }) => path.startsWith(prefix) && (isDirectory || !opts.directory)\n\t\t\t\t\t);\n\n\t\t\t\treturn items.map((item) => ({\n\t\t\t\t\tvalue: item.path,\n\t\t\t\t}));\n\t\t\t} catch (_e) {\n\t\t\t\treturn [];\n\t\t\t}\n\t\t},\n\t});\n};\n","import { styleText } from 'node:util';\nimport { block, getColumns, settings } from '@clack/core';\nimport { wrapAnsi } from 'fast-wrap-ansi';\nimport { cursor, erase } from 'sisteransi';\nimport {\n\ttype CommonOptions,\n\tisCI as isCIFn,\n\tS_BAR,\n\tS_STEP_CANCEL,\n\tS_STEP_ERROR,\n\tS_STEP_SUBMIT,\n\tunicode,\n} from './common.js';\n\nexport interface SpinnerOptions extends CommonOptions {\n\tindicator?: 'dots' | 'timer';\n\tonCancel?: () => void;\n\tcancelMessage?: string;\n\terrorMessage?: string;\n\tframes?: string[];\n\tdelay?: number;\n\tstyleFrame?: (frame: string) => string;\n}\n\nexport interface SpinnerResult {\n\tstart(msg?: string): void;\n\tstop(msg?: string): void;\n\tcancel(msg?: string): void;\n\terror(msg?: string): void;\n\tmessage(msg?: string): void;\n\tclear(): void;\n\treadonly isCancelled: boolean;\n}\n\nconst defaultStyleFn: SpinnerOptions['styleFrame'] = (frame) => styleText('magenta', frame);\n\nexport const spinner = ({\n\tindicator = 'dots',\n\tonCancel,\n\toutput = process.stdout,\n\tcancelMessage,\n\terrorMessage,\n\tframes = unicode ? ['◒', '◐', '◓', '◑'] : ['•', 'o', 'O', '0'],\n\tdelay = unicode ? 80 : 120,\n\tsignal,\n\t...opts\n}: SpinnerOptions = {}): SpinnerResult => {\n\tconst isCI = isCIFn();\n\n\tlet unblock: () => void;\n\tlet loop: NodeJS.Timeout;\n\tlet isSpinnerActive = false;\n\tlet isCancelled = false;\n\tlet _message = '';\n\tlet _prevMessage: string | undefined;\n\tlet _origin: number = performance.now();\n\tconst columns = getColumns(output);\n\tconst styleFn = opts?.styleFrame ?? defaultStyleFn;\n\n\tconst handleExit = (code: number) => {\n\t\tconst msg =\n\t\t\tcode > 1\n\t\t\t\t? (errorMessage ?? settings.messages.error)\n\t\t\t\t: (cancelMessage ?? settings.messages.cancel);\n\t\tisCancelled = code === 1;\n\t\tif (isSpinnerActive) {\n\t\t\t_stop(msg, code);\n\t\t\tif (isCancelled && typeof onCancel === 'function') {\n\t\t\t\tonCancel();\n\t\t\t}\n\t\t}\n\t};\n\n\tconst errorEventHandler = () => handleExit(2);\n\tconst signalEventHandler = () => handleExit(1);\n\n\tconst registerHooks = () => {\n\t\t// Reference: https://nodejs.org/api/process.html#event-uncaughtexception\n\t\tprocess.on('uncaughtExceptionMonitor', errorEventHandler);\n\t\t// Reference: https://nodejs.org/api/process.html#event-unhandledrejection\n\t\tprocess.on('unhandledRejection', errorEventHandler);\n\t\t// Reference Signal Events: https://nodejs.org/api/process.html#signal-events\n\t\tprocess.on('SIGINT', signalEventHandler);\n\t\tprocess.on('SIGTERM', signalEventHandler);\n\t\tprocess.on('exit', handleExit);\n\n\t\tif (signal) {\n\t\t\tsignal.addEventListener('abort', signalEventHandler);\n\t\t}\n\t};\n\n\tconst clearHooks = () => {\n\t\tprocess.removeListener('uncaughtExceptionMonitor', errorEventHandler);\n\t\tprocess.removeListener('unhandledRejection', errorEventHandler);\n\t\tprocess.removeListener('SIGINT', signalEventHandler);\n\t\tprocess.removeListener('SIGTERM', signalEventHandler);\n\t\tprocess.removeListener('exit', handleExit);\n\n\t\tif (signal) {\n\t\t\tsignal.removeEventListener('abort', signalEventHandler);\n\t\t}\n\t};\n\n\tconst clearPrevMessage = () => {\n\t\tif (_prevMessage === undefined) return;\n\t\tif (isCI) output.write('\\n');\n\t\tconst wrapped = wrapAnsi(_prevMessage, columns, {\n\t\t\thard: true,\n\t\t\ttrim: false,\n\t\t});\n\t\tconst prevLines = wrapped.split('\\n');\n\t\tif (prevLines.length > 1) {\n\t\t\toutput.write(cursor.up(prevLines.length - 1));\n\t\t}\n\t\toutput.write(cursor.to(0));\n\t\toutput.write(erase.down());\n\t};\n\n\tconst removeTrailingDots = (msg: string): string => {\n\t\treturn msg.replace(/\\.+$/, '');\n\t};\n\n\tconst formatTimer = (origin: number): string => {\n\t\tconst duration = (performance.now() - origin) / 1000;\n\t\tconst min = Math.floor(duration / 60);\n\t\tconst secs = Math.floor(duration % 60);\n\t\treturn min > 0 ? `[${min}m ${secs}s]` : `[${secs}s]`;\n\t};\n\n\tconst hasGuide = opts.withGuide ?? settings.withGuide;\n\n\tconst start = (msg = ''): void => {\n\t\tisSpinnerActive = true;\n\t\tunblock = block({ output });\n\t\t_message = removeTrailingDots(msg);\n\t\t_origin = performance.now();\n\t\tif (hasGuide) {\n\t\t\toutput.write(`${styleText('gray', S_BAR)}\\n`);\n\t\t}\n\t\tlet frameIndex = 0;\n\t\tlet indicatorTimer = 0;\n\t\tregisterHooks();\n\t\tloop = setInterval(() => {\n\t\t\tif (isCI && _message === _prevMessage) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tclearPrevMessage();\n\t\t\t_prevMessage = _message;\n\t\t\tconst frame = styleFn(frames[frameIndex]);\n\t\t\tlet outputMessage: string;\n\n\t\t\tif (isCI) {\n\t\t\t\toutputMessage = `${frame} ${_message}...`;\n\t\t\t} else if (indicator === 'timer') {\n\t\t\t\toutputMessage = `${frame} ${_message} ${formatTimer(_origin)}`;\n\t\t\t} else {\n\t\t\t\tconst loadingDots = '.'.repeat(Math.floor(indicatorTimer)).slice(0, 3);\n\t\t\t\toutputMessage = `${frame} ${_message}${loadingDots}`;\n\t\t\t}\n\n\t\t\tconst wrapped = wrapAnsi(outputMessage, columns, {\n\t\t\t\thard: true,\n\t\t\t\ttrim: false,\n\t\t\t});\n\t\t\toutput.write(wrapped);\n\n\t\t\tframeIndex = frameIndex + 1 < frames.length ? frameIndex + 1 : 0;\n\t\t\t// indicator increase by 1 every 8 frames\n\t\t\tindicatorTimer = indicatorTimer < 4 ? indicatorTimer + 0.125 : 0;\n\t\t}, delay);\n\t};\n\n\tconst _stop = (msg = '', code = 0, silent: boolean = false): void => {\n\t\tif (!isSpinnerActive) return;\n\t\tisSpinnerActive = false;\n\t\tclearInterval(loop);\n\t\tclearPrevMessage();\n\t\tconst step =\n\t\t\tcode === 0\n\t\t\t\t? styleText('green', S_STEP_SUBMIT)\n\t\t\t\t: code === 1\n\t\t\t\t\t? styleText('red', S_STEP_CANCEL)\n\t\t\t\t\t: styleText('red', S_STEP_ERROR);\n\t\t_message = msg ?? _message;\n\t\tif (!silent) {\n\t\t\tif (indicator === 'timer') {\n\t\t\t\toutput.write(`${step} ${_message} ${formatTimer(_origin)}\\n`);\n\t\t\t} else {\n\t\t\t\toutput.write(`${step} ${_message}\\n`);\n\t\t\t}\n\t\t}\n\t\tclearHooks();\n\t\tunblock();\n\t};\n\n\tconst stop = (msg = ''): void => _stop(msg, 0);\n\tconst cancel = (msg = ''): void => _stop(msg, 1);\n\tconst error = (msg = ''): void => _stop(msg, 2);\n\t// TODO (43081j): this will leave the initial S_BAR since we purposely\n\t// don't erase that in `clearPrevMessage`. In future, we may want to treat\n\t// `clear` as a special case and remove the bar too.\n\tconst clear = (): void => _stop('', 0, true);\n\n\tconst message = (msg = ''): void => {\n\t\t_message = removeTrailingDots(msg ?? _message);\n\t};\n\n\treturn {\n\t\tstart,\n\t\tstop,\n\t\tmessage,\n\t\tcancel,\n\t\terror,\n\t\tclear,\n\t\tget isCancelled() {\n\t\t\treturn isCancelled;\n\t\t},\n\t};\n};\n","import { styleText } from 'node:util';\nimport type { State } from '@clack/core';\nimport { unicodeOr } from './common.js';\nimport { type SpinnerOptions, type SpinnerResult, spinner } from './spinner.js';\n\nconst S_PROGRESS_CHAR: Record<NonNullable<ProgressOptions['style']>, string> = {\n\tlight: unicodeOr('─', '-'),\n\theavy: unicodeOr('━', '='),\n\tblock: unicodeOr('█', '#'),\n};\n\nexport interface ProgressOptions extends SpinnerOptions {\n\tstyle?: 'light' | 'heavy' | 'block';\n\tmax?: number;\n\tsize?: number;\n}\n\nexport interface ProgressResult extends SpinnerResult {\n\tadvance(step?: number, msg?: string): void;\n}\n\nexport function progress({\n\tstyle = 'heavy',\n\tmax: userMax = 100,\n\tsize: userSize = 40,\n\t...spinnerOptions\n}: ProgressOptions = {}): ProgressResult {\n\tconst spin = spinner(spinnerOptions);\n\tlet value = 0;\n\tlet previousMessage = '';\n\n\tconst max = Math.max(1, userMax);\n\tconst size = Math.max(1, userSize);\n\n\tconst activeStyle = (state: State) => {\n\t\tswitch (state) {\n\t\t\tcase 'initial':\n\t\t\tcase 'active':\n\t\t\t\treturn (text: string) => styleText('magenta', text);\n\t\t\tcase 'error':\n\t\t\tcase 'cancel':\n\t\t\t\treturn (text: string) => styleText('red', text);\n\t\t\tcase 'submit':\n\t\t\t\treturn (text: string) => styleText('green', text);\n\t\t\tdefault:\n\t\t\t\treturn (text: string) => styleText('magenta', text);\n\t\t}\n\t};\n\tconst drawProgress = (state: State, msg: string) => {\n\t\tconst active = Math.floor((value / max) * size);\n\t\treturn `${activeStyle(state)(S_PROGRESS_CHAR[style].repeat(active))}${styleText('dim', S_PROGRESS_CHAR[style].repeat(size - active))} ${msg}`;\n\t};\n\n\tconst start = (msg = '') => {\n\t\tpreviousMessage = msg;\n\t\tspin.start(drawProgress('initial', msg));\n\t};\n\tconst advance = (step = 1, msg?: string): void => {\n\t\tvalue = Math.min(max, step + value);\n\t\tspin.message(drawProgress('active', msg ?? previousMessage));\n\t\tpreviousMessage = msg ?? previousMessage;\n\t};\n\treturn {\n\t\tstart,\n\t\tstop: spin.stop,\n\t\tcancel: spin.cancel,\n\t\terror: spin.error,\n\t\tclear: spin.clear,\n\t\tadvance,\n\t\tisCancelled: spin.isCancelled,\n\t\tmessage: (msg: string) => advance(0, msg),\n\t};\n}\n","import { styleText } from 'node:util';\nimport { SelectPrompt, settings, wrapTextWithPrefix } from '@clack/core';\nimport {\n\ttype CommonOptions,\n\tS_BAR,\n\tS_BAR_END,\n\tS_RADIO_ACTIVE,\n\tS_RADIO_INACTIVE,\n\tsymbol,\n\tsymbolBar,\n} from './common.js';\nimport { limitOptions } from './limit-options.js';\n\ntype Primitive = Readonly<string | boolean | number>;\n\nexport type Option<Value> = Value extends Primitive\n\t? {\n\t\t\t/**\n\t\t\t * Internal data for this option.\n\t\t\t */\n\t\t\tvalue: Value;\n\t\t\t/**\n\t\t\t * The optional, user-facing text for this option.\n\t\t\t *\n\t\t\t * By default, the `value` is converted to a string.\n\t\t\t */\n\t\t\tlabel?: string;\n\t\t\t/**\n\t\t\t * An optional hint to display to the user when\n\t\t\t * this option might be selected.\n\t\t\t *\n\t\t\t * By default, no `hint` is displayed.\n\t\t\t */\n\t\t\thint?: string;\n\t\t\t/**\n\t\t\t * Whether this option is disabled.\n\t\t\t * Disabled options are visible but cannot be selected.\n\t\t\t *\n\t\t\t * By default, options are not disabled.\n\t\t\t */\n\t\t\tdisabled?: boolean;\n\t\t}\n\t: {\n\t\t\t/**\n\t\t\t * Internal data for this option.\n\t\t\t */\n\t\t\tvalue: Value;\n\t\t\t/**\n\t\t\t * Required. The user-facing text for this option.\n\t\t\t */\n\t\t\tlabel: string;\n\t\t\t/**\n\t\t\t * An optional hint to display to the user when\n\t\t\t * this option might be selected.\n\t\t\t *\n\t\t\t * By default, no `hint` is displayed.\n\t\t\t */\n\t\t\thint?: string;\n\t\t\t/**\n\t\t\t * Whether this option is disabled.\n\t\t\t * Disabled options are visible but cannot be selected.\n\t\t\t *\n\t\t\t * By default, options are not disabled.\n\t\t\t */\n\t\t\tdisabled?: boolean;\n\t\t};\n\nexport interface SelectOptions<Value> extends CommonOptions {\n\tmessage: string;\n\toptions: Option<Value>[];\n\tinitialValue?: Value;\n\tmaxItems?: number;\n}\n\nconst computeLabel = (label: string, format: (text: string) => string) => {\n\tif (!label.includes('\\n')) {\n\t\treturn format(label);\n\t}\n\treturn label\n\t\t.split('\\n')\n\t\t.map((line) => format(line))\n\t\t.join('\\n');\n};\n\nexport const select = <Value>(opts: SelectOptions<Value>) => {\n\tconst opt = (\n\t\toption: Option<Value>,\n\t\tstate: 'inactive' | 'active' | 'selected' | 'cancelled' | 'disabled'\n\t) => {\n\t\tconst label = option.label ?? String(option.value);\n\t\tswitch (state) {\n\t\t\tcase 'disabled':\n\t\t\t\treturn `${styleText('gray', S_RADIO_INACTIVE)} ${computeLabel(label, (text) => styleText('gray', text))}${\n\t\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint ?? 'disabled'})`)}` : ''\n\t\t\t\t}`;\n\t\t\tcase 'selected':\n\t\t\t\treturn `${computeLabel(label, (text) => styleText('dim', text))}`;\n\t\t\tcase 'active':\n\t\t\t\treturn `${styleText('green', S_RADIO_ACTIVE)} ${label}${\n\t\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t\t\t}`;\n\t\t\tcase 'cancelled':\n\t\t\t\treturn `${computeLabel(label, (str) => styleText(['strikethrough', 'dim'], str))}`;\n\t\t\tdefault:\n\t\t\t\treturn `${styleText('dim', S_RADIO_INACTIVE)} ${computeLabel(label, (text) => styleText('dim', text))}`;\n\t\t}\n\t};\n\n\treturn new SelectPrompt({\n\t\toptions: opts.options,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\toutput: opts.output,\n\t\tinitialValue: opts.initialValue,\n\t\trender() {\n\t\t\tconst hasGuide = opts.withGuide ?? settings.withGuide;\n\t\t\tconst titlePrefix = `${symbol(this.state)} `;\n\t\t\tconst titlePrefixBar = `${symbolBar(this.state)} `;\n\t\t\tconst messageLines = wrapTextWithPrefix(\n\t\t\t\topts.output,\n\t\t\t\topts.message,\n\t\t\t\ttitlePrefixBar,\n\t\t\t\ttitlePrefix\n\t\t\t);\n\t\t\tconst title = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${messageLines}\\n`;\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst submitPrefix = hasGuide ? `${styleText('gray', S_BAR)} ` : '';\n\t\t\t\t\tconst wrappedLines = wrapTextWithPrefix(\n\t\t\t\t\t\topts.output,\n\t\t\t\t\t\topt(this.options[this.cursor], 'selected'),\n\t\t\t\t\t\tsubmitPrefix\n\t\t\t\t\t);\n\t\t\t\t\treturn `${title}${wrappedLines}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst cancelPrefix = hasGuide ? `${styleText('gray', S_BAR)} ` : '';\n\t\t\t\t\tconst wrappedLines = wrapTextWithPrefix(\n\t\t\t\t\t\topts.output,\n\t\t\t\t\t\topt(this.options[this.cursor], 'cancelled'),\n\t\t\t\t\t\tcancelPrefix\n\t\t\t\t\t);\n\t\t\t\t\treturn `${title}${wrappedLines}${hasGuide ? `\\n${styleText('gray', S_BAR)}` : ''}`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst prefix = hasGuide ? `${styleText('cyan', S_BAR)} ` : '';\n\t\t\t\t\tconst prefixEnd = hasGuide ? styleText('cyan', S_BAR_END) : '';\n\t\t\t\t\t// Calculate rowPadding: title lines + footer lines (S_BAR_END + trailing newline)\n\t\t\t\t\tconst titleLineCount = title.split('\\n').length;\n\t\t\t\t\tconst footerLineCount = hasGuide ? 2 : 1; // S_BAR_END + trailing newline (or just trailing newline)\n\t\t\t\t\treturn `${title}${prefix}${limitOptions({\n\t\t\t\t\t\toutput: opts.output,\n\t\t\t\t\t\tcursor: this.cursor,\n\t\t\t\t\t\toptions: this.options,\n\t\t\t\t\t\tmaxItems: opts.maxItems,\n\t\t\t\t\t\tcolumnPadding: prefix.length,\n\t\t\t\t\t\trowPadding: titleLineCount + footerLineCount,\n\t\t\t\t\t\tstyle: (item, active) =>\n\t\t\t\t\t\t\topt(item, item.disabled ? 'disabled' : active ? 'active' : 'inactive'),\n\t\t\t\t\t}).join(`\\n${prefix}`)}\\n${prefixEnd}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<Value | symbol>;\n};\n","import { styleText } from 'node:util';\nimport { SelectKeyPrompt, settings, wrapTextWithPrefix } from '@clack/core';\nimport { type CommonOptions, S_BAR, S_BAR_END, symbol } from './common.js';\nimport type { Option } from './select.js';\n\nexport interface SelectKeyOptions<Value extends string> extends CommonOptions {\n\tmessage: string;\n\toptions: Option<Value>[];\n\tinitialValue?: Value;\n\tcaseSensitive?: boolean;\n}\n\nexport const selectKey = <Value extends string>(opts: SelectKeyOptions<Value>) => {\n\tconst opt = (\n\t\toption: Option<Value>,\n\t\tstate: 'inactive' | 'active' | 'selected' | 'cancelled' = 'inactive'\n\t) => {\n\t\tconst label = option.label ?? String(option.value);\n\t\tif (state === 'selected') {\n\t\t\treturn `${styleText('dim', label)}`;\n\t\t}\n\t\tif (state === 'cancelled') {\n\t\t\treturn `${styleText(['strikethrough', 'dim'], label)}`;\n\t\t}\n\t\tif (state === 'active') {\n\t\t\treturn `${styleText(['bgCyan', 'gray'], ` ${option.value} `)} ${label}${\n\t\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t\t}`;\n\t\t}\n\t\treturn `${styleText(['gray', 'bgWhite', 'inverse'], ` ${option.value} `)} ${label}${\n\t\t\toption.hint ? ` ${styleText('dim', `(${option.hint})`)}` : ''\n\t\t}`;\n\t};\n\n\treturn new SelectKeyPrompt({\n\t\toptions: opts.options,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\toutput: opts.output,\n\t\tinitialValue: opts.initialValue,\n\t\tcaseSensitive: opts.caseSensitive,\n\t\trender() {\n\t\t\tconst hasGuide = opts.withGuide ?? settings.withGuide;\n\t\t\tconst title = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${symbol(this.state)} ${opts.message}\\n`;\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst submitPrefix = hasGuide ? `${styleText('gray', S_BAR)} ` : '';\n\t\t\t\t\tconst selectedOption =\n\t\t\t\t\t\tthis.options.find((opt) => opt.value === this.value) ?? opts.options[0];\n\t\t\t\t\tconst wrapped = wrapTextWithPrefix(\n\t\t\t\t\t\topts.output,\n\t\t\t\t\t\topt(selectedOption, 'selected'),\n\t\t\t\t\t\tsubmitPrefix\n\t\t\t\t\t);\n\t\t\t\t\treturn `${title}${wrapped}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst cancelPrefix = hasGuide ? `${styleText('gray', S_BAR)} ` : '';\n\t\t\t\t\tconst wrapped = wrapTextWithPrefix(\n\t\t\t\t\t\topts.output,\n\t\t\t\t\t\topt(this.options[0], 'cancelled'),\n\t\t\t\t\t\tcancelPrefix\n\t\t\t\t\t);\n\t\t\t\t\treturn `${title}${wrapped}${hasGuide ? `\\n${styleText('gray', S_BAR)}` : ''}`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst defaultPrefix = hasGuide ? `${styleText('cyan', S_BAR)} ` : '';\n\t\t\t\t\tconst defaultPrefixEnd = hasGuide ? styleText('cyan', S_BAR_END) : '';\n\t\t\t\t\tconst wrapped = this.options\n\t\t\t\t\t\t.map((option, i) =>\n\t\t\t\t\t\t\twrapTextWithPrefix(\n\t\t\t\t\t\t\t\topts.output,\n\t\t\t\t\t\t\t\topt(option, i === this.cursor ? 'active' : 'inactive'),\n\t\t\t\t\t\t\t\tdefaultPrefix\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t)\n\t\t\t\t\t\t.join('\\n');\n\t\t\t\t\treturn `${title}${wrapped}\\n${defaultPrefixEnd}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<Value | symbol>;\n};\n","import { stripVTControlCharacters as strip, styleText } from 'node:util';\nimport { S_BAR, S_ERROR, S_INFO, S_STEP_SUBMIT, S_SUCCESS, S_WARN } from './common.js';\nimport type { LogMessageOptions } from './log.js';\n\nconst prefix = `${styleText('gray', S_BAR)} `;\n\n// TODO (43081j): this currently doesn't support custom `output` writables\n// because we rely on `columns` existing (i.e. `process.stdout.columns).\n//\n// If we want to support `output` being passed in, we will need to use\n// a condition like `if (output insance Writable)` to check if it has columns\nexport const stream = {\n\tmessage: async (\n\t\titerable: Iterable<string> | AsyncIterable<string>,\n\t\t{ symbol = styleText('gray', S_BAR) }: LogMessageOptions = {}\n\t) => {\n\t\tprocess.stdout.write(`${styleText('gray', S_BAR)}\\n${symbol} `);\n\t\tlet lineWidth = 3;\n\t\tfor await (let chunk of iterable) {\n\t\t\tchunk = chunk.replace(/\\n/g, `\\n${prefix}`);\n\t\t\tif (chunk.includes('\\n')) {\n\t\t\t\tlineWidth = 3 + strip(chunk.slice(chunk.lastIndexOf('\\n'))).length;\n\t\t\t}\n\t\t\tconst chunkLen = strip(chunk).length;\n\t\t\tif (lineWidth + chunkLen < process.stdout.columns) {\n\t\t\t\tlineWidth += chunkLen;\n\t\t\t\tprocess.stdout.write(chunk);\n\t\t\t} else {\n\t\t\t\tprocess.stdout.write(`\\n${prefix}${chunk.trimStart()}`);\n\t\t\t\tlineWidth = 3 + strip(chunk.trimStart()).length;\n\t\t\t}\n\t\t}\n\t\tprocess.stdout.write('\\n');\n\t},\n\tinfo: (iterable: Iterable<string> | AsyncIterable<string>) => {\n\t\treturn stream.message(iterable, { symbol: styleText('blue', S_INFO) });\n\t},\n\tsuccess: (iterable: Iterable<string> | AsyncIterable<string>) => {\n\t\treturn stream.message(iterable, { symbol: styleText('green', S_SUCCESS) });\n\t},\n\tstep: (iterable: Iterable<string> | AsyncIterable<string>) => {\n\t\treturn stream.message(iterable, { symbol: styleText('green', S_STEP_SUBMIT) });\n\t},\n\twarn: (iterable: Iterable<string> | AsyncIterable<string>) => {\n\t\treturn stream.message(iterable, { symbol: styleText('yellow', S_WARN) });\n\t},\n\t/** alias for `log.warn()`. */\n\twarning: (iterable: Iterable<string> | AsyncIterable<string>) => {\n\t\treturn stream.warn(iterable);\n\t},\n\terror: (iterable: Iterable<string> | AsyncIterable<string>) => {\n\t\treturn stream.message(iterable, { symbol: styleText('red', S_ERROR) });\n\t},\n};\n","import type { CommonOptions } from './common.js';\nimport { spinner } from './spinner.js';\n\nexport type Task = {\n\t/**\n\t * Task title\n\t */\n\ttitle: string;\n\t/**\n\t * Task function\n\t */\n\ttask: (message: (string: string) => void) => string | Promise<string> | void | Promise<void>;\n\n\t/**\n\t * If enabled === false the task will be skipped\n\t */\n\tenabled?: boolean;\n};\n\n/**\n * Define a group of tasks to be executed\n */\nexport const tasks = async (tasks: Task[], opts?: CommonOptions) => {\n\tfor (const task of tasks) {\n\t\tif (task.enabled === false) continue;\n\n\t\tconst s = spinner(opts);\n\t\ts.start(task.title);\n\t\tconst result = await task.task(s.message);\n\t\ts.stop(result || task.title);\n\t}\n};\n","import type { Writable } from 'node:stream';\nimport { styleText } from 'node:util';\nimport { getColumns } from '@clack/core';\nimport { erase } from 'sisteransi';\nimport {\n\ttype CommonOptions,\n\tisCI as isCIFn,\n\tisTTY as isTTYFn,\n\tS_BAR,\n\tS_STEP_SUBMIT,\n} from './common.js';\nimport { log } from './log.js';\n\nexport interface TaskLogOptions extends CommonOptions {\n\ttitle: string;\n\tlimit?: number;\n\tspacing?: number;\n\tretainLog?: boolean;\n}\n\nexport interface TaskLogMessageOptions {\n\traw?: boolean;\n}\n\nexport interface TaskLogCompletionOptions {\n\tshowLog?: boolean;\n}\n\ninterface BufferEntry {\n\theader?: string;\n\tvalue: string;\n\tfull: string;\n\tresult?: {\n\t\tstatus: 'success' | 'error';\n\t\tmessage: string;\n\t};\n}\n\nconst stripDestructiveANSI = (input: string): string => {\n\t// biome-ignore lint/suspicious/noControlCharactersInRegex: intentional\n\treturn input.replace(/\\x1b\\[(?:\\d+;)*\\d*[ABCDEFGHfJKSTsu]|\\x1b\\[(s|u)/g, '');\n};\n\n/**\n * Renders a log which clears on success and remains on failure\n */\nexport const taskLog = (opts: TaskLogOptions) => {\n\tconst output: Writable = opts.output ?? process.stdout;\n\tconst columns = getColumns(output);\n\tconst secondarySymbol = styleText('gray', S_BAR);\n\tconst spacing = opts.spacing ?? 1;\n\tconst barSize = 3;\n\tconst retainLog = opts.retainLog === true;\n\tconst isTTY = !isCIFn() && isTTYFn(output);\n\n\toutput.write(`${secondarySymbol}\\n`);\n\toutput.write(`${styleText('green', S_STEP_SUBMIT)} ${opts.title}\\n`);\n\tfor (let i = 0; i < spacing; i++) {\n\t\toutput.write(`${secondarySymbol}\\n`);\n\t}\n\n\tconst buffers: BufferEntry[] = [\n\t\t{\n\t\t\tvalue: '',\n\t\t\tfull: '',\n\t\t},\n\t];\n\tlet lastMessageWasRaw = false;\n\n\tconst clear = (clearTitle: boolean): void => {\n\t\tif (buffers.length === 0) {\n\t\t\treturn;\n\t\t}\n\n\t\tlet lines = 0;\n\n\t\tif (clearTitle) {\n\t\t\tlines += spacing + 2;\n\t\t}\n\n\t\tfor (const buffer of buffers) {\n\t\t\tconst { value, result } = buffer;\n\t\t\tlet text = result?.message ?? value;\n\n\t\t\tif (text.length === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (result === undefined && buffer.header !== undefined && buffer.header !== '') {\n\t\t\t\ttext += `\\n${buffer.header}`;\n\t\t\t}\n\n\t\t\tconst bufferHeight = text.split('\\n').reduce((count, line) => {\n\t\t\t\tif (line === '') {\n\t\t\t\t\treturn count + 1;\n\t\t\t\t}\n\t\t\t\treturn count + Math.ceil((line.length + barSize) / columns);\n\t\t\t}, 0);\n\n\t\t\tlines += bufferHeight;\n\t\t}\n\n\t\tif (lines > 0) {\n\t\t\tlines += 1;\n\t\t\toutput.write(erase.lines(lines));\n\t\t}\n\t};\n\tconst printBuffer = (buffer: BufferEntry, messageSpacing?: number, full?: boolean): void => {\n\t\tconst messages = full ? `${buffer.full}\\n${buffer.value}` : buffer.value;\n\t\tif (buffer.header !== undefined && buffer.header !== '') {\n\t\t\tlog.message(\n\t\t\t\tbuffer.header.split('\\n').map((line) => styleText('bold', line)),\n\t\t\t\t{\n\t\t\t\t\toutput,\n\t\t\t\t\tsecondarySymbol,\n\t\t\t\t\tsymbol: secondarySymbol,\n\t\t\t\t\tspacing: 0,\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\t\tlog.message(\n\t\t\tmessages.split('\\n').map((line) => styleText('dim', line)),\n\t\t\t{\n\t\t\t\toutput,\n\t\t\t\tsecondarySymbol,\n\t\t\t\tsymbol: secondarySymbol,\n\t\t\t\tspacing: messageSpacing ?? spacing,\n\t\t\t}\n\t\t);\n\t};\n\tconst renderBuffer = (): void => {\n\t\tfor (const buffer of buffers) {\n\t\t\tconst { header, value, full } = buffer;\n\t\t\tif ((header === undefined || header.length === 0) && value.length === 0) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tprintBuffer(buffer, undefined, retainLog === true && full.length > 0);\n\t\t}\n\t};\n\tconst message = (buffer: BufferEntry, msg: string, mopts?: TaskLogMessageOptions) => {\n\t\tclear(false);\n\t\tif ((mopts?.raw !== true || !lastMessageWasRaw) && buffer.value !== '') {\n\t\t\tbuffer.value += '\\n';\n\t\t}\n\t\tbuffer.value += stripDestructiveANSI(msg);\n\t\tlastMessageWasRaw = mopts?.raw === true;\n\t\tif (opts.limit !== undefined) {\n\t\t\tconst lines = buffer.value.split('\\n');\n\t\t\tconst linesToRemove = lines.length - opts.limit;\n\t\t\tif (linesToRemove > 0) {\n\t\t\t\tconst removedLines = lines.splice(0, linesToRemove);\n\t\t\t\tif (retainLog) {\n\t\t\t\t\tbuffer.full += (buffer.full === '' ? '' : '\\n') + removedLines.join('\\n');\n\t\t\t\t}\n\t\t\t}\n\t\t\tbuffer.value = lines.join('\\n');\n\t\t}\n\t\tif (isTTY) {\n\t\t\tprintBuffers();\n\t\t}\n\t};\n\tconst printBuffers = (): void => {\n\t\tfor (const buffer of buffers) {\n\t\t\tif (buffer.result) {\n\t\t\t\tif (buffer.result.status === 'error') {\n\t\t\t\t\tlog.error(buffer.result.message, { output, secondarySymbol, spacing: 0 });\n\t\t\t\t} else {\n\t\t\t\t\tlog.success(buffer.result.message, { output, secondarySymbol, spacing: 0 });\n\t\t\t\t}\n\t\t\t} else if (buffer.value !== '') {\n\t\t\t\tprintBuffer(buffer, 0);\n\t\t\t}\n\t\t}\n\t};\n\tconst completeBuffer = (buffer: BufferEntry, result: BufferEntry['result']): void => {\n\t\tclear(false);\n\n\t\tbuffer.result = result;\n\n\t\tif (isTTY) {\n\t\t\tprintBuffers();\n\t\t}\n\t};\n\n\treturn {\n\t\tmessage(msg: string, mopts?: TaskLogMessageOptions) {\n\t\t\tmessage(buffers[0], msg, mopts);\n\t\t},\n\t\tgroup(name: string) {\n\t\t\tconst buffer: BufferEntry = {\n\t\t\t\theader: name,\n\t\t\t\tvalue: '',\n\t\t\t\tfull: '',\n\t\t\t};\n\t\t\tbuffers.push(buffer);\n\t\t\treturn {\n\t\t\t\tmessage(msg: string, mopts?: TaskLogMessageOptions) {\n\t\t\t\t\tmessage(buffer, msg, mopts);\n\t\t\t\t},\n\t\t\t\terror(message: string) {\n\t\t\t\t\tcompleteBuffer(buffer, {\n\t\t\t\t\t\tstatus: 'error',\n\t\t\t\t\t\tmessage,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\tsuccess(message: string) {\n\t\t\t\t\tcompleteBuffer(buffer, {\n\t\t\t\t\t\tstatus: 'success',\n\t\t\t\t\t\tmessage,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\terror(message: string, opts?: TaskLogCompletionOptions): void {\n\t\t\tclear(true);\n\t\t\tlog.error(message, { output, secondarySymbol, spacing: 1 });\n\t\t\tif (opts?.showLog !== false) {\n\t\t\t\trenderBuffer();\n\t\t\t}\n\t\t\t// clear buffer since error is an end state\n\t\t\tbuffers.splice(1, buffers.length - 1);\n\t\t\tbuffers[0].value = '';\n\t\t\tbuffers[0].full = '';\n\t\t},\n\t\tsuccess(message: string, opts?: TaskLogCompletionOptions): void {\n\t\t\tclear(true);\n\t\t\tlog.success(message, { output, secondarySymbol, spacing: 1 });\n\t\t\tif (opts?.showLog === true) {\n\t\t\t\trenderBuffer();\n\t\t\t}\n\t\t\t// clear buffer since success is an end state\n\t\t\tbuffers.splice(1, buffers.length - 1);\n\t\t\tbuffers[0].value = '';\n\t\t\tbuffers[0].full = '';\n\t\t},\n\t};\n};\n","import { styleText } from 'node:util';\nimport { settings, TextPrompt } from '@clack/core';\nimport { type CommonOptions, S_BAR, S_BAR_END, symbol } from './common.js';\n\nexport interface TextOptions extends CommonOptions {\n\tmessage: string;\n\tplaceholder?: string;\n\tdefaultValue?: string;\n\tinitialValue?: string;\n\tvalidate?: (value: string | undefined) => string | Error | undefined;\n}\n\nexport const text = (opts: TextOptions) => {\n\treturn new TextPrompt({\n\t\tvalidate: opts.validate,\n\t\tplaceholder: opts.placeholder,\n\t\tdefaultValue: opts.defaultValue,\n\t\tinitialValue: opts.initialValue,\n\t\toutput: opts.output,\n\t\tsignal: opts.signal,\n\t\tinput: opts.input,\n\t\trender() {\n\t\t\tconst hasGuide = opts?.withGuide ?? settings.withGuide;\n\t\t\tconst titlePrefix = `${hasGuide ? `${styleText('gray', S_BAR)}\\n` : ''}${symbol(this.state)} `;\n\t\t\tconst title = `${titlePrefix}${opts.message}\\n`;\n\t\t\tconst placeholder = opts.placeholder\n\t\t\t\t? styleText('inverse', opts.placeholder[0]) + styleText('dim', opts.placeholder.slice(1))\n\t\t\t\t: styleText(['inverse', 'hidden'], '_');\n\t\t\tconst userInput = !this.userInput ? placeholder : this.userInputWithCursor;\n\t\t\tconst value = this.value ?? '';\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase 'error': {\n\t\t\t\t\tconst errorText = this.error ? ` ${styleText('yellow', this.error)}` : '';\n\t\t\t\t\tconst errorPrefix = hasGuide ? `${styleText('yellow', S_BAR)} ` : '';\n\t\t\t\t\tconst errorPrefixEnd = hasGuide ? styleText('yellow', S_BAR_END) : '';\n\t\t\t\t\treturn `${title.trim()}\\n${errorPrefix}${userInput}\\n${errorPrefixEnd}${errorText}\\n`;\n\t\t\t\t}\n\t\t\t\tcase 'submit': {\n\t\t\t\t\tconst valueText = value ? ` ${styleText('dim', value)}` : '';\n\t\t\t\t\tconst submitPrefix = hasGuide ? styleText('gray', S_BAR) : '';\n\t\t\t\t\treturn `${title}${submitPrefix}${valueText}`;\n\t\t\t\t}\n\t\t\t\tcase 'cancel': {\n\t\t\t\t\tconst valueText = value ? ` ${styleText(['strikethrough', 'dim'], value)}` : '';\n\t\t\t\t\tconst cancelPrefix = hasGuide ? styleText('gray', S_BAR) : '';\n\t\t\t\t\treturn `${title}${cancelPrefix}${valueText}${value.trim() ? `\\n${cancelPrefix}` : ''}`;\n\t\t\t\t}\n\t\t\t\tdefault: {\n\t\t\t\t\tconst defaultPrefix = hasGuide ? `${styleText('cyan', S_BAR)} ` : '';\n\t\t\t\t\tconst defaultPrefixEnd = hasGuide ? styleText('cyan', S_BAR_END) : '';\n\t\t\t\t\treturn `${title}${defaultPrefix}${userInput}\\n${defaultPrefixEnd}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}).prompt() as Promise<string | symbol>;\n};\n","/**\n * Update command — 비대화형 정책 파일 갱신.\n *\n * 왜 있나: `install`·`list`·`uninstall` 은 전부 플래그로 비대화형 실행이 되는데 `update` 만\n * 위저드 전용이었다. CI 로 하네스를 **깔 수는 있는데 갱신할 수는 없다**는 건 수요의 문제가\n * 아니라 명령 계열의 비대칭이다 — 빠진 쪽이 사유를 대야 한다 (사용자 지시 2026-07-20).\n *\n * 동작: 기존 설치를 감지해 위저드의 update 액션과 **동일한 spec**(`buildUpdateSpec`)으로\n * `mode: \"update\"` 파이프라인을 돈다. 백업은 update mode 가 자동으로 뜬다 (`.claude.backup-*`).\n *\n * 하지 않는 것: track 추가(=`install`), 자산 재설치, 대화형 확인. update 는 이미 깔린\n * 정책 파일만 최신판으로 맞춘다.\n */\n\nimport { resolve } from \"node:path\";\nimport { c, status } from \"../design.js\";\nimport { type DetectedInstall, detectInstallState } from \"../state.js\";\nimport type { InstallSpec } from \"../types.js\";\nimport { buildUpdateSpec } from \"../update-mode.js\";\nimport { type ExecuteSpecDeps, executeSpec } from \"./install.js\";\n\nexport interface UpdateOptions {\n projectDir?: string;\n}\n\nexport interface UpdateActionDeps {\n log?: (msg: string) => void;\n err?: (msg: string) => void;\n exit?: (code: number) => never;\n detect?: (projectDir: string) => DetectedInstall;\n execute?: (spec: InstallSpec, deps: ExecuteSpecDeps) => void;\n}\n\nexport function updateAction(options: UpdateOptions = {}, deps: UpdateActionDeps = {}): void {\n const log = deps.log ?? console.log;\n const err = deps.err ?? console.error;\n const exit = deps.exit ?? ((code: number) => process.exit(code) as never);\n const detect = deps.detect ?? detectInstallState;\n const execute = deps.execute ?? executeSpec;\n\n const projectDir = resolve(options.projectDir ?? process.cwd());\n const state = detect(projectDir);\n\n // Pre-flight: 갱신할 대상이 없으면 조용히 성공하지 않는다. 파이프라인도 같은 조건에서\n // throw 하지만, 그건 \"install failed\" 로 렌더돼 원인이 안 보인다.\n if (!state.hasClaudeDir) {\n err(status.failure(c.red(`No harness install found at ${projectDir}/.claude`)));\n err(c.dim(\" Run `agent-harness install --track <name>` first.\"));\n exit(1);\n return;\n }\n\n log(c.dim(`Updating policy files in ${projectDir}/.claude`));\n execute(buildUpdateSpec(projectDir, state.tracks), { log, err, exit, mode: \"update\" });\n}\n\nexport function registerUpdateCommand(cli: import(\"../cli.js\").Cli): void {\n cli\n .command(\n \"update\",\n \"Refresh installed policy files (rules / agents / commands / hooks / skills)\",\n )\n .option(\"--project-dir <path>\", \"[Project] Target project directory\", {\n default: process.cwd(),\n })\n /* v8 ignore next 3 — cac action callback. updateAction 자체는 별도 tests 로 검증. */\n .action((options: UpdateOptions) => {\n updateAction(options);\n });\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { isTrack, type Track } from \"./types.js\";\n\nexport type InstallState = \"new\" | \"existing\";\n\nexport interface DetectedInstall {\n state: InstallState;\n tracks: Track[];\n /** Source of the detected tracks: \"metafile\" (v27.17+), \"legacy\" (rules/*.md heuristic), or \"none\". */\n source: \"metafile\" | \"legacy\" | \"none\";\n hasClaudeDir: boolean;\n}\n\nconst META_FILE = \".claude/.installed-tracks\";\n\ninterface LegacySignature {\n rule: string;\n track: Track;\n}\n\nconst LEGACY_SIGNATURES: readonly LegacySignature[] = [\n { rule: \"htmx.md\", track: \"ssr-htmx\" },\n { rule: \"nextjs.md\", track: \"ssr-nextjs\" },\n { rule: \"data-analysis.md\", track: \"data\" },\n { rule: \"pyside6.md\", track: \"data\" },\n { rule: \"cli-development.md\", track: \"tooling\" },\n];\n\n/**\n * Detect what was previously installed in the given project directory.\n * Mirrors the v27.17 detect_install_state shell function (setup-harness.sh:191).\n */\nexport function detectInstallState(projectDir: string): DetectedInstall {\n const claudeDir = join(projectDir, \".claude\");\n const hasClaudeDir = existsSync(claudeDir);\n\n if (!hasClaudeDir) {\n return { state: \"new\", tracks: [], source: \"none\", hasClaudeDir: false };\n }\n\n const metaPath = join(projectDir, META_FILE);\n if (existsSync(metaPath)) {\n const tracks = readMetafile(metaPath);\n return { state: \"existing\", tracks, source: \"metafile\", hasClaudeDir: true };\n }\n\n const tracks = inferFromLegacySignatures(projectDir);\n return { state: \"existing\", tracks, source: \"legacy\", hasClaudeDir: true };\n}\n\nfunction readMetafile(path: string): Track[] {\n const raw = readFileSync(path, \"utf8\");\n const seen = new Set<Track>();\n for (const line of raw.split(/\\s+/)) {\n const trimmed = line.trim();\n if (isTrack(trimmed)) {\n seen.add(trimmed);\n }\n }\n return [...seen].sort();\n}\n\nfunction inferFromLegacySignatures(projectDir: string): Track[] {\n const rulesDir = join(projectDir, \".claude/rules\");\n if (!existsSync(rulesDir)) {\n return [];\n }\n const found = new Set<Track>();\n for (const sig of LEGACY_SIGNATURES) {\n if (existsSync(join(rulesDir, sig.rule))) {\n found.add(sig.track);\n }\n }\n return [...found].sort();\n}\n","import { formatResidentCostLine, residentCost, summarizeContextCost } from \"./context-cost.js\";\nimport { assetReachesCli, EXTERNAL_ASSETS } from \"./external-assets.js\";\nimport { readInstallLog } from \"./install-log.js\";\nimport type { InstallMode } from \"./installer.js\";\nimport { buildManifest } from \"./manifest.js\";\nimport {\n finalSelectedAssets,\n groupAssetsByCategory,\n recommendedExternalAssets,\n} from \"./preset-recommend.js\";\nimport {\n defaultPrompts,\n type InstallTargetId,\n type Prompts,\n VISIBLE_OPTION_DEFS,\n} from \"./prompts.js\";\nimport { type DetectedInstall, detectInstallState } from \"./state.js\";\nimport type { InstallSpec, OptionFlags, Track } from \"./types.js\";\nimport { buildUpdateSpec } from \"./update-mode.js\";\nimport { stepLabel, WIZARD } from \"./wizard-steps.js\";\n\n/**\n * v26.54.0 — All-in-one 결과 → option keys + asset id list 분리.\n * `option:<key>` → OptionFlags key\n * `asset:<id>` → EXTERNAL_ASSETS id\n */\nexport function splitInstallTargets(targets: ReadonlyArray<InstallTargetId>): {\n optionKeys: Array<keyof OptionFlags>;\n assetIds: Array<string>;\n} {\n const optionKeys: Array<keyof OptionFlags> = [];\n const assetIds: Array<string> = [];\n for (const t of targets) {\n if (t.startsWith(\"option:\")) {\n optionKeys.push(t.slice(\"option:\".length) as keyof OptionFlags);\n } else if (t.startsWith(\"asset:\")) {\n assetIds.push(t.slice(\"asset:\".length));\n }\n }\n return { optionKeys, assetIds };\n}\n\n/**\n * v26.81.0 (ADR-022) — 자산 1:1 boolean 13종 삭제 후 잔존 동작 옵션만 매핑.\n * wizard 의 자산 선택은 전부 `asset:<id>` → userOverride.forceInclude 경로.\n */\nexport function toOptionFlags(keys: ReadonlyArray<keyof OptionFlags>): OptionFlags {\n const picked = new Set<keyof OptionFlags>(keys);\n return {\n withPrune: picked.has(\"withPrune\"),\n withCodexTrust: picked.has(\"withCodexTrust\"),\n withKarpathyHook: picked.has(\"withKarpathyHook\"),\n };\n}\n\nexport interface InteractiveDeps {\n prompts?: Prompts;\n detect?: (projectDir: string) => DetectedInstall;\n isTty?: () => boolean;\n /** v26.125.0 — 설치 상태 주입 (테스트용). 미주입 시 install log 를 읽는다. */\n readInstalled?: (projectDir: string) => InstalledTargetState;\n}\n\n/**\n * v26.125.0 — wizard 가 참조하는 설치 상태.\n *\n * `installed` 와 `projectScoped` 를 나누는 이유: global scope 자산까지 사전 체크하면\n * step 4 에서 project 를 고른 순간 **같은 자산이 project 에 한 벌 더 깔린다**. 그래서\n * 표시(마커)는 전부 하고, 사전 체크는 project scope 만 한다.\n */\nexport interface InstalledTargetState {\n /** 마커를 붙일 자산 id — scope 무관 (설치돼 있다는 사실 자체는 참) */\n installed: ReadonlyArray<string>;\n /** 사전 체크할 자산 id — project scope 만 */\n projectScoped: ReadonlyArray<string>;\n}\n\n/** install log → wizard 표시용 설치 상태. 로그가 없으면(최초 설치) 빈 상태. */\nexport function installedTargetState(projectDir: string): InstalledTargetState {\n const log = readInstallLog(projectDir);\n if (!log) return { installed: [], projectScoped: [] };\n return {\n installed: log.assets.map((a) => a.id),\n projectScoped: log.assets.filter((a) => a.scope !== \"global\").map((a) => a.id),\n };\n}\n\n/**\n * step 3 의 초기 체크 = **트랙 추천 ∪ 이미 설치된 project 자산**.\n *\n * 추천만 쓰면 추천 밖의 설치된 자산이 빈칸으로 보여, 사용자가 \"안 깔렸다\"고 읽는다.\n * 합집합이므로 중복은 생기지 않는다 (헤더의 `n/m ✓` 카운트가 거짓이 되지 않아야 한다).\n */\nexport function initialTargetSelection(\n tracks: ReadonlyArray<Track>,\n installedProjectAssetIds: ReadonlyArray<string>,\n): InstallTargetId[] {\n const ids = new Set<string>(recommendedExternalAssets(tracks));\n for (const id of installedProjectAssetIds) ids.add(id);\n return [...ids].map((id) => `asset:${id}` as InstallTargetId);\n}\n\nexport interface InteractiveResult {\n ok: boolean;\n spec?: InstallSpec;\n mode?: InstallMode;\n reason?: \"no-tty\" | \"cancelled\" | \"disabled-action\" | \"exit\";\n message?: string;\n}\n\n/**\n * v26.54.0 — 3-step wizard. SPEC: docs/specs/v26-54-all-in-one-installer.md\n *\n * Step 1: tracks (ESC = exit + cancel msg)\n * Step 2: cli (ESC = silent back to tracks)\n * Step 3: install-targets all-in-one (ESC = silent back to cli)\n * confirm prompt (ESC = silent back to targets)\n *\n * 이전 5-step 의 options + 2-tier asset navigator 를 step 3 1 화면 group multiselect 로 흡수.\n */\nexport async function runInteractive(\n projectDir: string,\n deps: InteractiveDeps = {},\n): Promise<InteractiveResult> {\n const prompts = deps.prompts ?? defaultPrompts;\n const detect = deps.detect ?? detectInstallState;\n const isTty = deps.isTty ?? (() => Boolean(process.stdin.isTTY));\n\n if (!isTty()) {\n return {\n ok: false,\n reason: \"no-tty\",\n message:\n \"Interactive mode requires a TTY. Use `agent-harness install --track <name>` for non-interactive use.\",\n };\n }\n\n prompts.intro(\"uzys-agent-harness installer\");\n const state = detect(projectDir);\n // v26.125.0 — 위저드가 설치 상태를 읽는다. 이전에는 step 3 의 체크가 트랙 추천에서만 나와\n // **이미 깔린 자산이 빈칸으로 보였다** — 사용자가 그 체크박스를 설치 상태로 읽으므로 화면이\n // 거짓을 말한 셈이다. 마커는 표시 전용이고 체크를 풀어도 제거되지 않는다 (제거 = `uninstall`).\n const installed = (deps.readInstalled ?? installedTargetState)(projectDir);\n\n let initialTracks: Track[] | undefined;\n let mode: InstallMode = \"fresh\";\n if (state.state === \"existing\") {\n const action = await prompts.selectAction(state);\n if (action === null) {\n prompts.cancel(\"Cancelled.\");\n return { ok: false, reason: \"cancelled\" };\n }\n if (action === \"exit\") {\n prompts.outro(\"Exiting without changes.\");\n return { ok: false, reason: \"exit\" };\n }\n if (action === \"remove\") {\n prompts.cancel(\"Track removal is not automated — manually edit `.claude/`. Aborting.\");\n return { ok: false, reason: \"disabled-action\" };\n }\n if (action === \"update\") {\n mode = \"update\";\n // spec 은 `buildUpdateSpec` 단일 출처 — 비대화형 `update` 명령과 같은 것을 쓴다.\n const spec = buildUpdateSpec(projectDir, state.tracks);\n const confirmed = await prompts.confirmInstall(\n `UPDATE policy files only:\\n${formatSummary(spec)}`,\n );\n if (!confirmed) {\n prompts.outro(\"Cancelled.\");\n return { ok: false, reason: \"cancelled\" };\n }\n prompts.outro(\"Running update mode...\");\n return { ok: true, mode: \"update\", spec };\n }\n if (action === \"add\") {\n mode = \"add\";\n initialTracks = state.tracks;\n } else if (action === \"reinstall\") {\n mode = \"reinstall\";\n }\n }\n\n // v26.64.0 (ADR-020) — scope step 추가. Default \"project\". Step 3.5 (targets 직후, confirm 직전).\n type Step = \"tracks\" | \"cli\" | \"targets\" | \"scope\" | \"confirm\";\n let step: Step = \"tracks\";\n let tracks: Track[] | null = null;\n let cli: import(\"./types.js\").CliTargets | null = null;\n let targetSelections: ReadonlyArray<InstallTargetId> | null = null;\n let scope: import(\"./types.js\").InstallScope = \"project\";\n\n while (true) {\n if (step === \"tracks\") {\n const result = await prompts.selectTracks(tracks ?? initialTracks, WIZARD.TRACKS);\n if (result === null) {\n // Step 1 ESC = exit with cancel message (only step where ESC is \"cancel\")\n prompts.cancel(\"Cancelled.\");\n return { ok: false, reason: \"cancelled\" };\n }\n // preset 변경 감지 → install-targets reset (v26.50 정책 유지)\n if (tracks !== null && !tracksEqual(tracks, result)) {\n targetSelections = null;\n }\n tracks = result;\n step = \"cli\";\n } else if (step === \"cli\") {\n const result = await prompts.selectCli(cli ?? [\"claude\"], WIZARD.CLI);\n if (result === null) {\n step = \"tracks\"; // silent back\n continue;\n }\n cli = result;\n step = \"targets\";\n } else if (step === \"targets\") {\n const initial: InstallTargetId[] =\n targetSelections !== null\n ? [...targetSelections]\n : initialTargetSelection(tracks ?? [], installed.projectScoped);\n // v26.65.0 — step indicator SSOT (wizard-steps.ts). Phase: 3 targets → 4 scope → 5 confirm → 6 install.\n const result = await prompts.selectInstallTargets(initial, WIZARD.TARGETS, {\n tracks: tracks ?? [],\n cli: cli ?? [\"claude\"],\n installed: installed.installed.map((id) => `asset:${id}`),\n });\n if (result === null) {\n step = \"cli\"; // silent back\n continue;\n }\n targetSelections = result;\n step = \"scope\";\n } else if (step === \"scope\") {\n // v26.64.0 (ADR-020) — Installation scope select. Default \"project\" (D16).\n const result = await prompts.selectScope(scope, WIZARD.SCOPE);\n if (result === null) {\n step = \"targets\"; // silent back\n continue;\n }\n scope = result;\n step = \"confirm\";\n } else {\n // confirm\n // biome-ignore lint/style/noNonNullAssertion: confirm step 도달 = 모든 이전 step 완료 보장\n const finalTracks = tracks!;\n // biome-ignore lint/style/noNonNullAssertion: same as above\n const finalCli = cli!;\n const { optionKeys, assetIds } = splitInstallTargets(targetSelections ?? []);\n const options = toOptionFlags(optionKeys);\n const userOverride =\n targetSelections === null ? undefined : computeUserOverride(finalTracks, assetIds);\n // v26.64.0 (ADR-020) — Confirm summary 에 SCOPE 명시 (사용자 인지 + D16).\n const scopeLabel =\n scope === \"global\"\n ? \"Global (writes to ~/.claude/, ~/.codex/, npm -g)\"\n : \"Project (current directory only)\";\n const summary = `${formatSummary({\n tracks: finalTracks,\n options,\n cli: finalCli,\n projectDir,\n ...(userOverride ? { userOverride } : {}),\n })}\\n SCOPE ${scopeLabel}`;\n const confirmed = await prompts.confirmInstall(\n `${stepLabel(WIZARD.CONFIRM, \"Confirm\")}\\n${summary}`,\n );\n if (confirmed === null) {\n step = \"scope\"; // silent back\n continue;\n }\n if (!confirmed) {\n prompts.outro(\"Cancelled by user.\");\n return { ok: false, reason: \"cancelled\" };\n }\n prompts.outro(stepLabel(WIZARD.INSTALL, \"Installing...\"));\n return {\n ok: true,\n mode,\n spec: {\n tracks: finalTracks,\n options,\n cli: finalCli,\n projectDir,\n scope,\n ...(userOverride ? { userOverride } : {}),\n },\n };\n }\n }\n}\n\n/**\n * Track 배열 동등 비교 (순서 무관). Preset 변경 감지에 사용.\n */\nfunction tracksEqual(a: ReadonlyArray<Track>, b: ReadonlyArray<Track>): boolean {\n if (a.length !== b.length) return false;\n const sortedA = [...a].sort();\n const sortedB = [...b].sort();\n return sortedA.every((t, i) => t === sortedB[i]);\n}\n\n/**\n * v26.54.0 — Asset 선택 결과 (id 만) 와 preset 추천 비교 → forceInclude / forceExclude.\n * - `recommended - selected` → forceExclude (사용자가 unchecked)\n * - `selected - recommended` → forceInclude (사용자가 추가 선택)\n * 둘 다 비어있으면 undefined (no override).\n */\nexport function computeUserOverride(\n tracks: ReadonlyArray<Track>,\n assetIds: ReadonlyArray<string>,\n): { forceInclude: ReadonlyArray<string>; forceExclude: ReadonlyArray<string> } | undefined {\n const recommended = new Set(recommendedExternalAssets(tracks));\n const selected = new Set(assetIds);\n const forceExclude = [...recommended].filter((id) => !selected.has(id)).sort();\n const forceInclude = [...selected].filter((id) => !recommended.has(id)).sort();\n if (forceInclude.length === 0 && forceExclude.length === 0) return undefined;\n return { forceInclude, forceExclude };\n}\n\nexport function formatSummary(spec: InstallSpec): string {\n const opts = (Object.keys(spec.options) as Array<keyof OptionFlags>)\n .filter((k) => spec.options[k])\n .map((k) => k.replace(/^with/, \"\").toLowerCase());\n // v26.63.3 (clarify H1): \"(defaults only)\" 모호 → \"(none added)\" 명료.\n const optsLabel = opts.length > 0 ? opts.join(\", \") : \"(none added)\";\n const lines = [\n `Tracks: ${spec.tracks.join(\", \")}`,\n `Options: ${optsLabel}`,\n `CLI: ${spec.cli.join(\" · \")}`,\n `Target: ${spec.projectDir}`,\n ];\n\n // v26.62.3 — 실제 install 될 자산 list 명시. defaults 만으로는 사용자가\n // Step 3 에서 무엇을 confirm 했는지 알 수 없음. preset recommended +\n // userOverride 적용 후 최종 selected assets list 표시.\n // v26.82.0 (Phase R, S6) — merge/그룹화는 preset-recommend.ts 단일 구현 사용 (중복 제거).\n const finalAssets = finalSelectedAssets(spec.tracks, spec.userOverride);\n if (finalAssets.length > 0) {\n // v26.102.0 (ADR-031) — confirm 화면의 약속 숫자에 CLI 도달 분해 병기 (SOD 리뷰 F3:\n // \"4 selected\" 확정 후 0 설치이던 불일치 — 숨김 없이 고지만).\n const unreachable = finalAssets.filter((id) => {\n const asset = EXTERNAL_ASSETS.find((a) => a.id === id);\n return asset ? !assetReachesCli(asset, spec.cli) : false;\n });\n lines.push(\n unreachable.length > 0\n ? `Assets: ${finalAssets.length} selected (${unreachable.length} outside [${spec.cli.join(\", \")}] reach — not installed)`\n : `Assets: ${finalAssets.length} selected`,\n );\n for (const [cat, ids] of groupAssetsByCategory(finalAssets)) {\n lines.push(` · ${cat}: ${ids.join(\", \")}`);\n }\n // v26.103.0 (ADR-032) — header 와 동일 문구 (표면별 상이 문구 금지, v26.88.0 교훈).\n const cost = formatResidentCostLine(\n residentCost(buildManifest(spec).filter((e) => e.applies(spec))),\n summarizeContextCost(finalAssets).unmeasuredCount,\n );\n if (cost) lines.push(` · ${cost}`);\n }\n\n if (spec.userOverride) {\n if (spec.userOverride.forceInclude.length > 0) {\n lines.push(` +User added: ${spec.userOverride.forceInclude.join(\", \")}`);\n }\n if (spec.userOverride.forceExclude.length > 0) {\n lines.push(` -User removed: ${spec.userOverride.forceExclude.join(\", \")}`);\n }\n }\n return lines.join(\"\\n\");\n}\n\n// v26.54.0 — Re-exports to keep test imports stable (test의 mock 구조 변경 없음)\nexport { EXTERNAL_ASSETS, VISIBLE_OPTION_DEFS };\n","// prompts.ts is a thin adapter over @clack/prompts. It deliberately contains\n// no transformation logic — interactive.ts owns the business rules. This file\n// is excluded from coverage in vitest.config.ts (justification at exclude line).\n\nimport {\n cancel,\n confirm,\n groupMultiselect,\n intro,\n isCancel,\n multiselect,\n outro,\n select,\n} from \"@clack/prompts\";\nimport { CATEGORIES, CATEGORY_TITLES, type Category } from \"./categories.js\";\nimport { CLI_BASE_SORT_ORDER } from \"./cli-targets.js\";\nimport { assetTrustTier, DEV_METHOD_SKILL_IDS, EXTERNAL_ASSETS } from \"./external-assets.js\";\nimport { buildRouterChoices, type RouterAction, summarizeState } from \"./router.js\";\nimport type { DetectedInstall } from \"./state.js\";\nimport {\n type CliBase,\n type CliTargets,\n type InstallScope,\n type OptionFlags,\n TRACKS,\n type Track,\n} from \"./types.js\";\nimport { stepLabel, type WizardStep } from \"./wizard-steps.js\";\n\n/**\n * v26.54.0 — All-in-one install-targets value scheme.\n * groupMultiselect 의 단일 string value 에 두 source 통합:\n * - `option:<key>` → OPTION_DEFS 의 manifest-영향 build option (현재 빈 배열 — 아래 OPTION_DEFS 참조)\n * - `asset:<id>` → EXTERNAL_ASSETS 의 외부 자산\n * 다른 OptionFlags 항목 (withGsd, withEcc, withPrune, withTob, withKarpathyHook,\n * withAddyAgentSkills, withSuperpowers, withWshobsonAgents, withOpenspec, withBmad) 은\n * EXTERNAL_ASSETS 에 1:1 자산이 있어\n * 자산 체크 → userOverride.forceInclude 로 처리. UI 중복 표시 없음.\n */\nexport type InstallTargetId = `option:${keyof OptionFlags}` | `asset:${string}`;\n\nexport interface Prompts {\n intro: (msg: string) => void;\n outro: (msg: string) => void;\n cancel: (msg: string) => void;\n\n /**\n * v26.65.0 — step optional 두 번째 인자. 호출자가 `WIZARD.TRACKS` 전달 시 message 에\n * \"Step N/M — Select Track(s)\" 형식 indicator 자동 삽입. 미전달 시 prefix 없이 raw label.\n */\n selectTracks: (initial?: Track[], step?: WizardStep) => Promise<Track[] | null>;\n /** v0.7.0 — single select → multiselect (3 base 체크박스). default `[\"claude\"]`. */\n selectCli: (initial?: CliTargets, step?: WizardStep) => Promise<CliTargets | null>;\n selectAction: (state: DetectedInstall) => Promise<RouterAction | null>;\n /**\n * v26.64.0 (ADR-020) — Installation scope 선택. Default = \"project\" (pre-selected).\n * Global 은 사용자 명시 opt-in. null = silent back.\n */\n selectScope: (initial?: InstallScope, step?: WizardStep) => Promise<InstallScope | null>;\n confirmInstall: (summary: string) => Promise<boolean | null>;\n\n /**\n * v26.54.0 — Step 3 (all-in-one). EXTERNAL_ASSETS + 표시-대상 OPTION_DEFS 를\n * 카테고리 그룹화. 추천 ✓ pre-check. ESC → null (silent back).\n * v26.61.0 — recap (tracks/cli) 추가. alt screen 안에서 동작 — terminal scrollback\n * 본질 차단 → wizard scroll 시 cursor highlight 항상 visible.\n */\n selectInstallTargets: (\n initialChecked: ReadonlyArray<InstallTargetId>,\n step: { current: number; total: number },\n recap?: {\n tracks: ReadonlyArray<Track>;\n cli: CliTargets;\n /**\n * v26.125.0 — 이미 설치된 target id (표시 전용 마커). 체크를 풀어도 제거되지 않는다 —\n * 제거는 `agent-harness uninstall` 을 따로 실행한다 (사용자 결정 2026-07-19).\n */\n installed?: ReadonlyArray<string>;\n },\n ) => Promise<ReadonlyArray<InstallTargetId> | null>;\n}\n\nconst TRACK_LABELS: Record<Track, string> = {\n tooling: \"tooling — Bash + Markdown meta-project\",\n \"csr-supabase\": \"csr-supabase — Vite + React + Supabase\",\n \"csr-fastify\": \"csr-fastify — Vite + React + Fastify\",\n \"csr-fastapi\": \"csr-fastapi — Vite + React + FastAPI\",\n \"ssr-htmx\": \"ssr-htmx — htmx + FastAPI\",\n \"ssr-nextjs\": \"ssr-nextjs — Next.js (App Router)\",\n data: \"data — Python data / DuckDB / PySide6\",\n executive: \"executive — proposals / DD / pitch (no agent-skills)\",\n full: \"full — all dev capabilities\",\n \"project-management\": \"project-management — PM / Scrum / Jira / Confluence\",\n \"growth-marketing\": \"growth-marketing — Growth / Marketing / Content\",\n};\n\ninterface OptionDef {\n key: keyof OptionFlags;\n label: string;\n hint: string;\n category: Category;\n source: string;\n}\n\n/**\n * v26.54.0 — 표시 대상 OPTION_DEFS.\n * v26.81.0 (ADR-022) — **빈 배열로 소멸**. 마지막 항목(withTauri)이 내부\n * 자산(tauri-desktop — EXTERNAL_ASSETS `kind:\"internal\"`)으로 흡수돼 wizard 의\n * `option:` 특례가 사라짐. 자산 선택은 전부 `asset:<id>` 경로. 잔존 동작 옵션(D16 글로벌\n * 4종/karpathy hook/prune)은 wizard 미노출 (CLI `--with-*` 동작 플래그 전용 — 기존과 동일).\n */\nexport const VISIBLE_OPTION_DEFS: ReadonlyArray<OptionDef> = [];\n\nconst CLI_BASE_LABELS: Record<CliBase, string> = {\n claude: \"Claude Code\",\n codex: \"Codex (OpenAI)\",\n opencode: \"OpenCode (anomalyco)\",\n antigravity: \"Antigravity (Google)\",\n};\n\n/**\n * v26.78.1 — Step 3 wizard page layout (SSOT). 카테고리를 페이지로 묶어 clack\n * groupMultiselect 의 maxItems 한계(페이지당 옵션 ≤ ~30)를 우회.\n *\n * ⚠️ drift 가드 (no-false-ship): 모든 Category 는 정확히 한 페이지에 등장해야 한다.\n * 누락 시 해당 카테고리 자산이 wizard 에서 선택 불가가 되어 \"출하 거짓 광고\"가 된다\n * (v26.78.0 understanding 누락 회귀 — pages 가 selectInstallTargets 안에 하드코딩되어\n * CATEGORIES 추가와 drift). 아래 assertPagesCoverAllCategories 가 모듈 로드 시점에\n * 강제 — 신규 카테고리 미배치 시 즉시 throw. (tests/wizard-page-parity.test.ts 가 이중 가드)\n *\n * v26.99.0 — Dev 단일 페이지가 37행(옵션 32 + 헤더 5)으로 위 \"≤ ~30\" 제약을 스스로 위반하고\n * 있었다(실측). 터미널을 넘겨 스크롤이 생기는 것이 사용자가 보고한 \"선택 row 가 너무 많다\"의\n * 실제 메커니즘. → Dev 를 도메인(Core)과 도구(Tools)로 분할. 번들링(아래 DEV_METHOD_BUNDLE)만으론\n * 33행이라 부족했다 — Dev 32항목 중 dev-method 는 4개뿐이고, 번들 row 는 workflow 에 렌더되어\n * Dev 페이지에 남지 않으므로 37-4=33. ADR-028.\n *\n * 페이지 묶음 (전 페이지 ≤ 30 행):\n * Page 1: Dev Core — frontend + backend + data (20행)\n * Page 2: Dev Tools — dev-tools + understanding (13행)\n * Page 3: Business — business (documents) ( 9행)\n * Page 4: Visual&Media — visual-media (slides·diagrams·motion·video) (10행)\n * Page 5: Workflow/ECC — workflow(+ 방법론 번들 1행) + ecc-suite (10행)\n */\nexport interface InstallTargetPage {\n label: string;\n cats: ReadonlyArray<Category>;\n}\n\nexport const INSTALL_TARGET_PAGES: ReadonlyArray<InstallTargetPage> = [\n { label: \"Dev Core (Frontend · Backend · Data)\", cats: [\"frontend\", \"backend\", \"data\"] },\n { label: \"Dev Tools (Security · Quality · Understanding)\", cats: [\"dev-tools\", \"understanding\"] },\n { label: \"Business (PM · Executive · Documents)\", cats: [\"business\"] },\n // v26.85.0 — 코드-퍼스트 비주얼/미디어 제작 (용도별 섹션, 전부 opt-in).\n { label: \"Visual & Media (Slides · Diagrams · Motion · Video)\", cats: [\"visual-media\"] },\n { label: \"Workflow & ECC Suite\", cats: [\"workflow\", \"ecc-suite\"] },\n];\n\n/**\n * v26.99.0 (ADR-028) — dev-method 방법론 스킬 8종을 wizard 에서 **단일 row** 로 접는다.\n *\n * WHY: 8종은 전부 `has-dev-track` = 기본 설치다. 즉 **사실상 선택이 아닌데** 체크박스 8행을\n * 점유해, 진짜 선택인 서드파티 큐레이션을 밀어냈다(사용자 지적 2026-07-16). 8종은 개념적으로\n * 하나 — \"이 하네스의 작업 방법론\" — 이므로 한 줄이 정직한 표현이다.\n *\n * 순수 **표현 계층** 변환이다. 입력 시 접고(collapse) 제출 시 8개 asset id 로 펼쳐(expand)\n * 돌려주므로 downstream(computeUserOverride·installer·설치 보고)은 8개를 그대로 본다 —\n * **번들이 \"무엇이 설치되는지\"를 숨기지 않는다**(사용자 요구 가드). 구성원은\n * `DEV_METHOD_SKILL_IDS` 에서 derive → 자산 추가 시 자동 반영(하드코딩 금지, no-false-ship).\n *\n * 해제 시맨틱(사용자 확정 2026-07-16): 체크박스 1개 = 의미 1개 → **해제하면 8종 전부 제외**.\n * 개별 제어는 `--with <id>` / `--without <id>`.\n *\n * all-or-none 불변식: 8종이 **같은 condition(`has-dev-track`)** 을 공유하므로\n * `recommendedExternalAssets` 는 8개를 전부 넣거나 전부 뺀다 → 부분 선택 상태가 생기지 않는다.\n * 이 불변식이 깨지면 접기가 자산을 조용히 추가/삭제할 수 있으므로\n * `tests/wizard-bundle.test.ts` 가 강제한다 (Rule 12 fail loud).\n */\nexport const DEV_METHOD_BUNDLE_VALUE = \"bundle:dev-method\";\n\n/**\n * 번들 row 가 렌더되는 카테고리 — 방법론 = 개발 사이클 도구라 workflow.\n * export = SSOT (테스트가 `\"workflow\"` 를 재차 하드코딩하면 번들 위치 변경 시 게이트 수식이\n * 렌더와 조용히 갈린다 — no-false-ship \"2곳 이상 하드코딩 금지\").\n */\nexport const DEV_METHOD_BUNDLE_CATEGORY: Category = \"workflow\";\n\nconst bundleMemberValues = (): ReadonlyArray<string> =>\n DEV_METHOD_SKILL_IDS.map((id) => `asset:${id}`);\n\n/** 입력 접기 — dev-method 멤버가 (불변식상 전부) 있으면 번들 row 체크로 치환. */\nexport function collapseDevMethodBundle(ids: ReadonlyArray<string>): ReadonlyArray<string> {\n const members = new Set(bundleMemberValues());\n const rest = ids.filter((v) => !members.has(v));\n const anyMember = ids.some((v) => members.has(v));\n return anyMember ? [...rest, DEV_METHOD_BUNDLE_VALUE] : rest;\n}\n\n/** 제출 펼치기 — 번들 row 체크 → 8개 asset id. downstream 은 개별 자산만 본다. */\nexport function expandDevMethodBundle(ids: ReadonlyArray<string>): ReadonlyArray<string> {\n const rest = ids.filter((v) => v !== DEV_METHOD_BUNDLE_VALUE);\n return ids.includes(DEV_METHOD_BUNDLE_VALUE) ? [...rest, ...bundleMemberValues()] : rest;\n}\n\nexport interface PageItem {\n value: string;\n label: string;\n hint?: string;\n}\n\n/**\n * v26.99.0 (ADR-028) — Step 3 한 페이지의 group/item 구성. clack 의존 0 인 순수 함수.\n *\n * `selectInstallTargets` 안의 클로저였으나 export 로 승격했다 (SOD 리뷰 Important #2):\n * **이 함수가 dev-method 스킬 전원을 wizard 에서 도달 가능하게 만드는 유일한 코드**인데, 테스트가\n * 하나도 닿지 않았다. `wizard-page-parity` 는 \"자산의 **카테고리**가 페이지에 있다\"만 보는데,\n * 8종은 자기 카테고리에서 필터링되고 번들 row 로만 대표되므로 그 단언은 이제 8종에 대해\n * 비논리(non sequitur)다 — 번들 row 블록을 지워도 parity 는 통과하고 CI 는 green 인 채\n * 8종이 **어디서도 선택 불가**가 된다. v26.78.0 거짓출하의 정확한 재현이다.\n * (`prompts.ts` 는 coverage 제외 대상이라 커버리지 수치도 이 코드에 대해 아무 보장을 못 준다.)\n */\nexport function buildPageGroups(\n cats: ReadonlyArray<Category>,\n initialSet: ReadonlySet<string>,\n /**\n * v26.125.0 — 이미 설치된 target id. 라벨에 `● installed` 마커만 붙인다.\n * **체크 상태와 별개다** — 체크는 \"이번에 설치할 것\", 마커는 \"이미 있는 것\"이고,\n * 체크를 풀어도 제거되지 않는다(제거는 `uninstall` 을 따로 실행).\n */\n installedSet: ReadonlySet<string> = new Set(),\n): { groups: Record<string, PageItem[]>; flatItems: PageItem[] } {\n const installedMark = (value: string): string => (installedSet.has(value) ? \" ● installed\" : \"\");\n const groups: Record<string, PageItem[]> = {};\n const flatItems: PageItem[] = [];\n for (const cat of cats) {\n const items: PageItem[] = [];\n for (const o of VISIBLE_OPTION_DEFS.filter((d) => d.category === cat)) {\n items.push({\n value: `option:${o.key}`,\n // v26.62.3 — group header 와 옵션 사이 시각 hierarchy 강화. label prefix 4 space.\n label: ` ${o.label} [${o.source}]${installedMark(`option:${o.key}`)}`,\n hint: o.hint,\n });\n }\n // v26.99.0 (ADR-028) — 방법론 번들 row. 개별 8행 대신 1행. hint 에 구성원 id 를 전부\n // 노출 — 접는 것이 \"무엇이 설치되는지\" 를 숨기면 안 된다.\n if (cat === DEV_METHOD_BUNDLE_CATEGORY) {\n items.push({\n value: DEV_METHOD_BUNDLE_VALUE,\n label: ` uzys 하네스 방법론 ${DEV_METHOD_SKILL_IDS.length}종 [uzys] ★ official${installedMark(DEV_METHOD_BUNDLE_VALUE)}`,\n hint: DEV_METHOD_SKILL_IDS.join(\", \"),\n });\n }\n // v26.71.0 (PRD v26-71) — tier 우선 정렬 (official → vetted → experimental) + 배지.\n const tierOrder = { official: 0, vetted: 1, experimental: 2 } as const;\n const devMethod = new Set<string>(DEV_METHOD_SKILL_IDS);\n const catAssets = [...EXTERNAL_ASSETS.filter((x) => x.category === cat)]\n // 번들 구성원은 개별 row 로 렌더하지 않는다 (번들 1행이 대표).\n .filter((x) => !devMethod.has(x.id))\n .sort((a, b) => tierOrder[assetTrustTier(a.id)] - tierOrder[assetTrustTier(b.id)]);\n for (const a of catAssets) {\n const tier = assetTrustTier(a.id);\n const badge =\n tier === \"official\"\n ? \" ★ official\"\n : tier === \"experimental\"\n ? \" ⚠ experimental (opt-in)\"\n : \"\";\n items.push({\n value: `asset:${a.id}`,\n label: ` ${a.id} [${a.source}]${badge}${installedMark(`asset:${a.id}`)}`,\n hint: a.description,\n });\n }\n if (items.length === 0) continue;\n const selectedInCat = items.filter((it) => initialSet.has(it.value)).length;\n const header = `${CATEGORY_TITLES[cat]} [${selectedInCat}/${items.length} ✓ default]`;\n groups[header] = items;\n flatItems.push(...items);\n }\n return { groups, flatItems };\n}\n\n/**\n * 모든 Category 가 정확히 한 페이지에 등장하는지 모듈 로드 시 검증.\n * 누락(미배치) 또는 중복(2개 페이지)이면 throw — 값싼 fail-loud pre-flight.\n */\nfunction assertPagesCoverAllCategories(pages: ReadonlyArray<InstallTargetPage>): void {\n const counts = new Map<Category, number>();\n for (const page of pages) {\n for (const cat of page.cats) counts.set(cat, (counts.get(cat) ?? 0) + 1);\n }\n const missing = CATEGORIES.filter((c) => !counts.has(c));\n const duplicated = CATEGORIES.filter((c) => (counts.get(c) ?? 0) > 1);\n if (missing.length > 0 || duplicated.length > 0) {\n throw new Error(\n `INSTALL_TARGET_PAGES drift vs CATEGORIES — missing=[${missing.join(\", \")}] ` +\n `duplicated=[${duplicated.join(\", \")}]. 모든 카테고리는 정확히 한 페이지에 배치해야 한다 ` +\n `(no-false-ship: wizard 미노출 = 거짓 광고).`,\n );\n }\n}\n\nassertPagesCoverAllCategories(INSTALL_TARGET_PAGES);\n\n/**\n * v26.58.1 — Wizard viewport size. clack 의 limitOptions 가 maxItems 안에서만\n * cursor follow + ↕ ... indicator. 미지정 시 Infinity → terminal height 초과 시\n * 위 항목이 scrollback 으로 밀려 selected indicator 안 보임 (사용자 보고된 문제).\n *\n * rowPadding 10 = message line + status footer + safety margin.\n * floor 8 = 너무 작아도 최소한의 viewport 보장.\n */\nfunction viewportItems(itemCount: number): number {\n const rows = process.stdout.rows ?? 24;\n return Math.max(8, Math.min(itemCount, rows - 10));\n}\n\nexport const defaultPrompts: Prompts = {\n intro: (msg) => intro(msg),\n outro: (msg) => outro(msg),\n cancel: (msg) => cancel(msg),\n\n selectTracks: async (initial, step) => {\n // v26.65.0 — step indicator SSOT (wizard-steps.ts). 6-step 통합 (1 tracks · 2 cli · 3 targets · 4 scope · 5 confirm · 6 installing).\n const result = await multiselect({\n message: stepLabel(step, \"Select Track(s)\"),\n options: TRACKS.map((t) => ({ value: t, label: TRACK_LABELS[t] })),\n ...(initial ? { initialValues: initial } : {}),\n maxItems: viewportItems(11),\n required: true,\n });\n return isCancel(result) ? null : (result as Track[]);\n },\n\n selectCli: async (initial, step) => {\n const initialValues: CliBase[] = initial && initial.length > 0 ? [...initial] : [\"claude\"];\n const result = await multiselect({\n message: stepLabel(step, \"Target CLI(s)\"),\n options: [\n { value: \"claude\" as const, label: CLI_BASE_LABELS.claude },\n { value: \"codex\" as const, label: CLI_BASE_LABELS.codex },\n { value: \"opencode\" as const, label: CLI_BASE_LABELS.opencode },\n { value: \"antigravity\" as const, label: CLI_BASE_LABELS.antigravity },\n ],\n initialValues,\n required: true,\n });\n if (isCancel(result)) return null;\n return [...(result as CliBase[])].sort(\n (a, b) => CLI_BASE_SORT_ORDER[a] - CLI_BASE_SORT_ORDER[b],\n );\n },\n\n selectAction: async (state) => {\n const result = await select({\n message: summarizeState(state),\n options: buildRouterChoices(state).map((c) => {\n const label = c.enabled ? c.label : `${c.label} [disabled]`;\n // disabled:true → clack 이 cursor skip + strikethrough (선택 자체 차단).\n return {\n value: c.value,\n label,\n ...(c.hint ? { hint: c.hint } : {}),\n ...(c.enabled ? {} : { disabled: true }),\n };\n }),\n });\n return isCancel(result) ? null : (result as RouterAction);\n },\n\n /**\n * v26.64.0 (ADR-020) — Installation scope select. Default Project (D16 — no global write).\n * Global 은 사용자 명시 opt-in 시에만.\n */\n selectScope: async (initial = \"project\", step) => {\n const result = await select({\n message: stepLabel(step, \"Installation scope\"),\n initialValue: initial,\n options: [\n {\n value: \"project\",\n label: \"Project\",\n hint: \"Install in current directory (committed with your project)\",\n },\n {\n value: \"global\",\n label: \"Global\",\n hint: \"Write to ~/.claude/, ~/.codex/, npm -g (shared across all projects)\",\n },\n ],\n });\n return isCancel(result) ? null : (result as InstallScope);\n },\n\n confirmInstall: async (summary) => {\n const result = await confirm({\n message: `${summary}\\n\\nProceed?`,\n initialValue: true,\n });\n return isCancel(result) ? null : result;\n },\n\n selectInstallTargets: async (initialChecked, step, recap) => {\n // v26.62.2 — groupMultiselect 복귀 + page paginate.\n // v26.62.1 에서 multiselect + disabled separator 시도 → clack 가 disabled option 에\n // 체크박스 강제 + dim/strikethrough 효과 → 카테고리 헤더가 \"옵션 같지만 선택 불가\"\n // 처럼 보여 사용자 보고. groupMultiselect 의 group header 는 라이브러리에서 본래\n // 설명 라인 형태로 자연 표시 → 시각 명료.\n //\n // maxItems 한계 (GroupMultiSelectPrompt 미지원) 는 page 묶음으로 cover:\n // 한 page 안 옵션 ≤ ~30 → 사용자 iTerm2 (30+ rows) 환경에서 fit. 매우 작은 terminal\n // (< 25 rows) 한계는 follow-up.\n //\n // 페이지 정의 = 모듈 스코프 INSTALL_TARGET_PAGES (SSOT, 카테고리 전수 가드됨).\n const pages = INSTALL_TARGET_PAGES;\n // v26.99.0 (ADR-028) — 표현 계층에서만 번들로 접는다. 제출 시 다시 펼쳐 돌려주므로\n // downstream 계약(개별 asset id)은 불변.\n const displayInitial = collapseDevMethodBundle(initialChecked);\n const initialSet = new Set<string>(displayInitial);\n const collected = new Set<string>(displayInitial);\n\n const recapLine = recap\n ? `Tracks: ${recap.tracks.join(\", \")} · CLIs: ${recap.cli.join(\", \")}`\n : \"\";\n // v26.125.0 — 마커 전용. 체크 상태와 별개이며, 체크를 풀어도 제거되지 않는다.\n const installedSet = new Set<string>(\n collapseDevMethodBundle((recap?.installed ?? []) as ReadonlyArray<InstallTargetId>),\n );\n\n // alt screen for the whole Step 3 loop. page 전환 시 buffer 안에서 redraw.\n process.stdout.write(\"\\x1b[?1049h\");\n let resultIds: ReadonlyArray<InstallTargetId> | null = null;\n let aborted = false;\n try {\n let pageIdx = 0;\n while (pageIdx < pages.length) {\n const page = pages[pageIdx];\n if (!page) break;\n const { groups, flatItems } = buildPageGroups(page.cats, initialSet, installedSet);\n const selectedNow = flatItems.filter((it) => collected.has(it.value)).map((it) => it.value);\n const pageDefault = flatItems.filter((it) => initialSet.has(it.value)).length;\n const totalSelected = collected.size;\n const message = [\n `Step ${step.current}/${step.total} · Page ${pageIdx + 1}/${pages.length} · ${page.label}`,\n recapLine ? ` ${recapLine}` : \"\",\n ` Selected so far: ${totalSelected} items · This page default ✓ ${pageDefault}/${flatItems.length}`,\n // 마커의 뜻을 화면에서 바로 알려준다 — 체크 해제를 제거로 오해하는 것이 이 화면의\n // 원래 문제였으므로, 마커가 보일 때는 제거 경로를 같은 자리에서 말한다.\n installedSet.size > 0\n ? \" ● installed = 이미 설치됨 · 체크 해제해도 제거되지 않는다 (제거: agent-harness uninstall)\"\n : \"\",\n \" Space toggle · Enter → next · ESC → prev\",\n ]\n .filter(Boolean)\n .join(\"\\n\");\n\n const groupOpts = {\n message,\n options: groups,\n initialValues: selectedNow,\n required: false,\n selectableGroups: false,\n } as Parameters<typeof groupMultiselect>[0];\n const result = await groupMultiselect(groupOpts);\n if (isCancel(result)) {\n if (pageIdx === 0) {\n aborted = true; // first page ESC → Step 2 back\n break;\n }\n pageIdx--; // prev page\n continue;\n }\n // update collected: remove page items + add the new selection\n for (const it of flatItems) collected.delete(it.value);\n for (const v of result as ReadonlyArray<string>) collected.add(v);\n pageIdx++;\n }\n if (!aborted) {\n // 번들 → 개별 asset id 로 펼쳐 반환. 설치·보고는 멤버 전원을 개별로 본다.\n resultIds = expandDevMethodBundle([...collected]) as ReadonlyArray<InstallTargetId>;\n }\n } finally {\n process.stdout.write(\"\\x1b[?1049l\");\n }\n // v26.63.1 — alt screen exit 후 main buffer 에 Step 3 완료 라인 출력. alt buffer\n // 안 동작은 main 에 흔적 0 → Step 1·2·4 사이 Step 3 missing → 사용자 보고.\n // clack `◇` marker + `│` line 으로 다른 step 과 시각 일관성 유지.\n if (resultIds !== null) {\n process.stdout.write(\n `◇ Step ${step.current}/${step.total} — Install targets · ${resultIds.length} selected\\n│\\n`,\n );\n }\n return resultIds;\n },\n};\n","import type { DetectedInstall } from \"./state.js\";\n\nexport type RouterAction = \"add\" | \"update\" | \"remove\" | \"reinstall\" | \"exit\";\n\nexport interface RouterChoice {\n value: RouterAction;\n label: string;\n hint?: string;\n enabled: boolean;\n}\n\n/**\n * 5-action menu for an existing install. Mirrors prompt_action_router (setup-harness.sh:255).\n *\n * \"remove\" is exposed but disabled — no reliable file-ownership mapping yet (would risk data loss).\n */\nexport function buildRouterChoices(state: DetectedInstall): RouterChoice[] {\n const detected = state.tracks.length > 0 ? state.tracks.join(\", \") : \"(none detected)\";\n return [\n {\n value: \"add\",\n label: \"Add a new Track\",\n hint: `Current: ${detected}`,\n enabled: true,\n },\n {\n value: \"update\",\n label: \"Update policy files (auto-backup)\",\n // v26.126.0 (R-3a) — skills 가 목록에 들어왔다. 이 문구가 곧 update 의 광고이고\n // (update 는 위저드로만 도달한다) 실동작과 어긋나면 그 자체로 거짓출하다.\n hint: \"Refresh rules / agents / commands / hooks / skills — your edits are backed up\",\n enabled: true,\n },\n {\n value: \"remove\",\n label: \"Remove a Track (unsupported)\",\n hint: \"Manual edit of .claude/ required — not automated\",\n enabled: false,\n },\n {\n value: \"reinstall\",\n label: \"Reinstall (backs up current .claude/ first)\",\n hint: \"Use when state is corrupted\",\n enabled: true,\n },\n {\n value: \"exit\",\n label: \"Exit\",\n enabled: true,\n },\n ];\n}\n\nexport function summarizeState(state: DetectedInstall): string {\n if (state.state === \"new\") {\n return \"No prior install detected — new install flow.\";\n }\n const trackList = state.tracks.length > 0 ? state.tracks.join(\", \") : \"(no tracks resolved)\";\n const sourceLabel =\n state.source === \"metafile\"\n ? \"via .claude/.installed-tracks\"\n : state.source === \"legacy\"\n ? \"via legacy rules/*.md heuristic\"\n : \"via no source\";\n return `Existing install detected ${sourceLabel}. Tracks: ${trackList}.`;\n}\n","/**\n * Wizard step single source of truth — v26.65.0.\n *\n * v26.64.0 에서 wizard 가 5→6 step 으로 변경됐는데 prompts.ts 의 message 가 hardcoded\n * (\"Step 1/5\") 였음 → step indicator drift 가 무성. 본 모듈이 SSOT.\n *\n * 추가 step 도입 시 본 파일만 수정 → message 자동 정합.\n */\n\nexport interface WizardStep {\n current: number;\n total: number;\n}\n\nexport const WIZARD_TOTAL = 6;\n\nexport const WIZARD: {\n TRACKS: WizardStep;\n CLI: WizardStep;\n TARGETS: WizardStep;\n SCOPE: WizardStep;\n CONFIRM: WizardStep;\n INSTALL: WizardStep;\n} = {\n TRACKS: { current: 1, total: WIZARD_TOTAL },\n CLI: { current: 2, total: WIZARD_TOTAL },\n TARGETS: { current: 3, total: WIZARD_TOTAL },\n SCOPE: { current: 4, total: WIZARD_TOTAL },\n CONFIRM: { current: 5, total: WIZARD_TOTAL },\n INSTALL: { current: 6, total: WIZARD_TOTAL },\n};\n\n/**\n * Wizard step header — `Step N/M — <suffix>` 형식.\n *\n * step 미지정 시 suffix 만 반환 (backward compat — tests / non-wizard 호출).\n */\nexport function stepLabel(step: WizardStep | undefined, suffix: string): string {\n if (!step) return suffix;\n return `Step ${step.current}/${step.total} — ${suffix}`;\n}\n"],"mappings":"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","names":["ESC","CSI","k","j","v","b","cli","resolve","b","chmodSync","existsSync","mkdirSync","readdirSync","readFileSync","writeFileSync","basename","dirname","join","existsSync","readFileSync","join","d","join","existsSync","readFileSync","existsSync","join","v","join","existsSync","join","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","e","join","existsSync","readFileSync","writeFileSync","basename","join","k","v","join","basename","writeFileSync","existsSync","readFileSync","existsSync","readFileSync","writeFileSync","join","existsSync","readdirSync","readFileSync","homedir","join","b","cli","v","join","existsSync","c","at","homedir","readdirSync","readFileSync","existsSync","mkdirSync","readFileSync","writeFileSync","dirname","join","join","readFileSync","mkdirSync","dirname","writeFileSync","existsSync","existsSync","readFileSync","writeFileSync","readFileSync","existsSync","writeFileSync","existsSync","readFileSync","writeFileSync","basename","join","renameSlashes","renderAgentsMd","renameSlashes","j","readRequired","join","basename","readOptionalJson","renderAgentsMd","writeFileSync","existsSync","readFileSync","h","copyFileSync","existsSync","mkdirSync","readdirSync","readFileSync","writeFileSync","dirname","join","join","existsSync","copyFileSync","readdirSync","readFileSync","mkdirSync","dirname","writeFileSync","join","existsSync","readFileSync","e","chmodSync","writeFileSync","mkdirSync","dirname","basename","readdirSync","e","b","cli","v","k","p","w","resolve","e","cli","existsSync","readFileSync","join","resolve","resolve","d","join","existsSync","readFileSync","cli","spawnSync","existsSync","readFileSync","join","resolve","NO_TRUNCATION","dist_default","dist_default","findCursor","cursor","delta","options","opt","newCursor","maxCursor","clampedCursor","actions","DEFAULT_MONTH_NAMES","settings","days","month","min","max","isActionKey","key","action","settings","value","diffLines","a","b","aLines","bLines","numLines","diff","i","isWindows","CANCEL_SYMBOL","isCancel","setRawMode","input","getColumns","output","getRows","wrapTextWithPrefix","text","prefix","startPrefix","lineFormatter","columns","stdout","wrapAnsi","line","index","lineString","g$1","options","trackValue","input","stdin","render","signal","opts","event","params","cb","data","cbs","cleanup","subscriber","resolve","CANCEL_SYMBOL","readline","setRawMode","cursor","char","_key","_char","value","write","key","settings","problem","isActionKey","lines","frame","diff","diffLines","rows","diffOffsetAfter","diffOffsetBefore","diffLine","erase","adjustedDiffLine","newLines","ConfirmPrompt","Prompt","opts","confirm","cursor","GroupMultiSelectPrompt","Prompt","#selectableGroups","group","o","items","value","i","item","groupedItems","v","selected","opts","options","key","option","opt","currentIsGroup","Prompt","option","enabledOptions","allSelected","v","value","notSelected","selected","opts","cursor","findCursor","char","key","SelectPrompt","Prompt","opts","initialCursor","value","cursor","findCursor","key","isUnicodeSupported","process","unicode","unicodeOr","c","fallback","unicode","S_STEP_ACTIVE","S_STEP_CANCEL","S_STEP_ERROR","S_STEP_SUBMIT","S_BAR_START","S_BAR","S_BAR_END","S_BAR_START_RIGHT","S_BAR_END_RIGHT","S_RADIO_ACTIVE","S_RADIO_INACTIVE","S_CHECKBOX_ACTIVE","S_CHECKBOX_SELECTED","S_CHECKBOX_INACTIVE","S_PASSWORD_MASK","S_BAR_H","S_CORNER_TOP_RIGHT","S_CONNECT_LEFT","S_CORNER_BOTTOM_RIGHT","S_CORNER_BOTTOM_LEFT","S_CORNER_TOP_LEFT","S_INFO","S_SUCCESS","S_WARN","S_ERROR","symbol","state","styleText","symbolBar","trimLines","groups","initialLineCount","startIndex","endIndex","maxLines","lineCount","removals","i","group","limitOptions","cursor","options","style","output","maxItems","columnPadding","rowPadding","maxWidth","getColumns","rows","getRows","overflowFormat","outputMaxItems","computedMaxItems","slidingWindowLocation","shouldRenderTopEllipsis","shouldRenderBottomEllipsis","slidingWindowLocationEnd","lineGroups","slidingWindowLocationWithEllipsis","slidingWindowLocationEndWithEllipsis","wrappedLines","wrapAnsi","precedingRemovals","followingRemovals","newLineCount","cursorGroupIndex","trimLinesLocal","result","lineGroup","line","confirm","opts","active","inactive","ConfirmPrompt","hasGuide","settings","titlePrefix","symbol","titlePrefixBar","styleText","S_BAR","messageLines","wrapTextWithPrefix","title","value","submitPrefix","cancelPrefix","defaultPrefix","defaultPrefixEnd","S_BAR_END","S_RADIO_ACTIVE","S_RADIO_INACTIVE","groupMultiselect","opts","selectableGroups","groupSpacing","opt","option","state","options","label","isItem","next","isLast","prefix","S_BAR_END","S_BAR","spacingPrefix","spacingPrefixText","styleText","S_CHECKBOX_ACTIVE","S_CHECKBOX_SELECTED","selectedCheckbox","unselectedCheckbox","S_CHECKBOX_INACTIVE","required","GroupMultiSelectPrompt","selected","hasGuide","settings","title","symbol","value","selectedOptions","optionValue","optionsText","footer","ln","i","active","groupActive","optionText","optionsPrefix","cancel","message","opts","output","prefix","settings","styleText","S_BAR_END","intro","title","S_BAR_START","outro","S_BAR","computeLabel","label","format","line","multiselect","opts","opt","option","state","styleText","S_CHECKBOX_INACTIVE","str","S_CHECKBOX_ACTIVE","S_CHECKBOX_SELECTED","text","required","MultiSelectPrompt","selected","hasGuide","settings","wrappedMessage","wrapTextWithPrefix","symbolBar","symbol","title","S_BAR","value","styleOption","active","submitText","optionValue","wrappedSubmitText","wrappedLabel","prefix","footer","ln","i","S_BAR_END","titleLineCount","footerLineCount","limitOptions","S_PROGRESS_CHAR","unicodeOr","computeLabel","label","format","line","select","opts","opt","option","state","styleText","S_RADIO_INACTIVE","text","S_RADIO_ACTIVE","str","SelectPrompt","hasGuide","settings","titlePrefix","symbol","titlePrefixBar","symbolBar","messageLines","wrapTextWithPrefix","title","S_BAR","submitPrefix","wrappedLines","cancelPrefix","prefix","prefixEnd","S_BAR_END","titleLineCount","footerLineCount","limitOptions","item","active","prefix","styleText","S_BAR","ok","defaultSpawn","resolve","e","existsSync","join","readFileSync","h","spawnSync","cli","resolve","existsSync","readFileSync","join","join","existsSync","tracks","readFileSync","resolve","cli","v","d","b","it","c","cli","b","k","e","cli"]}
|