assetplex 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../node_modules/tsup/assets/esm_shims.js","../src/utils/logger.ts","../src/utils/paths.ts","../src/core/config.ts","../src/utils/fs.ts","../src/transforms/symlink.ts","../src/core/adapters/base.ts","../src/core/adapters/trae-cn.ts","../src/core/adapters/claude-code.ts","../src/transforms/json-toml.ts","../src/core/adapters/codex.ts","../src/transforms/env-interpolation.ts","../src/core/adapters/workbuddy.ts","../src/core/adapters/qoder.ts","../src/core/adapters/registry.ts","../src/core/scanner.ts","../src/core/merger.ts","../src/core/hub-files.ts","../src/core/sync-engine.ts","../src/server/lib/hub-context.ts","../src/core/overview.ts","../src/server/routes/hub.ts","../src/server/routes/tools.ts","../src/server/routes/sync.ts","../src/server/routes/files.ts","../src/core/assets.ts","../src/server/routes/assets.ts","../src/server/middleware/error.ts","../src/server/index.ts","../src/cli/commands/ui.ts","../src/cli/index.ts","../src/cli/commands/init.ts","../src/cli/templates.ts","../src/cli/commands/doctor.ts","../src/cli/commands/sync.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","/**\n * 终端日志工具(chalk 跨平台彩色输出)\n */\n\nimport chalk from 'chalk';\n\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'success';\n\nconst levelPriority: Record<LogLevel, number> = {\n debug: 10,\n info: 20,\n success: 25,\n warn: 30,\n error: 40,\n};\n\nlet currentLevel: LogLevel = 'info';\n\nexport function setLogLevel(level: LogLevel): void {\n currentLevel = level;\n}\n\nexport function getLogLevel(): LogLevel {\n return currentLevel;\n}\n\nfunction shouldLog(level: LogLevel): boolean {\n return levelPriority[level] >= levelPriority[currentLevel];\n}\n\nexport const log = {\n debug(msg: string, ...args: unknown[]): void {\n if (shouldLog('debug')) {\n console.error(chalk.gray(`[debug] ${msg}`), ...args);\n }\n },\n info(msg: string, ...args: unknown[]): void {\n if (shouldLog('info')) {\n console.log(chalk.cyan(msg), ...args);\n }\n },\n success(msg: string, ...args: unknown[]): void {\n if (shouldLog('success')) {\n console.log(chalk.green(`✓ ${msg}`), ...args);\n }\n },\n warn(msg: string, ...args: unknown[]): void {\n if (shouldLog('warn')) {\n console.warn(chalk.yellow(`! ${msg}`), ...args);\n }\n },\n error(msg: string, ...args: unknown[]): void {\n if (shouldLog('error')) {\n console.error(chalk.red(`✗ ${msg}`), ...args);\n }\n },\n raw(msg: string, ...args: unknown[]): void {\n console.log(msg, ...args);\n },\n};\n","/**\n * 路径工具:处理 ~ 展开、跨平台路径\n */\n\nimport { homedir } from 'node:os';\nimport { resolve, normalize } from 'node:path';\n\n/**\n * 展开 ~ 为 home 目录\n */\nexport function expandHome(filepath: string): string {\n if (!filepath) return filepath;\n if (filepath === '~') return homedir();\n if (filepath.startsWith('~/') || filepath.startsWith('~\\\\')) {\n return resolve(homedir(), filepath.slice(2));\n }\n if (filepath.startsWith('~')) {\n // ~username 形式(Windows 不支持,直接返回原值)\n return filepath;\n }\n return normalize(filepath);\n}\n\n/**\n * 获取 Hub 根目录(支持 ASSETPLEX_DIR 环境变量覆盖)\n */\nexport function getHubRoot(): string {\n const fromEnv = process.env.ASSETPLEX_DIR;\n if (fromEnv) return expandHome(fromEnv);\n return expandHome('~/.assetplex');\n}\n\n/**\n * 获取 Hub 内某文件的绝对路径\n */\nexport function hubPath(...segments: string[]): string {\n return resolve(getHubRoot(), ...segments);\n}\n","/**\n * hub.toml 配置 schema 与解析器\n *\n * 借鉴 Codex config.toml 的设计:用 TOML 作为主配置格式\n * 借鉴 zod 进行 schema 校验\n */\n\nimport { z } from 'zod';\nimport * as TOML from '@iarna/toml';\nimport { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';\nimport { resolve, dirname } from 'node:path';\nimport { expandHome } from '../utils/paths.js';\n\n/** 同步策略枚举 */\nexport const SyncStrategySchema = z.enum([\n 'native-import',\n 'symlink',\n 'copy',\n 'hybrid',\n 'per-project',\n]);\n\n/** MCP 格式枚举 */\nexport const McpFormatSchema = z.enum(['json', 'toml']);\n\n/** Hub 主配置 schema */\nexport const HubConfigSchema = z.object({\n hub: z\n .object({\n version: z.string().default('1.0'),\n defaultSyncStrategy: SyncStrategySchema.default('hybrid'),\n backupDir: z.string().default('~/.assetplex/.backups'),\n autoWatch: z.boolean().default(false),\n backupKeepCount: z.number().int().positive().default(10),\n })\n .default({}),\n identity: z\n .object({\n profileAutoLearn: z.boolean().default(true),\n learnSources: z.array(z.string()).default(['trae-cn', 'claude-code']),\n learnIntervalHours: z.number().int().positive().default(24),\n learnMaxFacts: z.number().int().positive().default(100),\n })\n .default({}),\n tools: z\n .object({\n 'trae-cn': z\n .object({\n enabled: z.boolean().default(true),\n configDir: z.string().default('~/.trae-cn'),\n syncStrategy: SyncStrategySchema.default('symlink'),\n mcpFormat: McpFormatSchema.default('json'),\n targets: z.array(z.string()).default([]),\n })\n .default({}),\n 'claude-code': z\n .object({\n enabled: z.boolean().default(true),\n configDir: z.string().default('~/.claude'),\n syncStrategy: SyncStrategySchema.default('native-import'),\n importMaxDepth: z.number().int().positive().max(5).default(4),\n claudeMdAggregator: z.boolean().default(true),\n })\n .default({}),\n codex: z\n .object({\n enabled: z.boolean().default(true),\n configDir: z.string().default('~/.codex'),\n syncStrategy: SyncStrategySchema.default('copy'),\n mcpFormat: McpFormatSchema.default('toml'),\n stripFrontmatterKeys: z.array(z.string()).default([]),\n })\n .default({}),\n workbuddy: z\n .object({\n enabled: z.boolean().default(true),\n configDir: z.string().default('~/.workbuddy'),\n syncStrategy: SyncStrategySchema.default('symlink'),\n envInterpolation: z.boolean().default(true),\n mcpFilename: z.string().default('.mcp.json'),\n })\n .default({}),\n qoder: z\n .object({\n enabled: z.boolean().default(false),\n syncStrategy: SyncStrategySchema.default('per-project'),\n projectTargets: z.array(z.string()).default([]),\n })\n .default({}),\n })\n .default({}),\n marketplace: z\n .object({\n enabled: z.boolean().default(true),\n sources: z.array(z.string()).default([\n 'https://claudeskills.info/api',\n 'https://agentskills.io/api',\n 'https://agskills.dev/api',\n ]),\n cacheDir: z.string().default('~/.assetplex/.marketplace-cache'),\n cacheTtlHours: z.number().int().positive().default(24),\n })\n .default({}),\n});\n\n/** Hub 配置类型 */\nexport type HubConfig = z.infer<typeof HubConfigSchema>;\n\n/**\n * 解析 hub.toml 文件\n * @param configPath 配置文件路径,默认 ~/.assetplex/hub.toml\n */\nexport function loadHubConfig(configPath?: string): HubConfig {\n const path = configPath ?? resolveHubConfigPath();\n if (!existsSync(path)) {\n return HubConfigSchema.parse({});\n }\n const raw = readFileSync(path, 'utf-8');\n const parsed = TOML.parse(raw);\n return HubConfigSchema.parse(parsed);\n}\n\n/** 获取默认 hub.toml 路径 */\nexport function resolveHubConfigPath(): string {\n const hubRoot = process.env.ASSETPLEX_DIR ?? '~/.assetplex';\n return resolve(expandHome(hubRoot), 'hub.toml');\n}\n\n/**\n * 保存 HubConfig 到 hub.toml\n * @param config 配置对象\n * @param configPath 配置文件路径,默认 ~/.assetplex/hub.toml\n */\nexport function saveHubConfig(config: HubConfig, configPath?: string): void {\n const path = configPath ?? resolveHubConfigPath();\n // 确保目录存在\n mkdirSync(dirname(path), { recursive: true });\n // 校验后再写\n const validated = HubConfigSchema.parse(config);\n const toml = TOML.stringify(validated as unknown as TOML.JsonMap);\n writeFileSync(path, toml, 'utf-8');\n}\n\n/** 生成默认配置的 TOML 字符串(用于 assetplex init) */\nexport function generateDefaultConfigToml(): string {\n return `# AssetPlex Configuration\n# See: https://github.com/wynter-cai/assetplex\n\n[hub]\nversion = \"1.0\"\ndefault_sync_strategy = \"hybrid\" # native-import | symlink | copy | hybrid | per-project\nbackup_dir = \"~/.assetplex/.backups\"\nauto_watch = false\nbackup_keep_count = 10\n\n[identity]\nprofile_auto_learn = true\nlearn_sources = [\"trae-cn\", \"claude-code\"]\nlearn_interval_hours = 24\nlearn_max_facts = 100\n\n[tools.trae-cn]\nenabled = true\nconfig_dir = \"~/.trae-cn\"\nsync_strategy = \"symlink\"\nmcp_format = \"json\"\ntargets = [\n \"memory/user_profile.md\",\n \"skills/\",\n \"rules/\",\n \"mcp.json\",\n]\n\n[tools.claude-code]\nenabled = true\nconfig_dir = \"~/.claude\"\nsync_strategy = \"native-import\"\nimport_max_depth = 4\nclaude_md_aggregator = true\n\n[tools.codex]\nenabled = true\nconfig_dir = \"~/.codex\"\nsync_strategy = \"copy\"\nmcp_format = \"toml\"\nstrip_frontmatter_keys = []\n\n[tools.workbuddy]\nenabled = true\nconfig_dir = \"~/.workbuddy\"\nsync_strategy = \"symlink\"\nenv_interpolation = true\nmcp_filename = \".mcp.json\"\n\n[tools.qoder]\nenabled = false\nsync_strategy = \"per-project\"\nproject_targets = []\n\n[marketplace]\nenabled = true\nsources = [\n \"https://claudeskills.info/api\",\n \"https://agentskills.io/api\",\n \"https://agskills.dev/api\",\n]\ncache_dir = \"~/.assetplex/.marketplace-cache\"\ncache_ttl_hours = 24\n`;\n}\n","/**\n * 文件系统跨平台工具集\n *\n * 统一封装 Node.js fs API,处理 Windows 上 junction/symlink 行为差异。\n */\n\nimport {\n existsSync,\n mkdirSync,\n readlinkSync,\n unlinkSync,\n rmdirSync,\n rmSync,\n copyFileSync,\n readdirSync,\n statSync,\n} from 'node:fs';\nimport { resolve, dirname, isAbsolute, relative, join } from 'node:path';\nimport { execSync } from 'node:child_process';\n\n/**\n * 确保目录存在(递归创建)\n */\nexport function ensureDir(path: string): void {\n if (!existsSync(path)) {\n mkdirSync(path, { recursive: true });\n }\n}\n\n/**\n * 判断路径是否为符号链接(Windows junction 也算)\n *\n * 注意:Node.js 的 lstatSync().isSymbolicLink() 在 Windows 上对 junction(目录连接)\n * 返回 false,但 junction 在功能上等价于 symlink。这里用 readlinkSync 尝试读取,\n * 不抛错即认为是 symlink/junction。\n */\nexport function isSymlink(path: string): boolean {\n if (!existsSync(path)) return false;\n try {\n readlinkSync(path);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * 读取符号链接目标路径(junction 和 symlink 都能读)\n *\n * @returns 目标绝对路径;若不是链接或读取失败返回 null\n */\nexport function readSymlinkTarget(path: string): string | null {\n try {\n const target = readlinkSync(path);\n // readlink 返回的是相对路径或绝对路径,统一转为绝对路径\n if (isAbsolute(target)) return target;\n return resolve(dirname(path), target);\n } catch {\n return null;\n }\n}\n\n/**\n * 安全删除:如果是符号链接只删链接不删源;如果是普通文件/目录直接删\n */\nexport function safeRemove(path: string): void {\n if (!existsSync(path) && !isSymlink(path)) return;\n\n if (isSymlink(path)) {\n // 符号链接:用 unlink 删除链接本身(不影响源)\n try {\n unlinkSync(path);\n return;\n } catch {\n // Windows 上目录链接可能需要 rmdir\n try {\n rmdirSync(path);\n return;\n } catch {\n // 继续尝试 rmSync\n }\n }\n }\n\n // 普通文件或目录:递归删除\n // Windows 上 rmSync 存在已知 bug:对包含文件的目录返回成功但未实际删除\n // 优先尝试 rmSync(带 maxRetries 内建重试),失败则用 Windows 原生 rmdir 命令\n try {\n rmSync(path, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 });\n } catch {\n // 忽略错误,下面兜底处理\n }\n\n // 验证是否真的删除了\n if (!existsSync(path)) return;\n\n // Windows 上 rmSync 可能假成功,使用原生命令 rmdir /S /Q 兜底\n if (process.platform === 'win32') {\n try {\n // 路径可能含空格,需用双引号包裹\n execSync(`rmdir /S /Q \"${path}\"`, { stdio: 'ignore' });\n } catch {\n // 忽略错误\n }\n }\n\n // 最终轮询验证(Windows 文件系统可能有延迟)\n for (let i = 0; i < 5; i++) {\n if (!existsSync(path)) return;\n const start = Date.now();\n while (Date.now() - start < 100) {\n // busy wait 100ms 让文件系统同步\n }\n }\n}\n\n/**\n * 复制文件或目录(递归)\n */\nexport function copyRecursive(src: string, dest: string): void {\n if (!existsSync(src)) {\n throw new Error(`源路径不存在: ${src}`);\n }\n\n const stat = statSync(src);\n\n if (stat.isFile()) {\n ensureDir(dirname(dest));\n copyFileSync(src, dest);\n return;\n }\n\n if (stat.isDirectory()) {\n // 如果目标已存在且是符号链接,先删除\n if (isSymlink(dest)) {\n safeRemove(dest);\n }\n ensureDir(dest);\n\n for (const entry of readdirSync(src)) {\n const srcPath = resolve(src, entry);\n const destPath = resolve(dest, entry);\n copyRecursive(srcPath, destPath);\n }\n return;\n }\n\n throw new Error(`不支持的文件类型: ${src}`);\n}\n\n/**\n * 判断两个路径是否指向同一文件(规范化后比较)\n *\n * 用于检测已有符号链接是否指向正确目标\n */\nexport function isSamePath(a: string, b: string): boolean {\n if (!a || !b) return false;\n const na = resolve(a).toLowerCase();\n const nb = resolve(b).toLowerCase();\n return na === nb;\n}\n\n/**\n * 判断路径是否为目录\n */\nexport function isDirectory(path: string): boolean {\n if (!existsSync(path)) return false;\n try {\n return statSync(path).isDirectory();\n } catch {\n return false;\n }\n}\n\n/**\n * 判断路径是否为普通文件\n */\nexport function isFile(path: string): boolean {\n if (!existsSync(path)) return false;\n try {\n return statSync(path).isFile();\n } catch {\n return false;\n }\n}\n\n/**\n * 返回相对路径(用于日志输出更友好)\n */\nexport function relativePath(from: string, to: string): string {\n return relative(from, to);\n}\n\n/**\n * 列出目录下所有 .md 文件(仅顶层,不递归),按文件名排序。\n * 目录不存在时返回空数组,不抛异常。\n *\n * 用于适配器在生成聚合文件(CLAUDE.md / AGENTS.md)时动态发现\n * rules/always/ 等目录下的规则文件,避免硬编码列表导致新增规则不生效。\n */\nexport function listMarkdownFiles(dir: string): string[] {\n if (!existsSync(dir)) return [];\n try {\n return readdirSync(dir)\n .filter((name) => name.toLowerCase().endsWith('.md'))\n .sort((a, b) => a.localeCompare(b));\n } catch {\n return [];\n }\n}\n\n/**\n * 列出目录下所有 .md 文件,返回相对于该目录的 POSIX 风格相对路径\n * (例如 \"always/global.md\")。不递归子目录的子目录以外层级,\n * 这里只做一层子目录 + 顶层文件的扫描,足够 rules/ 使用。\n */\nexport function listMarkdownFilesRecursive(dir: string): string[] {\n if (!existsSync(dir)) return [];\n const result: string[] = [];\n const walk = (current: string, prefix: string): void => {\n let entries: string[];\n try {\n entries = readdirSync(current);\n } catch {\n return;\n }\n for (const name of entries) {\n const full = join(current, name);\n let stat;\n try {\n stat = statSync(full);\n } catch {\n continue;\n }\n if (stat.isDirectory()) {\n walk(full, `${prefix}${name}/`);\n } else if (name.toLowerCase().endsWith('.md')) {\n result.push(`${prefix}${name}`);\n }\n }\n };\n walk(dir, '');\n return result.sort((a, b) => a.localeCompare(b));\n}\n","/**\n * 跨平台符号链接创建器\n *\n * 优先级:symlink > junction (Windows) > copy\n *\n * Windows 普通用户无 mklink /D 权限(需开发者模式或管理员),\n * 但 mklink /J(junction)不需要权限且行为等价于目录 symlink。\n * Linux/macOS 用 fs.symlink 即可。\n */\n\nimport { symlink, existsSync, lstatSync, readlinkSync, readdirSync, rmdirSync } from 'node:fs';\nimport { dirname, resolve, isAbsolute } from 'node:path';\nimport { ensureDir, safeRemove, isSymlink, copyRecursive } from '../utils/fs.js';\n\n/**\n * 判断路径是否是空目录(非 symlink)\n *\n * Windows 上若目标位置存在一个空的普通目录,会阻挡 symlink/junction 创建,\n * safeRemove 的 rmSync 偶尔因文件系统延迟返回成功但目录仍在,需要显式处理。\n */\nfunction isEmptyDir(path: string): boolean {\n try {\n const stat = lstatSync(path);\n if (!stat.isDirectory()) return false;\n if (isSymlink(path)) return false;\n return readdirSync(path).length === 0;\n } catch {\n return false;\n }\n}\n\nexport type SymlinkMethod = 'symlink' | 'junction' | 'copy';\n\nexport interface SymlinkResult {\n /** 是否成功 */\n success: boolean;\n /** 实际使用的方法 */\n method: SymlinkMethod;\n /** 附加信息(如降级原因) */\n message?: string;\n}\n\nexport interface CreateSymlinkOptions {\n /** 目标是目录还是文件(影响 Windows junction 判断) */\n isDirectory?: boolean;\n /** 若链接已存在或目标位置已有文件,是否强制覆盖 */\n force?: boolean;\n}\n\n/**\n * 创建跨平台符号链接(自动 fallback)\n *\n * @param target 源文件/目录绝对路径(Hub 内的)\n * @param linkPath 链接路径(工具目录内的)\n */\nexport async function createSymlink(\n target: string,\n linkPath: string,\n options: CreateSymlinkOptions = {},\n): Promise<SymlinkResult> {\n const { isDirectory = false, force = false } = options;\n\n // 确保 target 存在\n if (!existsSync(target)) {\n return {\n success: false,\n method: 'symlink',\n message: `源路径不存在: ${target}`,\n };\n }\n\n // 确保 linkPath 的父目录存在\n ensureDir(dirname(linkPath));\n\n // 若链接已存在\n if (existsSync(linkPath) || isSymlink(linkPath)) {\n if (!force) {\n // 检查是否已经指向正确目标\n const currentTarget = readLinkTargetSafe(linkPath);\n if (currentTarget && resolve(currentTarget) === resolve(target)) {\n return {\n success: true,\n method: 'symlink',\n message: '链接已存在且指向正确目标,跳过',\n };\n }\n return {\n success: false,\n method: 'symlink',\n message: `目标已存在: ${linkPath}(使用 force: true 覆盖)`,\n };\n }\n // force: 删除已有链接或文件\n safeRemove(linkPath);\n\n // Windows 兜底:safeRemove 后若空目录仍存在(文件系统延迟或 rmSync 静默失败),\n // 显式 rmdir 一次,避免后续 symlink/junction 因 EEXIST/ENOENT 失败。\n if (existsSync(linkPath) && isEmptyDir(linkPath)) {\n try {\n rmdirSync(linkPath);\n } catch {\n // 忽略,留给后续步骤报错\n }\n }\n }\n\n // 尝试方法 1: 原生 symlink(Linux/macOS 或 Windows 开发者模式)\n const symlinkType = isDirectory ? 'dir' : 'file';\n try {\n await new Promise<void>((resolvePromise, rejectPromise) => {\n symlink(target, linkPath, symlinkType, (err) => {\n if (err) rejectPromise(err);\n else resolvePromise();\n });\n });\n // Windows 上 symlink 可能\"假成功\"(回调无 err 但实际未创建)\n // 必须验证 linkPath 确实存在,否则继续 fallback\n if (existsSync(linkPath)) {\n return { success: true, method: 'symlink' };\n }\n // 假成功,继续 fallback(仅 Windows 会走到这里)\n } catch (err) {\n // Linux/macOS 上 symlink 失败是真实错误,不 fallback\n if (process.platform !== 'win32') {\n return {\n success: false,\n method: 'symlink',\n message: `symlink 创建失败: ${(err as Error).message}`,\n };\n }\n // Windows 继续 fallback\n }\n\n // 尝试方法 2: junction(仅 Windows 目录链接,无需权限)\n if (isDirectory && process.platform === 'win32') {\n try {\n await new Promise<void>((resolvePromise, rejectPromise) => {\n // Windows 上 type='junction' 创建目录 junction\n symlink(target, linkPath, 'junction', (err) => {\n if (err) rejectPromise(err);\n else resolvePromise();\n });\n });\n // junction 也可能假成功,验证存在性\n if (existsSync(linkPath)) {\n return {\n success: true,\n method: 'junction',\n message: '使用 junction(建议开启 Windows 开发者模式以获得原生 symlink)',\n };\n }\n } catch {\n // 继续降级到 copy\n }\n }\n\n // 终极 fallback: copy(保证功能可用,但失去实时性)\n try {\n copyRecursive(target, linkPath);\n return {\n success: true,\n method: 'copy',\n message: '降级为 copy(建议开启 Windows 开发者模式以获得原生 symlink)',\n };\n } catch (err) {\n return {\n success: false,\n method: 'copy',\n message: `copy fallback 失败: ${(err as Error).message}`,\n };\n }\n}\n\n/**\n * 删除符号链接(不删源)\n */\nexport async function removeSymlink(linkPath: string): Promise<void> {\n if (isSymlink(linkPath)) {\n safeRemove(linkPath);\n }\n}\n\n/**\n * 安全读取链接目标(兼容 symlink 和 junction)\n */\nfunction readLinkTargetSafe(linkPath: string): string | null {\n try {\n if (!existsSync(linkPath) && !isSymlink(linkPath)) return null;\n const stat = lstatSync(linkPath);\n if (!stat.isSymbolicLink()) return null;\n const target = readlinkSync(linkPath);\n if (isAbsolute(target)) return target;\n return resolve(dirname(linkPath), target);\n } catch {\n return null;\n }\n}\n","/**\n * Adapter 接口与基类\n *\n * 借鉴 agentsmesh 的 Plugin 架构:每个工具实现统一接口,\n * 新工具支持无需发版,社区可贡献第三方适配器。\n *\n * Stage 2 升级:apply/import/transform 从可选改为必需方法(模板方法模式)\n * - 默认实现基于 symlink/copy 自动派发\n * - 子类只需 override 特殊策略(native-import/per-project)\n */\n\nimport { existsSync, readFileSync, statSync, readdirSync } from 'node:fs';\nimport { resolve, normalize, relative, join } from 'node:path';\nimport { homedir } from 'node:os';\nimport type { HubItem, LintWarning, SyncTarget, ToolStatus, DiscoveredItem, DiscoveredCategory, ConflictStatus } from '../types.js';\nimport type { HubConfig } from '../config.js';\nimport type { ToolConfig } from './types.js';\nimport { log } from '../../utils/logger.js';\nimport { copyRecursive } from '../../utils/fs.js';\nimport { createSymlink } from '../../transforms/symlink.js';\nimport { hubPath } from '../../utils/paths.js';\n\n/**\n * 适配器接口\n *\n * 每个适配器必须实现:\n * - detect(): 检测工具是否安装、版本\n * - targets(): 返回同步目标路径列表(保留向后兼容)\n * - resolveHubItems(): 返回 (HubItem, SyncTarget) 关联列表(sync 引擎主用)\n * - apply(): 把 Hub 内容应用到工具\n * - import(): 从工具反向导入到 Hub\n * - scan(): 扫描工具目录发现所有可导入内容(导入向导用)\n * - transform(): 格式转换\n */\nexport interface ToolAdapter {\n /** 适配器名(与 hub.toml 中的 key 一致) */\n readonly name: string;\n\n /** 显示名(用于 CLI 输出) */\n readonly displayName: string;\n\n /** 工具官网或文档链接 */\n readonly homepage?: string;\n\n /** 检测工具是否安装、版本 */\n detect(): Promise<ToolStatus>;\n\n /** 返回该工具的同步目标路径列表(向后兼容) */\n targets(config: ToolConfig): SyncTarget[];\n\n /**\n * 返回 (HubItem, SyncTarget) 关联列表\n *\n * sync 引擎主用此方法:知道每个 target 对应 Hub 中的哪个文件\n *\n * @param hubConfig Hub 主配置\n * @param hubRoot Hub 根目录绝对路径\n */\n resolveHubItems(hubConfig: HubConfig, hubRoot: string): Array<{ item: HubItem; target: SyncTarget }>;\n\n /** 把 Hub 内容应用到工具 */\n apply(item: HubItem, target: SyncTarget): Promise<void>;\n\n /** 从工具反向导入到 Hub */\n import(targetPath: string): Promise<HubItem>;\n\n /**\n * 扫描工具目录,发现所有可导入内容\n *\n * 导入向导使用此方法获取工具中的所有 identity/skill/rule/mcp/preference 文件。\n * 默认返回空数组,子类必须重写以实现实际扫描逻辑。\n */\n scan(): Promise<DiscoveredItem[]>;\n\n /** 格式转换 */\n transform(content: Buffer, format: 'json' | 'toml' | 'md'): Buffer;\n\n /** 同步前 lint 检查(可选) */\n lint?(items: HubItem[]): LintWarning[];\n}\n\n/**\n * 适配器基类:提供通用 detect/apply/import/transform 实现\n *\n * 模板方法模式:\n * - apply() 根据 strategy 派发到具体实现(symlink/copy 走默认,native-import/per-project 走子类)\n * - import() 默认读取文件内容\n * - transform() 默认返回原内容\n */\nexport abstract class BaseAdapter implements ToolAdapter {\n abstract readonly name: string;\n abstract readonly displayName: string;\n readonly homepage?: string;\n\n /** 该工具的默认配置目录(如 ~/.claude) */\n protected abstract defaultConfigDir: string;\n\n /** 该工具的标志性文件(用于 detect,如 settings.json、config.toml) */\n protected abstract signatureFiles: string[];\n\n /** 该工具支持的目标类型 */\n protected abstract supportedTargets: string[];\n\n /**\n * 默认 detect 实现:检查配置目录是否存在,是否有标志性文件\n */\n async detect(): Promise<ToolStatus> {\n const configDir = this.getConfigDir();\n const configDirExists = configDir ? existsSync(configDir) : false;\n let installed = configDirExists;\n\n // 检查标志性文件\n if (configDirExists) {\n let hasSignature = false;\n for (const file of this.signatureFiles) {\n if (existsSync(resolve(configDir, file))) {\n hasSignature = true;\n break;\n }\n }\n installed = hasSignature;\n }\n\n // 尝试通过工具命令检测版本(可选)\n let version: string | undefined;\n try {\n version = await this.detectVersion();\n } catch {\n // 忽略版本检测失败\n }\n\n return {\n name: this.name,\n installed,\n configDirExists,\n version,\n configDir,\n error: installed\n ? undefined\n : configDirExists\n ? '缺少标志性文件'\n : '未安装',\n };\n }\n\n /**\n * 获取工具配置目录(子类可重写以支持环境变量重定向)\n */\n getConfigDir(): string {\n return this.expandHome(this.defaultConfigDir);\n }\n\n /**\n * 返回该工具的同步目标路径列表(子类必须实现)\n * 注意:此方法保留向后兼容;sync 引擎优先用 resolveHubItems()\n */\n abstract targets(config: ToolConfig): SyncTarget[];\n\n /**\n * 默认 resolveHubItems 实现:基于 targets() 返回路径,HubItem.relativePath 留空\n *\n * 子类应重写此方法以提供准确的 HubItem 关联\n */\n resolveHubItems(hubConfig: HubConfig, _hubRoot: string): Array<{ item: HubItem; target: SyncTarget }> {\n const toolConfig = this.getToolConfig(hubConfig);\n if (!toolConfig) return [];\n const targets = this.targets(toolConfig);\n return targets.map((target) => ({\n item: {\n type: 'preference',\n relativePath: '',\n absolutePath: '',\n },\n target,\n }));\n }\n\n /**\n * 默认 apply 实现:根据 SyncTarget.strategy 派发\n * - symlink: 用 createSymlink()\n * - copy: 用 copyRecursive()\n * - native-import: 调用子类的 applyNativeImport()\n * - per-project: 调用子类的 applyPerProject()\n */\n async apply(item: HubItem, target: SyncTarget): Promise<void> {\n if (!item.absolutePath) {\n throw new Error(`HubItem.absolutePath 为空,无法 apply 到 ${target.targetPath}`);\n }\n\n switch (target.strategy) {\n case 'symlink': {\n const r = await createSymlink(item.absolutePath, target.targetPath, {\n isDirectory: target.isDirectory,\n force: true,\n });\n if (!r.success) {\n throw new Error(`${this.name}: 创建 symlink 失败 - ${r.message}`);\n }\n if (r.method === 'copy') {\n log.warn(`${this.name}: symlink 降级为 copy(${r.message})`);\n } else if (r.method === 'junction') {\n log.debug(`${this.name}: 使用 junction(${r.message ?? ''})`);\n }\n break;\n }\n case 'copy': {\n copyRecursive(item.absolutePath, target.targetPath);\n break;\n }\n case 'native-import': {\n await this.applyNativeImport(item, target);\n break;\n }\n case 'per-project': {\n await this.applyPerProject(item, target);\n break;\n }\n default:\n throw new Error(`未知的同步策略: ${target.strategy}`);\n }\n }\n\n /** 子类可选实现:native-import 策略的具体逻辑 */\n protected async applyNativeImport(_item: HubItem, _target: SyncTarget): Promise<void> {\n throw new Error(`${this.name} 不支持 native-import 策略`);\n }\n\n /** 子类可选实现:per-project 策略的具体逻辑 */\n protected async applyPerProject(_item: HubItem, _target: SyncTarget): Promise<void> {\n throw new Error(`${this.name} 不支持 per-project 策略`);\n }\n\n /**\n * 默认 import 实现:读取目标文件内容返回 HubItem\n */\n async import(targetPath: string): Promise<HubItem> {\n const content = readFileSync(targetPath);\n return {\n type: 'preference',\n relativePath: '',\n absolutePath: targetPath,\n content,\n };\n }\n\n /** 默认 transform:直接返回原内容 */\n transform(content: Buffer, _format: 'json' | 'toml' | 'md'): Buffer {\n return content;\n }\n\n /**\n * 默认 scan 实现:返回空数组。\n * 子类必须重写此方法以扫描工具目录中的可导入内容。\n */\n async scan(): Promise<DiscoveredItem[]> {\n return [];\n }\n\n /**\n * 辅助方法:为单个文件创建 DiscoveredItem,自动检测冲突状态\n *\n * @param absolutePath 源文件绝对路径\n * @param baseDir 工具配置目录(用于计算 relativePath)\n * @param hubTargetPath 导入到 Hub 的目标相对路径\n * @param category 文件类别\n * @returns DiscoveredItem\n */\n protected makeDiscoveredItem(\n absolutePath: string,\n baseDir: string,\n hubTargetPath: string,\n category: DiscoveredCategory,\n ): DiscoveredItem | null {\n try {\n const stat = statSync(absolutePath);\n if (!stat.isFile()) return null;\n\n const relPath = relative(baseDir, absolutePath);\n const hubFullPath = hubPath(hubTargetPath);\n\n let conflict: ConflictStatus = 'none';\n let existingSize: number | undefined;\n\n if (existsSync(hubFullPath)) {\n try {\n const existingStat = statSync(hubFullPath);\n existingSize = existingStat.size;\n if (existingStat.size === stat.size) {\n const existingContent = readFileSync(hubFullPath);\n const newContent = readFileSync(absolutePath);\n conflict = existingContent.equals(newContent) ? 'exists' : 'differs';\n } else {\n conflict = 'differs';\n }\n } catch {\n conflict = 'differs';\n }\n }\n\n return {\n absolutePath,\n relativePath: relPath,\n size: stat.size,\n modified: stat.mtime.toISOString(),\n category,\n hubTargetPath,\n conflict,\n existingSize,\n tool: this.name,\n };\n } catch {\n return null;\n }\n }\n\n /**\n * 辅助方法:递归扫描目录下所有文件,为每个文件创建 DiscoveredItem\n *\n * @param dirPath 要扫描的目录绝对路径\n * @param baseDir 工具配置目录(用于计算 relativePath)\n * @param hubPrefix Hub 目标路径前缀(如 'skills'、'rules')\n * @param category 文件类别\n * @returns DiscoveredItem[]\n */\n protected scanDirectory(\n dirPath: string,\n baseDir: string,\n hubPrefix: string,\n category: DiscoveredCategory,\n ): DiscoveredItem[] {\n if (!existsSync(dirPath)) return [];\n\n const results: DiscoveredItem[] = [];\n\n const walk = (currentDir: string): void => {\n try {\n const entries = readdirSync(currentDir, { withFileTypes: true });\n for (const entry of entries) {\n const fullPath = join(currentDir, entry.name);\n if (entry.isDirectory()) {\n walk(fullPath);\n } else if (entry.isFile()) {\n const relFromDir = relative(dirPath, fullPath);\n const hubTarget = `${hubPrefix}/${relFromDir.split(/[/\\\\]/).join('/')}`;\n const item = this.makeDiscoveredItem(fullPath, baseDir, hubTarget, category);\n if (item) results.push(item);\n }\n }\n } catch {\n // 忽略权限错误等\n }\n };\n\n walk(dirPath);\n return results;\n }\n\n /**\n * 默认版本检测:返回 undefined,子类可重写\n */\n protected async detectVersion(): Promise<string | undefined> {\n return undefined;\n }\n\n /**\n * 从 hubConfig 中提取当前工具的配置\n */\n protected getToolConfig(hubConfig: HubConfig): ToolConfig | null {\n const tools = hubConfig.tools as unknown as Record<string, Record<string, unknown>>;\n const raw = tools[this.name];\n if (!raw) return null;\n return {\n enabled: (raw.enabled as boolean) ?? false,\n configDir: (raw.configDir as string) ?? '',\n syncStrategy: (raw.syncStrategy as ToolConfig['syncStrategy']) ?? 'hybrid',\n mcpFormat: raw.mcpFormat as ToolConfig['mcpFormat'] | undefined,\n ...raw,\n };\n }\n\n /**\n * 展开 ~ 为 home 目录\n */\n protected expandHome(filepath: string): string {\n if (!filepath) return filepath;\n if (filepath === '~') return homedir();\n if (filepath.startsWith('~/') || filepath.startsWith('~\\\\')) {\n return normalize(resolve(homedir(), filepath.slice(2)));\n }\n return normalize(filepath);\n }\n}\n","/**\n * TRAE 中国版适配器\n *\n * 配置目录:~/.trae-cn/\n * 标志文件:argv.json、skill-config.json、memory/user_profile.md\n * 同步目标:memory/user_profile.md、skills/、rules/、mcp.json\n *\n * TRAE 中国版的独特价值:memory/user_profile.md 是 AI 自动维护的用户画像,\n * 是 AssetPlex 身份层的天然数据源(核心差异化)\n */\n\nimport { BaseAdapter } from './base.js';\nimport type { HubItem, SyncTarget, DiscoveredItem } from '../types.js';\nimport type { HubConfig } from '../config.js';\nimport type { ToolConfig } from './types.js';\nimport { existsSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { hubPath } from '../../utils/paths.js';\n\nexport class TraeCnAdapter extends BaseAdapter {\n readonly name = 'trae-cn';\n readonly displayName = 'TRAE 中国版';\n readonly homepage = 'https://docs.trae.ai/';\n\n protected defaultConfigDir = '~/.trae-cn';\n protected signatureFiles = ['argv.json', 'skill-config.json'];\n protected supportedTargets = [\n 'memory/user_profile.md',\n 'skills/',\n 'rules/',\n 'mcp.json',\n ];\n\n /**\n * 重写 detect:TRAE CN 的特殊检测逻辑\n * - 检查 ~/.trae-cn/argv.json 是否存在\n * - 检查 ~/.trae-cn/memory/user_profile.md 是否存在(身份画像源)\n */\n async detect() {\n const configDir = this.getConfigDir();\n const argvPath = resolve(configDir, 'argv.json');\n const skillConfigPath = resolve(configDir, 'skill-config.json');\n const profilePath = resolve(configDir, 'memory/user_profile.md');\n\n const configDirExists = existsSync(configDir);\n const hasArgv = existsSync(argvPath);\n const hasSkillConfig = existsSync(skillConfigPath);\n const hasProfile = existsSync(profilePath);\n\n // 配置目录存在且有标志性文件之一即认为已安装\n const installed = configDirExists && (hasArgv || hasSkillConfig);\n\n // 将 hasProfile 状态附加到 error 字段(若已安装但 profile 缺失)\n let extraInfo: string | undefined;\n if (installed && !hasProfile) {\n extraInfo = '已安装,但 memory/user_profile.md 缺失(可运行 assetplex profile learn 生成)';\n }\n\n // 读取 ide_version.json 获取版本(如存在)\n let version: string | undefined;\n const versionPath = resolve(configDir, 'builtin/ide_version.json');\n if (existsSync(versionPath)) {\n try {\n const { readFileSync } = await import('node:fs');\n const data = JSON.parse(readFileSync(versionPath, 'utf-8'));\n version = data.version ?? data.ideVersion;\n } catch {\n // 忽略\n }\n }\n\n return {\n name: this.name,\n installed,\n configDirExists,\n version,\n configDir,\n error: installed\n ? extraInfo\n : configDirExists\n ? '缺少标志性文件'\n : '未安装',\n };\n }\n\n /**\n * 重写 resolveHubItems:明确关联 Hub 内文件与 TRAE CN 目标\n *\n * 关联关系:\n * - Hub: identity/profile.md → TRAE: memory/user_profile.md (symlink)\n * - Hub: skills/ → TRAE: skills (symlink, dir)\n * - Hub: rules/ → TRAE: rules (symlink, dir)\n * - Hub: mcp/mcp.sources.json → TRAE: mcp.json (copy, JSON 格式直接复制)\n */\n override resolveHubItems(_hubConfig: HubConfig, _hubRoot: string): Array<{ item: HubItem; target: SyncTarget }> {\n const base = this.getConfigDir();\n\n return [\n {\n item: {\n type: 'identity',\n relativePath: 'identity/profile.md',\n absolutePath: hubPath('identity/profile.md'),\n },\n target: {\n tool: this.name,\n targetPath: resolve(base, 'memory/user_profile.md'),\n strategy: 'symlink',\n isDirectory: false,\n },\n },\n {\n item: {\n type: 'skill',\n relativePath: 'skills',\n absolutePath: hubPath('skills'),\n },\n target: {\n tool: this.name,\n targetPath: resolve(base, 'skills'),\n strategy: 'symlink',\n isDirectory: true,\n },\n },\n {\n item: {\n type: 'rule',\n relativePath: 'rules',\n absolutePath: hubPath('rules'),\n },\n target: {\n tool: this.name,\n targetPath: resolve(base, 'rules'),\n strategy: 'symlink',\n isDirectory: true,\n },\n },\n {\n item: {\n type: 'mcp',\n relativePath: 'mcp/mcp.sources.json',\n absolutePath: hubPath('mcp/mcp.sources.json'),\n },\n target: {\n tool: this.name,\n targetPath: resolve(base, 'mcp.json'),\n strategy: 'copy',\n isDirectory: false,\n },\n },\n ];\n }\n\n /**\n * 同步目标列表(向后兼容)\n */\n targets(config: ToolConfig): SyncTarget[] {\n const configDir = config.configDir || this.defaultConfigDir;\n const base = this.expandHome(configDir);\n\n return [\n {\n tool: this.name,\n targetPath: resolve(base, 'memory/user_profile.md'),\n strategy: 'symlink',\n isDirectory: false,\n },\n {\n tool: this.name,\n targetPath: resolve(base, 'skills'),\n strategy: 'symlink',\n isDirectory: true,\n },\n {\n tool: this.name,\n targetPath: resolve(base, 'rules'),\n strategy: 'symlink',\n isDirectory: true,\n },\n {\n tool: this.name,\n targetPath: resolve(base, 'mcp.json'),\n strategy: 'copy',\n isDirectory: false,\n },\n ];\n }\n\n /**\n * 反向导入:从 TRAE CN 读取现有配置到 Hub\n *\n * 注意:memory/user_profile.md 是 TRAE AI 维护的,反向导入会覆盖 Hub 的 profile.md\n */\n override async import(targetPath: string): Promise<HubItem> {\n const { readFileSync } = await import('node:fs');\n const content = readFileSync(targetPath);\n\n // 根据 targetPath 推断类型\n let type: HubItem['type'] = 'preference';\n if (targetPath.includes('user_profile')) type = 'identity';\n else if (targetPath.includes('skills')) type = 'skill';\n else if (targetPath.includes('rules')) type = 'rule';\n else if (targetPath.includes('mcp')) type = 'mcp';\n\n return {\n type,\n relativePath: '',\n absolutePath: targetPath,\n content,\n };\n }\n\n /**\n * 扫描 TRAE CN 目录,发现所有可导入内容\n */\n override async scan(): Promise<DiscoveredItem[]> {\n const base = this.getConfigDir();\n const items: DiscoveredItem[] = [];\n\n // memory/user_profile.md → identity/profile.md\n const profilePath = resolve(base, 'memory/user_profile.md');\n const profileItem = this.makeDiscoveredItem(profilePath, base, 'identity/profile.md', 'identity');\n if (profileItem) items.push(profileItem);\n\n // memory/ 下其他 .md 文件 → preferences/(如 session_memory、topics 等)\n const memoryDir = resolve(base, 'memory');\n if (existsSync(memoryDir)) {\n const { readdirSync } = await import('node:fs');\n try {\n const memoryEntries = readdirSync(memoryDir, { withFileTypes: true });\n for (const entry of memoryEntries) {\n if (entry.isFile() && entry.name.endsWith('.md') && entry.name !== 'user_profile.md') {\n const fullPath = resolve(memoryDir, entry.name);\n const item = this.makeDiscoveredItem(fullPath, base, `preferences/${entry.name}`, 'preference');\n if (item) items.push(item);\n }\n }\n } catch {\n // 忽略\n }\n }\n\n // skills/ 目录 → skills/\n items.push(...this.scanDirectory(resolve(base, 'skills'), base, 'skills', 'skill'));\n\n // rules/ 目录 → rules/\n items.push(...this.scanDirectory(resolve(base, 'rules'), base, 'rules', 'rule'));\n\n // mcp.json → mcp/mcp.sources.json\n const mcpPath = resolve(base, 'mcp.json');\n const mcpItem = this.makeDiscoveredItem(mcpPath, base, 'mcp/mcp.sources.json', 'mcp');\n if (mcpItem) items.push(mcpItem);\n\n return items;\n }\n}\n","/**\n * Claude Code 适配器\n *\n * 配置目录:~/.claude/(支持 CLAUDE_CONFIG_DIR 环境变量重定向)\n * 全局 MCP:~/.claude.json(在 home 根,不在 .claude 内)\n * 标志文件:CLAUDE.md、settings.json\n *\n * 核心优势:Claude Code 原生支持 @path 导入语法,最大 5 层递归\n * AssetPlex 利用此机制,生成 ~/.claude/CLAUDE.md 聚合所有 Hub 内容的 @import\n */\n\nimport { BaseAdapter } from './base.js';\nimport type { HubItem, SyncTarget, DiscoveredItem } from '../types.js';\nimport type { HubConfig } from '../config.js';\nimport type { ToolConfig } from './types.js';\nimport { existsSync, writeFileSync, readFileSync } from 'node:fs';\nimport { resolve, basename } from 'node:path';\nimport { homedir } from 'node:os';\nimport { hubPath } from '../../utils/paths.js';\nimport { listMarkdownFilesRecursive } from '../../utils/fs.js';\n\n/**\n * CLAUDE.md 聚合内容中要 @import 的固定 Hub 文件列表\n *\n * rules/ 目录不在这里硬编码,而是在 applyNativeImport 时动态扫描,\n * 确保用户新增的规则文件无需改代码就能被 Claude Code 加载。\n */\nconst CLAUDE_MD_FIXED_IMPORTS = [\n 'identity/profile.md',\n 'identity/profile.auto.md',\n 'identity/communication-style.md',\n 'identity/tech-stack.md',\n 'identity/env.md',\n 'preferences/coding-style.md',\n 'preferences/git-workflow.md',\n];\n\n/**\n * 动态构造完整的 @import 列表:固定文件 + rules/ 下所有 .md\n */\nfunction buildImportList(): string[] {\n const rulesImports = listMarkdownFilesRecursive(hubPath('rules')).map(\n (rel) => `rules/${rel}`,\n );\n return [...CLAUDE_MD_FIXED_IMPORTS, ...rulesImports];\n}\n\n/** CLAUDE.md 自动生成头部 */\nconst CLAUDE_MD_HEADER =\n '<!-- AUTO-GENERATED by assetplex. Do not edit directly. Run `assetplex sync` to update. -->\\n';\n\nexport class ClaudeCodeAdapter extends BaseAdapter {\n readonly name = 'claude-code';\n readonly displayName = 'Claude Code';\n readonly homepage = 'https://code.claude.com/docs';\n\n protected defaultConfigDir = '~/.claude';\n protected signatureFiles = ['settings.json'];\n protected supportedTargets = [\n 'CLAUDE.md',\n 'skills/',\n 'rules/',\n 'commands/',\n 'agents/',\n ];\n\n /**\n * 重写 detect:\n * - 检查 ~/.claude/ 是否存在\n * - 支持 CLAUDE_CONFIG_DIR 环境变量重定向\n * - 检查 ~/.claude.json 是否存在(全局 MCP)\n */\n async detect() {\n const configDir = this.getConfigDir();\n const settingsPath = resolve(configDir, 'settings.json');\n const claudeMdPath = resolve(configDir, 'CLAUDE.md');\n\n const configDirExists = existsSync(configDir);\n const hasSettings = existsSync(settingsPath);\n const hasClaudeMd = existsSync(claudeMdPath);\n\n // 安装判断:目录存在且任一标志文件存在\n const installed = configDirExists && (hasSettings || hasClaudeMd);\n\n // 尝试获取 Claude Code CLI 版本\n let version: string | undefined;\n try {\n const { execSync } = await import('node:child_process');\n const output = execSync('claude --version 2>&1', {\n encoding: 'utf-8',\n timeout: 3000,\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n const match = output.match(/(\\d+\\.\\d+\\.\\d+)/);\n if (match) version = match[1];\n } catch {\n // CLI 未安装或不在 PATH\n }\n\n return {\n name: this.name,\n installed,\n configDirExists,\n version,\n configDir,\n error: installed\n ? undefined\n : configDirExists\n ? '缺少标志性文件 settings.json'\n : '未安装 Claude Code CLI',\n };\n }\n\n /**\n * 获取配置目录(支持 CLAUDE_CONFIG_DIR 环境变量)\n */\n override getConfigDir(): string {\n const fromEnv = process.env.CLAUDE_CONFIG_DIR;\n if (fromEnv) return this.expandHome(fromEnv);\n return this.expandHome(this.defaultConfigDir);\n }\n\n /**\n * 重写 resolveHubItems:明确关联 Hub 内文件与 Claude Code 目标\n *\n * 关联关系:\n * - Hub: identity/* + preferences/* + rules/* → Claude: CLAUDE.md (native-import)\n * - Hub: skills/ → Claude: skills (symlink, dir)\n * - Hub: rules/ → Claude: rules (symlink, dir)\n * - Hub: commands/ → Claude: commands (symlink, dir)\n * - Hub: agents/ → Claude: agents (symlink, dir)\n * - Hub: mcp/mcp.sources.json → Claude: ~/.claude.json (copy)\n */\n override resolveHubItems(_hubConfig: HubConfig, _hubRoot: string): Array<{ item: HubItem; target: SyncTarget }> {\n const base = this.getConfigDir();\n const home = homedir();\n\n // CLAUDE.md 用一个虚拟 HubItem 代表(applyNativeImport 会读取多个 Hub 文件聚合生成)\n const claudeMdItem: HubItem = {\n type: 'identity',\n relativePath: 'CLAUDE.md', // 虚拟路径,仅用于标识\n absolutePath: hubPath('identity/profile.md'), // 第一个被 import 的文件作为锚点\n };\n\n return [\n {\n item: claudeMdItem,\n target: {\n tool: this.name,\n targetPath: resolve(base, 'CLAUDE.md'),\n strategy: 'native-import',\n isDirectory: false,\n },\n },\n {\n item: {\n type: 'skill',\n relativePath: 'skills',\n absolutePath: hubPath('skills'),\n },\n target: {\n tool: this.name,\n targetPath: resolve(base, 'skills'),\n strategy: 'symlink',\n isDirectory: true,\n },\n },\n {\n item: {\n type: 'rule',\n relativePath: 'rules',\n absolutePath: hubPath('rules'),\n },\n target: {\n tool: this.name,\n targetPath: resolve(base, 'rules'),\n strategy: 'symlink',\n isDirectory: true,\n },\n },\n {\n item: {\n type: 'command',\n relativePath: 'commands',\n absolutePath: hubPath('commands'),\n },\n target: {\n tool: this.name,\n targetPath: resolve(base, 'commands'),\n strategy: 'symlink',\n isDirectory: true,\n },\n },\n {\n item: {\n type: 'agent',\n relativePath: 'agents',\n absolutePath: hubPath('agents'),\n },\n target: {\n tool: this.name,\n targetPath: resolve(base, 'agents'),\n strategy: 'symlink',\n isDirectory: true,\n },\n },\n // 全局 MCP 配置(在 home 根,不在 .claude 内)\n {\n item: {\n type: 'mcp',\n relativePath: 'mcp/mcp.sources.json',\n absolutePath: hubPath('mcp/mcp.sources.json'),\n },\n target: {\n tool: this.name,\n targetPath: resolve(home, '.claude.json'),\n strategy: 'copy',\n isDirectory: false,\n },\n },\n ];\n }\n\n /**\n * 同步目标列表(向后兼容)\n * 注意:CLAUDE.md 用 native-import 策略,其余用 symlink\n */\n targets(config: ToolConfig): SyncTarget[] {\n const configDir = config.configDir || this.defaultConfigDir;\n const base = this.expandHome(configDir);\n\n return [\n {\n tool: this.name,\n targetPath: resolve(base, 'CLAUDE.md'),\n strategy: 'native-import',\n isDirectory: false,\n },\n {\n tool: this.name,\n targetPath: resolve(base, 'skills'),\n strategy: 'symlink',\n isDirectory: true,\n },\n {\n tool: this.name,\n targetPath: resolve(base, 'rules'),\n strategy: 'symlink',\n isDirectory: true,\n },\n {\n tool: this.name,\n targetPath: resolve(base, 'commands'),\n strategy: 'symlink',\n isDirectory: true,\n },\n {\n tool: this.name,\n targetPath: resolve(base, 'agents'),\n strategy: 'symlink',\n isDirectory: true,\n },\n {\n tool: this.name,\n targetPath: resolve(homedir(), '.claude.json'),\n strategy: 'copy',\n isDirectory: false,\n },\n ];\n }\n\n /**\n * 重写 applyNativeImport:生成 CLAUDE.md 聚合 @import\n *\n * 生成内容:\n * <!-- AUTO-GENERATED by assetplex ... -->\n * @~/.assetplex/identity/profile.md\n * @~/.assetplex/identity/profile.auto.md\n * ...\n */\n protected override async applyNativeImport(_item: HubItem, target: SyncTarget): Promise<void> {\n const lines = [CLAUDE_MD_HEADER, ''];\n for (const relPath of buildImportList()) {\n const absPath = hubPath(relPath);\n if (existsSync(absPath)) {\n lines.push(`@${absPath.replace(/\\\\/g, '/')}`);\n }\n }\n lines.push('');\n\n writeFileSync(target.targetPath, lines.join('\\n'), 'utf-8');\n }\n\n /**\n * 重写 apply:处理 .claude.json 的特殊逻辑(直接复制,不转换格式)\n */\n override async apply(item: HubItem, target: SyncTarget): Promise<void> {\n // .claude.json 是 JSON 格式,Hub 的 mcp.sources.json 也是 JSON,直接 copy\n if (target.targetPath.endsWith('.claude.json')) {\n const content = readFileSync(item.absolutePath);\n writeFileSync(target.targetPath, content, 'utf-8');\n return;\n }\n // 其他情况走默认实现\n return super.apply(item, target);\n }\n\n /**\n * 反向导入:从 Claude Code 读 CLAUDE.md 到 Hub\n *\n * 注意:CLAUDE.md 是自动生成的,反向导入意义不大;\n * 但 .claude.json 反向导入可恢复 MCP 配置\n */\n override async import(targetPath: string): Promise<HubItem> {\n const content = readFileSync(targetPath);\n\n let type: HubItem['type'] = 'preference';\n if (targetPath.endsWith('CLAUDE.md')) type = 'identity';\n else if (targetPath.endsWith('.claude.json')) type = 'mcp';\n else if (targetPath.includes('skills')) type = 'skill';\n else if (targetPath.includes('rules')) type = 'rule';\n else if (targetPath.includes('commands')) type = 'command';\n else if (targetPath.includes('agents')) type = 'agent';\n\n return {\n type,\n relativePath: basename(targetPath),\n absolutePath: targetPath,\n content,\n };\n }\n\n /**\n * 扫描 Claude Code 目录,发现所有可导入内容\n */\n override async scan(): Promise<DiscoveredItem[]> {\n const base = this.getConfigDir();\n const home = homedir();\n const items: DiscoveredItem[] = [];\n\n // CLAUDE.md → identity/profile.md(如果不是 AUTO-GENERATED 的)\n const claudeMdPath = resolve(base, 'CLAUDE.md');\n if (existsSync(claudeMdPath)) {\n try {\n const content = readFileSync(claudeMdPath, 'utf-8');\n if (!content.includes('AUTO-GENERATED by assetplex')) {\n const item = this.makeDiscoveredItem(claudeMdPath, base, 'identity/claude-code.md', 'identity');\n if (item) items.push(item);\n }\n } catch {\n // 忽略\n }\n }\n\n // skills/ 目录\n items.push(...this.scanDirectory(resolve(base, 'skills'), base, 'skills', 'skill'));\n\n // rules/ 目录\n items.push(...this.scanDirectory(resolve(base, 'rules'), base, 'rules', 'rule'));\n\n // commands/ 目录 → commands/(preference 类别)\n items.push(...this.scanDirectory(resolve(base, 'commands'), base, 'commands', 'preference'));\n\n // agents/ 目录 → agents/(preference 类别)\n items.push(...this.scanDirectory(resolve(base, 'agents'), base, 'agents', 'preference'));\n\n // ~/.claude.json → mcp/mcp.sources.json\n const claudeJsonPath = resolve(home, '.claude.json');\n const claudeJsonItem = this.makeDiscoveredItem(claudeJsonPath, home, 'mcp/mcp.sources.json', 'mcp');\n if (claudeJsonItem) items.push(claudeJsonItem);\n\n return items;\n }\n}\n","/**\n * JSON ↔ TOML 互转器\n *\n * 主要场景:Hub 的 mcp.sources.json (JSON) → Codex 的 config.toml (TOML)\n *\n * 字段映射:\n * - mcpServers (Claude/JSON 格式) ↔ mcp_servers (Codex/TOML 格式)\n *\n * 注意:@iarna/toml 不保留注释,转换会丢注释\n */\n\nimport * as TOML from '@iarna/toml';\n\n/**\n * JSON 字符串 → TOML 字符串\n */\nexport function jsonToToml(jsonStr: string): string {\n const obj = JSON.parse(jsonStr);\n return jsonObjToToml(obj);\n}\n\n/**\n * JSON 对象 → TOML 字符串\n */\nexport function jsonObjToToml(obj: unknown): string {\n return TOML.stringify(obj as TOML.JsonMap);\n}\n\n/**\n * TOML 字符串 → JSON 对象\n */\nexport function tomlToJsonObj(tomlStr: string): unknown {\n return TOML.parse(tomlStr);\n}\n\n/**\n * TOML 字符串 → JSON 字符串(美化)\n */\nexport function tomlToJson(tomlStr: string): string {\n return JSON.stringify(TOML.parse(tomlStr), null, 2);\n}\n\n/**\n * MCP 配置:JSON → TOML\n *\n * Claude 格式:\n * { \"mcpServers\": { \"name\": { \"command\": \"...\", \"args\": [...] } } }\n *\n * Codex 格式:\n * [mcp_servers.name]\n * command = \"...\"\n * args = [...]\n *\n * 转换:mcpServers → mcp_servers(下划线转换)\n */\nexport function mcpJsonToToml(jsonStr: string): string {\n const obj = JSON.parse(jsonStr);\n const result: Record<string, unknown> = {};\n\n // 顶层 mcpServers → mcp_servers\n if (obj && typeof obj === 'object' && 'mcpServers' in obj) {\n result.mcp_servers = (obj as { mcpServers: Record<string, unknown> }).mcpServers;\n }\n\n // 保留其他顶层字段(如 model、log_level 等)\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n if (key !== 'mcpServers') {\n result[key] = value;\n }\n }\n\n return TOML.stringify(result as TOML.JsonMap);\n}\n\n/**\n * MCP 配置:TOML → JSON\n *\n * 反向:mcp_servers → mcpServers\n */\nexport function mcpTomlToJson(tomlStr: string): string {\n const obj = TOML.parse(tomlStr) as Record<string, unknown>;\n const result: Record<string, unknown> = {};\n\n // mcp_servers → mcpServers\n if ('mcp_servers' in obj) {\n result.mcpServers = obj.mcp_servers;\n }\n\n // 保留其他顶层字段\n for (const [key, value] of Object.entries(obj)) {\n if (key !== 'mcp_servers') {\n result[key] = value;\n }\n }\n\n return JSON.stringify(result, null, 2);\n}\n\n/**\n * 判断字符串是否为有效 TOML\n */\nexport function isValidToml(str: string): boolean {\n try {\n TOML.parse(str);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * 判断字符串是否为有效 JSON\n */\nexport function isValidJson(str: string): boolean {\n try {\n JSON.parse(str);\n return true;\n } catch {\n return false;\n }\n}\n","/**\n * Codex (OpenAI Codex CLI) 适配器\n *\n * 配置目录:~/.codex/\n * 标志文件:config.toml、AGENTS.md\n * MCP 格式:TOML([mcp_servers.x] 表),需要 JSON→TOML 转换\n *\n * Codex 是集成难度最大的工具:\n * - 用 TOML 格式(其他工具都用 JSON)\n * - 无 @import 显式 include 语法\n * - 仅沿目录树向上查找 AGENTS.md 合并\n *\n * Stage 2 实现:JSON→TOML 转换器 + AGENTS.md 聚合\n */\n\nimport { BaseAdapter } from './base.js';\nimport type { HubItem, SyncTarget, DiscoveredItem } from '../types.js';\nimport type { HubConfig } from '../config.js';\nimport type { ToolConfig } from './types.js';\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { hubPath } from '../../utils/paths.js';\nimport { listMarkdownFilesRecursive } from '../../utils/fs.js';\nimport { mcpJsonToToml, mcpTomlToJson } from '../../transforms/json-toml.js';\n\n/**\n * AGENTS.md 聚合内容中固定要包含的 Hub 文件\n *\n * Rules 分区动态扫描 rules/ 下所有 .md,确保新增规则无需改代码即可被 Codex 加载。\n */\nconst AGENTS_MD_FIXED_SECTIONS = [\n { title: 'Identity', files: [\n 'identity/profile.md',\n 'identity/profile.auto.md',\n 'identity/communication-style.md',\n 'identity/tech-stack.md',\n 'identity/env.md',\n ]},\n { title: 'Preferences', files: [\n 'preferences/coding-style.md',\n 'preferences/git-workflow.md',\n ]},\n];\n\n/**\n * 动态构造完整 sections:固定分区 + Rules 分区(扫描 rules/ 目录)\n */\nfunction buildAgentsSections(): Array<{ title: string; files: string[] }> {\n const rulesFiles = listMarkdownFilesRecursive(hubPath('rules')).map(\n (rel) => `rules/${rel}`,\n );\n return [...AGENTS_MD_FIXED_SECTIONS, { title: 'Rules', files: rulesFiles }];\n}\n\nexport class CodexAdapter extends BaseAdapter {\n readonly name = 'codex';\n readonly displayName = 'Codex (OpenAI Codex CLI)';\n readonly homepage = 'https://github.com/openai/codex';\n\n protected defaultConfigDir = '~/.codex';\n protected signatureFiles = ['config.toml'];\n protected supportedTargets = ['AGENTS.md', 'skills/', 'config.toml'];\n\n /**\n * 重写 detect:\n * - 检查 ~/.codex/config.toml 是否存在\n */\n async detect() {\n const configDir = this.getConfigDir();\n const configPath = resolve(configDir, 'config.toml');\n const agentsMdPath = resolve(configDir, 'AGENTS.md');\n\n const configDirExists = existsSync(configDir);\n const hasConfig = existsSync(configPath);\n const hasAgentsMd = existsSync(agentsMdPath);\n\n const installed = configDirExists && (hasConfig || hasAgentsMd);\n\n // 尝试获取 Codex CLI 版本\n let version: string | undefined;\n try {\n const { execSync } = await import('node:child_process');\n const output = execSync('codex --version 2>&1', {\n encoding: 'utf-8',\n timeout: 3000,\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n const match = output.match(/(\\d+\\.\\d+\\.\\d+)/);\n if (match) version = match[1];\n } catch {\n // CLI 未安装或不在 PATH\n }\n\n return {\n name: this.name,\n installed,\n configDirExists,\n version,\n configDir,\n error: installed\n ? undefined\n : configDirExists\n ? '缺少 config.toml'\n : '未安装 Codex CLI',\n };\n }\n\n /**\n * 重写 resolveHubItems:明确关联 Hub 内文件与 Codex 目标\n *\n * 关联关系:\n * - Hub: identity/* + preferences/* + rules/* → Codex: AGENTS.md (copy, 聚合)\n * - Hub: skills/ → Codex: skills (symlink, dir)\n * - Hub: mcp/mcp.sources.json → Codex: config.toml (copy, JSON→TOML 转换)\n */\n override resolveHubItems(_hubConfig: HubConfig, _hubRoot: string): Array<{ item: HubItem; target: SyncTarget }> {\n const base = this.getConfigDir();\n\n return [\n {\n item: {\n type: 'identity',\n relativePath: 'AGENTS.md', // 虚拟路径,apply 时会聚合多个 Hub 文件\n absolutePath: hubPath('identity/profile.md'), // 锚点文件\n },\n target: {\n tool: this.name,\n targetPath: resolve(base, 'AGENTS.md'),\n strategy: 'copy',\n isDirectory: false,\n },\n },\n {\n item: {\n type: 'skill',\n relativePath: 'skills',\n absolutePath: hubPath('skills'),\n },\n target: {\n tool: this.name,\n targetPath: resolve(base, 'skills'),\n strategy: 'symlink',\n isDirectory: true,\n },\n },\n {\n item: {\n type: 'mcp',\n relativePath: 'mcp/mcp.sources.json',\n absolutePath: hubPath('mcp/mcp.sources.json'),\n },\n target: {\n tool: this.name,\n targetPath: resolve(base, 'config.toml'),\n strategy: 'copy',\n isDirectory: false,\n },\n },\n ];\n }\n\n /**\n * 同步目标列表(向后兼容)\n */\n targets(config: ToolConfig): SyncTarget[] {\n const configDir = config.configDir || this.defaultConfigDir;\n const base = this.expandHome(configDir);\n\n return [\n {\n tool: this.name,\n targetPath: resolve(base, 'AGENTS.md'),\n strategy: 'copy',\n isDirectory: false,\n },\n {\n tool: this.name,\n targetPath: resolve(base, 'skills'),\n strategy: 'symlink',\n isDirectory: true,\n },\n {\n tool: this.name,\n targetPath: resolve(base, 'config.toml'),\n strategy: 'copy',\n isDirectory: false,\n },\n ];\n }\n\n /**\n * 重写 apply:处理 AGENTS.md 聚合 和 config.toml JSON→TOML 转换\n */\n override async apply(item: HubItem, target: SyncTarget): Promise<void> {\n // AGENTS.md:聚合多个 Hub 文件\n if (target.targetPath.endsWith('AGENTS.md')) {\n this.applyAgentsMd(target);\n return;\n }\n\n // config.toml:JSON → TOML 转换\n if (target.targetPath.endsWith('config.toml')) {\n this.applyConfigToml(item, target);\n return;\n }\n\n // 其他情况走默认实现(如 skills/ 的 symlink)\n return super.apply(item, target);\n }\n\n /**\n * 生成 AGENTS.md:聚合 Hub 内 identity + preferences + rules 内容\n */\n private applyAgentsMd(target: SyncTarget): void {\n const lines: string[] = [\n '<!-- AUTO-GENERATED by assetplex. Do not edit directly. Run `assetplex sync` to update. -->',\n '# AGENTS.md',\n '',\n '> 此文件由 assetplex 自动聚合 Hub 中的身份、偏好和规则文件生成。',\n '> 修改请编辑 ~/.assetplex/ 下对应文件后运行 `assetplex sync`。',\n '',\n ];\n\n for (const section of buildAgentsSections()) {\n lines.push(`## ${section.title}`, '');\n for (const relPath of section.files) {\n const absPath = hubPath(relPath);\n if (existsSync(absPath)) {\n const content = readFileSync(absPath, 'utf-8').trim();\n if (content) {\n lines.push(`### ${relPath}`, '', content, '');\n }\n }\n }\n }\n\n writeFileSync(target.targetPath, lines.join('\\n'), 'utf-8');\n }\n\n /**\n * 生成 config.toml:从 mcp.sources.json (JSON) 转换为 TOML\n */\n private applyConfigToml(item: HubItem, target: SyncTarget): void {\n const jsonContent = readFileSync(item.absolutePath, 'utf-8');\n const tomlContent = mcpJsonToToml(jsonContent);\n writeFileSync(target.targetPath, tomlContent, 'utf-8');\n }\n\n /**\n * 重写 transform:JSON → TOML 转换\n */\n override transform(content: Buffer, format: 'json' | 'toml' | 'md'): Buffer {\n if (format === 'toml') {\n const jsonStr = content.toString('utf-8');\n const tomlStr = mcpJsonToToml(jsonStr);\n return Buffer.from(tomlStr, 'utf-8');\n }\n return content;\n }\n\n /**\n * 反向导入:从 Codex 读 config.toml 转 JSON 到 Hub\n */\n override async import(targetPath: string): Promise<HubItem> {\n const content = readFileSync(targetPath);\n\n let type: HubItem['type'] = 'preference';\n if (targetPath.endsWith('config.toml')) type = 'mcp';\n else if (targetPath.endsWith('AGENTS.md')) type = 'identity';\n else if (targetPath.includes('skills')) type = 'skill';\n\n // 对 config.toml 做反向 TOML → JSON 转换\n if (targetPath.endsWith('config.toml')) {\n const tomlStr = content.toString('utf-8');\n const jsonStr = mcpTomlToJson(tomlStr);\n return {\n type,\n relativePath: 'mcp/mcp.sources.json',\n absolutePath: targetPath,\n content: Buffer.from(jsonStr, 'utf-8'),\n };\n }\n\n return {\n type,\n relativePath: '',\n absolutePath: targetPath,\n content,\n };\n }\n\n /**\n * 扫描 Codex 目录,发现所有可导入内容\n */\n override async scan(): Promise<DiscoveredItem[]> {\n const base = this.getConfigDir();\n const items: DiscoveredItem[] = [];\n\n // AGENTS.md → identity/codex.md(如果不是 AUTO-GENERATED 的)\n const agentsMdPath = resolve(base, 'AGENTS.md');\n if (existsSync(agentsMdPath)) {\n try {\n const content = readFileSync(agentsMdPath, 'utf-8');\n if (!content.includes('AUTO-GENERATED by assetplex')) {\n const item = this.makeDiscoveredItem(agentsMdPath, base, 'identity/codex.md', 'identity');\n if (item) items.push(item);\n }\n } catch {\n // 忽略\n }\n }\n\n // skills/ 目录\n items.push(...this.scanDirectory(resolve(base, 'skills'), base, 'skills', 'skill'));\n\n // config.toml 中的 MCP 配置 → mcp/mcp.sources.json\n // 注意:config.toml 是 TOML,makeDiscoveredItem 做的是字节比较,\n // TOML 和 JSON 格式不同会判定为 differs,这是正确行为——导入时会走 merge 逻辑\n const configTomlPath = resolve(base, 'config.toml');\n const tomlItem = this.makeDiscoveredItem(configTomlPath, base, 'mcp/mcp.sources.json', 'mcp');\n if (tomlItem) items.push(tomlItem);\n\n return items;\n }\n}\n","/**\n * 环境变量插值器\n *\n * 把字符串中的 ${VAR} 替换为 process.env.VAR 的实际值。\n *\n * 主要场景:WorkBuddy 的 .mcp.json 支持 ${VAR} 语法引用环境变量,\n * Hub 单源不能硬编码 secret,必须在同步时插值。\n *\n * 反向导入时用 desinterpolateEnv 把实际值替换回 ${VAR},\n * 但需要 envMap 提供 actual_value → VAR_NAME 的映射。\n */\n\nconst ENV_VAR_PATTERN = /\\$\\{([A-Z_][A-Z0-9_]*)\\}/g;\n\nexport interface InterpolateOptions {\n /** 自定义环境变量来源(默认 process.env) */\n env?: Record<string, string | undefined>;\n /** 严格模式:缺失变量时抛错(默认 false,缺失变量保留原样) */\n strict?: boolean;\n}\n\nexport interface InterpolateResult {\n /** 插值后的字符串 */\n output: string;\n /** 缺失的环境变量名列表 */\n missing: string[];\n /** 替换的变量名列表 */\n replaced: string[];\n}\n\n/**\n * 把字符串中的 ${VAR} 替换为 process.env.VAR\n *\n * 找不到的环境变量默认保留原样,并加入 missing 列表\n */\nexport function interpolateEnv(\n input: string,\n options: InterpolateOptions = {},\n): InterpolateResult {\n const env = options.env ?? process.env;\n const strict = options.strict ?? false;\n\n const missing = new Set<string>();\n const replaced = new Set<string>();\n\n const output = input.replace(ENV_VAR_PATTERN, (match, varName: string) => {\n const value = env[varName];\n if (value === undefined || value === '') {\n if (strict) {\n throw new Error(`环境变量缺失: ${varName}`);\n }\n missing.add(varName);\n return match; // 保留原样\n }\n replaced.add(varName);\n return value;\n });\n\n return {\n output,\n missing: Array.from(missing),\n replaced: Array.from(replaced),\n };\n}\n\n/**\n * 反向:把实际值替换回 ${VAR}\n *\n * 通过 envMap: { \"actual_value\": \"VAR_NAME\" } 反查\n *\n * 例:envMap = { \"/Users/caiwe\": \"HOME\" }\n * 输入 \"/Users/caiwe/.mcp\" → \"${HOME}/.mcp\"\n */\nexport function desinterpolateEnv(\n input: string,\n envMap: Record<string, string>,\n): string {\n let result = input;\n // 按值长度倒序排序,避免短前缀先匹配\n const sortedValues = Object.keys(envMap).sort((a, b) => b.length - a.length);\n for (const value of sortedValues) {\n if (!value) continue;\n const varName = envMap[value];\n const escaped = value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n result = result.replace(new RegExp(escaped, 'g'), `\\${${varName}}`);\n }\n return result;\n}\n\n/**\n * 从字符串中提取所有 ${VAR} 引用的变量名\n */\nexport function extractEnvVars(input: string): string[] {\n const matches = new Set<string>();\n let match: RegExpExecArray | null;\n const pattern = new RegExp(ENV_VAR_PATTERN.source, 'g');\n while ((match = pattern.exec(input)) !== null) {\n matches.add(match[1]);\n }\n return Array.from(matches);\n}\n\n/**\n * 构建 desinterpolateEnv 所需的 envMap\n *\n * @param varNames 需要反查的环境变量名列表\n * @param env 环境变量来源(默认 process.env)\n * @returns { actualValue: varName } 映射\n */\nexport function buildEnvMap(\n varNames: string[],\n env: Record<string, string | undefined> = process.env,\n): Record<string, string> {\n const map: Record<string, string> = {};\n for (const name of varNames) {\n const value = env[name];\n if (value) {\n map[value] = name;\n }\n }\n return map;\n}\n","/**\n * WorkBuddy / CodeBuddy 适配器\n *\n * 配置目录:~/.workbuddy/ 或 ~/.codebuddy/\n * 标志文件:.mcp.json(注意前导点,与 Claude Code 的 .mcp.json 同名但路径不同)\n * MCP 格式:JSON,支持 ${VAR} 环境变量插值\n *\n * WorkBuddy 特性:\n * - 同时维护新旧两个 MCP 文件(.mcp.json 与 mcp.json)\n * - models.json 用于自定义模型接入\n * - 配置文件需保存为 UTF-8 without BOM\n *\n * Stage 2 实现:${VAR} 环境变量插值(同步时展开,反向导入时去插值)\n */\n\nimport { BaseAdapter } from './base.js';\nimport type { HubItem, SyncTarget, DiscoveredItem } from '../types.js';\nimport type { HubConfig } from '../config.js';\nimport type { ToolConfig } from './types.js';\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { hubPath } from '../../utils/paths.js';\nimport {\n interpolateEnv,\n extractEnvVars,\n buildEnvMap,\n desinterpolateEnv,\n} from '../../transforms/env-interpolation.js';\n\nexport class WorkBuddyAdapter extends BaseAdapter {\n readonly name = 'workbuddy';\n readonly displayName = 'WorkBuddy / CodeBuddy';\n readonly homepage = 'https://www.tencentcloud.com/products/codebuddy';\n\n protected defaultConfigDir = '~/.workbuddy';\n protected signatureFiles = ['.mcp.json', 'mcp.json', 'models.json'];\n protected supportedTargets = ['rules/', 'skills/', '.mcp.json'];\n\n /**\n * 重写 detect:同时检查 ~/.workbuddy 和 ~/.codebuddy\n */\n async detect() {\n const workbuddyDir = this.expandHome('~/.workbuddy');\n const codebuddyDir = this.expandHome('~/.codebuddy');\n\n const workbuddyExists = existsSync(workbuddyDir);\n const codebuddyExists = existsSync(codebuddyDir);\n\n // 优先 workbuddy,回退 codebuddy\n const configDir = workbuddyExists ? workbuddyDir : codebuddyDir;\n const configDirExists = workbuddyExists || codebuddyExists;\n\n let hasSignature = false;\n if (workbuddyExists) {\n hasSignature =\n existsSync(resolve(workbuddyDir, '.mcp.json')) ||\n existsSync(resolve(workbuddyDir, 'mcp.json')) ||\n existsSync(resolve(workbuddyDir, 'models.json'));\n }\n if (!hasSignature && codebuddyExists) {\n hasSignature =\n existsSync(resolve(codebuddyDir, '.mcp.json')) ||\n existsSync(resolve(codebuddyDir, 'mcp.json')) ||\n existsSync(resolve(codebuddyDir, 'models.json'));\n }\n\n const installed = configDirExists && hasSignature;\n\n return {\n name: this.name,\n installed,\n configDirExists,\n configDir,\n error: installed\n ? undefined\n : configDirExists\n ? '缺少标志性文件'\n : '未安装 WorkBuddy/CodeBuddy',\n };\n }\n\n /**\n * 获取配置目录(动态:workbuddy 或 codebuddy)\n */\n override getConfigDir(): string {\n const workbuddyDir = this.expandHome('~/.workbuddy');\n const codebuddyDir = this.expandHome('~/.codebuddy');\n if (existsSync(workbuddyDir)) return workbuddyDir;\n if (existsSync(codebuddyDir)) return codebuddyDir;\n return workbuddyDir; // 默认\n }\n\n /**\n * 重写 resolveHubItems:明确关联 Hub 内文件与 WorkBuddy 目标\n *\n * 关联关系:\n * - Hub: rules/ → WorkBuddy: rules (symlink, dir)\n * - Hub: skills/ → WorkBuddy: skills (symlink, dir)\n * - Hub: mcp/mcp.sources.json → WorkBuddy: .mcp.json (copy, ${VAR} 插值)\n */\n override resolveHubItems(_hubConfig: HubConfig, _hubRoot: string): Array<{ item: HubItem; target: SyncTarget }> {\n const base = this.getConfigDir();\n\n return [\n {\n item: {\n type: 'rule',\n relativePath: 'rules',\n absolutePath: hubPath('rules'),\n },\n target: {\n tool: this.name,\n targetPath: resolve(base, 'rules'),\n strategy: 'symlink',\n isDirectory: true,\n },\n },\n {\n item: {\n type: 'skill',\n relativePath: 'skills',\n absolutePath: hubPath('skills'),\n },\n target: {\n tool: this.name,\n targetPath: resolve(base, 'skills'),\n strategy: 'symlink',\n isDirectory: true,\n },\n },\n // 注意前导点(与 Claude Code 的 .mcp.json 同名但路径不同)\n {\n item: {\n type: 'mcp',\n relativePath: 'mcp/mcp.sources.json',\n absolutePath: hubPath('mcp/mcp.sources.json'),\n },\n target: {\n tool: this.name,\n targetPath: resolve(base, '.mcp.json'),\n strategy: 'copy', // 需要 ${VAR} 插值\n isDirectory: false,\n },\n },\n ];\n }\n\n /**\n * 同步目标列表(向后兼容)\n */\n targets(config: ToolConfig): SyncTarget[] {\n const configDir = config.configDir || this.defaultConfigDir;\n const base = this.expandHome(configDir);\n\n return [\n {\n tool: this.name,\n targetPath: resolve(base, 'rules'),\n strategy: 'symlink',\n isDirectory: true,\n },\n {\n tool: this.name,\n targetPath: resolve(base, 'skills'),\n strategy: 'symlink',\n isDirectory: true,\n },\n {\n tool: this.name,\n targetPath: resolve(base, '.mcp.json'),\n strategy: 'copy',\n isDirectory: false,\n },\n ];\n }\n\n /**\n * 重写 apply:处理 .mcp.json 的 ${VAR} 插值\n */\n override async apply(item: HubItem, target: SyncTarget): Promise<void> {\n // .mcp.json:从 Hub 读取 JSON,做 ${VAR} 插值后写入\n if (target.targetPath.endsWith('.mcp.json')) {\n this.applyMcpJson(item, target);\n return;\n }\n\n // 其他情况走默认实现(symlink 等)\n return super.apply(item, target);\n }\n\n /**\n * 生成 .mcp.json:读取 Hub 的 mcp.sources.json,做 ${VAR} 插值\n */\n private applyMcpJson(item: HubItem, target: SyncTarget): void {\n const content = readFileSync(item.absolutePath, 'utf-8');\n\n // 提取所有 ${VAR} 引用,做插值\n const varNames = extractEnvVars(content);\n if (varNames.length === 0) {\n // 无 ${VAR},直接复制\n writeFileSync(target.targetPath, content, 'utf-8');\n return;\n }\n\n const result = interpolateEnv(content);\n if (result.missing.length > 0) {\n // 缺失变量:保留原样并记录警告(仍写入文件)\n console.warn(`[workbuddy] 缺失环境变量: ${result.missing.join(', ')}(保留为 \\${VAR} 原样)`);\n }\n writeFileSync(target.targetPath, result.output, 'utf-8');\n }\n\n /**\n * 反向导入:从 WorkBuddy 读 .mcp.json,去插值后写回 Hub\n */\n override async import(targetPath: string): Promise<HubItem> {\n const content = readFileSync(targetPath);\n\n let type: HubItem['type'] = 'preference';\n if (targetPath.endsWith('.mcp.json')) type = 'mcp';\n else if (targetPath.includes('skills')) type = 'skill';\n else if (targetPath.includes('rules')) type = 'rule';\n\n // 对 .mcp.json 做反向去插值\n if (targetPath.endsWith('.mcp.json')) {\n const str = content.toString('utf-8');\n const varNames = extractEnvVars(str);\n const envMap = buildEnvMap(varNames);\n if (Object.keys(envMap).length > 0) {\n const restored = desinterpolateEnv(str, envMap);\n return {\n type,\n relativePath: 'mcp/mcp.sources.json',\n absolutePath: targetPath,\n content: Buffer.from(restored, 'utf-8'),\n };\n }\n }\n\n return {\n type,\n relativePath: '',\n absolutePath: targetPath,\n content,\n };\n }\n\n /**\n * 扫描 WorkBuddy/CodeBuddy 目录,发现所有可导入内容\n */\n override async scan(): Promise<DiscoveredItem[]> {\n const base = this.getConfigDir();\n const items: DiscoveredItem[] = [];\n\n // skills/ 目录\n items.push(...this.scanDirectory(resolve(base, 'skills'), base, 'skills', 'skill'));\n\n // rules/ 目录\n items.push(...this.scanDirectory(resolve(base, 'rules'), base, 'rules', 'rule'));\n\n // .mcp.json → mcp/mcp.sources.json(WorkBuddy 主 MCP 文件)\n const mcpDotPath = resolve(base, '.mcp.json');\n const mcpDotItem = this.makeDiscoveredItem(mcpDotPath, base, 'mcp/mcp.sources.json', 'mcp');\n if (mcpDotItem) items.push(mcpDotItem);\n\n // mcp.json(备用,无前导点)\n const mcpPath = resolve(base, 'mcp.json');\n if (existsSync(mcpPath)) {\n // 如果 .mcp.json 不存在则使用 mcp.json,否则作为额外 MCP 文件导入到 preferences\n if (!mcpDotItem) {\n const item = this.makeDiscoveredItem(mcpPath, base, 'mcp/mcp.sources.json', 'mcp');\n if (item) items.push(item);\n } else {\n const item = this.makeDiscoveredItem(mcpPath, base, 'preferences/mcp.json', 'preference');\n if (item) items.push(item);\n }\n }\n\n // models.json → preferences/models.json\n const modelsPath = resolve(base, 'models.json');\n const modelsItem = this.makeDiscoveredItem(modelsPath, base, 'preferences/models.json', 'preference');\n if (modelsItem) items.push(modelsItem);\n\n return items;\n }\n}\n","/**\n * Qoder 适配器\n *\n * Qoder 是项目级工具,配置围绕 .qoder/ 目录展开,\n * 没有独立的用户级配置目录。\n *\n * 同步策略:per-project\n * - 按用户在 hub.toml 中配置的 project_targets 列表分发\n * - 兼容 AGENTS.md(项目根放入 AGENTS.md 自动识别)\n *\n * 权限配置 8 层优先级(来自官方 CLI 文档):\n * defaults → userSettings → localSettings → flagSettings → projectSettings\n * → enterpriseManaged → commandLine → runtime\n */\n\nimport { BaseAdapter } from './base.js';\nimport type { HubItem, SyncTarget, DiscoveredItem } from '../types.js';\nimport type { HubConfig } from '../config.js';\nimport type { ToolConfig } from './types.js';\nimport { existsSync, writeFileSync, readFileSync } from 'node:fs';\nimport { resolve, basename } from 'node:path';\nimport { hubPath } from '../../utils/paths.js';\nimport { ensureDir, copyRecursive, listMarkdownFilesRecursive } from '../../utils/fs.js';\nimport { createSymlink } from '../../transforms/symlink.js';\nimport { loadHubConfig } from '../config.js';\n\n/**\n * Qoder 项目级 AGENTS.md 中固定聚合的 Hub 文件\n *\n * rules/ 下所有 .md 动态扫描,确保新增规则无需改代码。\n */\nconst QODER_FIXED_SECTIONS = [\n 'identity/profile.md',\n 'identity/profile.auto.md',\n 'identity/communication-style.md',\n 'identity/tech-stack.md',\n 'preferences/coding-style.md',\n 'preferences/git-workflow.md',\n];\n\n/**\n * 动态构造完整聚合列表:固定文件 + rules/ 下所有 .md\n */\nfunction buildQoderSections(): string[] {\n const rulesFiles = listMarkdownFilesRecursive(hubPath('rules')).map(\n (rel) => `rules/${rel}`,\n );\n return [...QODER_FIXED_SECTIONS, ...rulesFiles];\n}\n\nexport class QoderAdapter extends BaseAdapter {\n readonly name = 'qoder';\n readonly displayName = 'Qoder';\n readonly homepage = 'https://docs.qoder.com/';\n\n protected defaultConfigDir = ''; // Qoder 无统一用户级目录\n protected signatureFiles: string[] = []; // 由项目级 .qoder/ 判定\n protected supportedTargets = ['rules/', 'skills/', 'quests/', 'knowledge/'];\n\n /**\n * 重写 detect:Qoder 无用户级目录,detect 永远返回未安装\n * sync 时会通过 resolveHubItems 返回的 targets 处理 per-project\n */\n async detect() {\n return {\n name: this.name,\n installed: false,\n configDirExists: false,\n configDir: '',\n error: 'Qoder 是项目级工具,无用户级目录;请在项目根目录扫描 .qoder/',\n };\n }\n\n /**\n * 获取配置目录(Qoder 不适用,返回空)\n */\n override getConfigDir(): string {\n return '';\n }\n\n /**\n * 重写 resolveHubItems:从 hub.toml 读取 project_targets,\n * 为每个项目生成 rules/skills/AGENTS.md 三个 target\n */\n override resolveHubItems(hubConfig: HubConfig, _hubRoot: string): Array<{ item: HubItem; target: SyncTarget }> {\n // 从 hubConfig.tools.qoder 中提取 projectTargets\n const tools = hubConfig.tools as unknown as Record<string, Record<string, unknown>>;\n const qoderConfig = tools[this.name];\n const projectTargets = (qoderConfig?.projectTargets as string[]) ?? [];\n\n // 若 enabled=false 或无 project_targets,返回空\n if (!qoderConfig?.enabled || projectTargets.length === 0) {\n return [];\n }\n\n const results: Array<{ item: HubItem; target: SyncTarget }> = [];\n\n for (const projectRoot of projectTargets) {\n const base = this.expandHome(projectRoot);\n\n // .qoder/rules ← Hub: rules/\n results.push({\n item: {\n type: 'rule',\n relativePath: 'rules',\n absolutePath: hubPath('rules'),\n },\n target: {\n tool: this.name,\n targetPath: resolve(base, '.qoder/rules'),\n strategy: 'per-project',\n isDirectory: true,\n },\n });\n\n // .qoder/skills ← Hub: skills/\n results.push({\n item: {\n type: 'skill',\n relativePath: 'skills',\n absolutePath: hubPath('skills'),\n },\n target: {\n tool: this.name,\n targetPath: resolve(base, '.qoder/skills'),\n strategy: 'per-project',\n isDirectory: true,\n },\n });\n\n // 项目根 AGENTS.md ← Hub: 聚合多个文件\n results.push({\n item: {\n type: 'identity',\n relativePath: 'AGENTS.md',\n absolutePath: hubPath('identity/profile.md'), // 锚点\n },\n target: {\n tool: this.name,\n targetPath: resolve(base, 'AGENTS.md'),\n strategy: 'per-project',\n isDirectory: false,\n },\n });\n }\n\n return results;\n }\n\n /**\n * 同步目标列表(向后兼容)\n */\n targets(config: ToolConfig): SyncTarget[] {\n const projectTargets = (config.projectTargets as string[]) ?? [];\n\n const results: SyncTarget[] = [];\n for (const projectRoot of projectTargets) {\n const base = this.expandHome(projectRoot);\n results.push({\n tool: this.name,\n targetPath: resolve(base, '.qoder/rules'),\n strategy: 'per-project',\n isDirectory: true,\n });\n results.push({\n tool: this.name,\n targetPath: resolve(base, '.qoder/skills'),\n strategy: 'per-project',\n isDirectory: true,\n });\n results.push({\n tool: this.name,\n targetPath: resolve(base, 'AGENTS.md'),\n strategy: 'per-project',\n isDirectory: false,\n });\n }\n return results;\n }\n\n /**\n * 重写 applyPerProject:\n * - 目录类(rules/skills):用 symlink,fallback 到 copy\n * - AGENTS.md:聚合 Hub 内容生成\n */\n protected override async applyPerProject(item: HubItem, target: SyncTarget): Promise<void> {\n if (target.targetPath.endsWith('AGENTS.md')) {\n this.applyAgentsMd(target);\n return;\n }\n\n // 目录类:确保父目录存在,然后创建 symlink\n ensureDir(resolve(target.targetPath, '..'));\n\n if (target.isDirectory) {\n const r = await createSymlink(item.absolutePath, target.targetPath, {\n isDirectory: true,\n force: true,\n });\n if (!r.success) {\n // symlink 失败,fallback 到 copy\n copyRecursive(item.absolutePath, target.targetPath);\n }\n } else {\n // 单文件 per-project:copy\n copyRecursive(item.absolutePath, target.targetPath);\n }\n }\n\n /**\n * 生成 AGENTS.md:聚合 Hub 内容(与 Codex 相同的聚合逻辑)\n */\n private applyAgentsMd(target: SyncTarget): void {\n const lines: string[] = [\n '<!-- AUTO-GENERATED by assetplex. Do not edit directly. Run `assetplex sync` to update. -->',\n '# AGENTS.md',\n '',\n '> 此文件由 assetplex 自动聚合 Hub 中的身份、偏好和规则文件生成。',\n '',\n ];\n\n for (const relPath of buildQoderSections()) {\n const absPath = hubPath(relPath);\n if (existsSync(absPath)) {\n const content = readFileSync(absPath, 'utf-8').trim();\n if (content) {\n lines.push(`## ${relPath}`, '', content, '');\n }\n }\n }\n\n // 确保目标目录存在\n ensureDir(resolve(target.targetPath, '..'));\n writeFileSync(target.targetPath, lines.join('\\n'), 'utf-8');\n }\n\n /**\n * 反向导入:从 Qoder 项目读文件\n */\n override async import(targetPath: string): Promise<HubItem> {\n const content = readFileSync(targetPath);\n\n let type: HubItem['type'] = 'preference';\n if (targetPath.endsWith('AGENTS.md')) type = 'identity';\n else if (targetPath.includes('skills')) type = 'skill';\n else if (targetPath.includes('rules')) type = 'rule';\n\n return {\n type,\n relativePath: basename(targetPath),\n absolutePath: targetPath,\n content,\n };\n }\n\n /**\n * 扫描 Qoder 项目目录,发现所有可导入内容\n *\n * Qoder 是项目级工具,从 hub.toml 读取 projectTargets 来确定扫描范围。\n * 为每个项目扫描 .qoder/skills/、.qoder/rules/ 和项目根 AGENTS.md。\n */\n override async scan(): Promise<DiscoveredItem[]> {\n // 读取 hub 配置获取 projectTargets\n let projectTargets: string[] = [];\n try {\n const config = loadHubConfig();\n const tools = config.tools as unknown as Record<string, { enabled?: boolean; projectTargets?: string[] }>;\n const qoderConfig = tools.qoder;\n if (qoderConfig?.enabled && qoderConfig.projectTargets?.length) {\n projectTargets = qoderConfig.projectTargets;\n }\n } catch {\n // 无法读取配置,返回空\n return [];\n }\n\n const items: DiscoveredItem[] = [];\n\n for (const projectRoot of projectTargets) {\n const base = this.expandHome(projectRoot);\n if (!existsSync(base)) continue;\n\n // 项目根 AGENTS.md → identity/qoder-<projectname>.md\n const agentsMdPath = resolve(base, 'AGENTS.md');\n if (existsSync(agentsMdPath)) {\n const projectName = basename(base) || 'project';\n try {\n const content = readFileSync(agentsMdPath, 'utf-8');\n if (!content.includes('AUTO-GENERATED by assetplex')) {\n const item = this.makeDiscoveredItem(\n agentsMdPath,\n base,\n `identity/qoder-${projectName}.md`,\n 'identity',\n );\n if (item) items.push(item);\n }\n } catch {\n // 忽略\n }\n }\n\n // .qoder/skills/ → skills/\n items.push(...this.scanDirectory(resolve(base, '.qoder/skills'), base, 'skills', 'skill'));\n\n // .qoder/rules/ → rules/\n items.push(...this.scanDirectory(resolve(base, '.qoder/rules'), base, 'rules', 'rule'));\n }\n\n return items;\n }\n}\n","/**\n * 适配器注册表\n *\n * 借鉴 agentsmesh 的 Plugin 架构:\n * - 内置适配器默认注册\n * - 第三方适配器可通过 registerAdapter() 注册\n * - 新工具支持无需发版\n */\n\nimport type { ToolAdapter } from './base.js';\nimport { TraeCnAdapter } from './trae-cn.js';\nimport { ClaudeCodeAdapter } from './claude-code.js';\nimport { CodexAdapter } from './codex.js';\nimport { WorkBuddyAdapter } from './workbuddy.js';\nimport { QoderAdapter } from './qoder.js';\n\nconst registry = new Map<string, ToolAdapter>();\n\n/** 注册适配器 */\nexport function registerAdapter(adapter: ToolAdapter): void {\n registry.set(adapter.name, adapter);\n}\n\n/** 获取适配器 */\nexport function getAdapter(name: string): ToolAdapter | undefined {\n return registry.get(name);\n}\n\n/** 获取所有已注册适配器 */\nexport function getAllAdapters(): ToolAdapter[] {\n return Array.from(registry.values());\n}\n\n/** 获取所有适配器名 */\nexport function getAdapterNames(): string[] {\n return Array.from(registry.keys());\n}\n\n/** 注册内置适配器 */\nexport function registerBuiltinAdapters(): void {\n registerAdapter(new TraeCnAdapter());\n registerAdapter(new ClaudeCodeAdapter());\n registerAdapter(new CodexAdapter());\n registerAdapter(new WorkBuddyAdapter());\n registerAdapter(new QoderAdapter());\n}\n","/**\n * 扫描器核心:协调所有适配器的 scan() 方法,返回统一的工具内容清单\n */\n\nimport type { DiscoveredItem, ToolInventory } from './types.js';\nimport { getAllAdapters } from './adapters/registry.js';\nimport { log } from '../utils/logger.js';\n\n/**\n * 扫描所有已注册工具的可导入内容\n *\n * @returns ToolInventory[] 每个工具的扫描结果\n */\nexport async function scanAll(): Promise<ToolInventory[]> {\n const adapters = getAllAdapters();\n const results: ToolInventory[] = [];\n\n for (const adapter of adapters) {\n try {\n const status = await adapter.detect();\n\n let items: DiscoveredItem[] = [];\n // Qoder 始终可扫描(项目级,detect 返回 installed=false)\n if (status.installed || adapter.name === 'qoder') {\n try {\n items = await adapter.scan();\n } catch (scanErr) {\n log.warn(`[${adapter.name}] scan 失败: ${(scanErr as Error).message}`);\n items = [];\n }\n }\n\n results.push({\n toolName: adapter.name,\n displayName: adapter.displayName,\n installed: status.installed,\n configDir: status.configDir,\n items,\n });\n } catch (err) {\n log.warn(`[${adapter.name}] detect 失败: ${(err as Error).message}`);\n results.push({\n toolName: adapter.name,\n displayName: adapter.displayName,\n installed: false,\n configDir: '',\n items: [],\n });\n }\n }\n\n return results;\n}\n","/**\n * 智能合并引擎:按文件类型处理冲突合并\n *\n * 合并策略:\n * - .md (Markdown): Hub 内容在前 + 分隔线 + 来源标注 + 新内容在后\n * - identity/*.md:结构化合并(字段级),同名字段用新值更新,新字段追加\n * - .json (MCP 配置): 深度合并 mcpServers,Hub 优先\n * - .toml: 转 JSON 合并后转回 TOML(供 Codex config.toml 使用)\n * - 其他类型: 按 Markdown 方式追加\n */\n\nimport { mcpTomlToJson, mcpJsonToToml } from '../transforms/json-toml.js';\n\n/**\n * 判断文件类型\n */\nexport function getFileType(filepath: string): 'md' | 'json' | 'toml' | 'other' {\n if (filepath.endsWith('.md')) return 'md';\n if (filepath.endsWith('.json')) return 'json';\n if (filepath.endsWith('.toml')) return 'toml';\n return 'other';\n}\n\n/**\n * Markdown 合并:Hub 内容在前,新内容追加在后\n */\nexport function mergeMarkdown(existingContent: string, newContent: string, source: string): string {\n const sourceLabel = `<!-- 以下内容从 ${source} 导入,导入时间: ${new Date().toISOString()} -->`;\n return [\n existingContent.trimEnd(),\n '',\n '---',\n '',\n sourceLabel,\n '',\n newContent.trimStart(),\n ].join('\\n');\n}\n\n/**\n * JSON 深度合并(用于 MCP 配置)\n *\n * 合并规则:\n * - mcpServers 中,Hub 已有的 server 保留(Hub 优先),新工具的 server 追加\n * - 其他顶层字段以 Hub 为准\n */\nexport function mergeMcpJson(existingContent: string, newContent: string): string {\n try {\n const existing = JSON.parse(existingContent);\n const incoming = JSON.parse(newContent);\n\n // 深度合并 mcpServers\n if (incoming.mcpServers && typeof incoming.mcpServers === 'object') {\n if (!existing.mcpServers) {\n existing.mcpServers = {};\n }\n // Hub 优先,只追加 Hub 中不存在的 server\n for (const [key, value] of Object.entries(incoming.mcpServers)) {\n if (!(key in existing.mcpServers)) {\n existing.mcpServers[key] = value;\n }\n }\n }\n\n return JSON.stringify(existing, null, 2);\n } catch {\n // JSON 解析失败,降级为 markdown 风格追加\n return mergeMarkdown(existingContent, newContent, 'mcp-json');\n }\n}\n\n/**\n * TOML 合并:转 JSON → 合并 → 转回 TOML\n */\nexport function mergeToml(existingContent: string, newContent: string): string {\n try {\n const existingJson = mcpTomlToJson(existingContent);\n const newJson = mcpTomlToJson(newContent);\n const mergedJson = mergeMcpJson(existingJson, newJson);\n return mcpJsonToToml(mergedJson);\n } catch {\n // 转换失败,降级为 markdown 风格追加\n return mergeMarkdown(existingContent, newContent, 'toml');\n }\n}\n\n/**\n * 按文件类型分发合并\n *\n * @param hubTargetPath Hub 中的目标路径(用于判断文件类型)\n * @param newContent 新内容(要导入的内容)\n * @param existingContent Hub 中已有内容\n * @param source 来源工具名(用于标注)\n * @returns 合并后的内容\n */\nexport function mergeFile(\n hubTargetPath: string,\n newContent: string,\n existingContent: string,\n source: string,\n): { content: string; action: 'merged' } {\n // identity/*.md 文件走结构化合并\n if (isStructuredTarget(hubTargetPath)) {\n return mergeStructuredMd(existingContent, newContent, source);\n }\n\n const type = getFileType(hubTargetPath);\n\n switch (type) {\n case 'json':\n return { content: mergeMcpJson(existingContent, newContent), action: 'merged' };\n case 'toml':\n return { content: mergeToml(existingContent, newContent), action: 'merged' };\n case 'md':\n default:\n return { content: mergeMarkdown(existingContent, newContent, source), action: 'merged' };\n }\n}\n\n// ========== 结构化 Markdown 合并(P1) ==========\n\n/** 结构化字段匹配模式:**字段名**:值 或 - **字段名**:值 */\nconst STRUCTURED_FIELD_RE = /^[-*\\s]*\\*\\*(.+?)\\*\\*[::]\\s*(.*)$/;\n\n/**\n * 判断目标路径是否应启用结构化合并\n * 仅 identity/ 目录下的 .md 文件启用\n */\nfunction isStructuredTarget(hubTargetPath: string): boolean {\n return hubTargetPath.startsWith('identity/') && hubTargetPath.endsWith('.md');\n}\n\n/**\n * 解析结构化 Markdown 内容\n * 将内容分为结构化字段 map 和非结构化行列表\n */\nfunction parseStructuredMd(content: string): {\n fields: Map<string, string>;\n unstructured: string[];\n} {\n const fields = new Map<string, string>();\n const unstructured: string[] = [];\n const lines = content.split('\\n');\n\n for (const line of lines) {\n const trimmed = line.trim();\n const match = trimmed.match(STRUCTURED_FIELD_RE);\n if (match) {\n const key = match[1].trim();\n const value = match[2].trim();\n fields.set(key, value);\n } else {\n unstructured.push(line);\n }\n }\n\n return { fields, unstructured };\n}\n\n/**\n * 结构化 Markdown 合并\n *\n * 策略:\n * - Hub 中有、新内容无 → 保留 Hub 字段\n * - Hub 中有、新内容有 → 用新内容更新(导入源优先)\n * - Hub 中无、新内容有 → 添加新字段\n * - 非结构化行:Hub 在前,分隔线后追加新内容的非结构化行\n */\nfunction mergeStructuredMd(\n existingContent: string,\n newContent: string,\n source: string,\n): { content: string; action: 'merged' } {\n const existing = parseStructuredMd(existingContent);\n const incoming = parseStructuredMd(newContent);\n\n const mergedFields = new Map(existing.fields);\n\n // 合并字段:新内容覆盖同名,新增不同名\n for (const [key, value] of incoming.fields) {\n mergedFields.set(key, value);\n }\n\n // 构建输出\n const lines: string[] = [];\n\n // 结构化字段(按 key 排序保证稳定输出)\n const sortedKeys = [...mergedFields.keys()].sort();\n for (const key of sortedKeys) {\n const value = mergedFields.get(key) ?? '';\n lines.push(`**${key}**:${value}`);\n }\n\n // 非结构化内容\n const existingUnstructured = existing.unstructured\n .map((l) => l.trimEnd())\n .filter((l) => l.length > 0);\n const incomingUnstructured = incoming.unstructured\n .map((l) => l.trimEnd())\n .filter((l) => l.length > 0);\n\n if (existingUnstructured.length > 0 || incomingUnstructured.length > 0) {\n lines.push('');\n if (existingUnstructured.length > 0) {\n lines.push(...existingUnstructured);\n }\n if (incomingUnstructured.length > 0) {\n if (existingUnstructured.length > 0) {\n lines.push('');\n lines.push('---');\n lines.push(`<!-- 以下内容从 ${source} 导入 -->`);\n lines.push('');\n }\n lines.push(...incomingUnstructured);\n }\n }\n\n return { content: lines.join('\\n') + '\\n', action: 'merged' };\n}\n","/**\n * Hub 文件 CRUD 封装\n *\n * 为 Web UI 提供统一的 Hub 文件列出/读取/写入/删除 API。\n */\n\nimport {\n existsSync,\n readdirSync,\n readFileSync,\n writeFileSync,\n statSync,\n unlinkSync,\n} from 'node:fs';\nimport { join, resolve, dirname, relative } from 'node:path';\nimport { getHubRoot } from '../utils/paths.js';\nimport { ensureDir } from '../utils/fs.js';\n\n/** Hub 文件类别 */\nexport type HubFileCategory =\n | 'identity'\n | 'skills'\n | 'rules'\n | 'preferences'\n | 'mcp'\n | 'commands'\n | 'agents';\n\n/** Hub 文件信息 */\nexport interface HubFileInfo {\n /** 相对于 Hub 根目录的路径,如 'identity/profile.md' */\n relativePath: string;\n /** 绝对路径 */\n absolutePath: string;\n /** 文件大小(字节) */\n size: number;\n /** 最后修改时间(ISO 字符串) */\n modified: string;\n /** 是否目录 */\n isDirectory: boolean;\n}\n\n/** 支持的类别列表 */\nexport const HUB_CATEGORIES: HubFileCategory[] = [\n 'identity',\n 'skills',\n 'rules',\n 'preferences',\n 'mcp',\n 'commands',\n 'agents',\n];\n\n/**\n * 列出指定类别下的所有文件(递归)\n */\nexport function listHubFiles(category: HubFileCategory): HubFileInfo[] {\n const hubRoot = getHubRoot();\n const categoryDir = join(hubRoot, category);\n\n if (!existsSync(categoryDir)) {\n return [];\n }\n\n const files: HubFileInfo[] = [];\n collectFiles(categoryDir, hubRoot, files);\n return files.sort((a, b) => a.relativePath.localeCompare(b.relativePath));\n}\n\nfunction collectFiles(currentDir: string, hubRoot: string, out: HubFileInfo[]): void {\n const entries = readdirSync(currentDir, { withFileTypes: true });\n for (const entry of entries) {\n const fullPath = join(currentDir, entry.name);\n if (entry.isDirectory()) {\n // 跳过隐藏目录(如 .backups、.marketplace-cache)\n if (entry.name.startsWith('.')) continue;\n collectFiles(fullPath, hubRoot, out);\n } else if (entry.isFile()) {\n // 跳过隐藏文件\n if (entry.name.startsWith('.')) continue;\n const stat = statSync(fullPath);\n out.push({\n relativePath: relative(hubRoot, fullPath).replace(/\\\\/g, '/'),\n absolutePath: fullPath,\n size: stat.size,\n modified: stat.mtime.toISOString(),\n isDirectory: false,\n });\n }\n }\n}\n\n/**\n * 读取 Hub 文件内容\n * @param relativePath 相对于 Hub 根目录的路径,如 'identity/profile.md'\n */\nexport function readHubFile(relativePath: string): { content: string; size: number; modified: string } | null {\n const hubRoot = getHubRoot();\n const fullPath = resolve(hubRoot, relativePath);\n\n // 安全检查:必须位于 hubRoot 内\n if (!fullPath.startsWith(hubRoot)) {\n throw new Error(`路径越界:${relativePath}`);\n }\n\n if (!existsSync(fullPath)) {\n return null;\n }\n\n const stat = statSync(fullPath);\n if (stat.isDirectory()) {\n throw new Error(`路径是目录而非文件:${relativePath}`);\n }\n\n return {\n content: readFileSync(fullPath, 'utf-8'),\n size: stat.size,\n modified: stat.mtime.toISOString(),\n };\n}\n\n/**\n * 写入 Hub 文件\n * @param relativePath 相对于 Hub 根目录的路径\n * @param content 文件内容\n */\nexport function writeHubFile(relativePath: string, content: string): void {\n const hubRoot = getHubRoot();\n const fullPath = resolve(hubRoot, relativePath);\n\n // 安全检查\n if (!fullPath.startsWith(hubRoot)) {\n throw new Error(`路径越界:${relativePath}`);\n }\n\n ensureDir(dirname(fullPath));\n writeFileSync(fullPath, content, 'utf-8');\n}\n\n/**\n * 删除 Hub 文件\n */\nexport function deleteHubFile(relativePath: string): void {\n const hubRoot = getHubRoot();\n const fullPath = resolve(hubRoot, relativePath);\n\n if (!fullPath.startsWith(hubRoot)) {\n throw new Error(`路径越界:${relativePath}`);\n }\n\n if (!existsSync(fullPath)) {\n return;\n }\n\n const stat = statSync(fullPath);\n if (stat.isDirectory()) {\n throw new Error(`暂不支持删除目录:${relativePath}`);\n }\n\n unlinkSync(fullPath);\n}\n\n/**\n * 创建新 Hub 文件(如果已存在则抛错)\n */\nexport function createHubFile(relativePath: string, content: string): void {\n const hubRoot = getHubRoot();\n const fullPath = resolve(hubRoot, relativePath);\n\n if (!fullPath.startsWith(hubRoot)) {\n throw new Error(`路径越界:${relativePath}`);\n }\n\n if (existsSync(fullPath)) {\n throw new Error(`文件已存在:${relativePath}`);\n }\n\n ensureDir(dirname(fullPath));\n writeFileSync(fullPath, content, 'utf-8');\n}\n\n/**\n * Hub 健康度检查\n */\nexport interface HubHealth {\n hubRoot: string;\n hubExists: boolean;\n hubTomlExists: boolean;\n fileCountByCategory: Record<string, number>;\n totalFiles: number;\n}\n\nexport function checkHubHealth(): HubHealth {\n const hubRoot = getHubRoot();\n const health: HubHealth = {\n hubRoot,\n hubExists: existsSync(hubRoot),\n hubTomlExists: existsSync(join(hubRoot, 'hub.toml')),\n fileCountByCategory: {},\n totalFiles: 0,\n };\n\n for (const cat of HUB_CATEGORIES) {\n const files = listHubFiles(cat);\n health.fileCountByCategory[cat] = files.length;\n health.totalFiles += files.length;\n }\n\n return health;\n}\n","/**\n * SyncEngine - 核心同步引擎\n *\n * 串联 Hub → 适配器 → 工具目录的完整流程。\n *\n * 借鉴:\n * - agentsmesh 的 plan/run 分离(plan 用于 --dry-run,run 用于实际执行)\n * - agentsync 的 CI-friendly skip(不可用工具优雅跳过)\n * - sync-coding-agents 的\"leave non-symlinks untouched\"\n *\n * 算法:\n * 1. plan():遍历 enabled 适配器,跳过未安装工具,对每个 (item, target) 检查状态\n * 2. run():调用 plan() 后执行 adapter.apply()\n * 3. --dry-run:只调 plan() 不执行\n * 4. --json:把 plan/result 输出为 JSON\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport type {\n HubItem,\n SyncPlan,\n SyncPlanItem,\n SyncResult,\n SyncOptions,\n SyncAction,\n ToolInventory,\n ImportRequest,\n ImportResult,\n} from './types.js';\nimport type { HubConfig } from './config.js';\nimport type { ToolAdapter } from './adapters/base.js';\nimport { getAllAdapters } from './adapters/registry.js';\nimport { getHubRoot } from '../utils/paths.js';\nimport { log } from '../utils/logger.js';\nimport { isSymlink, readSymlinkTarget } from '../utils/fs.js';\nimport { resolve } from 'node:path';\nimport { scanAll as scanAllAdapters } from './scanner.js';\nimport { mergeFile } from './merger.js';\nimport { writeHubFile, readHubFile } from './hub-files.js';\n\n/** 哨兵:工具被过滤条件排除时返回,plan() 会跳过该工具 */\nconst FILTERED_OUT = Symbol('FILTERED_OUT');\n\nexport class SyncEngine {\n constructor(\n private hubConfig: HubConfig,\n private adapters: ToolAdapter[] = getAllAdapters(),\n ) {}\n\n /**\n * 计算同步计划(不执行)\n *\n * 算法:\n * 1. 过滤 adapters:仅保留 enabled 且(--tool 指定或全部)\n * 2. 对每个 adapter:\n * - 调用 detect() 检查工具是否安装\n * - 调用 resolveHubItems() 获取 (item, target) 列表\n * - 对每个 (item, target):\n * - 检查 item.absolutePath 是否存在(不存在 → skip)\n * - 检查 target.targetPath 当前状态(已是正确 symlink → skip)\n * - 否则 → 待执行 action\n */\n async plan(options: SyncOptions = {}): Promise<SyncPlan[]> {\n const hubRoot = getHubRoot();\n const plans: SyncPlan[] = [];\n\n for (const adapter of this.adapters) {\n const planForTool = await this.planForAdapter(adapter, hubRoot, options);\n // 工具过滤时,跳过被排除工具返回的哨兵\n if (planForTool === FILTERED_OUT) continue;\n plans.push(planForTool);\n }\n\n return plans;\n }\n\n /**\n * 为单个适配器计算计划\n */\n private async planForAdapter(\n adapter: ToolAdapter,\n hubRoot: string,\n options: SyncOptions,\n ): Promise<SyncPlan | typeof FILTERED_OUT> {\n const toolName = adapter.name;\n\n // 工具过滤:兼容单工具 tool 与多工具 tools\n const toolFilter = options.tools?.length ? options.tools : options.tool ? [options.tool] : undefined;\n if (toolFilter && !toolFilter.includes(toolName)) {\n return FILTERED_OUT;\n }\n\n // 从 hubConfig 检查 enabled\n if (!this.isToolEnabled(toolName)) {\n return {\n tool: toolName,\n toolInstalled: false,\n items: [],\n };\n }\n\n // detect 工具是否安装\n let status;\n try {\n status = await adapter.detect();\n } catch (err) {\n return {\n tool: toolName,\n toolInstalled: false,\n items: [\n {\n item: { type: 'preference', relativePath: '', absolutePath: '' },\n target: {\n tool: toolName,\n targetPath: '',\n strategy: 'symlink',\n isDirectory: false,\n },\n action: 'skip',\n reason: `detect 失败: ${(err as Error).message}`,\n },\n ],\n };\n }\n\n // Qoder 即使 detect 返回未安装,仍可 per-project 同步(特殊处理)\n const isQoder = toolName === 'qoder';\n if (!status.installed && !isQoder) {\n return {\n tool: toolName,\n toolInstalled: false,\n items: [\n {\n item: { type: 'preference', relativePath: '', absolutePath: '' },\n target: {\n tool: toolName,\n targetPath: status.configDir,\n strategy: 'symlink',\n isDirectory: false,\n },\n action: 'skip',\n reason: status.error ?? 'tool not installed',\n },\n ],\n };\n }\n\n // 调用 resolveHubItems 获取 (item, target) 列表\n const hubItems = adapter.resolveHubItems(this.hubConfig, hubRoot);\n\n const items: SyncPlanItem[] = hubItems.map(({ item, target }) => {\n // 检查 Hub 源文件是否存在\n if (!item.absolutePath || !existsSync(item.absolutePath)) {\n return {\n item,\n target,\n action: 'skip',\n reason: `Hub 源不存在: ${item.relativePath || item.absolutePath}`,\n };\n }\n\n // 检查目标是否已是正确 symlink\n if (target.strategy === 'symlink' && isSymlink(target.targetPath)) {\n const currentTarget = readSymlinkTarget(target.targetPath);\n if (currentTarget && resolve(currentTarget) === resolve(item.absolutePath)) {\n return {\n item,\n target,\n action: 'skip',\n reason: '已是正确符号链接,跳过',\n };\n }\n }\n\n // 检查目标路径是否已有非 symlink 文件(覆盖预警)\n let warning: string | undefined;\n if (existsSync(target.targetPath) && !isSymlink(target.targetPath)) {\n warning = '目标路径已有非 symlink 文件,同步后将覆盖';\n }\n\n // 待执行\n return {\n item,\n target,\n action: target.strategy as SyncAction,\n warning,\n };\n });\n\n return {\n tool: toolName,\n toolInstalled: status.installed,\n items,\n };\n }\n\n /**\n * 执行同步\n */\n async run(options: SyncOptions = {}): Promise<SyncResult[]> {\n const plans = await this.plan(options);\n const results: SyncResult[] = [];\n\n for (const plan of plans) {\n const result = await this.runPlan(plan);\n results.push(result);\n }\n\n return results;\n }\n\n /**\n * 执行单个工具的同步计划\n */\n private async runPlan(plan: SyncPlan): Promise<SyncResult> {\n const startTime = Date.now();\n const errors: string[] = [];\n const warnings: string[] = [];\n let itemCount = 0;\n let skippedCount = 0;\n\n const adapter = this.adapters.find((a) => a.name === plan.tool);\n if (!adapter) {\n return {\n tool: plan.tool,\n success: false,\n itemCount: 0,\n skippedCount: plan.items.length,\n errors: [`适配器未注册: ${plan.tool}`],\n warnings: [],\n durationMs: Date.now() - startTime,\n };\n }\n\n for (const planItem of plan.items) {\n if (planItem.action === 'skip') {\n skippedCount++;\n if (planItem.reason) {\n log.debug(`[${plan.tool}] 跳过: ${planItem.reason}`);\n }\n continue;\n }\n\n try {\n await adapter.apply(planItem.item, planItem.target);\n itemCount++;\n log.debug(`[${plan.tool}] ✓ ${planItem.target.targetPath}`);\n } catch (err) {\n const msg = `${planItem.target.targetPath}: ${(err as Error).message}`;\n errors.push(msg);\n log.warn(`[${plan.tool}] ✗ ${msg}`);\n }\n }\n\n return {\n tool: plan.tool,\n success: errors.length === 0,\n itemCount,\n skippedCount,\n errors,\n warnings,\n durationMs: Date.now() - startTime,\n };\n }\n\n /**\n * 反向导入:从工具目录读回 Hub\n *\n * 注意:当前 MVP 实现仅返回 HubItem 列表,不写入 Hub;\n * 由 CLI 命令决定如何处理(询问用户确认后写入)\n */\n async reverseImport(options: SyncOptions = {}): Promise<Array<{ tool: string; items: HubItem[] }>> {\n const hubRoot = getHubRoot();\n const results: Array<{ tool: string; items: HubItem[] }> = [];\n\n for (const adapter of this.adapters) {\n const toolFilter = options.tools?.length ? options.tools : options.tool ? [options.tool] : undefined;\n if (toolFilter && !toolFilter.includes(adapter.name)) continue;\n if (!this.isToolEnabled(adapter.name)) continue;\n\n const status = await adapter.detect();\n if (!status.installed && adapter.name !== 'qoder') continue;\n\n const hubItems = adapter.resolveHubItems(this.hubConfig, hubRoot);\n const imported: HubItem[] = [];\n\n for (const { target } of hubItems) {\n if (!target.targetPath || !existsSync(target.targetPath)) continue;\n try {\n const item = await adapter.import(target.targetPath);\n imported.push(item);\n } catch (err) {\n log.warn(`[${adapter.name}] import 失败 ${target.targetPath}: ${(err as Error).message}`);\n }\n }\n\n results.push({ tool: adapter.name, items: imported });\n }\n\n return results;\n }\n\n /**\n * 扫描所有工具的可导入内容(导入向导 Step 1-2 使用)\n */\n async scanAll(): Promise<ToolInventory[]> {\n return scanAllAdapters();\n }\n\n /**\n * 执行导入:接收用户选择的条目列表,写入 Hub(导入向导 Step 4 使用)\n */\n async executeImport(request: ImportRequest): Promise<ImportResult> {\n const result: ImportResult = {\n success: true,\n created: 0,\n merged: 0,\n overwritten: 0,\n skipped: 0,\n errors: 0,\n items: [],\n };\n\n for (const item of request.items) {\n try {\n // 读取源文件内容\n const sourceContent = readFileSync(item.absolutePath, 'utf-8');\n\n // 对 Codex config.toml 做 TOML → JSON 转换\n let contentToWrite = sourceContent;\n if (item.absolutePath.endsWith('config.toml') && item.hubTargetPath.endsWith('.json')) {\n const { mcpTomlToJson } = await import('../transforms/json-toml.js');\n contentToWrite = mcpTomlToJson(sourceContent);\n }\n\n // 对 WorkBuddy .mcp.json 做去插值\n if (item.tool === 'workbuddy' && item.absolutePath.endsWith('.mcp.json')) {\n const { extractEnvVars, buildEnvMap, desinterpolateEnv } = await import(\n '../transforms/env-interpolation.js'\n );\n const varNames = extractEnvVars(contentToWrite);\n const envMap = buildEnvMap(varNames);\n if (Object.keys(envMap).length > 0) {\n contentToWrite = desinterpolateEnv(contentToWrite, envMap);\n }\n }\n\n const existing = readHubFile(item.hubTargetPath);\n\n if (!existing) {\n // 新文件:直接写入\n writeHubFile(item.hubTargetPath, contentToWrite);\n result.items.push({\n tool: item.tool,\n hubTargetPath: item.hubTargetPath,\n status: 'created',\n });\n result.created++;\n } else if (item.strategy === 'overwrite') {\n // 覆盖\n writeHubFile(item.hubTargetPath, contentToWrite);\n result.items.push({\n tool: item.tool,\n hubTargetPath: item.hubTargetPath,\n status: 'overwritten',\n });\n result.overwritten++;\n } else if (item.strategy === 'merge') {\n // 智能合并\n const merged = mergeFile(item.hubTargetPath, contentToWrite, existing.content, item.tool);\n writeHubFile(item.hubTargetPath, merged.content);\n result.items.push({\n tool: item.tool,\n hubTargetPath: item.hubTargetPath,\n status: 'merged',\n });\n result.merged++;\n } else {\n // 跳过(包括 strategy === 'skip' 或未指定策略且文件已存在)\n result.items.push({\n tool: item.tool,\n hubTargetPath: item.hubTargetPath,\n status: 'skipped',\n });\n result.skipped++;\n }\n } catch (err) {\n result.items.push({\n tool: item.tool,\n hubTargetPath: item.hubTargetPath,\n status: 'error',\n message: (err as Error).message,\n });\n result.errors++;\n result.success = false;\n }\n }\n\n return result;\n }\n\n /**\n * 判断工具在 hubConfig 中是否 enabled\n */\n private isToolEnabled(toolName: string): boolean {\n const tools = this.hubConfig.tools as unknown as Record<string, { enabled?: boolean }>;\n return tools?.[toolName]?.enabled ?? false;\n }\n}\n\n/**\n * 打印同步计划(人类可读)\n */\nexport function printSyncPlan(plans: SyncPlan[]): void {\n for (const plan of plans) {\n log.info('');\n log.info(`工具: ${plan.tool} ${plan.toolInstalled ? '✓' : '✗'}`);\n\n if (plan.items.length === 0) {\n log.info(' (无待同步条目)');\n continue;\n }\n\n for (const item of plan.items) {\n const icon = item.action === 'skip' ? '·' : '→';\n const action = item.action.padEnd(15);\n const target = item.target.targetPath || '(无)';\n log.info(` ${icon} ${action} ${target}`);\n if (item.reason) {\n log.info(` └ ${item.reason}`);\n }\n }\n }\n}\n\n/**\n * 打印同步结果(人类可读)\n */\nexport function printSyncResult(results: SyncResult[]): void {\n log.info('');\n log.info('同步结果');\n log.info('='.repeat(60));\n\n let totalItem = 0;\n let totalSkip = 0;\n let totalError = 0;\n\n for (const r of results) {\n const icon = r.success ? '✓' : '✗';\n log.info(`${icon} ${r.tool.padEnd(15)} 同步 ${r.itemCount},跳过 ${r.skippedCount},错误 ${r.errors.length}(${r.durationMs}ms)`);\n totalItem += r.itemCount;\n totalSkip += r.skippedCount;\n totalError += r.errors.length;\n\n for (const err of r.errors) {\n log.warn(` └ ${err}`);\n }\n }\n\n log.info('-'.repeat(60));\n log.info(`总计:同步 ${totalItem},跳过 ${totalSkip},错误 ${totalError}`);\n}\n","import { loadHubConfig, saveHubConfig, type HubConfig } from '../../core/config.js';\nimport { SyncEngine } from '../../core/sync-engine.js';\nimport {\n registerBuiltinAdapters,\n getAllAdapters,\n getAdapter,\n} from '../../core/adapters/registry.js';\nimport type { ToolAdapter } from '../../core/adapters/base.js';\n\n/**\n * Hub 应用上下文(单例)\n *\n * 缓存 HubConfig 与 SyncEngine 实例,避免每次请求都重新加载;\n * 配置变更时调用 saveConfig / reloadConfig 让缓存失效。\n */\nclass HubContext {\n private config: HubConfig | null = null;\n private engine: SyncEngine | null = null;\n private adaptersRegistered = false;\n\n /** 获取当前 Hub 配置(懒加载) */\n getConfig(): HubConfig {\n if (!this.config) {\n this.config = loadHubConfig();\n }\n this.ensureAdaptersRegistered();\n return this.config;\n }\n\n /** 确保内置适配器已注册(幂等) */\n private ensureAdaptersRegistered(): void {\n if (!this.adaptersRegistered) {\n registerBuiltinAdapters();\n this.adaptersRegistered = true;\n }\n }\n\n /** 获取 SyncEngine 实例(懒加载) */\n getEngine(): SyncEngine {\n if (!this.engine) {\n this.engine = new SyncEngine(this.getConfig(), this.getAllAdapters());\n }\n return this.engine;\n }\n\n /** 获取所有已注册的适配器 */\n getAllAdapters(): ToolAdapter[] {\n this.ensureAdaptersRegistered();\n return getAllAdapters();\n }\n\n /** 按 name 查找适配器 */\n getAdapter(name: string): ToolAdapter | undefined {\n return getAdapter(name);\n }\n\n /** 让配置/引擎缓存失效,下次访问时重新加载 */\n reloadConfig(): void {\n this.config = null;\n this.engine = null;\n }\n\n /** 保存新配置并刷新缓存 */\n saveConfig(config: HubConfig): void {\n saveHubConfig(config);\n this.config = config;\n this.engine = null; // 引擎依赖配置,需重建\n }\n}\n\nexport const hubContext = new HubContext();\n","/**\n * 首页 overview 聚合服务\n *\n * 聚合资产统计、连接状态、最近活动等数据,\n * 为前端首页提供单一 API 入口,避免前端多次请求。\n *\n * 对应 api-contract: GetOverviewApi\n */\n\nimport { checkHubHealth, HUB_CATEGORIES } from './hub-files.js';\nimport { hubContext } from '../server/lib/hub-context.js';\nimport type { ToolAdapter } from './adapters/base.js';\n\n/** 前端资产类别(单数形式) */\nexport type FrontendCategory = 'identity' | 'skill' | 'rule' | 'mcp';\n\n/** 后端类别到前端类别的映射 */\nconst CATEGORY_MAP: Record<string, FrontendCategory> = {\n identity: 'identity',\n skills: 'skill',\n rules: 'rule',\n mcp: 'mcp',\n};\n\n/** 工具连接状态(前端用) */\nexport type ConnectionStatus = 'synced' | 'pending' | 'not_connected' | 'not_installed';\n\n/** 工具连接信息 */\nexport interface ConnectionInfo {\n toolId: string;\n toolName: string;\n status: ConnectionStatus;\n assetCount: number;\n pendingCount: number;\n lastSyncedAt?: string;\n}\n\n/** 活动项 */\nexport interface ActivityInfo {\n id: string;\n type: 'import' | 'sync' | 'edit' | 'create';\n description: string;\n occurredAt: string;\n}\n\n/** overview 返回结构 */\nexport interface OverviewData {\n assetStats: Record<FrontendCategory, number>;\n connections: ConnectionInfo[];\n recentActivities: ActivityInfo[];\n hubInitialized: boolean;\n healthScore: number;\n}\n\n/**\n * 获取首页聚合数据\n */\nexport async function getOverview(): Promise<OverviewData> {\n const health = checkHubHealth();\n\n // 1. 资产统计(后端复数类别 → 前端单数类别)\n const assetStats = {\n identity: 0,\n skill: 0,\n rule: 0,\n mcp: 0,\n } as Record<FrontendCategory, number>;\n\n for (const cat of HUB_CATEGORIES) {\n const frontendCat = CATEGORY_MAP[cat];\n if (frontendCat) {\n assetStats[frontendCat] = health.fileCountByCategory[cat] ?? 0;\n }\n }\n\n const totalAssets = Object.values(assetStats).reduce((s, n) => s + n, 0);\n const hubInitialized = health.hubExists && health.hubTomlExists && totalAssets > 0;\n\n // 2. 健康度计算(简单算法)\n const healthScore = computeHealthScore(totalAssets);\n\n // 3. 工具连接状态\n const connections = await getConnections();\n\n // 4. 最近活动\n const recentActivities = getRecentActivities();\n\n return {\n assetStats,\n connections,\n recentActivities,\n hubInitialized,\n healthScore,\n };\n}\n\nfunction computeHealthScore(totalAssets: number): number {\n if (totalAssets === 0) return 0;\n return Math.min(100, 60 + totalAssets * 4);\n}\n\nasync function getConnections(): Promise<ConnectionInfo[]> {\n const adapters = hubContext.getAllAdapters() as ToolAdapter[];\n const config = hubContext.getConfig();\n\n const results: ConnectionInfo[] = [];\n\n for (const adapter of adapters) {\n try {\n const status = await adapter.detect();\n const toolConfig = (config.tools as Record<string, { enabled?: boolean }> | undefined)?.[adapter.name];\n const enabled = toolConfig?.enabled ?? false;\n\n if (!status.installed) {\n results.push({\n toolId: adapter.name,\n toolName: adapter.displayName,\n status: 'not_installed',\n assetCount: 0,\n pendingCount: 0,\n });\n continue;\n }\n\n // 已安装但未启用 → not_connected\n if (!enabled) {\n results.push({\n toolId: adapter.name,\n toolName: adapter.displayName,\n status: 'not_connected',\n assetCount: 0,\n pendingCount: 0,\n });\n continue;\n }\n\n // 已安装且已启用 → synced(Phase 1 简化,Phase 2 精确判断 pending)\n results.push({\n toolId: adapter.name,\n toolName: adapter.displayName,\n status: 'synced',\n assetCount: 0,\n pendingCount: 0,\n });\n } catch {\n results.push({\n toolId: adapter.name,\n toolName: adapter.displayName,\n status: 'not_installed',\n assetCount: 0,\n pendingCount: 0,\n });\n }\n }\n\n // 排序:已安装的在前\n const statusOrder: Record<ConnectionStatus, number> = { synced: 0, pending: 1, not_connected: 2, not_installed: 3 };\n results.sort((a, b) => statusOrder[a.status] - statusOrder[b.status]);\n\n return results;\n}\n\n/**\n * 获取最近活动\n *\n * Phase 1 返回空数组,Phase 3 活动页实现时接入 sync history。\n */\nfunction getRecentActivities(): ActivityInfo[] {\n return [];\n}\n","/**\n * Hub 配置相关路由\n */\n\nimport { Hono } from 'hono';\nimport { HubConfigSchema } from '../../core/config.js';\nimport { hubContext } from '../lib/hub-context.js';\nimport { checkHubHealth } from '../../core/hub-files.js';\nimport { getOverview } from '../../core/overview.js';\n\nexport const hubRoutes = new Hono();\n\n/** 读取 hub.toml 配置 */\nhubRoutes.get('/config', (c) => {\n return c.json(hubContext.getConfig());\n});\n\n/** 保存 hub.toml 配置 */\nhubRoutes.put('/config', async (c) => {\n const body = await c.req.json();\n const config = HubConfigSchema.parse(body);\n hubContext.saveConfig(config);\n return c.json({ success: true });\n});\n\n/** Hub 健康度 */\nhubRoutes.get('/health', (c) => {\n return c.json(checkHubHealth());\n});\n\n/** 首页聚合数据(资产统计 + 连接状态 + 最近活动) */\nhubRoutes.get('/overview', async (c) => {\n try {\n const data = await getOverview();\n return c.json(data);\n } catch (err) {\n return c.json(\n { error: err instanceof Error ? err.message : String(err) },\n 500,\n );\n }\n});\n","/**\n * 工具状态相关路由\n */\n\nimport { Hono } from 'hono';\nimport { hubContext } from '../lib/hub-context.js';\nimport type { DiscoveredItem } from '../../core/types.js';\n\nexport const toolsRoutes = new Hono();\n\n/** 列出所有工具及其状态 */\ntoolsRoutes.get('/', async (c) => {\n const config = hubContext.getConfig();\n const adapters = hubContext.getAllAdapters();\n const statuses = await Promise.all(adapters.map((adapter) => adapter.detect()));\n const tools = adapters.map((adapter, i) => {\n const toolConfig = (config.tools as Record<string, { enabled?: boolean }>)[adapter.name];\n return {\n ...statuses[i],\n enabled: toolConfig?.enabled ?? false,\n };\n });\n return c.json({ tools });\n});\n\n/** 单个工具详情 */\ntoolsRoutes.get('/:name', async (c) => {\n const name = c.req.param('name');\n const adapter = hubContext.getAdapter(name);\n if (!adapter) {\n return c.json({ error: `未找到工具适配器:${name}` }, 404);\n }\n const status = await adapter.detect();\n const config = hubContext.getConfig();\n const toolConfig = (config.tools as Record<string, { enabled?: boolean }>)[name];\n return c.json({\n ...status,\n enabled: toolConfig?.enabled ?? false,\n });\n});\n\n/** 切换工具启用状态 */\ntoolsRoutes.post('/:name/toggle', async (c) => {\n const name = c.req.param('name');\n const body = await c.req.json().catch(() => ({}));\n const enabled = body.enabled as boolean | undefined;\n\n const config = hubContext.getConfig();\n const tools = config.tools as Record<string, Record<string, unknown>>;\n if (!tools[name]) {\n return c.json({ error: `未找到工具配置:${name}` }, 404);\n }\n\n // 若 body 提供 enabled,则用之;否则取反当前值\n const nextEnabled = typeof enabled === 'boolean' ? enabled : !tools[name].enabled;\n tools[name].enabled = nextEnabled;\n\n hubContext.saveConfig(config);\n return c.json({ success: true, enabled: nextEnabled });\n});\n\n/** 重新检测工具 */\ntoolsRoutes.post('/:name/detect', async (c) => {\n const name = c.req.param('name');\n const adapter = hubContext.getAdapter(name);\n if (!adapter) {\n return c.json({ error: `未找到工具适配器:${name}` }, 404);\n }\n const status = await adapter.detect();\n return c.json(status);\n});\n\n/** 工具连接详情(含发现的资产文件) */\ntoolsRoutes.get('/:name/detail', async (c) => {\n const name = c.req.param('name');\n const adapter = hubContext.getAdapter(name);\n if (!adapter) {\n return c.json({ error: `未找到工具适配器:${name}` }, 404);\n }\n const status = await adapter.detect();\n const config = hubContext.getConfig();\n const toolConfig = (config.tools as Record<string, { enabled?: boolean }>)[name];\n\n const tool: Record<string, unknown> = {\n ...status,\n enabled: toolConfig?.enabled ?? false,\n };\n\n // 如果已安装,扫描发现的资产文件(用于显示\"未入库\"列表)\n let discovered:\n | {\n identities: Array<{ path: string; size: number }>;\n rules: Array<{ path: string; size: number }>;\n skills: Array<{ path: string; size: number }>;\n mcps: Array<{ path: string; size: number }>;\n }\n | undefined;\n if (status.installed) {\n try {\n const items: DiscoveredItem[] = await adapter.scan();\n discovered = {\n identities: items.filter((i) => i.category === 'identity').map((f) => ({ path: f.absolutePath, size: f.size })),\n rules: items.filter((i) => i.category === 'rule').map((f) => ({ path: f.absolutePath, size: f.size })),\n skills: items.filter((i) => i.category === 'skill').map((f) => ({ path: f.absolutePath, size: f.size })),\n mcps: items.filter((i) => i.category === 'mcp').map((f) => ({ path: f.absolutePath, size: f.size })),\n };\n } catch {\n discovered = undefined;\n }\n }\n\n return c.json({ tool, discovered });\n});\n","/**\n * 同步操作相关路由\n */\n\nimport { Hono } from 'hono';\nimport { hubContext } from '../lib/hub-context.js';\nimport type { ImportRequest } from '../../core/types.js';\n\nexport const syncRoutes = new Hono();\n\n// 简单内存历史记录(首版不持久化)\nconst syncHistory: Array<{\n timestamp: string;\n tool?: string;\n dryRun: boolean;\n results: unknown[];\n}> = [];\n\n/** 解析工具过滤参数:支持 ?tool=a&tool=b 或 ?tools=a,b */\nfunction parseTools(query: Record<string, string | string[]>): { tool?: string; tools?: string[] } {\n const raw = query.tool;\n const list = Array.isArray(raw) ? raw : raw ? [raw] : [];\n const toolsRaw = query.tools;\n const fromCsv = (Array.isArray(toolsRaw) ? toolsRaw.join(',') : toolsRaw ?? '')\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n const all = [...list, ...fromCsv];\n if (all.length === 0) return {};\n if (all.length === 1) return { tool: all[0] };\n return { tools: all };\n}\n\n/** 获取同步计划 */\nsyncRoutes.get('/plan', async (c) => {\n const filter = parseTools(c.req.query() as Record<string, string | string[]>);\n const engine = hubContext.getEngine();\n const plans = await engine.plan(filter);\n return c.json({ plans });\n});\n\n/** 执行同步 */\nsyncRoutes.post('/run', async (c) => {\n const filter = parseTools(c.req.query() as Record<string, string | string[]>);\n const dryRun = c.req.query('dryRun') === 'true';\n const engine = hubContext.getEngine();\n const results = await engine.run({ ...filter, dryRun });\n\n // 记录历史\n syncHistory.unshift({\n timestamp: new Date().toISOString(),\n tool: filter.tool,\n dryRun,\n results,\n });\n // 保留最近 20 条\n if (syncHistory.length > 20) syncHistory.pop();\n\n return c.json({ results });\n});\n\n/** 反向导入 */\nsyncRoutes.post('/reverse-import', async (c) => {\n const filter = parseTools(c.req.query() as Record<string, string | string[]>);\n const engine = hubContext.getEngine();\n const results = await engine.reverseImport(filter);\n return c.json({ results });\n});\n\n/** 同步历史记录 */\nsyncRoutes.get('/history', (c) => {\n return c.json({ history: syncHistory });\n});\n\n/** 扫描所有工具的可导入内容(导入向导 Step 1-2) */\nsyncRoutes.get('/scan', async (c) => {\n const engine = hubContext.getEngine();\n const inventories = await engine.scanAll();\n return c.json({ inventories });\n});\n\n/** 获取文件内容用于 diff 对比(导入向导 Step 3 冲突预览) */\nsyncRoutes.get('/diff', async (c) => {\n const sourcePath = c.req.query('sourcePath');\n const hubTargetPath = c.req.query('hubTargetPath');\n\n if (!sourcePath || !hubTargetPath) {\n return c.json({ error: '缺少 sourcePath 或 hubTargetPath 参数' }, 400);\n }\n\n const { existsSync, readFileSync } = await import('node:fs');\n const { readHubFile } = await import('../../core/hub-files.js');\n\n // 安全校验:sourcePath 必须是绝对路径且在用户目录下\n const { homedir } = await import('node:os');\n const { resolve: pathResolve } = await import('node:path');\n const home = pathResolve(homedir());\n const normalizedSource = pathResolve(sourcePath);\n if (!normalizedSource.startsWith(home)) {\n return c.json({ error: 'sourcePath 不在用户目录范围内' }, 403);\n }\n if (!existsSync(normalizedSource)) {\n return c.json({ error: '源文件不存在' }, 404);\n }\n\n let sourceContent: string;\n try {\n sourceContent = readFileSync(normalizedSource, 'utf-8');\n } catch {\n return c.json({ error: '无法读取源文件' }, 500);\n }\n\n let hubContent: string | null = null;\n const hubFile = readHubFile(hubTargetPath);\n if (hubFile) {\n hubContent = hubFile.content;\n }\n\n return c.json({\n sourceContent,\n hubContent,\n sourcePath,\n hubTargetPath,\n });\n});\n\n/** 执行导入(导入向导 Step 4) */\nsyncRoutes.post('/execute-import', async (c) => {\n const body = await c.req.json<ImportRequest>();\n if (!body.items || !Array.isArray(body.items)) {\n return c.json({ error: '缺少 items 字段或格式错误' }, 400);\n }\n const engine = hubContext.getEngine();\n const result = await engine.executeImport(body);\n return c.json(result);\n});\n","/**\n * Hub 文件 CRUD 路由\n */\n\nimport { Hono } from 'hono';\nimport {\n listHubFiles,\n readHubFile,\n writeHubFile,\n deleteHubFile,\n createHubFile,\n HUB_CATEGORIES,\n type HubFileCategory,\n} from '../../core/hub-files.js';\n\nexport const filesRoutes = new Hono();\n\n/** 列出 Hub 文件(按类别) */\nfilesRoutes.get('/', (c) => {\n const category = c.req.query('category') as HubFileCategory | undefined;\n\n if (category) {\n if (!HUB_CATEGORIES.includes(category)) {\n return c.json(\n { error: `无效的类别:${category},支持:${HUB_CATEGORIES.join(', ')}` },\n 400,\n );\n }\n return c.json({ files: listHubFiles(category) });\n }\n\n // 无 category 时返回所有类别\n const allFiles = HUB_CATEGORIES.flatMap((cat) => listHubFiles(cat));\n return c.json({ files: allFiles });\n});\n\n/** 读取单个文件 */\nfilesRoutes.get('/*', (c) => {\n const path = c.req.path.replace('/api/files/', '');\n if (!path) {\n return c.json({ error: '缺少文件路径' }, 400);\n }\n const file = readHubFile(path);\n if (!file) {\n return c.json({ error: `文件不存在:${path}` }, 404);\n }\n return c.json({ path, ...file });\n});\n\n/** 写入文件(已存在则覆盖) */\nfilesRoutes.put('/*', async (c) => {\n const path = c.req.path.replace('/api/files/', '');\n if (!path) {\n return c.json({ error: '缺少文件路径' }, 400);\n }\n const body = await c.req.json();\n if (typeof body.content !== 'string') {\n return c.json({ error: '请求体必须包含 content 字段' }, 400);\n }\n writeHubFile(path, body.content);\n return c.json({ success: true, path });\n});\n\n/** 创建新文件(已存在则报错) */\nfilesRoutes.post('/', async (c) => {\n const body = await c.req.json();\n if (typeof body.path !== 'string' || typeof body.content !== 'string') {\n return c.json({ error: '请求体必须包含 path 和 content 字段' }, 400);\n }\n try {\n createHubFile(body.path, body.content);\n return c.json({ success: true, path: body.path });\n } catch (err) {\n return c.json(\n { error: err instanceof Error ? err.message : String(err) },\n 400,\n );\n }\n});\n\n/** 删除文件 */\nfilesRoutes.delete('/*', (c) => {\n const path = c.req.path.replace('/api/files/', '');\n if (!path) {\n return c.json({ error: '缺少文件路径' }, 400);\n }\n try {\n deleteHubFile(path);\n return c.json({ success: true });\n } catch (err) {\n return c.json(\n { error: err instanceof Error ? err.message : String(err) },\n 400,\n );\n }\n});\n","/**\n * 资产查询服务\n *\n * 将 Hub 文件系统中的文件转换为前端所需的 Asset 对象,\n * 支持按类别筛选、关键字搜索。\n *\n * 对应 api-contract: ListAssetsApi, GetAssetApi\n */\n\nimport {\n listHubFiles,\n readHubFile,\n HUB_CATEGORIES,\n type HubFileInfo,\n type HubFileCategory,\n} from './hub-files.js';\n\n/** 前端资产类别 */\nexport type AssetCategory = 'identity' | 'skill' | 'rule' | 'mcp';\n\n/** 资产来源(Phase 1 统一为 manual,Phase 2 记录真实来源) */\nexport type AssetSource = 'trae' | 'workbuddy' | 'claude' | 'codex' | 'qoder' | 'manual' | 'merged';\n\n/** 同步状态 */\nexport type SyncStatus = 'synced' | 'pending' | 'conflict' | 'not_enabled' | 'not_installed';\n\n/** 资产分发状态 */\nexport interface AssetDistribution {\n toolId: string;\n toolName: string;\n status: SyncStatus;\n toolPath?: string;\n lastSyncedAt?: string;\n}\n\n/** Hub 中的资产 */\nexport interface Asset {\n id: string;\n name: string;\n category: AssetCategory;\n hubPath: string;\n source: AssetSource;\n lastModifiedAt: string;\n size: number;\n distributions: AssetDistribution[];\n}\n\n/** 资产详情(含内容) */\nexport interface AssetDetail extends Asset {\n content: string;\n}\n\n/** 后端目录到前端类别的映射 */\nconst DIR_TO_CATEGORY: Record<string, AssetCategory> = {\n identity: 'identity',\n skills: 'skill',\n rules: 'rule',\n mcp: 'mcp',\n};\n\n/** 查询参数 */\nexport interface ListAssetsParams {\n category?: AssetCategory;\n search?: string;\n}\n\n/** 查询结果 */\nexport interface ListAssetsResult {\n items: Asset[];\n total: number;\n}\n\n/**\n * 列出 Hub 中的资产\n */\nexport async function listAssets(params: ListAssetsParams = {}): Promise<ListAssetsResult> {\n const { category, search } = params;\n\n // 确定要扫描的后端目录\n const categoriesToScan: HubFileCategory[] = category\n ? (() => {\n // 前端类别 → 后端目录名(反向映射)\n const reverse: Record<AssetCategory, HubFileCategory> = {\n identity: 'identity',\n skill: 'skills',\n rule: 'rules',\n mcp: 'mcp',\n };\n return [reverse[category]];\n })()\n : HUB_CATEGORIES.filter((c) => c in DIR_TO_CATEGORY);\n\n // 收集所有文件\n const allFiles: Array<{ file: HubFileInfo; category: AssetCategory }> = [];\n for (const hubCat of categoriesToScan) {\n const frontendCat = DIR_TO_CATEGORY[hubCat];\n if (!frontendCat) continue;\n const files = listHubFiles(hubCat);\n for (const f of files) {\n allFiles.push({ file: f, category: frontendCat });\n }\n }\n\n // 转换为 Asset\n let assets = allFiles.map(({ file, category }) => hubFileToAsset(file, category));\n\n // 搜索过滤\n if (search && search.trim()) {\n const q = search.trim().toLowerCase();\n assets = assets.filter((a) => a.name.toLowerCase().includes(q));\n }\n\n // 按修改时间倒序\n assets.sort((a, b) => new Date(b.lastModifiedAt).getTime() - new Date(a.lastModifiedAt).getTime());\n\n return { items: assets, total: assets.length };\n}\n\n/**\n * 获取单个资产详情(含内容)\n */\nexport async function getAsset(hubPath: string): Promise<AssetDetail | null> {\n const fileData = readHubFile(hubPath);\n if (!fileData) return null;\n\n // 从路径推断类别\n const category = inferCategoryFromPath(hubPath);\n if (!category) return null;\n\n // 构造一个 HubFileInfo 用于转换\n const file: HubFileInfo = {\n relativePath: hubPath,\n absolutePath: '',\n size: fileData.size,\n modified: fileData.modified,\n isDirectory: false,\n };\n\n const asset = hubFileToAsset(file, category);\n return {\n ...asset,\n content: fileData.content,\n };\n}\n\n/**\n * 从 Hub 文件路径推断资产类别\n */\nfunction inferCategoryFromPath(hubPath: string): AssetCategory | null {\n const firstSegment = hubPath.split('/')[0];\n return DIR_TO_CATEGORY[firstSegment] ?? null;\n}\n\n/**\n * 将 HubFileInfo 转换为前端 Asset\n */\nfunction hubFileToAsset(file: HubFileInfo, category: AssetCategory): Asset {\n const name = extractName(file.relativePath, category);\n return {\n id: file.relativePath,\n name,\n category,\n hubPath: file.relativePath,\n source: 'manual', // Phase 1 默认,Phase 2 从导入记录中读取真实来源\n lastModifiedAt: file.modified,\n size: file.size,\n distributions: [], // Phase 1 空数组,Phase 2 连接页实现时填充\n };\n}\n\n/**\n * 从相对路径提取资产名称(不含扩展名和目录前缀)\n */\nfunction extractName(relativePath: string, _category: AssetCategory): string {\n // 取最后一段,去掉扩展名\n const basename = relativePath.split('/').pop() ?? relativePath;\n const dotIndex = basename.lastIndexOf('.');\n return dotIndex > 0 ? basename.substring(0, dotIndex) : basename;\n}\n","/**\n * 资产 API 路由\n *\n * 提供资产列表查询、单资产详情、创建/更新/删除、分发配置等接口。\n * 对应 api-contract: ListAssetsApi, GetAssetApi, CreateAssetApi, UpdateAssetApi 等\n */\n\nimport { Hono } from 'hono';\nimport { listAssets, getAsset } from '../../core/assets.js';\nimport { createHubFile, writeHubFile } from '../../core/hub-files.js';\nimport type { AssetCategory } from '../../core/assets.js';\n\nexport const assetsRoutes = new Hono();\n\n/** 列出资产 */\nassetsRoutes.get('/', async (c) => {\n const category = c.req.query('category') as AssetCategory | undefined;\n const search = c.req.query('search') as string | undefined;\n\n // 校验 category\n const validCategories: AssetCategory[] = ['identity', 'skill', 'rule', 'mcp'];\n if (category && !validCategories.includes(category)) {\n return c.json({ error: `无效类别:${category},支持:${validCategories.join(', ')}` }, 400);\n }\n\n const result = await listAssets({ category, search });\n return c.json(result);\n});\n\n/** 获取单个资产详情 */\nassetsRoutes.get('/:id{.+}', async (c) => {\n const id = c.req.param('id');\n if (!id) return c.json({ error: '缺少资产ID' }, 400);\n\n // ID 即 hubPath,需要从 URL 中还原路径\n const hubPath = decodeURIComponent(id);\n const asset = await getAsset(hubPath);\n if (!asset) {\n return c.json({ error: `资产不存在:${hubPath}` }, 404);\n }\n return c.json(asset);\n});\n\n/** 创建新资产 */\nassetsRoutes.post('/', async (c) => {\n const body = await c.req.json<{ name: string; category: AssetCategory; content: string }>();\n if (!body.name || !body.category || typeof body.content !== 'string') {\n return c.json({ error: '必须提供 name、category、content 字段' }, 400);\n }\n\n const validCategories: AssetCategory[] = ['identity', 'skill', 'rule', 'mcp'];\n if (!validCategories.includes(body.category)) {\n return c.json({ error: `无效类别:${body.category}` }, 400);\n }\n\n // 前端类别 → 后端目录\n const dirMap: Record<AssetCategory, string> = {\n identity: 'identity',\n skill: 'skills',\n rule: 'rules',\n mcp: 'mcp',\n };\n const ext = body.category === 'mcp' ? '.json' : '.md';\n const hubPath = `${dirMap[body.category]}/${body.name}${ext}`;\n\n try {\n createHubFile(hubPath, body.content);\n const asset = await getAsset(hubPath);\n return c.json({ asset }, 201);\n } catch (err) {\n return c.json({ error: err instanceof Error ? err.message : String(err) }, 400);\n }\n});\n\n/** 更新资产内容 */\nassetsRoutes.put('/:id{.+}', async (c) => {\n const id = c.req.param('id');\n const hubPath = decodeURIComponent(id);\n const body = await c.req.json<{ content: string }>();\n if (typeof body.content !== 'string') {\n return c.json({ error: '必须提供 content 字段' }, 400);\n }\n\n try {\n writeHubFile(hubPath, body.content);\n const asset = await getAsset(hubPath);\n return c.json({ asset });\n } catch (err) {\n return c.json({ error: err instanceof Error ? err.message : String(err) }, 400);\n }\n});\n","import type { Context, Next } from 'hono';\nimport { ZodError } from 'zod';\n\n/**\n * 统一错误处理中间件\n * - ZodError → 400 校验失败\n * - 其他错误 → 500 内部错误\n */\nexport async function errorHandler(c: Context, next: Next) {\n try {\n await next();\n } catch (err) {\n if (err instanceof ZodError) {\n return c.json(\n {\n error: '请求参数校验失败',\n details: err.errors,\n },\n 400,\n );\n }\n const message = err instanceof Error ? err.message : String(err);\n return c.json({ error: message }, 500);\n }\n}\n","/**\n * AssetPlex Web UI HTTP 服务入口\n *\n * 使用 Hono 框架承载 API 与静态前端资源。\n * 用户运行 `assetplex ui` 后启动此服务,浏览器访问即可。\n */\n\nimport { Hono } from 'hono';\nimport { logger } from 'hono/logger';\nimport { cors } from 'hono/cors';\nimport { serve } from '@hono/node-server';\nimport { serveStatic } from '@hono/node-server/serve-static';\nimport { log as appLog } from '../utils/logger.js';\nimport { hubRoutes } from './routes/hub.js';\nimport { toolsRoutes } from './routes/tools.js';\nimport { syncRoutes } from './routes/sync.js';\nimport { filesRoutes } from './routes/files.js';\nimport { assetsRoutes } from './routes/assets.js';\nimport { errorHandler } from './middleware/error.js';\n\nexport interface ServerOptions {\n /** 端口号,默认 17521 */\n port?: number;\n /** 监听地址,默认 127.0.0.1(仅本机) */\n host?: string;\n /** 是否自动打开浏览器,默认 true */\n openBrowser?: boolean;\n}\n\n/**\n * 启动 Web UI HTTP 服务\n *\n * - /api/* 由 Hono 路由处理\n * - 其他路径由静态文件服务处理(生产环境,前端产物位于 ./web/dist)\n */\nexport async function startServer(options: ServerOptions = {}): Promise<void> {\n const { port = 17521, host = '127.0.0.1', openBrowser = true } = options;\n\n const app = new Hono();\n\n // 中间件\n app.use('*', logger());\n app.use('*', cors({ origin: [`http://localhost:${port}`, `http://${host}:${port}`] }));\n app.use('*', errorHandler);\n\n // 健康检查\n app.get('/api/health', (c) => c.json({ status: 'ok', version: '0.1.0' }));\n\n // API 路由\n app.route('/api/hub', hubRoutes);\n app.route('/api/tools', toolsRoutes);\n app.route('/api/sync', syncRoutes);\n app.route('/api/files', filesRoutes);\n app.route('/api/assets', assetsRoutes);\n\n // 静态文件服务(前端构建产物)\n // 开发模式下前端跑在 5173 端口,这里只服务 API;\n // 生产模式下前端产物位于 ./web/dist\n app.use(\n '/*',\n serveStatic({\n root: './web/dist',\n // SPA 回退:非静态资源路径(无文件扩展名)回退到 index.html\n rewriteRequestPath: (path) => {\n // 有文件扩展名的是静态资源(.js, .css, .svg, .ico 等),正常查找\n if (path.includes('.') && !path.endsWith('.html')) {\n return path;\n }\n // 无扩展名的是 SPA 路由,回退到 index.html\n return '/index.html';\n },\n }),\n );\n\n await serve({ fetch: app.fetch, port, hostname: host });\n\n appLog.success(`AssetPlex Web UI 运行中: http://${host}:${port}`);\n appLog.info('按 Ctrl+C 停止服务');\n\n if (openBrowser) {\n try {\n const { default: open } = await import('open');\n await open(`http://${host}:${port}`);\n } catch {\n appLog.warn('自动打开浏览器失败,请手动访问上述地址');\n }\n }\n\n // 保持进程运行\n return new Promise<void>((resolve) => {\n process.on('SIGINT', () => {\n appLog.info('Web UI 已停止');\n resolve();\n });\n process.on('SIGTERM', () => {\n appLog.info('Web UI 已停止');\n resolve();\n });\n });\n}\n","/**\n * assetplex ui 命令实现\n *\n * 启动 Web UI HTTP 服务,并自动打开浏览器。\n */\n\nimport { startServer } from '../../server/index.js';\nimport { log } from '../../utils/logger.js';\n\nexport interface UiOptions {\n /** 端口号 */\n port?: number;\n /** 监听地址 */\n host?: string;\n /** 不自动打开浏览器 */\n noOpen?: boolean;\n}\n\nexport async function uiCommand(opts: UiOptions): Promise<void> {\n log.info('启动 AssetPlex Web UI...');\n await startServer({\n port: opts.port ?? 17521,\n host: opts.host ?? '127.0.0.1',\n openBrowser: !opts.noOpen,\n });\n}\n","/**\n * AssetPlex CLI 入口\n *\n * 使用 Commander.js 注册所有子命令\n */\n\nimport { Command } from 'commander';\nimport { log, setLogLevel } from '../utils/logger.js';\nimport { initCommand } from './commands/init.js';\nimport { doctorCommand } from './commands/doctor.js';\nimport { syncCommand } from './commands/sync.js';\n\nconst program = new Command();\n\nprogram\n .name('assetplex')\n .description('One identity, every AI agent — built for the China stack and beyond.')\n .version('0.1.0')\n .option('-v, --verbose', '启用详细日志输出', () => setLogLevel('debug'))\n .option('-q, --quiet', '静默模式(仅输出错误)', () => setLogLevel('error'));\n\n// init 命令\nprogram\n .command('init')\n .description('初始化 ~/.assetplex/ 目录与模板文件')\n .option('-f, --force', '强制覆盖已存在文件')\n .option('--import-existing', '从现有各工具反向导入配置')\n .option('-y, --yes', '跳过交互提示,使用默认值')\n .action(async (opts) => {\n try {\n await initCommand(opts);\n } catch (err) {\n log.error('初始化失败:', err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n// doctor 命令\nprogram\n .command('doctor')\n .description('体检:检测各 AI 工具安装状态、Hub 完整性')\n .option('--fix', '自动修复检测到的问题')\n .option('--json', 'JSON 输出(脚本友好)')\n .option('--tool <name>', '仅检查指定工具')\n .action(async (opts) => {\n try {\n await doctorCommand(opts);\n } catch (err) {\n log.error('体检失败:', err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n// sync 命令\nprogram\n .command('sync')\n .description('同步 Hub 内容到所有启用的工具')\n .option('--tool <name>', '仅同步到指定工具')\n .option('--watch', '监听文件变化自动同步(Stage 2.5 实现)')\n .option('--dry-run', '预览变更不写入')\n .option('--json', 'JSON 输出')\n .action(async (opts) => {\n try {\n await syncCommand(opts);\n } catch (err) {\n log.error('同步失败:', err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n// ui 命令(Web UI 可视化管理)\nprogram\n .command('ui')\n .description('启动 Web UI 可视化管理界面')\n .option('-p, --port <port>', '端口号', '17521')\n .option('-H, --host <host>', '监听地址', '127.0.0.1')\n .option('--no-open', '不自动打开浏览器')\n .action(async (opts) => {\n try {\n const { uiCommand } = await import('./commands/ui.js');\n await uiCommand({\n port: parseInt(opts.port, 10),\n host: opts.host,\n noOpen: !opts.open,\n });\n } catch (err) {\n log.error('启动 UI 失败:', err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n// 解析参数\nprogram.parseAsync(process.argv).catch((err) => {\n log.error('执行失败:', err instanceof Error ? err.message : String(err));\n process.exit(1);\n});\n","/**\n * assetplex init 命令\n *\n * 初始化 ~/.assetplex/ 目录结构,生成模板文件\n *\n * 借鉴:\n * - agentsync 的 bundled skill 提示(init 时询问是否安装自带 SKILL)\n * - Claude Code 的 /init 命令\n */\n\nimport { existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { resolve } from 'node:path';\nimport { log } from '../../utils/logger.js';\nimport { getHubRoot, hubPath } from '../../utils/paths.js';\nimport { generateDefaultConfigToml } from '../../core/config.js';\nimport {\n PROFILE_TEMPLATE,\n COMMUNICATION_STYLE_TEMPLATE,\n TECH_STACK_TEMPLATE,\n CODING_STYLE_TEMPLATE,\n GIT_WORKFLOW_TEMPLATE,\n ENV_TEMPLATE,\n HUB_README_TEMPLATE,\n} from '../templates.js';\n\nexport interface InitOptions {\n /** 强制覆盖已存在的目录 */\n force?: boolean;\n /** 从现有各工具反向导入 */\n importExisting?: boolean;\n /** 不显示交互提示 */\n yes?: boolean;\n}\n\n/** Hub 目录结构定义 */\nconst HUB_DIRECTORIES = [\n 'identity',\n 'skills',\n 'rules/always',\n 'rules/by-glob',\n 'rules/by-project',\n 'preferences',\n 'mcp',\n 'commands',\n 'agents',\n '.backups',\n];\n\n/** Hub 初始文件定义(路径 -> 内容) */\nconst HUB_INITIAL_FILES: Array<{ path: string[]; content: string; overwrite: boolean }> = [\n {\n path: ['hub.toml'],\n content: generateDefaultConfigToml(),\n overwrite: false,\n },\n {\n path: ['README.md'],\n content: HUB_README_TEMPLATE,\n overwrite: false,\n },\n {\n path: ['identity', 'profile.md'],\n content: PROFILE_TEMPLATE,\n overwrite: false,\n },\n {\n path: ['identity', 'profile.auto.md'],\n content: [\n '<!-- AUTO-GENERATED by assetplex profile learn. Do not edit manually. -->',\n '# Auto-Learned Profile',\n '',\n '> 此文件由 \\`assetplex profile learn\\` 命令维护,记录 AI 从你的行为中学习到的事实。',\n '> 不要手动编辑此文件。运行 \\`assetplex profile learn --dry-run\\` 预览将要写入的事实。',\n '',\n '## 最近学习到的事实',\n '<!-- (尚无数据,运行 assetplex profile learn 学习) -->',\n '',\n '## 常用工作流',\n '<!-- (尚无数据) -->',\n '',\n '## 错误教训(Lessons)',\n '<!-- (尚无数据) -->',\n '',\n ].join('\\n'),\n overwrite: false,\n },\n {\n path: ['identity', 'communication-style.md'],\n content: COMMUNICATION_STYLE_TEMPLATE,\n overwrite: false,\n },\n {\n path: ['identity', 'tech-stack.md'],\n content: TECH_STACK_TEMPLATE,\n overwrite: false,\n },\n {\n path: ['identity', 'env.md'],\n content: ENV_TEMPLATE,\n overwrite: false,\n },\n {\n path: ['preferences', 'coding-style.md'],\n content: CODING_STYLE_TEMPLATE,\n overwrite: false,\n },\n {\n path: ['preferences', 'git-workflow.md'],\n content: GIT_WORKFLOW_TEMPLATE,\n overwrite: false,\n },\n // 初始规则文件\n {\n path: ['rules', 'always', 'global.md'],\n content: [\n '# Global Rules',\n '',\n '> 此规则文件会同步到所有工具的 rules/always/,对所有 AI 助手始终生效。',\n '',\n '## 通用规则',\n '- 修改代码前先阅读相关文件',\n '- 不要做未被请求的改动',\n '- 不要添加未被请求的注释、文档或类型注解',\n '- 优先编辑现有文件,而非创建新文件',\n '- 简单优先,避免过度设计',\n '',\n ].join('\\n'),\n overwrite: false,\n },\n // MCP 单源配置\n {\n path: ['mcp', 'mcp.sources.json'],\n content: [\n '{',\n ' \"$schema\": \"https://json-schema.org/draft-07/schema\",',\n ' \"mcpServers\": {',\n ' // 在此添加 MCP 服务器配置,assetplex 会自动同步到各工具:',\n ' // - Claude Code 的 ~/.claude.json',\n ' // - Codex 的 ~/.codex/config.toml [mcp_servers.x]',\n ' // - TRAE CN 的 ~/.trae-cn/mcp.json',\n ' // - WorkBuddy 的 ~/.workbuddy/.mcp.json',\n ' }',\n '}',\n '',\n ].join('\\n'),\n overwrite: false,\n },\n];\n\n/**\n * assetplex init 实现\n */\nexport async function initCommand(options: InitOptions = {}): Promise<void> {\n const hubRoot = getHubRoot();\n\n log.info(`正在初始化 AssetPlex...`);\n log.info(`Hub 根目录: ${hubRoot}`);\n\n // 检查目录是否已存在\n if (existsSync(hubRoot) && !options.force) {\n // 检查是否有 hub.toml\n const hubTomlPath = hubPath('hub.toml');\n if (existsSync(hubTomlPath)) {\n log.warn(`Hub 已存在:${hubRoot}`);\n log.warn(`如需重新初始化,请使用 --force 选项`);\n return;\n }\n }\n\n // 创建目录结构\n log.info('创建目录结构...');\n for (const dir of HUB_DIRECTORIES) {\n const dirPath = resolve(hubRoot, dir);\n mkdirSync(dirPath, { recursive: true });\n log.debug(` 创建目录: ${dir}`);\n }\n\n // 写入初始文件\n log.info('写入模板文件...');\n let createdCount = 0;\n let skippedCount = 0;\n for (const file of HUB_INITIAL_FILES) {\n const filePath = resolve(hubRoot, ...file.path);\n if (existsSync(filePath) && !file.overwrite && !options.force) {\n log.debug(` 跳过已存在: ${file.path.join('/')}`);\n skippedCount++;\n continue;\n }\n writeFileSync(filePath, file.content, 'utf-8');\n log.debug(` 写入文件: ${file.path.join('/')}`);\n createdCount++;\n }\n\n log.success(`AssetPlex 初始化完成!`);\n log.info(` 根目录: ${hubRoot}`);\n log.info(` 创建文件: ${createdCount} 个`);\n if (skippedCount > 0) {\n log.info(` 跳过已存在: ${skippedCount} 个`);\n }\n\n // 显示后续步骤\n log.info('');\n log.info('下一步:');\n log.info(' 1. 编辑 ~/.assetplex/identity/profile.md 填写你的个人画像');\n log.info(' 2. 运行 `assetplex doctor` 检测各 AI 工具安装状态');\n log.info(' 3. 运行 `assetplex sync` 同步到所有工具');\n log.info(' 4. 运行 `assetplex --help` 查看所有命令');\n}\n","/**\n * 初始化模板字符串\n *\n * 所有模板以字符串形式存于此,避免文件系统读取,\n * 使 assetplex init 命令自包含\n */\n\nexport const PROFILE_TEMPLATE = `# User Profile\n\n> 此文件由用户手写。AssetPlex 会自动同步到所有启用的工具\n> (Claude Code 的 CLAUDE.md、Codex 的 AGENTS.md、TRAE CN 的 memory/user_profile.md 等)\n\n## 沟通偏好\n- 语言:中文\n- 风格:实用、干货、可收藏\n\n## 技术栈\n- 主要:TypeScript, React, Node.js\n- 辅助:Python, SQL\n\n## 背景\n- (填写你的职业背景)\n- (填写你的认证或专业身份)\n\n## 工作习惯\n- 操作系统:(Windows / macOS / Linux)\n- 编辑器:(Trae / VS Code / Cursor / 其他)\n- 终端:(PowerShell / zsh / bash)\n`;\n\nexport const COMMUNICATION_STYLE_TEMPLATE = `# Communication Style\n\n## 输出格式\n- 优先使用 Markdown\n- 代码块必须有语言标签\n- 文件路径用反引号包裹:\\`src/index.ts\\`\n\n## 风格\n- 直接、简洁,不绕弯\n- 中文回答,代码注释也用中文\n- 复杂问题分步骤说明\n- 优先给可执行方案,再补充背景\n\n## 禁止\n- 不要用 emoji(除非明确要求)\n- 不要在每段话开头说\"好的\"、\"明白了\"\n- 不要重复用户的问题\n`;\n\nexport const TECH_STACK_TEMPLATE = `# Tech Stack\n\n## 主语言\n- TypeScript (Node.js 18+)\n- Python 3.11+\n\n## 前端\n- React 18+\n- Vite\n- Tailwind CSS\n\n## 后端\n- Node.js + Express / Fastify\n- Python + FastAPI\n\n## 数据库\n- PostgreSQL\n- Redis\n\n## DevOps\n- Docker\n- GitHub Actions\n\n## AI / LLM\n- OpenAI API\n- Anthropic Claude API\n- Volcano Engine (火山引擎)\n`;\n\nexport const CODING_STYLE_TEMPLATE = `# Coding Style\n\n## TypeScript\n- 严格模式:\\`strict: true\\`\n- 优先用 \\`const\\` 而非 \\`let\\`\n- 禁止 \\`any\\`,必要时用 \\`unknown\\` + 类型守卫\n- 用 interface 而非 type 描述对象形状\n- 函数优先用箭头函数\n\n## 命名约定\n- 变量:camelCase\n- 类型/接口:PascalCase\n- 常量:UPPER_SNAKE_CASE\n- 文件名:kebab-case\n\n## 注释\n- 只在\"为什么\"非显然时写注释\n- 不写\"做什么\"注释(代码应自解释)\n- 复杂逻辑用块注释,简单技巧用行注释\n\n## 测试\n- 测试文件与源文件同目录:\\`foo.ts\\` → \\`foo.test.ts\\`\n- 用 Vitest\n- 一个测试只测一件事\n`;\n\nexport const GIT_WORKFLOW_TEMPLATE = `# Git Workflow\n\n## 提交规范\n- 用 Conventional Commits: \\`feat: ...\\`, \\`fix: ...\\`, \\`docs: ...\\`, \\`refactor: ...\\`\n- 提交消息用英文,正文可中文\n- 单次提交不要超过 200 行 diff\n\n## 分支\n- main / master:受保护,不直接 push\n- feature/<name>:新功能\n- fix/<name>:bug 修复\n- chore/<name>:杂项\n\n## PR\n- 标题用英文,描述可中文\n- 必须包含 \"What\" 和 \"Why\"\n- 不超过 500 行 diff(除非重构)\n`;\n\nexport const ENV_TEMPLATE = `# Environment\n\n## 系统\n- OS: ${process.platform}\n- Shell: ${process.env.SHELL ?? process.env.COMSPEC ?? 'unknown'}\n- Home: ${process.env.HOME ?? process.env.USERPROFILE ?? 'unknown'}\n\n## 运行时\n- Node.js: ${process.version}\n- AssetPlex 版本: 0.1.0\n`;\n\nexport const HUB_README_TEMPLATE = `# AssetPlex — 个人 AI 工具配置中心\n\n此目录由 [AssetPlex](https://github.com/wynter-cai/assetplex) 管理。\n修改任意文件后,运行 \\`assetplex sync\\` 同步到所有启用的工具。\n\n## 目录结构\n- \\`identity/\\` — 你的个人身份画像(手写 + AI 自动维护)\n- \\`skills/\\` — 跨工具 Skills 库\n- \\`rules/\\` — 通用规则\n- \\`preferences/\\` — 个人偏好(编码风格、Git 工作流等)\n- \\`mcp/\\` — MCP 服务器集中配置\n- \\`commands/\\` — 自定义 slash commands\n- \\`agents/\\` — 子代理定义\n- \\`hub.toml\\` — Hub 主配置\n\n## 常用命令\n\\`\\`\\`bash\nassetplex sync # 同步到所有工具\nassetplex sync --dry-run # 预览变更\nassetplex doctor # 体检\nassetplex profile learn # 让 AI 学习最近行为\nassetplex skill search <q> # 搜索社区 skills\n\\`\\`\\`\n`;\n","/**\n * assetplex doctor 命令\n *\n * 体检:检测各 AI 工具安装状态、Hub 完整性、配置问题\n *\n * 借鉴:\n * - agentsync 的 CI-friendly skip(不可用工具优雅跳过)\n * - yurukusa/cc-safe-setup 的 drift checker hook\n */\n\nimport { existsSync } from 'node:fs';\nimport { log } from '../../utils/logger.js';\nimport { getHubRoot, hubPath } from '../../utils/paths.js';\nimport {\n registerBuiltinAdapters,\n getAllAdapters,\n} from '../../core/adapters/registry.js';\nimport type { ToolStatus } from '../../core/types.js';\n\nexport interface DoctorOptions {\n /** 自动修复 */\n fix?: boolean;\n /** JSON 输出 */\n json?: boolean;\n /** 仅检查某工具 */\n tool?: string;\n}\n\n/**\n * assetplex doctor 实现\n */\nexport async function doctorCommand(options: DoctorOptions = {}): Promise<void> {\n // 注册内置适配器\n registerBuiltinAdapters();\n\n const hubRoot = getHubRoot();\n const hubTomlExists = existsSync(hubPath('hub.toml'));\n\n const result: {\n hubRoot: string;\n hubInitialized: boolean;\n hubTomlExists: boolean;\n tools: ToolStatus[];\n issues: string[];\n } = {\n hubRoot,\n hubInitialized: hubTomlExists,\n hubTomlExists,\n tools: [],\n issues: [],\n };\n\n // 检查 Hub 状态\n if (!hubTomlExists) {\n result.issues.push('Hub 未初始化。请先运行 `assetplex init`。');\n }\n\n // 检查各工具\n const adapters = options.tool\n ? getAllAdapters().filter((a) => a.name === options.tool)\n : getAllAdapters();\n\n for (const adapter of adapters) {\n try {\n const status = await adapter.detect();\n result.tools.push(status);\n } catch (err) {\n result.tools.push({\n name: adapter.name,\n installed: false,\n configDirExists: false,\n configDir: '',\n error: err instanceof Error ? err.message : String(err),\n });\n }\n }\n\n // 输出结果\n if (options.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n printDoctorReport(result);\n}\n\n/**\n * 打印体检报告(人类可读)\n */\nfunction printDoctorReport(result: {\n hubRoot: string;\n hubInitialized: boolean;\n hubTomlExists: boolean;\n tools: ToolStatus[];\n issues: string[];\n}): void {\n log.info('AssetPlex 体检报告');\n log.info('='.repeat(60));\n log.info(`Hub 根目录: ${result.hubRoot}`);\n log.info(`Hub 已初始化: ${result.hubInitialized ? '✓' : '✗'}`);\n log.info('');\n\n // Hub 问题\n if (result.issues.length > 0) {\n log.warn('Hub 问题:');\n for (const issue of result.issues) {\n log.warn(` - ${issue}`);\n }\n log.info('');\n }\n\n // 工具状态表\n log.info('已注册工具状态:');\n log.info('-'.repeat(60));\n for (const tool of result.tools) {\n const status = tool.installed ? '✓ 已安装' : '✗ 未安装';\n const version = tool.version ? ` v${tool.version}` : '';\n const dir = tool.configDir || '(无)';\n log.info(` ${tool.name.padEnd(15)} ${status}${version}`);\n log.info(` ${' '.repeat(15)} 配置目录: ${dir}`);\n if (tool.error) {\n log.warn(` ${' '.repeat(15)} 备注: ${tool.error}`);\n }\n log.info('');\n }\n\n // 总结\n const installedCount = result.tools.filter((t) => t.installed).length;\n const totalCount = result.tools.length;\n log.info('-'.repeat(60));\n log.info(`总结: ${installedCount}/${totalCount} 个工具已安装`);\n\n if (installedCount === 0) {\n log.warn('');\n log.warn('未检测到任何 AI 工具,请先安装至少一个工具。');\n } else if (!result.hubInitialized) {\n log.warn('');\n log.warn('Hub 未初始化,请运行: assetplex init');\n } else {\n log.success('');\n log.success('体检完成,可运行 `assetplex sync` 同步配置');\n }\n}\n","/**\n * assetplex sync 命令\n *\n * 同步 Hub 内容到所有已启用的工具\n *\n * 借鉴:\n * - sync-rules 的 shell chaining(`sync-rules && claude --chat`)\n * - agentsync 的 CI-friendly skip\n */\n\nimport { log } from '../../utils/logger.js';\nimport { getHubRoot, hubPath } from '../../utils/paths.js';\nimport { existsSync } from 'node:fs';\nimport {\n loadHubConfig,\n resolveHubConfigPath,\n} from '../../core/config.js';\nimport {\n registerBuiltinAdapters,\n getAllAdapters,\n} from '../../core/adapters/registry.js';\nimport {\n SyncEngine,\n printSyncPlan,\n printSyncResult,\n} from '../../core/sync-engine.js';\nimport type { SyncOptions } from '../../core/types.js';\n\nexport interface SyncCommandOptions extends SyncOptions {\n /** 监听模式(暂未实现) */\n watch?: boolean;\n}\n\n/**\n * assetplex sync 实现\n */\nexport async function syncCommand(options: SyncCommandOptions = {}): Promise<void> {\n // 1. --watch 暂未实现\n if (options.watch) {\n log.warn('--watch 将在 Stage 2.5 实现');\n return;\n }\n\n // 2. 检查 Hub 是否初始化\n const hubRoot = getHubRoot();\n const hubTomlPath = hubPath('hub.toml');\n if (!existsSync(hubTomlPath)) {\n log.error(`Hub 未初始化:${hubTomlPath} 不存在`);\n log.error('请先运行 `assetplex init`');\n process.exit(1);\n }\n\n // 3. 加载 hub.toml 配置\n let hubConfig;\n try {\n hubConfig = loadHubConfig(resolveHubConfigPath());\n } catch (err) {\n log.error(`加载 hub.toml 失败: ${(err as Error).message}`);\n process.exit(1);\n }\n\n // 4. 注册适配器\n registerBuiltinAdapters();\n const adapters = getAllAdapters();\n\n log.info(`Hub 根目录: ${hubRoot}`);\n log.info(`已注册适配器: ${adapters.length} 个`);\n if (options.tool) {\n log.info(`指定工具: ${options.tool}`);\n }\n if (options.dryRun) {\n log.info('模式: --dry-run(仅预览不写入)');\n }\n\n // 5. 构造 SyncEngine\n const engine = new SyncEngine(hubConfig, adapters);\n\n // 6. 执行\n if (options.dryRun) {\n const plans = await engine.plan(options);\n\n if (options.json) {\n console.log(JSON.stringify(plans, null, 2));\n return;\n }\n\n log.info('');\n log.info('同步计划(dry-run)');\n log.info('='.repeat(60));\n printSyncPlan(plans);\n return;\n }\n\n // 真实同步\n const results = await engine.run(options);\n\n if (options.json) {\n console.log(JSON.stringify(results, null, 2));\n return;\n }\n\n printSyncResult(results);\n\n // 7. 总结\n const failedTools = results.filter((r) => !r.success);\n if (failedTools.length > 0) {\n log.warn('');\n log.warn(`有 ${failedTools.length} 个工具同步失败`);\n process.exit(1);\n } else {\n log.success('');\n log.success('同步完成!');\n }\n}\n"],"mappings":"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","names":["resolve","path","existsSync","mkdirSync","resolve","dirname","path","existsSync","readlinkSync","readdirSync","rmdirSync","dirname","resolve","isAbsolute","path","existsSync","readFileSync","statSync","readdirSync","resolve","normalize","relative","join","homedir","existsSync","resolve","readFileSync","readdirSync","existsSync","writeFileSync","readFileSync","resolve","homedir","execSync","TOML","existsSync","readFileSync","writeFileSync","resolve","execSync","existsSync","readFileSync","writeFileSync","resolve","existsSync","writeFileSync","readFileSync","resolve","basename","existsSync","readdirSync","readFileSync","writeFileSync","statSync","unlinkSync","join","resolve","dirname","relative","existsSync","readFileSync","resolve","mcpTomlToJson","extractEnvVars","buildEnvMap","desinterpolateEnv","Hono","Hono","existsSync","readFileSync","readHubFile","homedir","Hono","path","category","hubPath","basename","Hono","init_assets","hubPath","Hono","path","resolve","init_assets","existsSync","mkdirSync","writeFileSync","resolve","existsSync","resolve","mkdirSync","writeFileSync","existsSync","existsSync","uiCommand"]}