create-napukettoqq 0.2.39 → 0.2.40

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/dist/index.mjs CHANGED
@@ -3,7 +3,7 @@ import { spawn } from "node:child_process";
3
3
  import { readFileSync } from "node:fs";
4
4
  import path, { join, relative } from "node:path";
5
5
  import process from "node:process";
6
- import { cancel, confirm, intro, isCancel, log, outro, spinner, text } from "@clack/prompts";
6
+ import { cancel, confirm, intro, log, outro, spinner, text } from "@clack/prompts";
7
7
  import pc from "picocolors";
8
8
  import { mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
9
9
  //#region src/scaffold.ts
@@ -242,7 +242,7 @@ async function askProjectName(yes) {
242
242
  }
243
243
  }
244
244
  });
245
- if (isCancel(name)) {
245
+ if (typeof name !== "string") {
246
246
  cancel("操作已取消");
247
247
  process.exit(0);
248
248
  }
@@ -284,7 +284,7 @@ async function confirmRemove(dirName) {
284
284
  message: `目录 "${dirName}" 已存在且非空,移除现有文件并继续?`,
285
285
  initialValue: false
286
286
  });
287
- if (isCancel(ok)) {
287
+ if (typeof ok !== "boolean") {
288
288
  cancel("操作已取消");
289
289
  process.exit(0);
290
290
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/scaffold.ts","../src/index.ts"],"sourcesContent":["/**\n * create-napukettoqq 脚手架核心:模板渲染 + 目标目录创建 + 文件写入。\n *\n * 模板为独立文件(templates/ 目录,运行时读取),不硬编码在源码里;\n * 需要插值的占位符用 {{key}} 标记(见 renderTemplate)。\n * 依赖极轻(node:fs/promises / node:os / node:path / node:process)。\n * 生成的用户项目依赖发布版的 @napuketto/cli,用户 install 后经 cli → loader\n * 自建宿主启动。\n */\n\nimport { readFileSync } from \"node:fs\";\nimport { mkdir, readdir, readFile, rm, writeFile } from \"node:fs/promises\";\n\nimport path from \"node:path\";\nimport process from \"node:process\";\n\n/** 模板目录(相对本文件:src 与 dist 都在包根下,../templates 均指向包根/templates)。 */\nconst TEMPLATES = new URL(\"../templates/\", import.meta.url);\n\n/** npm registry 查询超时(毫秒;兜底链路,超时不阻塞脚手架)。 */\nconst REGISTRY_TIMEOUT_MS = 3000;\n\n/** npm registry 上 @napuketto/cli 的最新版本(查询失败返回 null)。 */\nasync function fetchLatestCliVersion(): Promise<string | null> {\n try {\n const res = await fetch(\"https://registry.npmjs.org/@napuketto/cli/latest\", {\n signal: AbortSignal.timeout(REGISTRY_TIMEOUT_MS),\n });\n if (!res.ok) {\n return null;\n }\n const json = (await res.json()) as { version?: unknown };\n return typeof json.version === \"string\" && json.version !== \"\" ? json.version : null;\n } catch {\n return null;\n }\n}\n\n/**\n * 生成的用户项目所依赖的 @napuketto/cli 版本范围(自动最新版,不交互选版本)。\n * 优先级:\n * 1. 脚手架自身 package.json 的 dependencies[\"@napuketto/cli\"](发版时 changesets\n * 升版本 + 发布改写为实际版本,模板版本自动跟随)\n * 2. npm registry 查询最新版(自身依赖缺失 / 仍是 workspace:*(发布泄漏兜底)——\n * 2026-08-16 修复:published 包曾泄漏 workspace:*,yarn create 被迫交互选版本)\n * 3. ^0.0.1(离线 / registry 查询失败兜底)\n * workspace:* 只在本地 monorepo 直跑脚手架时出现(发布后被替换为实际版本)。\n */\nasync function cliVersionRange(): Promise<string> {\n try {\n const ownPkg = JSON.parse(\n readFileSync(new URL(\"../package.json\", import.meta.url), \"utf8\"),\n ) as { dependencies?: Record<string, string> };\n const range = ownPkg.dependencies?.[\"@napuketto/cli\"];\n if (range !== undefined && range !== \"workspace:*\") {\n return range;\n }\n } catch {\n // package.json 缺失(异常环境)→ 走 registry 兜底\n }\n const latest = await fetchLatestCliVersion();\n if (latest !== null) {\n return `^${latest}`;\n }\n return \"^0.0.1\";\n}\n\n/** 默认部署文件夹名(用户交互回车缺省值)。 */\nexport const DEFAULT_PROJECT_NAME = \"NapukettoQQ\";\n\n/** 用户可用的包管理器(npm_config_user_agent 检测)。 */\nexport type PackageManager = \"pnpm\" | \"yarn\" | \"npm\";\n\n/**\n * 由 npm_config_user_agent 检测调用方包管理器(yarn create / npm create /\n * pnpm create 都会注入该变量)。兜底 pnpm(项目生态,或直接 node 运行)。\n */\nexport function detectPackageManager(): PackageManager {\n // noPropertyAccessFromIndexSignature:process.env 是索引签名,必须括号访问\n const ua = process.env[\"npm_config_user_agent\"] ?? \"\";\n if (ua.startsWith(\"yarn/\")) {\n return \"yarn\";\n }\n if (ua.startsWith(\"npm/\")) {\n return \"npm\";\n }\n return \"pnpm\";\n}\n\n/** Windows 下包管理器 bin 需带 .cmd 后缀(CreateProcess 不认无扩展名 shim)。 */\nexport function pmBin(pm: PackageManager): string {\n return process.platform === \"win32\" ? `${pm}.cmd` : pm;\n}\n\n/** Windows 路径非法字符(项目文件夹名校验用)。 */\nconst ILLEGAL_NAME = /[\\\\/:*?\"<>|]/;\n\n/** 脚手架生成结果。 */\nexport interface ScaffoldResult {\n /** 目标目录绝对路径。 */\n dir: string;\n /** 派生出的 npm 包名(小写、空格 → -)。 */\n packageName: string;\n}\n\n/** 校验文件夹名:非空、非 . / ..、不含 Windows 非法字符。 */\nexport function validateProjectName(raw: string): string {\n const name = raw.trim();\n if (name === \"\" || name === \".\" || name === \"..\") {\n throw new Error(\"文件夹名不能为空或为 . / ..\");\n }\n if (ILLEGAL_NAME.test(name)) {\n throw new Error(`文件夹名含非法字符:${name}(不允许 \\\\ / : * ? \" < > |)`);\n }\n return name;\n}\n\n/** 由文件夹名派生 npm 包名(小写、空格 → -)。 */\nfunction derivePackageName(dirName: string): string {\n return dirName.toLowerCase().replace(/\\s+/g, \"-\");\n}\n\n/** 解析目标目录绝对路径(校验名称后,基于 cwd)。 */\nexport function resolveTargetDir(dirName: string): string {\n return path.resolve(process.cwd(), validateProjectName(dirName));\n}\n\n/** 目标目录状态:不存在 / 空 / 非空。 */\nexport type DirStatus = \"missing\" | \"empty\" | \"nonempty\";\n\n/** 检测目标目录状态(供交互层决定是否询问清空)。 */\nexport async function checkDirStatus(dir: string): Promise<DirStatus> {\n let entries: string[] = [];\n try {\n entries = await readdir(dir);\n } catch {\n return \"missing\";\n }\n return entries.length === 0 ? \"empty\" : \"nonempty\";\n}\n\n/** 清空目录内容(保留目录本身)。 */\nasync function emptyDir(dir: string): Promise<void> {\n for (const entry of await readdir(dir)) {\n await rm(path.join(dir, entry), { recursive: true, force: true });\n }\n}\n\n/** 读取模板文件(templates/ 目录,UTF-8)。 */\nfunction readTemplate(file: string): Promise<string> {\n return readFile(new URL(file, TEMPLATES), \"utf8\");\n}\n\n/**\n * 占位符渲染:把 {{key}} 替换为 vars[key]。\n * 模板中出现未提供的占位符 → 抛错(防漏插值写出半成品)。\n */\nfunction renderTemplate(content: string, vars: Record<string, string>): string {\n return content.replace(/\\{\\{(\\w+)\\}\\}/g, (match, key: string) => {\n const value = vars[key];\n if (value === undefined) {\n throw new Error(`模板占位符未提供:{{${key}}}(模板 ${match} 无法渲染)`);\n }\n return value;\n });\n}\n\n/**\n * 生成 NapukettoQQ 项目骨架到当前目录下的 <dirName>/。\n * 目标目录已存在且非空:overwrite=false → 抛错;overwrite=true → 清空后生成。\n * 模板与写入目标一一对应(同文件名)。pm 为调用方包管理器:yarn 时额外生成\n * 空 yarn.lock 把用户项目隔离成独立项目——yarn install 会向上探测父目录的\n * package.json/yarn.lock,若用户父目录(如 ~)恰好有这些文件,yarn 会把生成\n * 目录误当作其 workspace 子包并报「nearest package directory doesn't seem to\n * be part of the project declared in <父目录>」。空 yarn.lock 让 yarn 把生成\n * 目录视为独立项目根(yarn 自身报错信息也建议此做法),pnpm/npm 无此问题。\n */\nexport async function scaffoldProject(\n dirName: string,\n overwrite = false,\n pm: PackageManager = \"pnpm\",\n): Promise<ScaffoldResult> {\n const name = validateProjectName(dirName);\n const packageName = derivePackageName(name);\n const dir = resolveTargetDir(name);\n\n const status = await checkDirStatus(dir);\n if (status === \"nonempty\" && !overwrite) {\n throw new Error(`目录已存在且非空:${dir}\\n请换一个文件夹名,或先清空该目录。`);\n }\n if (status === \"nonempty\") {\n await emptyDir(dir);\n }\n\n // 渲染变量(napuketto.toml 模板不再插值 dataDir——缺省 = 项目根/.napuketto,跨平台)\n const vars: Record<string, string> = {\n packageName,\n cliVersion: await cliVersionRange(),\n };\n // 用户项目是「运行壳」:不开发代码,只需 package.json(依赖 + start)+ napuketto.toml(配置)\n // 模板文件为 templates/<name>.tmpl(.tmpl 后缀避免 TOML/JSON 语言服务把占位符当非法语法)\n const files = [\"package.json\", \"napuketto.toml\"];\n\n await mkdir(dir, { recursive: true });\n for (const file of files) {\n const rendered = renderTemplate(await readTemplate(`${file}.tmpl`), vars);\n await writeFile(path.join(dir, file), rendered, \"utf8\");\n }\n\n // yarn:写空 yarn.lock 隔离成独立项目(见函数 JSDoc)。yarn install 会重写\n // 该文件为真实锁文件;空文件只用于阻断向上探测,无运行时副作用。\n if (pm === \"yarn\") {\n await writeFile(path.join(dir, \"yarn.lock\"), \"\", \"utf8\");\n }\n\n return { dir, packageName };\n}\n","#!/usr/bin/env node\n\n/**\n * create-napukettoqq 入口(2026-08-07 美化 v3,交互层用 @clack/prompts——\n * 现代脚手架交互标准,create-vue / create-turbo 同款)。\n *\n * 用法:\n * create-napukettoqq # intro + 交互问部署文件夹名(默认 NapukettoQQ)\n * create-napukettoqq my-bot # 位置参数指定文件夹名,跳过命名交互\n * create-napukettoqq my-bot -f # 目标目录非空时强制清空覆盖\n * create-napukettoqq -y # 全默认(命名用默认值)\n * create-napukettoqq -h # 打印帮助\n *\n * 流程:intro → 问文件夹名 → 目标目录准备(非空需确认清空)→ spinner 生成骨架\n * (package.json / napuketto.toml)→ 用调用方包管理器自动 install →\n * 打开 napuketto.toml 供填写 QQ 号(不自动启动)+ 打印启动指引 → outro 收尾。\n */\n\nimport { spawn } from \"node:child_process\";\nimport { readFileSync } from \"node:fs\";\nimport { join, relative } from \"node:path\";\nimport process from \"node:process\";\nimport { cancel, confirm, intro, isCancel, log, outro, spinner, text } from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport type { PackageManager, ScaffoldResult } from \"./scaffold.js\";\nimport {\n checkDirStatus,\n DEFAULT_PROJECT_NAME,\n detectPackageManager,\n pmBin,\n resolveTargetDir,\n scaffoldProject,\n validateProjectName,\n} from \"./scaffold.js\";\n\n// picocolors 是 CJS 包(无 ESM 命名导出),Node ESM 下需 default import 再解构\nconst { blue, bold, cyan, dim, red, yellow } = pc;\n\n/** CLI 参数解析结果。 */\ninterface CliOptions {\n /** 位置参数:部署文件夹名(可选)。 */\n name?: string;\n /** -f/--forced:目标目录非空时强制清空覆盖。 */\n forced: boolean;\n /** -y/--yes:跳过所有交互提示(使用默认值)。 */\n yes: boolean;\n /** -h/--help:显示帮助。 */\n help: boolean;\n}\n\n/** 帮助文本(-h/--help)。 */\nconst HELP = ` 用法: create-napukettoqq [name] [选项]\n\n 选项:\n -f, --forced 目标目录非空时强制清空并覆盖\n -y, --yes 跳过所有交互提示(使用默认值)\n -h, --help 显示本帮助\n`;\n\n/** 配置文件文件名(生成后引导用户填写 QQ 号)。 */\nconst CONFIG_FILE = \"napuketto.toml\";\n\n/**\n * 用系统默认应用打开文件(引导编辑配置用;尽力而为,失败不阻塞创建流程)。\n * Windows:经 cmd.exe 执行内建 start(CreateProcess 不认内建命令);\n * macOS/Linux:open / xdg-open。detached + unref:不挂到脚手架进程树。\n */\nfunction openInEditor(file: string): void {\n try {\n if (process.platform === \"win32\") {\n // start 首参是窗口标题(\"\" 占位),文件路径带引号防空格\n spawn(\"cmd.exe\", [\"/d\", \"/s\", \"/c\", `start \"\" \"${file}\"`], {\n stdio: \"ignore\",\n windowsHide: true,\n detached: true,\n }).unref();\n return;\n }\n const opener = process.platform === \"darwin\" ? \"open\" : \"xdg-open\";\n spawn(opener, [file], { stdio: \"ignore\", detached: true }).unref();\n } catch {\n // 打开失败不影响创建流程(提示仍会打印)\n }\n}\n\n/** 解析命令行参数(flag 仅三个,手写保持自包含,不引 yargs-parser)。 */\nfunction parseArgs(argv: string[]): CliOptions {\n const opts: CliOptions = { forced: false, yes: false, help: false };\n for (const arg of argv) {\n if (arg === \"-f\" || arg === \"--forced\") {\n opts.forced = true;\n } else if (arg === \"-y\" || arg === \"--yes\") {\n opts.yes = true;\n } else if (arg === \"-h\" || arg === \"--help\") {\n opts.help = true;\n } else if (arg.startsWith(\"-\")) {\n throw new Error(`未知参数:${arg}`);\n } else if (opts.name === undefined) {\n opts.name = arg;\n } else {\n throw new Error(`多余的位置参数:${arg}`);\n }\n }\n return opts;\n}\n\n/** 读取脚手架自身版本号(intro 显示;dist 场景 import.meta.url 指向包内)。 */\nfunction readVersion(): string {\n try {\n const ownPkg = JSON.parse(\n readFileSync(new URL(\"../package.json\", import.meta.url), \"utf8\"),\n ) as { version?: string };\n return ownPkg.version ?? \"0.0.0\";\n } catch {\n // package.json 缺失(异常环境)→ 兜底\n return \"0.0.0\";\n }\n}\n\n/** 交互询问部署文件夹名(回车取默认值;-y 直接返回默认值)。 */\nasync function askProjectName(yes: boolean): Promise<string> {\n if (yes) {\n return DEFAULT_PROJECT_NAME;\n }\n // placeholder = 淡灰默认名:直接回车 = 用默认名,键入任意字符 = 从空自定义。\n // 不设 initialValue——否则 clack 渲染的是已输入态(蓝色、光标在末尾),\n // 淡灰 placeholder 不显示(对齐 koishi create 的观感)。\n const name = await text({\n message: \"部署文件夹名\",\n placeholder: DEFAULT_PROJECT_NAME,\n validate: (input: string | undefined) => {\n // 空输入 = 使用默认名,不报错\n if (input === undefined || input.trim() === \"\") {\n return undefined;\n }\n try {\n validateProjectName(input);\n return undefined;\n } catch (err) {\n return err instanceof Error ? err.message : String(err);\n }\n },\n });\n if (isCancel(name)) {\n cancel(\"操作已取消\");\n process.exit(0);\n }\n const trimmed = name.trim();\n return trimmed === \"\" ? DEFAULT_PROJECT_NAME : validateProjectName(trimmed);\n}\n\n/**\n * 包管理器品牌色(美化 v4,对齐 koishi create 观感)。\n * 16 色近似 + bold:兼容所有终端(不依赖 truecolor),Windows Terminal /\n * 老 conhost 都能正常显示。只做「标题 + 命令」两层,不做三套 UI。\n */\nfunction brandColor(pm: PackageManager): (text: string) => string {\n switch (pm) {\n case \"pnpm\":\n return (t) => yellow(bold(t));\n case \"yarn\":\n return (t) => blue(bold(t));\n case \"npm\":\n return (t) => red(bold(t));\n }\n}\n\n/**\n * 生成后的项目骨架文件树(提升完成感,dim 树枝 + 品牌色勾)。\n * yarn 时多一项空 yarn.lock(隔离独立项目,见 scaffold.ts 注释),树枝符按是否\n * 含该文件调整(末项用 └──,其余用 ├──)。\n */\nfunction renderTree(dirName: string, brand: (t: string) => string, pm: PackageManager): string {\n const hasLock = pm === \"yarn\";\n const tomlBranch = hasLock ? \" ├── \" : \" └── \";\n const lines = [\n brand(\"✓\") + dim(\" 生成的文件:\"),\n dim(` ${dirName}/`),\n dim(\" ├── \") + cyan(\"package.json\"),\n dim(tomlBranch) + cyan(\"napuketto.toml\"),\n ];\n if (hasLock) {\n lines.push(dim(\" └── \") + cyan(\"yarn.lock\") + dim(\" # 空:隔离独立项目\"));\n }\n return lines.join(\"\\n\");\n}\n\n/** 询问是否移除现有文件并继续(目标目录非空时)。 */\nasync function confirmRemove(dirName: string): Promise<boolean> {\n const ok = await confirm({\n message: `目录 \"${dirName}\" 已存在且非空,移除现有文件并继续?`,\n initialValue: false,\n });\n if (isCancel(ok)) {\n cancel(\"操作已取消\");\n process.exit(0);\n }\n return ok;\n}\n\n/** 空白/引号判定。 */\nconst SHELL_WHITESPACE_RE = /[\\s\"]/;\n/** 内部引号转义。 */\nconst QUOTE_RE = /\"/g;\n\n/** 拼命令行时最小转义:含空白/引号则加双引号包裹(参数均为内部字面量,仅兜底)。 */\nfunction quoteShellArg(arg: string): string {\n return SHELL_WHITESPACE_RE.test(arg) ? `\"${arg.replace(QUOTE_RE, '\\\\\"')}\"` : arg;\n}\n\n/**\n * 去掉 NODE_OPTIONS 里 yarn dlx 注入的 PnP 加载器条目(--require/--import 后跟\n * .pnp.cjs / .pnp.loader.mjs 路径),其余选项原样保留。\n *\n * 背景:`yarn create napukettoqq` 实为 `yarn dlx`,脚手架本身跑在临时 PnP\n * 项目里,其 PnP 钩子经 NODE_OPTIONS 注入进程环境。install 子进程若继承该变量,\n * corepack 解析 yarn 版本时 `require(\"corepack/package.json\")` 会被 PnP 拦截,\n * 报「tried to access corepack, but it isn't declared in your dependencies」。\n * 生成的用户项目与脚手架的 PnP 上下文无关,剥掉即可恢复标准 Node 解析。\n */\nfunction subprocessEnv(): NodeJS.ProcessEnv {\n const env = { ...process.env };\n const nodeOptions = env[\"NODE_OPTIONS\"];\n if (nodeOptions !== undefined) {\n // 逐个剥掉 PnP 加载器条目(路径含空格时 Yarn 不生成,\\S* 足够)\n const cleaned = nodeOptions\n .replace(/(?:^|\\s)--(?:require|import)(?:=|\\s+)\\S*\\.pnp\\.(?:cjs|loader\\.mjs)/g, \"\")\n .replace(/\\s{2,}/g, \" \")\n .trim();\n if (cleaned !== nodeOptions) {\n if (cleaned === \"\") {\n delete env[\"NODE_OPTIONS\"];\n } else {\n env[\"NODE_OPTIONS\"] = cleaned;\n }\n }\n }\n return env;\n}\n\n/** 前台执行命令(stdio 继承,用户可见进度/交互),返回退出码。 */\nfunction runInteractive(bin: string, args: string[], cwd: string): Promise<number> {\n return new Promise((resolve) => {\n // Windows 下 .cmd shim 不能直接 CreateProcess 执行,需 shell:true 经 cmd.exe;\n // 但 Node ≥22 对「shell:true + args 数组」触发 DEP0190 告警(args 仅简单拼接、不转义),\n // 因此 shell 模式下把命令拼成单个字符串传给 spawn 以规避告警;\n // POSIX 下无 shell,保持 bin + args。\n const shell = process.platform === \"win32\";\n const child = spawn(\n shell ? [bin, ...args.map(quoteShellArg)].join(\" \") : bin,\n shell ? [] : args,\n {\n cwd,\n env: subprocessEnv(),\n stdio: \"inherit\",\n windowsHide: false,\n shell,\n },\n );\n child.on(\"exit\", (code) => {\n resolve(code ?? 0);\n });\n });\n}\n\n/** 目标目录准备:非空需确认清空(-f 跳过确认;-y 不隐式清空)。返回 null = 已取消。 */\nasync function prepareTargetDir(\n dirName: string,\n opts: CliOptions,\n): Promise<{ targetDir: string; overwrite: boolean } | null> {\n const targetDir = resolveTargetDir(dirName);\n let overwrite = false;\n if ((await checkDirStatus(targetDir)) === \"nonempty\") {\n if (!opts.forced) {\n log.warn(`目标目录 \"${dirName}\" 已存在且非空。`);\n overwrite = await confirmRemove(dirName);\n if (!overwrite) {\n outro(\"已取消,未做任何修改。\");\n return null;\n }\n } else {\n overwrite = true;\n }\n }\n return { targetDir, overwrite };\n}\n\n/** 安装依赖(失败提示手动安装路径)。返回是否继续。 */\nasync function installDeps(pm: PackageManager, result: ScaffoldResult): Promise<boolean> {\n const color = brandColor(pm);\n log.info(\"前置要求:本机已安装 QQ NT(wrapper.node 来自 QQ 安装目录)。\");\n log.info(`正在安装依赖(${color(pm)} install)...`);\n const installCode = await runInteractive(pmBin(pm), [\"install\"], result.dir);\n if (installCode === 0) {\n return true;\n }\n log.error(`依赖安装失败(退出码 ${installCode})。请手动执行:`);\n log.step(`cd ${result.dir}`);\n log.step(color(`${pm} install`));\n outro(\"创建失败,请手动安装后重试。\");\n process.exitCode = 1;\n return false;\n}\n\nasync function main(): Promise<void> {\n const opts = parseArgs(process.argv.slice(2));\n if (opts.help) {\n console.log(HELP);\n return;\n }\n\n // 包管理器提前检测:intro 品牌色 + install/start 命令都按它定向\n const pm = detectPackageManager();\n const brand = brandColor(pm);\n\n // intro:品牌色标题(按调用方包管理器取色,PNPM 黄 / Yarn 蓝 / npm 红)\n intro(brand(`create-napukettoqq v${readVersion()}`));\n\n const dirName = opts.name ?? (await askProjectName(opts.yes));\n const prepared = await prepareTargetDir(dirName, opts);\n if (prepared === null) {\n return;\n }\n const { targetDir, overwrite } = prepared;\n\n // 生成骨架(spinner 进度)\n const s = spinner();\n s.start(`正在生成项目骨架 ${dirName} ...`);\n const result = await scaffoldProject(dirName, overwrite, pm);\n s.stop(`项目骨架已生成:${dirName}`);\n log.message(renderTree(dirName, brand, pm));\n log.success(`位置:${result.dir}`);\n\n // 自动安装依赖(用调用方包管理器)\n if (!(await installDeps(pm, result))) {\n return;\n }\n\n // 不自动启动(2026-08-16 用户拍板):打开配置文件供填写 QQ 号 + 打印启动指引。\n // 占位账号(qq = \"123456\")启动无意义,且自动前台运行会占用终端。\n log.message(`请编辑 ${CONFIG_FILE} 填写你的 QQ 号([[accounts]] 段 qq 字段),然后启动:`);\n if (targetDir !== process.cwd()) {\n const related = relative(process.cwd(), targetDir);\n log.step(`cd ${related}`);\n }\n log.step(brand(`${pm} start`));\n log.message(\"启动后 Ctrl+C 停止;协议与端口配置见项目内 napuketto.toml。\");\n openInEditor(join(result.dir, CONFIG_FILE));\n\n outro(\"完成。\");\n}\n\nmain().catch((err: unknown) => {\n const message = err instanceof Error ? err.message : String(err);\n log.error(`创建失败:${message}`);\n process.exitCode = 1;\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/scaffold.ts","../src/index.ts"],"sourcesContent":["/**\n * create-napukettoqq 脚手架核心:模板渲染 + 目标目录创建 + 文件写入。\n *\n * 模板为独立文件(templates/ 目录,运行时读取),不硬编码在源码里;\n * 需要插值的占位符用 {{key}} 标记(见 renderTemplate)。\n * 依赖极轻(node:fs/promises / node:os / node:path / node:process)。\n * 生成的用户项目依赖发布版的 @napuketto/cli,用户 install 后经 cli → loader\n * 自建宿主启动。\n */\n\nimport { readFileSync } from \"node:fs\";\nimport { mkdir, readdir, readFile, rm, writeFile } from \"node:fs/promises\";\n\nimport path from \"node:path\";\nimport process from \"node:process\";\n\n/** 模板目录(相对本文件:src 与 dist 都在包根下,../templates 均指向包根/templates)。 */\nconst TEMPLATES = new URL(\"../templates/\", import.meta.url);\n\n/** npm registry 查询超时(毫秒;兜底链路,超时不阻塞脚手架)。 */\nconst REGISTRY_TIMEOUT_MS = 3000;\n\n/** npm registry 上 @napuketto/cli 的最新版本(查询失败返回 null)。 */\nasync function fetchLatestCliVersion(): Promise<string | null> {\n try {\n const res = await fetch(\"https://registry.npmjs.org/@napuketto/cli/latest\", {\n signal: AbortSignal.timeout(REGISTRY_TIMEOUT_MS),\n });\n if (!res.ok) {\n return null;\n }\n const json = (await res.json()) as { version?: unknown };\n return typeof json.version === \"string\" && json.version !== \"\" ? json.version : null;\n } catch {\n return null;\n }\n}\n\n/**\n * 生成的用户项目所依赖的 @napuketto/cli 版本范围(自动最新版,不交互选版本)。\n * 优先级:\n * 1. 脚手架自身 package.json 的 dependencies[\"@napuketto/cli\"](发版时 changesets\n * 升版本 + 发布改写为实际版本,模板版本自动跟随)\n * 2. npm registry 查询最新版(自身依赖缺失 / 仍是 workspace:*(发布泄漏兜底)——\n * 2026-08-16 修复:published 包曾泄漏 workspace:*,yarn create 被迫交互选版本)\n * 3. ^0.0.1(离线 / registry 查询失败兜底)\n * workspace:* 只在本地 monorepo 直跑脚手架时出现(发布后被替换为实际版本)。\n */\nasync function cliVersionRange(): Promise<string> {\n try {\n const ownPkg = JSON.parse(\n readFileSync(new URL(\"../package.json\", import.meta.url), \"utf8\"),\n ) as { dependencies?: Record<string, string> };\n const range = ownPkg.dependencies?.[\"@napuketto/cli\"];\n if (range !== undefined && range !== \"workspace:*\") {\n return range;\n }\n } catch {\n // package.json 缺失(异常环境)→ 走 registry 兜底\n }\n const latest = await fetchLatestCliVersion();\n if (latest !== null) {\n return `^${latest}`;\n }\n return \"^0.0.1\";\n}\n\n/** 默认部署文件夹名(用户交互回车缺省值)。 */\nexport const DEFAULT_PROJECT_NAME = \"NapukettoQQ\";\n\n/** 用户可用的包管理器(npm_config_user_agent 检测)。 */\nexport type PackageManager = \"pnpm\" | \"yarn\" | \"npm\";\n\n/**\n * 由 npm_config_user_agent 检测调用方包管理器(yarn create / npm create /\n * pnpm create 都会注入该变量)。兜底 pnpm(项目生态,或直接 node 运行)。\n */\nexport function detectPackageManager(): PackageManager {\n // noPropertyAccessFromIndexSignature:process.env 是索引签名,必须括号访问\n const ua = process.env[\"npm_config_user_agent\"] ?? \"\";\n if (ua.startsWith(\"yarn/\")) {\n return \"yarn\";\n }\n if (ua.startsWith(\"npm/\")) {\n return \"npm\";\n }\n return \"pnpm\";\n}\n\n/** Windows 下包管理器 bin 需带 .cmd 后缀(CreateProcess 不认无扩展名 shim)。 */\nexport function pmBin(pm: PackageManager): string {\n return process.platform === \"win32\" ? `${pm}.cmd` : pm;\n}\n\n/** Windows 路径非法字符(项目文件夹名校验用)。 */\nconst ILLEGAL_NAME = /[\\\\/:*?\"<>|]/;\n\n/** 脚手架生成结果。 */\nexport interface ScaffoldResult {\n /** 目标目录绝对路径。 */\n dir: string;\n /** 派生出的 npm 包名(小写、空格 → -)。 */\n packageName: string;\n}\n\n/** 校验文件夹名:非空、非 . / ..、不含 Windows 非法字符。 */\nexport function validateProjectName(raw: string): string {\n const name = raw.trim();\n if (name === \"\" || name === \".\" || name === \"..\") {\n throw new Error(\"文件夹名不能为空或为 . / ..\");\n }\n if (ILLEGAL_NAME.test(name)) {\n throw new Error(`文件夹名含非法字符:${name}(不允许 \\\\ / : * ? \" < > |)`);\n }\n return name;\n}\n\n/** 由文件夹名派生 npm 包名(小写、空格 → -)。 */\nfunction derivePackageName(dirName: string): string {\n return dirName.toLowerCase().replace(/\\s+/g, \"-\");\n}\n\n/** 解析目标目录绝对路径(校验名称后,基于 cwd)。 */\nexport function resolveTargetDir(dirName: string): string {\n return path.resolve(process.cwd(), validateProjectName(dirName));\n}\n\n/** 目标目录状态:不存在 / 空 / 非空。 */\nexport type DirStatus = \"missing\" | \"empty\" | \"nonempty\";\n\n/** 检测目标目录状态(供交互层决定是否询问清空)。 */\nexport async function checkDirStatus(dir: string): Promise<DirStatus> {\n let entries: string[] = [];\n try {\n entries = await readdir(dir);\n } catch {\n return \"missing\";\n }\n return entries.length === 0 ? \"empty\" : \"nonempty\";\n}\n\n/** 清空目录内容(保留目录本身)。 */\nasync function emptyDir(dir: string): Promise<void> {\n for (const entry of await readdir(dir)) {\n await rm(path.join(dir, entry), { recursive: true, force: true });\n }\n}\n\n/** 读取模板文件(templates/ 目录,UTF-8)。 */\nfunction readTemplate(file: string): Promise<string> {\n return readFile(new URL(file, TEMPLATES), \"utf8\");\n}\n\n/**\n * 占位符渲染:把 {{key}} 替换为 vars[key]。\n * 模板中出现未提供的占位符 → 抛错(防漏插值写出半成品)。\n */\nfunction renderTemplate(content: string, vars: Record<string, string>): string {\n return content.replace(/\\{\\{(\\w+)\\}\\}/g, (match, key: string) => {\n const value = vars[key];\n if (value === undefined) {\n throw new Error(`模板占位符未提供:{{${key}}}(模板 ${match} 无法渲染)`);\n }\n return value;\n });\n}\n\n/**\n * 生成 NapukettoQQ 项目骨架到当前目录下的 <dirName>/。\n * 目标目录已存在且非空:overwrite=false → 抛错;overwrite=true → 清空后生成。\n * 模板与写入目标一一对应(同文件名)。pm 为调用方包管理器:yarn 时额外生成\n * 空 yarn.lock 把用户项目隔离成独立项目——yarn install 会向上探测父目录的\n * package.json/yarn.lock,若用户父目录(如 ~)恰好有这些文件,yarn 会把生成\n * 目录误当作其 workspace 子包并报「nearest package directory doesn't seem to\n * be part of the project declared in <父目录>」。空 yarn.lock 让 yarn 把生成\n * 目录视为独立项目根(yarn 自身报错信息也建议此做法),pnpm/npm 无此问题。\n */\nexport async function scaffoldProject(\n dirName: string,\n overwrite = false,\n pm: PackageManager = \"pnpm\",\n): Promise<ScaffoldResult> {\n const name = validateProjectName(dirName);\n const packageName = derivePackageName(name);\n const dir = resolveTargetDir(name);\n\n const status = await checkDirStatus(dir);\n if (status === \"nonempty\" && !overwrite) {\n throw new Error(`目录已存在且非空:${dir}\\n请换一个文件夹名,或先清空该目录。`);\n }\n if (status === \"nonempty\") {\n await emptyDir(dir);\n }\n\n // 渲染变量(napuketto.toml 模板不再插值 dataDir——缺省 = 项目根/.napuketto,跨平台)\n const vars: Record<string, string> = {\n packageName,\n cliVersion: await cliVersionRange(),\n };\n // 用户项目是「运行壳」:不开发代码,只需 package.json(依赖 + start)+ napuketto.toml(配置)\n // 模板文件为 templates/<name>.tmpl(.tmpl 后缀避免 TOML/JSON 语言服务把占位符当非法语法)\n const files = [\"package.json\", \"napuketto.toml\"];\n\n await mkdir(dir, { recursive: true });\n for (const file of files) {\n const rendered = renderTemplate(await readTemplate(`${file}.tmpl`), vars);\n await writeFile(path.join(dir, file), rendered, \"utf8\");\n }\n\n // yarn:写空 yarn.lock 隔离成独立项目(见函数 JSDoc)。yarn install 会重写\n // 该文件为真实锁文件;空文件只用于阻断向上探测,无运行时副作用。\n if (pm === \"yarn\") {\n await writeFile(path.join(dir, \"yarn.lock\"), \"\", \"utf8\");\n }\n\n return { dir, packageName };\n}\n","#!/usr/bin/env node\n\n/**\n * create-napukettoqq 入口(2026-08-07 美化 v3,交互层用 @clack/prompts——\n * 现代脚手架交互标准,create-vue / create-turbo 同款)。\n *\n * 用法:\n * create-napukettoqq # intro + 交互问部署文件夹名(默认 NapukettoQQ)\n * create-napukettoqq my-bot # 位置参数指定文件夹名,跳过命名交互\n * create-napukettoqq my-bot -f # 目标目录非空时强制清空覆盖\n * create-napukettoqq -y # 全默认(命名用默认值)\n * create-napukettoqq -h # 打印帮助\n *\n * 流程:intro → 问文件夹名 → 目标目录准备(非空需确认清空)→ spinner 生成骨架\n * (package.json / napuketto.toml)→ 用调用方包管理器自动 install →\n * 打开 napuketto.toml 供填写 QQ 号(不自动启动)+ 打印启动指引 → outro 收尾。\n */\n\nimport { spawn } from \"node:child_process\";\nimport { readFileSync } from \"node:fs\";\nimport { join, relative } from \"node:path\";\nimport process from \"node:process\";\nimport { cancel, confirm, intro, log, outro, spinner, text } from \"@clack/prompts\";\nimport pc from \"picocolors\";\nimport type { PackageManager, ScaffoldResult } from \"./scaffold.js\";\nimport {\n checkDirStatus,\n DEFAULT_PROJECT_NAME,\n detectPackageManager,\n pmBin,\n resolveTargetDir,\n scaffoldProject,\n validateProjectName,\n} from \"./scaffold.js\";\n\n// picocolors 是 CJS 包(无 ESM 命名导出),Node ESM 下需 default import 再解构\nconst { blue, bold, cyan, dim, red, yellow } = pc;\n\n/** CLI 参数解析结果。 */\ninterface CliOptions {\n /** 位置参数:部署文件夹名(可选)。 */\n name?: string;\n /** -f/--forced:目标目录非空时强制清空覆盖。 */\n forced: boolean;\n /** -y/--yes:跳过所有交互提示(使用默认值)。 */\n yes: boolean;\n /** -h/--help:显示帮助。 */\n help: boolean;\n}\n\n/** 帮助文本(-h/--help)。 */\nconst HELP = ` 用法: create-napukettoqq [name] [选项]\n\n 选项:\n -f, --forced 目标目录非空时强制清空并覆盖\n -y, --yes 跳过所有交互提示(使用默认值)\n -h, --help 显示本帮助\n`;\n\n/** 配置文件文件名(生成后引导用户填写 QQ 号)。 */\nconst CONFIG_FILE = \"napuketto.toml\";\n\n/**\n * 用系统默认应用打开文件(引导编辑配置用;尽力而为,失败不阻塞创建流程)。\n * Windows:经 cmd.exe 执行内建 start(CreateProcess 不认内建命令);\n * macOS/Linux:open / xdg-open。detached + unref:不挂到脚手架进程树。\n */\nfunction openInEditor(file: string): void {\n try {\n if (process.platform === \"win32\") {\n // start 首参是窗口标题(\"\" 占位),文件路径带引号防空格\n spawn(\"cmd.exe\", [\"/d\", \"/s\", \"/c\", `start \"\" \"${file}\"`], {\n stdio: \"ignore\",\n windowsHide: true,\n detached: true,\n }).unref();\n return;\n }\n const opener = process.platform === \"darwin\" ? \"open\" : \"xdg-open\";\n spawn(opener, [file], { stdio: \"ignore\", detached: true }).unref();\n } catch {\n // 打开失败不影响创建流程(提示仍会打印)\n }\n}\n\n/** 解析命令行参数(flag 仅三个,手写保持自包含,不引 yargs-parser)。 */\nfunction parseArgs(argv: string[]): CliOptions {\n const opts: CliOptions = { forced: false, yes: false, help: false };\n for (const arg of argv) {\n if (arg === \"-f\" || arg === \"--forced\") {\n opts.forced = true;\n } else if (arg === \"-y\" || arg === \"--yes\") {\n opts.yes = true;\n } else if (arg === \"-h\" || arg === \"--help\") {\n opts.help = true;\n } else if (arg.startsWith(\"-\")) {\n throw new Error(`未知参数:${arg}`);\n } else if (opts.name === undefined) {\n opts.name = arg;\n } else {\n throw new Error(`多余的位置参数:${arg}`);\n }\n }\n return opts;\n}\n\n/** 读取脚手架自身版本号(intro 显示;dist 场景 import.meta.url 指向包内)。 */\nfunction readVersion(): string {\n try {\n const ownPkg = JSON.parse(\n readFileSync(new URL(\"../package.json\", import.meta.url), \"utf8\"),\n ) as { version?: string };\n return ownPkg.version ?? \"0.0.0\";\n } catch {\n // package.json 缺失(异常环境)→ 兜底\n return \"0.0.0\";\n }\n}\n\n/** 交互询问部署文件夹名(回车取默认值;-y 直接返回默认值)。 */\nasync function askProjectName(yes: boolean): Promise<string> {\n if (yes) {\n return DEFAULT_PROJECT_NAME;\n }\n // placeholder = 淡灰默认名:直接回车 = 用默认名,键入任意字符 = 从空自定义。\n // 不设 initialValue——否则 clack 渲染的是已输入态(蓝色、光标在末尾),\n // 淡灰 placeholder 不显示(对齐 koishi create 的观感)。\n const name = await text({\n message: \"部署文件夹名\",\n placeholder: DEFAULT_PROJECT_NAME,\n validate: (input: string | undefined) => {\n // 空输入 = 使用默认名,不报错\n if (input === undefined || input.trim() === \"\") {\n return undefined;\n }\n try {\n validateProjectName(input);\n return undefined;\n } catch (err) {\n return err instanceof Error ? err.message : String(err);\n }\n },\n });\n // 不用 isCancel:@clack/prompts 1.8 起类型守卫收窄为 `value is typeof CANCEL_SYMBOL`\n // (unique symbol),无法把 `string | symbol` 里的 symbol 排除掉,收窄失效。\n // 这里按运行期类型判定,语义等价且不依赖上游类型细节。\n if (typeof name !== \"string\") {\n cancel(\"操作已取消\");\n process.exit(0);\n }\n const trimmed = name.trim();\n return trimmed === \"\" ? DEFAULT_PROJECT_NAME : validateProjectName(trimmed);\n}\n\n/**\n * 包管理器品牌色(美化 v4,对齐 koishi create 观感)。\n * 16 色近似 + bold:兼容所有终端(不依赖 truecolor),Windows Terminal /\n * 老 conhost 都能正常显示。只做「标题 + 命令」两层,不做三套 UI。\n */\nfunction brandColor(pm: PackageManager): (text: string) => string {\n switch (pm) {\n case \"pnpm\":\n return (t) => yellow(bold(t));\n case \"yarn\":\n return (t) => blue(bold(t));\n case \"npm\":\n return (t) => red(bold(t));\n }\n}\n\n/**\n * 生成后的项目骨架文件树(提升完成感,dim 树枝 + 品牌色勾)。\n * yarn 时多一项空 yarn.lock(隔离独立项目,见 scaffold.ts 注释),树枝符按是否\n * 含该文件调整(末项用 └──,其余用 ├──)。\n */\nfunction renderTree(dirName: string, brand: (t: string) => string, pm: PackageManager): string {\n const hasLock = pm === \"yarn\";\n const tomlBranch = hasLock ? \" ├── \" : \" └── \";\n const lines = [\n brand(\"✓\") + dim(\" 生成的文件:\"),\n dim(` ${dirName}/`),\n dim(\" ├── \") + cyan(\"package.json\"),\n dim(tomlBranch) + cyan(\"napuketto.toml\"),\n ];\n if (hasLock) {\n lines.push(dim(\" └── \") + cyan(\"yarn.lock\") + dim(\" # 空:隔离独立项目\"));\n }\n return lines.join(\"\\n\");\n}\n\n/** 询问是否移除现有文件并继续(目标目录非空时)。 */\nasync function confirmRemove(dirName: string): Promise<boolean> {\n const ok = await confirm({\n message: `目录 \"${dirName}\" 已存在且非空,移除现有文件并继续?`,\n initialValue: false,\n });\n if (typeof ok !== \"boolean\") {\n cancel(\"操作已取消\");\n process.exit(0);\n }\n return ok;\n}\n\n/** 空白/引号判定。 */\nconst SHELL_WHITESPACE_RE = /[\\s\"]/;\n/** 内部引号转义。 */\nconst QUOTE_RE = /\"/g;\n\n/** 拼命令行时最小转义:含空白/引号则加双引号包裹(参数均为内部字面量,仅兜底)。 */\nfunction quoteShellArg(arg: string): string {\n return SHELL_WHITESPACE_RE.test(arg) ? `\"${arg.replace(QUOTE_RE, '\\\\\"')}\"` : arg;\n}\n\n/**\n * 去掉 NODE_OPTIONS 里 yarn dlx 注入的 PnP 加载器条目(--require/--import 后跟\n * .pnp.cjs / .pnp.loader.mjs 路径),其余选项原样保留。\n *\n * 背景:`yarn create napukettoqq` 实为 `yarn dlx`,脚手架本身跑在临时 PnP\n * 项目里,其 PnP 钩子经 NODE_OPTIONS 注入进程环境。install 子进程若继承该变量,\n * corepack 解析 yarn 版本时 `require(\"corepack/package.json\")` 会被 PnP 拦截,\n * 报「tried to access corepack, but it isn't declared in your dependencies」。\n * 生成的用户项目与脚手架的 PnP 上下文无关,剥掉即可恢复标准 Node 解析。\n */\nfunction subprocessEnv(): NodeJS.ProcessEnv {\n const env = { ...process.env };\n const nodeOptions = env[\"NODE_OPTIONS\"];\n if (nodeOptions !== undefined) {\n // 逐个剥掉 PnP 加载器条目(路径含空格时 Yarn 不生成,\\S* 足够)\n const cleaned = nodeOptions\n .replace(/(?:^|\\s)--(?:require|import)(?:=|\\s+)\\S*\\.pnp\\.(?:cjs|loader\\.mjs)/g, \"\")\n .replace(/\\s{2,}/g, \" \")\n .trim();\n if (cleaned !== nodeOptions) {\n if (cleaned === \"\") {\n delete env[\"NODE_OPTIONS\"];\n } else {\n env[\"NODE_OPTIONS\"] = cleaned;\n }\n }\n }\n return env;\n}\n\n/** 前台执行命令(stdio 继承,用户可见进度/交互),返回退出码。 */\nfunction runInteractive(bin: string, args: string[], cwd: string): Promise<number> {\n return new Promise((resolve) => {\n // Windows 下 .cmd shim 不能直接 CreateProcess 执行,需 shell:true 经 cmd.exe;\n // 但 Node ≥22 对「shell:true + args 数组」触发 DEP0190 告警(args 仅简单拼接、不转义),\n // 因此 shell 模式下把命令拼成单个字符串传给 spawn 以规避告警;\n // POSIX 下无 shell,保持 bin + args。\n const shell = process.platform === \"win32\";\n const child = spawn(\n shell ? [bin, ...args.map(quoteShellArg)].join(\" \") : bin,\n shell ? [] : args,\n {\n cwd,\n env: subprocessEnv(),\n stdio: \"inherit\",\n windowsHide: false,\n shell,\n },\n );\n child.on(\"exit\", (code) => {\n resolve(code ?? 0);\n });\n });\n}\n\n/** 目标目录准备:非空需确认清空(-f 跳过确认;-y 不隐式清空)。返回 null = 已取消。 */\nasync function prepareTargetDir(\n dirName: string,\n opts: CliOptions,\n): Promise<{ targetDir: string; overwrite: boolean } | null> {\n const targetDir = resolveTargetDir(dirName);\n let overwrite = false;\n if ((await checkDirStatus(targetDir)) === \"nonempty\") {\n if (!opts.forced) {\n log.warn(`目标目录 \"${dirName}\" 已存在且非空。`);\n overwrite = await confirmRemove(dirName);\n if (!overwrite) {\n outro(\"已取消,未做任何修改。\");\n return null;\n }\n } else {\n overwrite = true;\n }\n }\n return { targetDir, overwrite };\n}\n\n/** 安装依赖(失败提示手动安装路径)。返回是否继续。 */\nasync function installDeps(pm: PackageManager, result: ScaffoldResult): Promise<boolean> {\n const color = brandColor(pm);\n log.info(\"前置要求:本机已安装 QQ NT(wrapper.node 来自 QQ 安装目录)。\");\n log.info(`正在安装依赖(${color(pm)} install)...`);\n const installCode = await runInteractive(pmBin(pm), [\"install\"], result.dir);\n if (installCode === 0) {\n return true;\n }\n log.error(`依赖安装失败(退出码 ${installCode})。请手动执行:`);\n log.step(`cd ${result.dir}`);\n log.step(color(`${pm} install`));\n outro(\"创建失败,请手动安装后重试。\");\n process.exitCode = 1;\n return false;\n}\n\nasync function main(): Promise<void> {\n const opts = parseArgs(process.argv.slice(2));\n if (opts.help) {\n console.log(HELP);\n return;\n }\n\n // 包管理器提前检测:intro 品牌色 + install/start 命令都按它定向\n const pm = detectPackageManager();\n const brand = brandColor(pm);\n\n // intro:品牌色标题(按调用方包管理器取色,PNPM 黄 / Yarn 蓝 / npm 红)\n intro(brand(`create-napukettoqq v${readVersion()}`));\n\n const dirName = opts.name ?? (await askProjectName(opts.yes));\n const prepared = await prepareTargetDir(dirName, opts);\n if (prepared === null) {\n return;\n }\n const { targetDir, overwrite } = prepared;\n\n // 生成骨架(spinner 进度)\n const s = spinner();\n s.start(`正在生成项目骨架 ${dirName} ...`);\n const result = await scaffoldProject(dirName, overwrite, pm);\n s.stop(`项目骨架已生成:${dirName}`);\n log.message(renderTree(dirName, brand, pm));\n log.success(`位置:${result.dir}`);\n\n // 自动安装依赖(用调用方包管理器)\n if (!(await installDeps(pm, result))) {\n return;\n }\n\n // 不自动启动(2026-08-16 用户拍板):打开配置文件供填写 QQ 号 + 打印启动指引。\n // 占位账号(qq = \"123456\")启动无意义,且自动前台运行会占用终端。\n log.message(`请编辑 ${CONFIG_FILE} 填写你的 QQ 号([[accounts]] 段 qq 字段),然后启动:`);\n if (targetDir !== process.cwd()) {\n const related = relative(process.cwd(), targetDir);\n log.step(`cd ${related}`);\n }\n log.step(brand(`${pm} start`));\n log.message(\"启动后 Ctrl+C 停止;协议与端口配置见项目内 napuketto.toml。\");\n openInEditor(join(result.dir, CONFIG_FILE));\n\n outro(\"完成。\");\n}\n\nmain().catch((err: unknown) => {\n const message = err instanceof Error ? err.message : String(err);\n log.error(`创建失败:${message}`);\n process.exitCode = 1;\n});\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-napukettoqq",
3
- "version": "0.2.39",
3
+ "version": "0.2.40",
4
4
  "description": "一键生成 NapukettoQQ 机器人项目(yarn/pnpm/npm create napukettoqq)",
5
5
  "type": "module",
6
6
  "files": [