xling 0.2.4 → 0.3.1

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.
Files changed (105) hide show
  1. package/README.md +47 -0
  2. package/dist/{base-Cm9xh6sW.js → base-BWvHbkly.js} +2 -3
  3. package/dist/base-CMD91CAe.d.ts +44 -0
  4. package/dist/base-DdIJJBHV.js +33 -0
  5. package/dist/{base-BlaKDtDu.d.ts → base-DkEUpUS3.d.ts} +19 -20
  6. package/dist/claude-BsdlWM7z.js +30 -0
  7. package/dist/{claude-l3zomoHg.js → claude-D7KdpYHQ.js} +4 -5
  8. package/dist/{claudeDefault-Fk1-kHLE.js → claudeDefault-pd-Kyu6o.js} +1 -2
  9. package/dist/codex-Crifr9cw.js +31 -0
  10. package/dist/{codex-CR8xqNrZ.js → codex-UJ2PYHA6.js} +3 -4
  11. package/dist/commands/settings/get.d.ts +5 -13
  12. package/dist/commands/settings/get.js +8 -9
  13. package/dist/commands/settings/inspect.d.ts +4 -10
  14. package/dist/commands/settings/inspect.js +8 -9
  15. package/dist/commands/settings/list.d.ts +4 -11
  16. package/dist/commands/settings/list.js +8 -9
  17. package/dist/commands/settings/set.d.ts +5 -13
  18. package/dist/commands/settings/set.js +8 -9
  19. package/dist/commands/settings/switch.d.ts +5 -15
  20. package/dist/commands/settings/switch.js +8 -9
  21. package/dist/commands/x/index.d.ts +14 -0
  22. package/dist/commands/x/index.js +129 -0
  23. package/dist/dispatcher-BUU7wUgm.js +93 -0
  24. package/dist/{dispatcher-JXm3OqRQ.js → dispatcher-Co94YvDc.js} +4 -5
  25. package/dist/domain/interfaces.d.ts +3 -3
  26. package/dist/domain/types.d.ts +2 -2
  27. package/dist/domain/validators.d.ts +17 -72
  28. package/dist/domain/validators.js +1 -2
  29. package/dist/editor-D4qoje1V.js +1 -2
  30. package/dist/errors-CAZ5k5YT.js +1 -2
  31. package/dist/format-Cqecj3RS.js +1 -2
  32. package/dist/{fsStore-i-3731TM.js → fsStore-BPnFUGta.js} +1 -2
  33. package/dist/{gemini-aNNm-QGE.js → gemini-Qo5146d_.js} +2 -3
  34. package/dist/interfaces-BD6_y1tC.d.ts +74 -0
  35. package/dist/run.js +1 -2
  36. package/dist/runner-BE7zZq1g.js +88 -0
  37. package/dist/services/launch/adapters/base.d.ts +4 -0
  38. package/dist/services/launch/adapters/base.js +4 -0
  39. package/dist/services/launch/adapters/claude.d.ts +24 -0
  40. package/dist/services/launch/adapters/claude.js +5 -0
  41. package/dist/services/launch/adapters/codex.d.ts +25 -0
  42. package/dist/services/launch/adapters/codex.js +5 -0
  43. package/dist/services/launch/dispatcher.d.ts +43 -0
  44. package/dist/services/launch/dispatcher.js +8 -0
  45. package/dist/services/settings/adapters/base.d.ts +3 -3
  46. package/dist/services/settings/adapters/base.js +2 -2
  47. package/dist/services/settings/adapters/claude.d.ts +19 -20
  48. package/dist/services/settings/adapters/claude.js +4 -4
  49. package/dist/services/settings/adapters/codex.d.ts +23 -24
  50. package/dist/services/settings/adapters/codex.js +3 -3
  51. package/dist/services/settings/adapters/gemini.d.ts +17 -18
  52. package/dist/services/settings/adapters/gemini.js +3 -3
  53. package/dist/services/settings/dispatcher.d.ts +18 -19
  54. package/dist/services/settings/dispatcher.js +7 -7
  55. package/dist/services/settings/fsStore.d.ts +24 -27
  56. package/dist/services/settings/fsStore.js +1 -1
  57. package/dist/services/settings/templates/claudeDefault.d.ts +3 -4
  58. package/dist/services/settings/templates/claudeDefault.js +1 -1
  59. package/dist/{types-BfNSo2rs.d.ts → types-DSBuWLh6.d.ts} +42 -10
  60. package/dist/utils/editor.d.ts +1 -2
  61. package/dist/utils/errors.d.ts +21 -22
  62. package/dist/utils/format.d.ts +8 -9
  63. package/dist/utils/logger.d.ts +9 -10
  64. package/dist/utils/logger.js +1 -2
  65. package/dist/utils/runner.d.ts +34 -0
  66. package/dist/utils/runner.js +3 -0
  67. package/package.json +1 -1
  68. package/dist/base-BlaKDtDu.d.ts.map +0 -1
  69. package/dist/base-Cm9xh6sW.js.map +0 -1
  70. package/dist/claude-l3zomoHg.js.map +0 -1
  71. package/dist/claudeDefault-Fk1-kHLE.js.map +0 -1
  72. package/dist/codex-CR8xqNrZ.js.map +0 -1
  73. package/dist/commands/settings/get.d.ts.map +0 -1
  74. package/dist/commands/settings/get.js.map +0 -1
  75. package/dist/commands/settings/inspect.d.ts.map +0 -1
  76. package/dist/commands/settings/inspect.js.map +0 -1
  77. package/dist/commands/settings/list.d.ts.map +0 -1
  78. package/dist/commands/settings/list.js.map +0 -1
  79. package/dist/commands/settings/set.d.ts.map +0 -1
  80. package/dist/commands/settings/set.js.map +0 -1
  81. package/dist/commands/settings/switch.d.ts.map +0 -1
  82. package/dist/commands/settings/switch.js.map +0 -1
  83. package/dist/dispatcher-JXm3OqRQ.js.map +0 -1
  84. package/dist/domain/validators.d.ts.map +0 -1
  85. package/dist/domain/validators.js.map +0 -1
  86. package/dist/editor-D4qoje1V.js.map +0 -1
  87. package/dist/errors-CAZ5k5YT.js.map +0 -1
  88. package/dist/format-Cqecj3RS.js.map +0 -1
  89. package/dist/fsStore-i-3731TM.js.map +0 -1
  90. package/dist/gemini-aNNm-QGE.js.map +0 -1
  91. package/dist/interfaces-CriQW6hF.d.ts +0 -41
  92. package/dist/interfaces-CriQW6hF.d.ts.map +0 -1
  93. package/dist/run.js.map +0 -1
  94. package/dist/services/settings/adapters/claude.d.ts.map +0 -1
  95. package/dist/services/settings/adapters/codex.d.ts.map +0 -1
  96. package/dist/services/settings/adapters/gemini.d.ts.map +0 -1
  97. package/dist/services/settings/dispatcher.d.ts.map +0 -1
  98. package/dist/services/settings/fsStore.d.ts.map +0 -1
  99. package/dist/services/settings/templates/claudeDefault.d.ts.map +0 -1
  100. package/dist/types-BfNSo2rs.d.ts.map +0 -1
  101. package/dist/utils/editor.d.ts.map +0 -1
  102. package/dist/utils/errors.d.ts.map +0 -1
  103. package/dist/utils/format.d.ts.map +0 -1
  104. package/dist/utils/logger.d.ts.map +0 -1
  105. package/dist/utils/logger.js.map +0 -1
@@ -1,20 +1,19 @@
1
- import { o as SettingsFileEntry } from "../types-BfNSo2rs.js";
1
+ import { l as SettingsFileEntry } from "../types-DSBuWLh6.js";
2
2
 
3
3
  //#region src/utils/format.d.ts
4
4
 
5
5
  /**
6
- * 格式化为 JSON 字符串
7
- */
6
+ * 格式化为 JSON 字符串
7
+ */
8
8
  declare function formatJson(data: unknown, pretty?: boolean): string;
9
9
  /**
10
- * 格式化为表格
11
- */
10
+ * 格式化为表格
11
+ */
12
12
  declare function formatTable(data: Record<string, unknown>): string;
13
13
  /**
14
- * 格式化 settings 文件清单
15
- */
14
+ * 格式化 settings 文件清单
15
+ */
16
16
  declare function formatFilesTable(files: SettingsFileEntry[]): string;
17
17
  declare function formatDiff(currentValue: unknown, nextValue: unknown): string | null;
18
18
  //#endregion
19
- export { formatDiff, formatFilesTable, formatJson, formatTable };
20
- //# sourceMappingURL=format.d.ts.map
19
+ export { formatDiff, formatFilesTable, formatJson, formatTable };
@@ -1,10 +1,10 @@
1
1
  //#region src/utils/logger.d.ts
2
2
  /**
3
- * 日志工具
4
- */
3
+ * 日志工具
4
+ */
5
5
  /**
6
- * 日志级别
7
- */
6
+ * 日志级别
7
+ */
8
8
  declare enum LogLevel {
9
9
  DEBUG = 0,
10
10
  INFO = 1,
@@ -12,8 +12,8 @@ declare enum LogLevel {
12
12
  ERROR = 3,
13
13
  }
14
14
  /**
15
- * 简单的日志工具类
16
- */
15
+ * 简单的日志工具类
16
+ */
17
17
  declare class Logger {
18
18
  private level;
19
19
  constructor(level?: LogLevel);
@@ -24,9 +24,8 @@ declare class Logger {
24
24
  error(message: string, ...args: unknown[]): void;
25
25
  }
26
26
  /**
27
- * 默认 logger 实例
28
- */
27
+ * 默认 logger 实例
28
+ */
29
29
  declare const logger: Logger;
30
30
  //#endregion
31
- export { LogLevel, Logger, logger };
32
- //# sourceMappingURL=logger.d.ts.map
31
+ export { LogLevel, Logger, logger };
@@ -42,5 +42,4 @@ var Logger = class {
42
42
  const logger = new Logger();
43
43
 
44
44
  //#endregion
45
- export { LogLevel, Logger, logger };
46
- //# sourceMappingURL=logger.js.map
45
+ export { LogLevel, Logger, logger };
@@ -0,0 +1,34 @@
1
+ import { r as LaunchCommandSpec } from "../types-DSBuWLh6.js";
2
+
3
+ //#region src/utils/runner.d.ts
4
+ interface SpawnOptions {
5
+ cwd?: string;
6
+ env?: Record<string, string>;
7
+ args?: string[];
8
+ }
9
+ interface SpawnResult {
10
+ pid: number;
11
+ command: string;
12
+ }
13
+ /**
14
+ * 启动子进程
15
+ * @param spec 命令规范
16
+ * @param options 启动选项
17
+ * @returns 进程 ID 和完整命令
18
+ */
19
+ declare function spawnProcess(spec: LaunchCommandSpec, options?: SpawnOptions): Promise<SpawnResult>;
20
+ /**
21
+ * 检查可执行文件是否存在于 PATH 中
22
+ * @param name 可执行文件名
23
+ * @returns 是否存在
24
+ */
25
+ declare function checkExecutable(name: string): Promise<boolean>;
26
+ /**
27
+ * 获取可执行文件的版本信息
28
+ * @param executable 可执行文件名
29
+ * @param versionArgs 版本参数(默认 --version)
30
+ * @returns 版本字符串
31
+ */
32
+ declare function getExecutableVersion(executable: string, versionArgs?: string[]): Promise<string>;
33
+ //#endregion
34
+ export { SpawnOptions, SpawnResult, checkExecutable, getExecutableVersion, spawnProcess };
@@ -0,0 +1,3 @@
1
+ import { n as getExecutableVersion, r as spawnProcess, t as checkExecutable } from "../runner-BE7zZq1g.js";
2
+
3
+ export { checkExecutable, getExecutableVersion, spawnProcess };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xling",
3
- "version": "0.2.4",
3
+ "version": "0.3.1",
4
4
  "description": "Unified CLI for managing AI tool settings",
5
5
  "homepage": "https://github.com/kingsword09/xling/tree/main#readme",
6
6
  "bugs": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"base-BlaKDtDu.d.ts","names":[],"sources":["../src/services/settings/adapters/base.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAiCoC,uBAZd,WAAA,YAAuB,eAYT,CAAA;EAAR,kBAAA,MAAA,EAXA,MAWA;EAmBhB;;;EAGP,SAAA,WAAA,CAAA,KAAA,EA5ByB,KA4BzB,CAAA,EAAA,MAAA;EAOkB,SAAA,aAAA,CAAA,KAAA,EAlCS,KAkCT,CAAA,EAAA,OAAA;EAAgB;;;EA8BF,IAAA,CAAA,KAAA,EA3DjB,KA2DiB,CAAA,EA3DT,OA2DS,CA3DD,gBA2DC,CAAA;EAAsB;;;EAgBjD,aAAA,CAAA,MAAA,EAxDE,KAwDF,EAAA,QAAA,EAAA,MAAA,EAAA,QAAA,CAAA,EAtDK,aAsDL,CAAA,EArDL,OAqDK,CArDG,cAqDH,CAAA;EAvFmC;;;iBAyCtB,QAAQ,QAAQ;;;;cA8BnB,iBAAiB,cAAc,QAAQ;;;;sCAOrB;;;;4CAS5B"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"base-Cm9xh6sW.js","names":["fsStore.fileExists","fsStore.getFileInfo","fsStore.readJSON"],"sources":["../src/services/settings/adapters/base.ts"],"sourcesContent":["/**\n * 适配器抽象基类\n * 实现通用逻辑,减少重复代码(DRY 原则)\n */\n\nimport type { SettingsAdapter } from \"@/domain/interfaces.ts\";\nimport type {\n ToolId,\n Scope,\n InspectResult,\n SettingsListData,\n SettingsResult,\n EditOptions,\n SwitchOptions,\n} from \"@/domain/types.ts\";\nimport { InvalidScopeError } from \"@/utils/errors.ts\";\nimport * as fsStore from \"@/services/settings/fsStore.ts\";\n\n/**\n * 抽象基类\n */\nexport abstract class BaseAdapter implements SettingsAdapter {\n abstract readonly toolId: ToolId;\n\n /**\n * 子类必须实现的方法\n */\n abstract resolvePath(scope: Scope): string;\n abstract validateScope(scope: Scope): boolean;\n\n /**\n * 列出所有配置\n */\n async list(scope: Scope): Promise<SettingsListData> {\n if (!this.validateScope(scope)) {\n throw new InvalidScopeError(scope);\n }\n\n const path = this.resolvePath(scope);\n const config = this.readConfig(path);\n\n return {\n type: \"entries\",\n entries: config,\n filePath: path,\n };\n }\n\n /**\n * 默认 switchProfile 会抛出,子类可覆盖\n */\n async switchProfile(\n _scope: Scope,\n _profile: string,\n _options?: SwitchOptions,\n ): Promise<SettingsResult> {\n throw new Error(`Tool ${this.toolId} does not support profile switching`);\n }\n\n /**\n * 检查配置文件\n */\n async inspect(scope: Scope): Promise<InspectResult> {\n if (!this.validateScope(scope)) {\n throw new InvalidScopeError(scope);\n }\n\n const path = this.resolvePath(scope);\n const exists = fsStore.fileExists(path);\n\n if (!exists) {\n return {\n path,\n exists: false,\n };\n }\n\n const fileInfo = fsStore.getFileInfo(path);\n const config = this.readConfig(path);\n\n return {\n path,\n exists: true,\n content: JSON.stringify(config, null, 2),\n size: fileInfo?.size,\n lastModified: fileInfo?.lastModified,\n };\n }\n\n /**\n * 默认 edit 会抛出,子类可覆盖\n */\n async edit(scope: Scope, _options: EditOptions): Promise<SettingsResult> {\n throw new Error(`Tool ${this.toolId} does not support edit for ${scope}`);\n }\n\n /**\n * 读取配置文件(子类可覆盖)\n */\n protected readConfig(path: string): Record<string, unknown> {\n return fsStore.readJSON(path);\n }\n\n /**\n * 写入配置文件(子类可覆盖)\n */\n protected writeConfig(\n path: string,\n data: Record<string, unknown>,\n backup = true,\n ): void {\n fsStore.writeJSON(path, data, backup);\n }\n}\n"],"mappings":";;;;;;;AAqBA,IAAsB,cAAtB,MAA6D;;;;CAY3D,MAAM,KAAK,OAAyC;AAClD,MAAI,CAAC,KAAK,cAAc,MAAM,CAC5B,OAAM,IAAI,kBAAkB,MAAM;EAGpC,MAAM,OAAO,KAAK,YAAY,MAAM;AAGpC,SAAO;GACL,MAAM;GACN,SAJa,KAAK,WAAW,KAAK;GAKlC,UAAU;GACX;;;;;CAMH,MAAM,cACJ,QACA,UACA,UACyB;AACzB,QAAM,IAAI,MAAM,QAAQ,KAAK,OAAO,qCAAqC;;;;;CAM3E,MAAM,QAAQ,OAAsC;AAClD,MAAI,CAAC,KAAK,cAAc,MAAM,CAC5B,OAAM,IAAI,kBAAkB,MAAM;EAGpC,MAAM,OAAO,KAAK,YAAY,MAAM;AAGpC,MAAI,CAFWA,WAAmB,KAAK,CAGrC,QAAO;GACL;GACA,QAAQ;GACT;EAGH,MAAM,WAAWC,YAAoB,KAAK;EAC1C,MAAM,SAAS,KAAK,WAAW,KAAK;AAEpC,SAAO;GACL;GACA,QAAQ;GACR,SAAS,KAAK,UAAU,QAAQ,MAAM,EAAE;GACxC,MAAM,UAAU;GAChB,cAAc,UAAU;GACzB;;;;;CAMH,MAAM,KAAK,OAAc,UAAgD;AACvE,QAAM,IAAI,MAAM,QAAQ,KAAK,OAAO,6BAA6B,QAAQ;;;;;CAM3E,AAAU,WAAW,MAAuC;AAC1D,SAAOC,SAAiB,KAAK;;;;;CAM/B,AAAU,YACR,MACA,MACA,SAAS,MACH;AACN,YAAkB,MAAM,MAAM,OAAO"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"claude-l3zomoHg.js","names":["fsStore.resolveHome","files: SettingsFileEntry[]","currentConfig: Record<string, unknown>","fsStore.getFileInfo","candidates: string[]"],"sources":["../src/services/settings/adapters/claude.ts"],"sourcesContent":["/**\n * Claude Code 适配器\n */\n\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport type {\n Scope,\n SettingsListData,\n SettingsFileEntry,\n SettingsResult,\n EditOptions,\n SwitchOptions,\n} from \"@/domain/types.ts\";\nimport { BaseAdapter } from \"./base.ts\";\nimport * as fsStore from \"@/services/settings/fsStore.ts\";\nimport {\n InvalidScopeError,\n SettingsVariantNotFoundError,\n} from \"@/utils/errors.ts\";\nimport { CLAUDE_SETTINGS_TEMPLATE } from \"@/services/settings/templates/claudeDefault.ts\";\nimport { openInEditor, resolveEditorCommand } from \"@/utils/editor.ts\";\nimport { formatDiff } from \"@/utils/format.ts\";\n\n/**\n * Claude Code 配置适配器\n *\n * 配置文件路径:\n * - user: ~/.claude/settings.json\n * - project: <cwd>/.claude/settings.json\n * - local: <cwd>/.claude/settings.local.json\n */\nexport class ClaudeAdapter extends BaseAdapter {\n readonly toolId = \"claude\" as const;\n\n /**\n * 列出所有 settings.*.json 文件\n */\n override async list(scope: Scope): Promise<SettingsListData> {\n if (!this.validateScope(scope)) {\n throw new InvalidScopeError(scope);\n }\n\n const activePath = fsStore.resolveHome(this.resolvePath(scope));\n const directory = path.dirname(activePath);\n const activeFilename = path.basename(activePath);\n\n const files: SettingsFileEntry[] = [\n this.buildEntry(activePath, scope, true),\n ];\n\n if (fs.existsSync(directory)) {\n const entries = fs.readdirSync(directory, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isFile()) continue;\n if (entry.name === activeFilename) continue;\n if (!this.isSettingsFile(entry.name)) continue;\n\n const entryPath = path.join(directory, entry.name);\n files.push(this.buildEntry(entryPath, scope, false));\n }\n }\n\n return {\n type: \"files\",\n files: this.sortFiles(files),\n };\n }\n\n /**\n * 解析配置文件路径\n */\n resolvePath(scope: Scope): string {\n switch (scope) {\n case \"user\":\n return \"~/.claude/settings.json\";\n case \"project\":\n return \".claude/settings.json\";\n case \"local\":\n return \".claude/settings.local.json\";\n default:\n throw new Error(`Unsupported scope for Claude: ${scope}`);\n }\n }\n\n /**\n * 验证 scope 是否有效\n */\n validateScope(scope: Scope): boolean {\n return [\"user\", \"project\", \"local\"].includes(scope);\n }\n\n /**\n * 切换 settings.<variant>.json 到活动文件\n */\n override async switchProfile(\n scope: Scope,\n profile: string,\n options?: SwitchOptions,\n ): Promise<SettingsResult> {\n if (!this.validateScope(scope)) {\n throw new InvalidScopeError(scope);\n }\n\n const variant = profile.trim();\n if (!variant) {\n throw new Error(\"Variant name cannot be empty\");\n }\n\n const targetPath = fsStore.resolveHome(this.resolvePath(scope));\n const directory = path.dirname(targetPath);\n const sourcePath = this.findVariantPath(directory, variant, targetPath);\n\n if (!sourcePath) {\n throw new SettingsVariantNotFoundError(variant);\n }\n\n const nextConfig = this.readConfig(sourcePath);\n\n let currentConfig: Record<string, unknown> = {};\n try {\n currentConfig = this.readConfig(targetPath);\n } catch {\n currentConfig = {};\n }\n\n const diff = formatDiff(currentConfig, nextConfig);\n\n if (options?.preview) {\n return {\n success: true,\n preview: true,\n filePath: targetPath,\n diff: diff ?? undefined,\n data: {\n from: sourcePath,\n to: targetPath,\n hasChanges: Boolean(diff),\n },\n message: diff\n ? \"Preview generated. Review diff before applying.\"\n : \"Current settings already match the selected variant.\",\n };\n }\n\n if (!diff) {\n return {\n success: true,\n message: \"Current settings already match the selected variant.\",\n filePath: targetPath,\n };\n }\n\n const shouldBackup = options?.backup ?? false;\n this.writeConfig(targetPath, nextConfig, shouldBackup);\n\n return {\n success: true,\n message: `Switched to ${path.basename(sourcePath)}`,\n filePath: targetPath,\n data: {\n from: sourcePath,\n to: targetPath,\n },\n };\n }\n\n override async edit(\n scope: Scope,\n options: EditOptions,\n ): Promise<SettingsResult> {\n if (!this.validateScope(scope)) {\n throw new InvalidScopeError(scope);\n }\n\n const basePath = fsStore.resolveHome(this.resolvePath(scope));\n const directory = path.dirname(basePath);\n const variantName = options.name?.trim();\n const resolvedEditor = resolveEditorCommand(options.ide);\n\n fsStore.ensureDir(directory);\n\n let targetPath = basePath;\n let label = \"default\";\n\n if (variantName && variantName !== \"\" && variantName !== \"default\") {\n const existingPath = this.findVariantPath(\n directory,\n variantName,\n basePath,\n );\n if (existingPath) {\n targetPath = existingPath;\n } else {\n targetPath = path.join(directory, `settings.${variantName}.json`);\n if (!fs.existsSync(targetPath)) {\n const seed = this.buildSeedConfig(basePath);\n fsStore.writeJSON(targetPath, seed, false);\n }\n }\n label = variantName;\n } else if (!fs.existsSync(targetPath)) {\n const seed = this.buildSeedConfig(basePath);\n fsStore.writeJSON(targetPath, seed, false);\n }\n\n await openInEditor(resolvedEditor, targetPath);\n\n return {\n success: true,\n message: `Opened ${label} settings in ${resolvedEditor}`,\n filePath: targetPath,\n data: {\n variant: label,\n ide: resolvedEditor,\n },\n };\n }\n\n private buildEntry(\n filePath: string,\n scope: Scope,\n active: boolean,\n ): SettingsFileEntry {\n const info = fsStore.getFileInfo(filePath);\n\n return {\n filename: path.basename(filePath),\n variant: this.extractVariant(filePath),\n path: filePath,\n scope,\n active,\n exists: Boolean(info),\n size: info?.size,\n lastModified: info?.lastModified,\n };\n }\n\n private extractVariant(filePath: string): string {\n const filename = path.basename(filePath);\n const match = filename.match(/^settings(?:[._-](.+))?\\.json$/);\n if (!match) {\n return filename.replace(/\\.json$/, \"\");\n }\n return match[1] ?? \"default\";\n }\n\n private buildSeedConfig(basePath: string): Record<string, unknown> {\n try {\n if (fs.existsSync(basePath)) {\n const content = fs.readFileSync(basePath, \"utf-8\");\n return JSON.parse(content);\n }\n } catch {\n // ignore, fallback to template\n }\n return { ...CLAUDE_SETTINGS_TEMPLATE };\n }\n\n private isSettingsFile(filename: string): boolean {\n return /^settings[._-].+\\.json$/.test(filename);\n }\n\n private sortFiles(files: SettingsFileEntry[]): SettingsFileEntry[] {\n return files.sort((a, b) => {\n if (a.active && !b.active) return -1;\n if (!a.active && b.active) return 1;\n return a.variant.localeCompare(b.variant);\n });\n }\n\n private findVariantPath(\n directory: string,\n profile: string,\n defaultPath: string,\n ): string | null {\n const candidates: string[] = [];\n const pushCandidate = (value: string) => {\n if (!candidates.includes(value)) {\n candidates.push(value);\n }\n };\n\n if (profile === \"default\") {\n pushCandidate(defaultPath);\n }\n\n if (profile.endsWith(\".json\")) {\n pushCandidate(\n path.isAbsolute(profile) ? profile : path.join(directory, profile),\n );\n } else {\n pushCandidate(path.join(directory, `settings.${profile}.json`));\n pushCandidate(path.join(directory, `settings-${profile}.json`));\n pushCandidate(path.join(directory, `settings_${profile}.json`));\n }\n\n for (const candidate of candidates) {\n if (fs.existsSync(candidate)) {\n return candidate;\n }\n }\n\n return null;\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"claudeDefault-Fk1-kHLE.js","names":[],"sources":["../src/services/settings/templates/claudeDefault.ts"],"sourcesContent":["export const CLAUDE_SETTINGS_TEMPLATE = {\n env: {\n ANTHROPIC_AUTH_TOKEN: \"\",\n ANTHROPIC_BASE_URL: \"https://api.anthropic.com\",\n CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC: \"1\",\n ANTHROPIC_MODEL: \"claude-sonnet-4-5-20250929\",\n ANTHROPIC_SMALL_FAST_MODEL: \"claude-haiku-4-5-20251001\",\n },\n permissions: {\n allow: [],\n deny: [],\n },\n enabledPlugins: {\n \"example-skills@anthropic-agent-skills\": false,\n },\n} satisfies Record<string, unknown>;\n"],"mappings":";AAAA,MAAa,2BAA2B;CACtC,KAAK;EACH,sBAAsB;EACtB,oBAAoB;EACpB,0CAA0C;EAC1C,iBAAiB;EACjB,4BAA4B;EAC7B;CACD,aAAa;EACX,OAAO,EAAE;EACT,MAAM,EAAE;EACT;CACD,gBAAgB,EACd,yCAAyC,OAC1C;CACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"codex-CR8xqNrZ.js","names":["fsStore.readTOML"],"sources":["../src/services/settings/adapters/codex.ts"],"sourcesContent":["/**\n * Codex 适配器\n */\n\nimport type {\n Scope,\n SettingsResult,\n SettingsListData,\n SwitchOptions,\n} from \"@/domain/types.ts\";\nimport { BaseAdapter } from \"./base.ts\";\nimport { InvalidScopeError, ProfileNotFoundError } from \"@/utils/errors.ts\";\nimport * as fsStore from \"@/services/settings/fsStore.ts\";\n\n/**\n * Codex 配置适配器\n *\n * 配置文件路径:\n * - user: ~/.codex/config.toml\n *\n * 支持 profile 切换\n */\nexport class CodexAdapter extends BaseAdapter {\n readonly toolId = \"codex\" as const;\n\n /**\n * 自定义 list:聚焦 model_providers\n */\n override async list(scope: Scope): Promise<SettingsListData> {\n if (!this.validateScope(scope)) {\n throw new InvalidScopeError(scope);\n }\n\n const path = this.resolvePath(scope);\n const config = this.readConfig(path);\n const providers = this.extractProviders(config);\n\n return {\n type: \"entries\",\n entries: providers,\n filePath: path,\n };\n }\n\n /**\n * 解析配置文件路径\n */\n resolvePath(scope: Scope): string {\n switch (scope) {\n case \"user\":\n return \"~/.codex/config.toml\";\n default:\n throw new Error(`Unsupported scope for Codex: ${scope}`);\n }\n }\n\n /**\n * 验证 scope 是否有效\n */\n validateScope(scope: Scope): boolean {\n return scope === \"user\";\n }\n\n /**\n * 切换 profile\n */\n async switchProfile(\n scope: Scope,\n profile: string,\n _options?: SwitchOptions,\n ): Promise<SettingsResult> {\n if (!this.validateScope(scope)) {\n throw new InvalidScopeError(scope);\n }\n\n const path = this.resolvePath(scope);\n const config = this.readConfig(path);\n\n // 检查 profile 是否存在\n const profiles = config.profiles as Record<string, unknown> | undefined;\n if (!profiles || !(profile in profiles)) {\n throw new ProfileNotFoundError(profile);\n }\n\n // 获取 profile 配置\n const profileConfig = profiles[profile] as Record<string, unknown>;\n\n // 将 profile 配置合并到根配置\n const newConfig = { ...config };\n for (const [key, value] of Object.entries(profileConfig)) {\n newConfig[key] = value;\n }\n\n // 设置当前 profile\n newConfig.current_profile = profile;\n\n // 写入配置\n this.writeConfig(path, newConfig);\n\n return {\n success: true,\n message: `Switched to profile: ${profile}`,\n filePath: path,\n };\n }\n\n /**\n * 读取 TOML 配置文件\n */\n protected readConfig(path: string): Record<string, unknown> {\n return fsStore.readTOML(path);\n }\n\n /**\n * 写入 TOML 配置文件\n */\n protected writeConfig(path: string, data: Record<string, unknown>): void {\n fsStore.writeTOML(path, data);\n }\n\n private extractProviders(\n config: Record<string, unknown>,\n ): Record<string, unknown> {\n const providers = config.model_providers;\n if (\n typeof providers === \"object\" &&\n providers !== null &&\n !Array.isArray(providers)\n ) {\n return providers as Record<string, unknown>;\n }\n return {};\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAsBA,IAAa,eAAb,cAAkC,YAAY;CAC5C,AAAS,SAAS;;;;CAKlB,MAAe,KAAK,OAAyC;AAC3D,MAAI,CAAC,KAAK,cAAc,MAAM,CAC5B,OAAM,IAAI,kBAAkB,MAAM;EAGpC,MAAM,OAAO,KAAK,YAAY,MAAM;EACpC,MAAM,SAAS,KAAK,WAAW,KAAK;AAGpC,SAAO;GACL,MAAM;GACN,SAJgB,KAAK,iBAAiB,OAAO;GAK7C,UAAU;GACX;;;;;CAMH,YAAY,OAAsB;AAChC,UAAQ,OAAR;GACE,KAAK,OACH,QAAO;GACT,QACE,OAAM,IAAI,MAAM,gCAAgC,QAAQ;;;;;;CAO9D,cAAc,OAAuB;AACnC,SAAO,UAAU;;;;;CAMnB,MAAM,cACJ,OACA,SACA,UACyB;AACzB,MAAI,CAAC,KAAK,cAAc,MAAM,CAC5B,OAAM,IAAI,kBAAkB,MAAM;EAGpC,MAAM,OAAO,KAAK,YAAY,MAAM;EACpC,MAAM,SAAS,KAAK,WAAW,KAAK;EAGpC,MAAM,WAAW,OAAO;AACxB,MAAI,CAAC,YAAY,EAAE,WAAW,UAC5B,OAAM,IAAI,qBAAqB,QAAQ;EAIzC,MAAM,gBAAgB,SAAS;EAG/B,MAAM,YAAY,EAAE,GAAG,QAAQ;AAC/B,OAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,cAAc,CACtD,WAAU,OAAO;AAInB,YAAU,kBAAkB;AAG5B,OAAK,YAAY,MAAM,UAAU;AAEjC,SAAO;GACL,SAAS;GACT,SAAS,wBAAwB;GACjC,UAAU;GACX;;;;;CAMH,AAAU,WAAW,MAAuC;AAC1D,SAAOA,SAAiB,KAAK;;;;;CAM/B,AAAU,YAAY,MAAc,MAAqC;AACvE,YAAkB,MAAM,KAAK;;CAG/B,AAAQ,iBACN,QACyB;EACzB,MAAM,YAAY,OAAO;AACzB,MACE,OAAO,cAAc,YACrB,cAAc,QACd,CAAC,MAAM,QAAQ,UAAU,CAEzB,QAAO;AAET,SAAO,EAAE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"get.d.ts","names":[],"sources":["../../../src/commands/settings/get.ts"],"sourcesContent":[],"mappings":";;;;;cAcqB,WAAA,SAAoB,OAAA;;;;;;EAmC1B,CAAA;EAnC0B,OAAA,KAAA,EAAA;IAAO,IAAA,oCAAA,CAAA,MAAA,wCAAA;;;SAmCjC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"get.js","names":["fsStore.resolveHome"],"sources":["../../../src/commands/settings/get.ts"],"sourcesContent":["/**\n * settings:get 命令\n * 获取指定配置项的值\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Args, Command, Flags } from \"@oclif/core\";\nimport { SettingsDispatcher } from \"@/services/settings/dispatcher.ts\";\nimport { formatJson } from \"@/utils/format.ts\";\nimport * as fsStore from \"@/services/settings/fsStore.ts\";\nimport { ClaudeAdapter } from \"@/services/settings/adapters/claude.ts\";\nimport type { ToolId, Scope, InspectResult } from \"@/domain/types.ts\";\n\nexport default class SettingsGet extends Command {\n static summary = \"View the full configuration file\";\n\n static description = `\n Print the entire configuration file for the selected tool/scope.\n Use --json for structured output or --no-json for plain text.\n `;\n\n static examples = [\n \"<%= config.bin %> <%= command.id %> --tool claude --scope user\",\n \"<%= config.bin %> <%= command.id %> --tool codex --no-json\",\n ];\n\n static args = {\n name: Args.string({\n description: \"Claude variant name (optional). Example: settings:get hxi\",\n required: false,\n }),\n };\n\n static flags = {\n tool: Flags.string({\n char: \"t\",\n description: \"AI CLI tool to manage\",\n options: [\"claude\", \"codex\", \"gemini\"],\n default: \"claude\",\n }),\n scope: Flags.string({\n char: \"s\",\n description: \"Configuration scope\",\n options: [\"user\", \"project\", \"local\", \"system\"],\n default: \"user\",\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(SettingsGet);\n\n try {\n const tool = flags.tool as ToolId;\n const scope = flags.scope as Scope;\n const data =\n tool === \"claude\" && args.name\n ? await this.inspectClaudeVariant(scope, args.name)\n : await this.inspectViaDispatcher(tool, scope);\n\n if (flags.json) {\n this.log(formatJson({ success: true, data }));\n return;\n }\n\n if (!data.exists) {\n this.warn(`Config file not found: ${data.path}`);\n return;\n }\n\n if (data.content) {\n this.log(data.content);\n } else {\n this.log(\"File is empty.\");\n }\n } catch (error) {\n this.error((error as Error).message, { exit: 1 });\n }\n }\n\n private async inspectViaDispatcher(tool: ToolId, scope: Scope) {\n const dispatcher = new SettingsDispatcher();\n const result = await dispatcher.execute({\n tool,\n scope,\n action: \"inspect\",\n });\n return result.data as InspectResult;\n }\n\n private async inspectClaudeVariant(\n scope: Scope,\n name: string,\n ): Promise<InspectResult> {\n const adapter = new ClaudeAdapter();\n if (!adapter.validateScope(scope)) {\n throw new Error(`Invalid scope for Claude: ${scope}`);\n }\n\n const normalized = name.trim();\n if (!normalized || normalized === \"default\") {\n return this.inspectViaDispatcher(\"claude\", scope);\n }\n\n const basePath = adapter.resolvePath(scope);\n const resolvedBase = fsStore.resolveHome(basePath);\n const directory = path.dirname(resolvedBase);\n const variantPath =\n this.findVariantPath(directory, normalized) ??\n path.join(directory, `settings.${normalized}.json`);\n\n if (!fs.existsSync(variantPath)) {\n return {\n path: variantPath,\n exists: false,\n };\n }\n\n const stats = fs.statSync(variantPath);\n return {\n path: variantPath,\n exists: true,\n content: fs.readFileSync(variantPath, \"utf-8\"),\n size: stats.size,\n lastModified: stats.mtime,\n };\n }\n\n private findVariantPath(directory: string, name: string): string | null {\n const candidates = [`settings.${name}.json`, `settings-${name}.json`];\n\n for (const candidate of candidates) {\n const fullPath = path.join(directory, candidate);\n if (fs.existsSync(fullPath)) {\n return fullPath;\n }\n }\n return null;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAcA,IAAqB,cAArB,MAAqB,oBAAoB,QAAQ;CAC/C,OAAO,UAAU;CAEjB,OAAO,cAAc;;;;CAKrB,OAAO,WAAW,CAChB,kEACA,6DACD;CAED,OAAO,OAAO,EACZ,MAAM,KAAK,OAAO;EAChB,aAAa;EACb,UAAU;EACX,CAAC,EACH;CAED,OAAO,QAAQ;EACb,MAAM,MAAM,OAAO;GACjB,MAAM;GACN,aAAa;GACb,SAAS;IAAC;IAAU;IAAS;IAAS;GACtC,SAAS;GACV,CAAC;EACF,OAAO,MAAM,OAAO;GAClB,MAAM;GACN,aAAa;GACb,SAAS;IAAC;IAAQ;IAAW;IAAS;IAAS;GAC/C,SAAS;GACV,CAAC;EACH;CAED,MAAM,MAAqB;EACzB,MAAM,EAAE,MAAM,UAAU,MAAM,KAAK,MAAM,YAAY;AAErD,MAAI;GACF,MAAM,OAAO,MAAM;GACnB,MAAM,QAAQ,MAAM;GACpB,MAAM,OACJ,SAAS,YAAY,KAAK,OACtB,MAAM,KAAK,qBAAqB,OAAO,KAAK,KAAK,GACjD,MAAM,KAAK,qBAAqB,MAAM,MAAM;AAElD,OAAI,MAAM,MAAM;AACd,SAAK,IAAI,WAAW;KAAE,SAAS;KAAM;KAAM,CAAC,CAAC;AAC7C;;AAGF,OAAI,CAAC,KAAK,QAAQ;AAChB,SAAK,KAAK,0BAA0B,KAAK,OAAO;AAChD;;AAGF,OAAI,KAAK,QACP,MAAK,IAAI,KAAK,QAAQ;OAEtB,MAAK,IAAI,iBAAiB;WAErB,OAAO;AACd,QAAK,MAAO,MAAgB,SAAS,EAAE,MAAM,GAAG,CAAC;;;CAIrD,MAAc,qBAAqB,MAAc,OAAc;AAO7D,UALe,MADI,IAAI,oBAAoB,CACX,QAAQ;GACtC;GACA;GACA,QAAQ;GACT,CAAC,EACY;;CAGhB,MAAc,qBACZ,OACA,MACwB;EACxB,MAAM,UAAU,IAAI,eAAe;AACnC,MAAI,CAAC,QAAQ,cAAc,MAAM,CAC/B,OAAM,IAAI,MAAM,6BAA6B,QAAQ;EAGvD,MAAM,aAAa,KAAK,MAAM;AAC9B,MAAI,CAAC,cAAc,eAAe,UAChC,QAAO,KAAK,qBAAqB,UAAU,MAAM;EAGnD,MAAM,WAAW,QAAQ,YAAY,MAAM;EAC3C,MAAM,eAAeA,YAAoB,SAAS;EAClD,MAAM,YAAY,KAAK,QAAQ,aAAa;EAC5C,MAAM,cACJ,KAAK,gBAAgB,WAAW,WAAW,IAC3C,KAAK,KAAK,WAAW,YAAY,WAAW,OAAO;AAErD,MAAI,CAAC,GAAG,WAAW,YAAY,CAC7B,QAAO;GACL,MAAM;GACN,QAAQ;GACT;EAGH,MAAM,QAAQ,GAAG,SAAS,YAAY;AACtC,SAAO;GACL,MAAM;GACN,QAAQ;GACR,SAAS,GAAG,aAAa,aAAa,QAAQ;GAC9C,MAAM,MAAM;GACZ,cAAc,MAAM;GACrB;;CAGH,AAAQ,gBAAgB,WAAmB,MAA6B;EACtE,MAAM,aAAa,CAAC,YAAY,KAAK,QAAQ,YAAY,KAAK,OAAO;AAErE,OAAK,MAAM,aAAa,YAAY;GAClC,MAAM,WAAW,KAAK,KAAK,WAAW,UAAU;AAChD,OAAI,GAAG,WAAW,SAAS,CACzB,QAAO;;AAGX,SAAO"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"inspect.d.ts","names":[],"sources":["../../../src/commands/settings/inspect.ts"],"sourcesContent":[],"mappings":";;;;;AAUqC,cAAhB,eAAA,SAAwB,OAAA,CAAR;;;;;IAqCtB,IAAA,qCAAA,CAAA,MAAA,EArCsB,wBAAA,CAAA,aAAA,CAqCtB;IArC8B,KAAA,qCAAA,CAAA,MAAA,yCAAA;IAAO,IAAA,sCAAA,CAAA,OAAA,CAAA;;SAqCrC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"inspect.js","names":[],"sources":["../../../src/commands/settings/inspect.ts"],"sourcesContent":["/**\n * settings:inspect 命令\n * 检查配置文件状态\n */\n\nimport { Command, Flags } from \"@oclif/core\";\nimport { SettingsDispatcher } from \"@/services/settings/dispatcher.ts\";\nimport { formatJson } from \"@/utils/format.ts\";\nimport type { ToolId, Scope, InspectResult } from \"@/domain/types.ts\";\n\nexport default class SettingsInspect extends Command {\n static summary = \"Inspect configuration file status\";\n\n static description = `\n Display information about the configuration file, including:\n - File path\n - Existence status\n - File size\n - Last modified date\n - File contents (if exists)\n `;\n\n static examples = [\n \"<%= config.bin %> <%= command.id %> --tool claude --scope user\",\n \"<%= config.bin %> <%= command.id %> --tool codex --json\",\n ];\n\n static flags = {\n tool: Flags.string({\n char: \"t\",\n description: \"AI CLI tool to manage\",\n options: [\"claude\", \"codex\", \"gemini\"],\n default: \"claude\",\n }),\n scope: Flags.string({\n char: \"s\",\n description: \"Configuration scope\",\n options: [\"user\", \"project\", \"local\", \"system\"],\n default: \"user\",\n }),\n json: Flags.boolean({\n description: \"Output JSON (default)\",\n default: true,\n allowNo: true,\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(SettingsInspect);\n\n try {\n const dispatcher = new SettingsDispatcher();\n const result = await dispatcher.execute({\n tool: flags.tool as ToolId,\n scope: flags.scope as Scope,\n action: \"inspect\",\n });\n\n if (flags.json) {\n this.log(formatJson(result));\n return;\n }\n\n const data = result.data as InspectResult;\n this.log(`Path: ${data.path}`);\n this.log(`Exists: ${data.exists ? \"Yes\" : \"No\"}`);\n\n if (data.exists) {\n if (data.size !== undefined) {\n this.log(`Size: ${data.size} bytes`);\n }\n if (data.lastModified) {\n this.log(`Last Modified: ${data.lastModified.toISOString()}`);\n }\n if (data.content) {\n this.log(\"\\nContents:\");\n this.log(data.content);\n }\n }\n } catch (error) {\n this.error((error as Error).message, { exit: 1 });\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAUA,IAAqB,kBAArB,MAAqB,wBAAwB,QAAQ;CACnD,OAAO,UAAU;CAEjB,OAAO,cAAc;;;;;;;;CASrB,OAAO,WAAW,CAChB,kEACA,0DACD;CAED,OAAO,QAAQ;EACb,MAAM,MAAM,OAAO;GACjB,MAAM;GACN,aAAa;GACb,SAAS;IAAC;IAAU;IAAS;IAAS;GACtC,SAAS;GACV,CAAC;EACF,OAAO,MAAM,OAAO;GAClB,MAAM;GACN,aAAa;GACb,SAAS;IAAC;IAAQ;IAAW;IAAS;IAAS;GAC/C,SAAS;GACV,CAAC;EACF,MAAM,MAAM,QAAQ;GAClB,aAAa;GACb,SAAS;GACT,SAAS;GACV,CAAC;EACH;CAED,MAAM,MAAqB;EACzB,MAAM,EAAE,UAAU,MAAM,KAAK,MAAM,gBAAgB;AAEnD,MAAI;GAEF,MAAM,SAAS,MADI,IAAI,oBAAoB,CACX,QAAQ;IACtC,MAAM,MAAM;IACZ,OAAO,MAAM;IACb,QAAQ;IACT,CAAC;AAEF,OAAI,MAAM,MAAM;AACd,SAAK,IAAI,WAAW,OAAO,CAAC;AAC5B;;GAGF,MAAM,OAAO,OAAO;AACpB,QAAK,IAAI,SAAS,KAAK,OAAO;AAC9B,QAAK,IAAI,WAAW,KAAK,SAAS,QAAQ,OAAO;AAEjD,OAAI,KAAK,QAAQ;AACf,QAAI,KAAK,SAAS,OAChB,MAAK,IAAI,SAAS,KAAK,KAAK,QAAQ;AAEtC,QAAI,KAAK,aACP,MAAK,IAAI,kBAAkB,KAAK,aAAa,aAAa,GAAG;AAE/D,QAAI,KAAK,SAAS;AAChB,UAAK,IAAI,cAAc;AACvB,UAAK,IAAI,KAAK,QAAQ;;;WAGnB,OAAO;AACd,QAAK,MAAO,MAAgB,SAAS,EAAE,MAAM,GAAG,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"list.d.ts","names":[],"sources":["../../../src/commands/settings/list.ts"],"sourcesContent":[],"mappings":";;;;;AAekC,cAAb,YAAA,SAAqB,OAAA,CAAR;;;;;sDAAA,wBAAA,CAAA,aAAA;IAqCnB,KAAA,qCAAA,CAAA,MAAA,yCAAA;IArC2B,IAAA,sCAAA,CAAA,OAAA,CAAA;IAAO,KAAA,sCAAA,CAAA,OAAA,CAAA;;SAqClC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"list.js","names":[],"sources":["../../../src/commands/settings/list.ts"],"sourcesContent":["/**\n * settings:list 命令\n * 列出指定工具的所有配置\n */\n\nimport { Command, Flags } from \"@oclif/core\";\nimport { SettingsDispatcher } from \"@/services/settings/dispatcher.ts\";\nimport { formatFilesTable, formatJson, formatTable } from \"@/utils/format.ts\";\nimport type {\n ToolId,\n Scope,\n SettingsListData,\n SettingsFileEntry,\n} from \"@/domain/types.ts\";\n\nexport default class SettingsList extends Command {\n static summary = \"List all settings for a tool\";\n\n static description = `\n Display all configuration settings for the specified AI CLI tool.\n Supports multiple scopes (user, project, local, system).\n `;\n\n static examples = [\n \"<%= config.bin %> <%= command.id %> --tool claude --scope user\",\n \"<%= config.bin %> <%= command.id %> --tool codex --scope user --table\",\n \"<%= config.bin %> -t gemini -s project --no-json\",\n ];\n\n static flags = {\n tool: Flags.string({\n char: \"t\",\n description: \"AI CLI tool to manage\",\n options: [\"claude\", \"codex\", \"gemini\"],\n default: \"claude\",\n }),\n scope: Flags.string({\n char: \"s\",\n description: \"Configuration scope\",\n options: [\"user\", \"project\", \"local\", \"system\"],\n default: \"user\",\n }),\n json: Flags.boolean({\n description: \"Output JSON instead of text summary\",\n default: false,\n }),\n table: Flags.boolean({\n description: \"Render table output instead of JSON\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(SettingsList);\n\n try {\n const dispatcher = new SettingsDispatcher();\n const result = await dispatcher.execute({\n tool: flags.tool as ToolId,\n scope: flags.scope as Scope,\n action: \"list\",\n });\n\n if (flags.table) {\n this.renderDetailed(result.data as SettingsListData | undefined);\n return;\n }\n\n if (flags.json) {\n this.log(formatJson(result));\n return;\n }\n\n this.renderSummary(result.data as SettingsListData | undefined);\n } catch (error) {\n this.error((error as Error).message, { exit: 1 });\n }\n }\n\n private renderSummary(data?: SettingsListData): void {\n if (!data) {\n this.log(\"No settings found.\");\n return;\n }\n\n if (data.type === \"files\") {\n if (data.files.length === 0) {\n this.log(\"No settings files found.\");\n return;\n }\n this.log(this.formatFilesSummary(data.files));\n return;\n }\n\n if (Object.keys(data.entries).length === 0) {\n this.log(\"No settings found.\");\n return;\n }\n\n this.log(this.formatEntriesSummary(data.entries, data.filePath));\n }\n\n private renderDetailed(data?: SettingsListData): void {\n if (!data) {\n this.log(\"No settings found.\");\n return;\n }\n\n if (data.type === \"files\") {\n if (data.files.length === 0) {\n this.log(\"No settings files found.\");\n return;\n }\n this.log(formatFilesTable(data.files));\n return;\n }\n\n if (Object.keys(data.entries).length === 0) {\n this.log(\"No settings found.\");\n return;\n }\n\n this.log(formatTable(data.entries));\n this.log(`File: ${data.filePath}`);\n }\n\n private formatFilesSummary(files: SettingsFileEntry[]): string {\n const lines = files.map((file) => {\n const prefix = file.active ? \"* \" : \"- \";\n return (\n `${prefix}${file.variant} -> ${file.path}` +\n (file.exists ? \"\" : \" (missing)\")\n );\n });\n return [\"files:\"].concat(lines).join(\"\\n\");\n }\n\n private formatEntriesSummary(\n entries: Record<string, unknown>,\n filePath: string,\n ): string {\n const lines = [\"entries:\"];\n for (const [key, value] of Object.entries(entries)) {\n const formatted = this.stringify(value);\n if (formatted.includes(\"\\n\")) {\n lines.push(`- ${key}:`);\n for (const line of formatted.split(\"\\n\")) {\n lines.push(` ${line}`);\n }\n } else {\n lines.push(`- ${key}: ${formatted}`);\n }\n }\n lines.push(`file: ${filePath}`);\n return lines.join(\"\\n\");\n }\n\n private stringify(value: unknown): string {\n if (value === null || value === undefined) return \"null\";\n if (typeof value === \"object\") {\n return JSON.stringify(value, null, 2);\n }\n return String(value);\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"set.d.ts","names":[],"sources":["../../../src/commands/settings/set.ts"],"sourcesContent":[],"mappings":";;;;;AAUiC,cAAZ,WAAA,SAAoB,OAAA,CAAR;;;;;;sDAAA,wBAAA,CAAA,aAAA;;;IA2ClB,GAAA,qCAAA,CAAA,MAAA,yCAAA;IA3C0B,IAAA,sCAAA,CAAA,OAAA,CAAA;EAAO,CAAA;SA2CjC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"set.js","names":[],"sources":["../../../src/commands/settings/set.ts"],"sourcesContent":["/**\n * settings:set 命令\n * 设置配置项的值\n */\n\nimport { Command, Flags } from \"@oclif/core\";\nimport { SettingsDispatcher } from \"@/services/settings/dispatcher.ts\";\nimport { formatJson } from \"@/utils/format.ts\";\nimport type { ToolId, Scope } from \"@/domain/types.ts\";\n\nexport default class SettingsSet extends Command {\n static summary = \"Open settings files in your IDE (Claude only)\";\n\n static description = `\n Create or open Claude settings variants in your preferred editor.\n Provide --name to edit settings.<name>.json (default: settings.json).\n `;\n\n static examples = [\n \"<%= config.bin %> <%= command.id %> --tool claude --scope user --name hxi\",\n \"<%= config.bin %> <%= command.id %> --tool claude --scope project --name default --ide cursor\",\n ];\n\n static args = {};\n\n static flags = {\n tool: Flags.string({\n char: \"t\",\n description: \"AI CLI tool to manage\",\n options: [\"claude\", \"codex\", \"gemini\"],\n default: \"claude\",\n }),\n scope: Flags.string({\n char: \"s\",\n description: \"Configuration scope\",\n options: [\"user\", \"project\", \"local\", \"system\"],\n default: \"user\",\n }),\n name: Flags.string({\n description:\n \"Claude variant name (e.g., hxi). Creates settings.<name>.json if missing and opens it in the IDE.\",\n }),\n ide: Flags.string({\n description: \"Editor command or alias (default: code for VS Code)\",\n default: \"code\",\n }),\n json: Flags.boolean({\n description: \"Output JSON (default)\",\n default: true,\n allowNo: true,\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(SettingsSet);\n\n try {\n if (flags.tool !== \"claude\") {\n this.error(\n \"Editing settings files is currently only supported for Claude.\",\n {\n exit: 1,\n },\n );\n }\n\n const dispatcher = new SettingsDispatcher();\n const result = await dispatcher.execute({\n tool: flags.tool as ToolId,\n scope: flags.scope as Scope,\n action: \"edit\",\n name: flags.name,\n ide: flags.ide,\n });\n\n if (flags.json) {\n this.log(formatJson(result));\n } else {\n this.log(result.message ?? \"Opened settings file\");\n if (result.filePath) {\n this.log(`File: ${result.filePath}`);\n }\n }\n } catch (error) {\n this.error((error as Error).message, { exit: 1 });\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAUA,IAAqB,cAArB,MAAqB,oBAAoB,QAAQ;CAC/C,OAAO,UAAU;CAEjB,OAAO,cAAc;;;;CAKrB,OAAO,WAAW,CAChB,6EACA,gGACD;CAED,OAAO,OAAO,EAAE;CAEhB,OAAO,QAAQ;EACb,MAAM,MAAM,OAAO;GACjB,MAAM;GACN,aAAa;GACb,SAAS;IAAC;IAAU;IAAS;IAAS;GACtC,SAAS;GACV,CAAC;EACF,OAAO,MAAM,OAAO;GAClB,MAAM;GACN,aAAa;GACb,SAAS;IAAC;IAAQ;IAAW;IAAS;IAAS;GAC/C,SAAS;GACV,CAAC;EACF,MAAM,MAAM,OAAO,EACjB,aACE,qGACH,CAAC;EACF,KAAK,MAAM,OAAO;GAChB,aAAa;GACb,SAAS;GACV,CAAC;EACF,MAAM,MAAM,QAAQ;GAClB,aAAa;GACb,SAAS;GACT,SAAS;GACV,CAAC;EACH;CAED,MAAM,MAAqB;EACzB,MAAM,EAAE,UAAU,MAAM,KAAK,MAAM,YAAY;AAE/C,MAAI;AACF,OAAI,MAAM,SAAS,SACjB,MAAK,MACH,kEACA,EACE,MAAM,GACP,CACF;GAIH,MAAM,SAAS,MADI,IAAI,oBAAoB,CACX,QAAQ;IACtC,MAAM,MAAM;IACZ,OAAO,MAAM;IACb,QAAQ;IACR,MAAM,MAAM;IACZ,KAAK,MAAM;IACZ,CAAC;AAEF,OAAI,MAAM,KACR,MAAK,IAAI,WAAW,OAAO,CAAC;QACvB;AACL,SAAK,IAAI,OAAO,WAAW,uBAAuB;AAClD,QAAI,OAAO,SACT,MAAK,IAAI,SAAS,OAAO,WAAW;;WAGjC,OAAO;AACd,QAAK,MAAO,MAAgB,SAAS,EAAE,MAAM,GAAG,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"switch.d.ts","names":[],"sources":["../../../src/commands/settings/switch.ts"],"sourcesContent":[],"mappings":";;;;;cAYqB,cAAA,SAAuB,OAAA;;;;;;;;;IAgD7B,KAAA,oCAAA,CAAA,MAAA,wCAAA;IAhD6B,IAAA,qCAAA,CAAA,OAAA,CAAA;IAAO,KAAA,qCAAA,CAAA,OAAA,CAAA;;;SAgDpC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"switch.js","names":[],"sources":["../../../src/commands/settings/switch.ts"],"sourcesContent":["/**\n * settings:switch 命令\n * 切换 profile(仅 Codex 支持)\n */\n\nimport { Args, Command, Flags } from \"@oclif/core\";\nimport readline from \"node:readline/promises\";\nimport { stdin as input, stdout as output } from \"node:process\";\nimport { SettingsDispatcher } from \"@/services/settings/dispatcher.ts\";\nimport { formatJson } from \"@/utils/format.ts\";\nimport type { ToolId, Scope, SettingsResult } from \"@/domain/types.ts\";\n\nexport default class SettingsSwitch extends Command {\n static summary = \"Switch Codex profiles or Claude settings variants\";\n\n static description = `\n Switch to a different profile configuration for Codex\n or activate a specific settings.<variant>.json for Claude.\n `;\n\n static examples = [\n \"<%= config.bin %> <%= command.id %> oss --tool codex\",\n \"<%= config.bin %> <%= command.id %> production --tool codex\",\n \"<%= config.bin %> <%= command.id %> hxi --tool claude --scope user\",\n ];\n\n static args = {\n profile: Args.string({\n description: \"Profile name to switch to\",\n required: true,\n }),\n };\n\n static flags = {\n tool: Flags.string({\n char: \"t\",\n description: \"AI CLI tool to manage\",\n options: [\"claude\", \"codex\", \"gemini\"],\n default: \"claude\",\n }),\n scope: Flags.string({\n char: \"s\",\n description: \"Configuration scope\",\n options: [\"user\", \"project\", \"local\", \"system\"],\n default: \"user\",\n }),\n json: Flags.boolean({\n description: \"Output JSON instead of interactive text\",\n default: false,\n }),\n force: Flags.boolean({\n description: \"Skip confirmation prompts (Claude only)\",\n default: false,\n }),\n backup: Flags.boolean({\n description: \"Create a .bak backup when switching (Claude only)\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(SettingsSwitch);\n\n try {\n const dispatcher = new SettingsDispatcher();\n const result =\n flags.tool === \"claude\"\n ? await this.handleClaudeSwitch(dispatcher, args.profile, flags)\n : await dispatcher.execute({\n tool: flags.tool as ToolId,\n scope: flags.scope as Scope,\n action: \"switch-profile\",\n profile: args.profile,\n });\n\n if (!result) {\n return;\n }\n\n this.printResult(result, args.profile, flags);\n } catch (error) {\n this.error((error as Error).message, { exit: 1 });\n }\n }\n\n private async handleClaudeSwitch(\n dispatcher: SettingsDispatcher,\n profile: string,\n flags: Record<string, any>,\n ): Promise<SettingsResult | null> {\n if (flags.json && !flags.force) {\n this.error(\"--json requires --force when switching Claude settings.\", {\n exit: 1,\n });\n }\n\n const preview = await dispatcher.execute({\n tool: \"claude\",\n scope: flags.scope as Scope,\n action: \"switch-profile\",\n profile,\n switchOptions: { preview: true },\n });\n\n if (preview.diff) {\n this.log(\"Proposed changes:\\n\" + preview.diff);\n } else {\n this.log(\n \"No differences detected. Current settings already match the selected variant.\",\n );\n return preview;\n }\n\n let backup = Boolean(flags.backup);\n if (!flags.force && !backup) {\n const action = await this.promptClaudeAction();\n if (action === \"cancel\") {\n this.log(\"Switch cancelled.\");\n return null;\n }\n backup = action === \"backup\";\n }\n\n const result = await dispatcher.execute({\n tool: \"claude\",\n scope: flags.scope as Scope,\n action: \"switch-profile\",\n profile,\n switchOptions: { backup },\n });\n result.diff = preview.diff;\n return result;\n }\n\n private async promptClaudeAction(): Promise<\n \"overwrite\" | \"backup\" | \"cancel\"\n > {\n const rl = readline.createInterface({ input, output });\n try {\n while (true) {\n const answer = (\n await rl.question(\"Choose action ([o]verwrite/[b]ackup/[c]ancel): \")\n )\n .trim()\n .toLowerCase();\n if ([\"overwrite\", \"backup\", \"cancel\"].includes(answer)) {\n return answer as \"overwrite\" | \"backup\" | \"cancel\";\n }\n if ([\"o\", \"b\", \"c\"].includes(answer)) {\n return {\n o: \"overwrite\",\n b: \"backup\",\n c: \"cancel\",\n }[answer] as \"overwrite\" | \"backup\" | \"cancel\";\n }\n }\n } finally {\n rl.close();\n }\n }\n\n private printResult(\n result: SettingsResult,\n profile: string,\n flags: Record<string, any>,\n ): void {\n if (flags.json) {\n this.log(formatJson(result));\n return;\n }\n\n if (result.preview) {\n this.log(\"Preview only. No changes applied.\");\n if (result.diff) {\n this.log(result.diff);\n }\n return;\n }\n\n this.log(result.message ?? `✓ Switched to profile: ${profile}`);\n if (result.filePath) {\n this.log(` File: ${result.filePath}`);\n }\n if (result.diff) {\n this.log(\"Applied diff:\\n\" + result.diff);\n }\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"dispatcher-JXm3OqRQ.js","names":[],"sources":["../src/services/settings/dispatcher.ts"],"sourcesContent":["/**\n * Settings 调度器\n * 负责将请求路由到对应的适配器(DIP 原则)\n */\n\nimport type { SettingsAdapter } from \"@/domain/interfaces.ts\";\nimport type {\n SettingsPayload,\n SettingsResult,\n ToolId,\n} from \"@/domain/types.ts\";\nimport { ClaudeAdapter } from \"./adapters/claude.ts\";\nimport { CodexAdapter } from \"./adapters/codex.ts\";\nimport { GeminiAdapter } from \"./adapters/gemini.ts\";\nimport { UnsupportedToolError } from \"@/utils/errors.ts\";\n\n/**\n * Settings 调度器\n *\n * 体现 SOLID 原则:\n * - OCP: 新增工具只需在构造函数中注册适配器\n * - DIP: 依赖 SettingsAdapter 接口,不依赖具体实现\n * - SRP: 只负责调度,不处理具体逻辑\n */\nexport class SettingsDispatcher {\n private adapters: Map<ToolId, SettingsAdapter>;\n\n constructor() {\n // 注册所有适配器\n this.adapters = new Map<ToolId, SettingsAdapter>();\n this.adapters.set(\"claude\", new ClaudeAdapter());\n this.adapters.set(\"codex\", new CodexAdapter());\n this.adapters.set(\"gemini\", new GeminiAdapter());\n }\n\n /**\n * 执行 settings 操作\n */\n async execute(payload: SettingsPayload): Promise<SettingsResult> {\n const adapter = this.getAdapter(payload.tool);\n\n switch (payload.action) {\n case \"list\":\n return {\n success: true,\n data: await adapter.list(payload.scope),\n };\n\n case \"switch-profile\":\n if (!payload.profile) {\n throw new Error(\"Profile is required for switch-profile action\");\n }\n if (!adapter.switchProfile) {\n throw new Error(\n `Tool ${payload.tool} does not support profile switching`,\n );\n }\n return await adapter.switchProfile(\n payload.scope,\n payload.profile,\n payload.switchOptions,\n );\n\n case \"edit\":\n if (!adapter.edit) {\n throw new Error(\n `Tool ${payload.tool} does not support editing via CLI`,\n );\n }\n return await adapter.edit(payload.scope, {\n name: payload.name,\n ide: payload.ide,\n });\n\n case \"inspect\":\n if (!adapter.inspect) {\n throw new Error(\n `Tool ${payload.tool} does not support inspect action`,\n );\n }\n return {\n success: true,\n data: await adapter.inspect(payload.scope),\n };\n\n default:\n throw new Error(`Unsupported action: ${payload.action}`);\n }\n }\n\n /**\n * 获取适配器\n */\n private getAdapter(tool: ToolId): SettingsAdapter {\n const adapter = this.adapters.get(tool);\n if (!adapter) {\n throw new UnsupportedToolError(tool);\n }\n return adapter;\n }\n\n /**\n * 注册新的适配器(扩展点)\n */\n registerAdapter(adapter: SettingsAdapter): void {\n this.adapters.set(adapter.toolId, adapter);\n }\n\n /**\n * 获取所有支持的工具\n */\n getSupportedTools(): ToolId[] {\n return Array.from(this.adapters.keys());\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAwBA,IAAa,qBAAb,MAAgC;CAC9B,AAAQ;CAER,cAAc;AAEZ,OAAK,2BAAW,IAAI,KAA8B;AAClD,OAAK,SAAS,IAAI,UAAU,IAAI,eAAe,CAAC;AAChD,OAAK,SAAS,IAAI,SAAS,IAAI,cAAc,CAAC;AAC9C,OAAK,SAAS,IAAI,UAAU,IAAI,eAAe,CAAC;;;;;CAMlD,MAAM,QAAQ,SAAmD;EAC/D,MAAM,UAAU,KAAK,WAAW,QAAQ,KAAK;AAE7C,UAAQ,QAAQ,QAAhB;GACE,KAAK,OACH,QAAO;IACL,SAAS;IACT,MAAM,MAAM,QAAQ,KAAK,QAAQ,MAAM;IACxC;GAEH,KAAK;AACH,QAAI,CAAC,QAAQ,QACX,OAAM,IAAI,MAAM,gDAAgD;AAElE,QAAI,CAAC,QAAQ,cACX,OAAM,IAAI,MACR,QAAQ,QAAQ,KAAK,qCACtB;AAEH,WAAO,MAAM,QAAQ,cACnB,QAAQ,OACR,QAAQ,SACR,QAAQ,cACT;GAEH,KAAK;AACH,QAAI,CAAC,QAAQ,KACX,OAAM,IAAI,MACR,QAAQ,QAAQ,KAAK,mCACtB;AAEH,WAAO,MAAM,QAAQ,KAAK,QAAQ,OAAO;KACvC,MAAM,QAAQ;KACd,KAAK,QAAQ;KACd,CAAC;GAEJ,KAAK;AACH,QAAI,CAAC,QAAQ,QACX,OAAM,IAAI,MACR,QAAQ,QAAQ,KAAK,kCACtB;AAEH,WAAO;KACL,SAAS;KACT,MAAM,MAAM,QAAQ,QAAQ,QAAQ,MAAM;KAC3C;GAEH,QACE,OAAM,IAAI,MAAM,uBAAuB,QAAQ,SAAS;;;;;;CAO9D,AAAQ,WAAW,MAA+B;EAChD,MAAM,UAAU,KAAK,SAAS,IAAI,KAAK;AACvC,MAAI,CAAC,QACH,OAAM,IAAI,qBAAqB,KAAK;AAEtC,SAAO;;;;;CAMT,gBAAgB,SAAgC;AAC9C,OAAK,SAAS,IAAI,QAAQ,QAAQ,QAAQ;;;;;CAM5C,oBAA8B;AAC5B,SAAO,MAAM,KAAK,KAAK,SAAS,MAAM,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"validators.d.ts","names":[],"sources":["../../src/domain/validators.ts"],"sourcesContent":[],"mappings":";;;;AAcA;AAKA;AAUA;cApBa,cAAY,CAAA,CAAA;;;;;;;;cAKZ,aAAW,CAAA,CAAA;;;;;;;;;cAKX,qBAAmB,CAAA,CAAA;;EAUE,IAAA,EAAA,MAAA;EAAA,gBAAA,EAAA,gBAAA;EAmBlB,OAAA,EAAA,SAAe;;;;;cAnBlB,uBAAqB,CAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmBlB,eAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"validators.js","names":[],"sources":["../../src/domain/validators.ts"],"sourcesContent":["/**\n * 配置验证器\n */\n\nimport { z } from \"zod\";\n\n/**\n * ToolId 验证 schema\n */\nexport const ToolIdSchema = z.enum([\"claude\", \"codex\", \"gemini\"]);\n\n/**\n * Scope 验证 schema\n */\nexport const ScopeSchema = z.enum([\"user\", \"project\", \"local\", \"system\"]);\n\n/**\n * SettingAction 验证 schema\n */\nexport const SettingActionSchema = z.enum([\n \"list\",\n \"edit\",\n \"switch-profile\",\n \"inspect\",\n]);\n\n/**\n * SettingsPayload 验证 schema\n */\nexport const SettingsPayloadSchema = z.object({\n tool: ToolIdSchema,\n scope: ScopeSchema,\n action: SettingActionSchema,\n profile: z.string().optional(),\n name: z.string().optional(),\n ide: z.string().optional(),\n format: z.enum([\"json\", \"table\"]).optional(),\n switchOptions: z\n .object({\n preview: z.boolean().optional(),\n backup: z.boolean().optional(),\n })\n .optional(),\n});\n\n/**\n * 验证 SettingsPayload\n */\nexport function validatePayload(payload: unknown) {\n return SettingsPayloadSchema.parse(payload);\n}\n"],"mappings":";;;;;;;;;AASA,MAAa,eAAe,EAAE,KAAK;CAAC;CAAU;CAAS;CAAS,CAAC;;;;AAKjE,MAAa,cAAc,EAAE,KAAK;CAAC;CAAQ;CAAW;CAAS;CAAS,CAAC;;;;AAKzE,MAAa,sBAAsB,EAAE,KAAK;CACxC;CACA;CACA;CACA;CACD,CAAC;;;;AAKF,MAAa,wBAAwB,EAAE,OAAO;CAC5C,MAAM;CACN,OAAO;CACP,QAAQ;CACR,SAAS,EAAE,QAAQ,CAAC,UAAU;CAC9B,MAAM,EAAE,QAAQ,CAAC,UAAU;CAC3B,KAAK,EAAE,QAAQ,CAAC,UAAU;CAC1B,QAAQ,EAAE,KAAK,CAAC,QAAQ,QAAQ,CAAC,CAAC,UAAU;CAC5C,eAAe,EACZ,OAAO;EACN,SAAS,EAAE,SAAS,CAAC,UAAU;EAC/B,QAAQ,EAAE,SAAS,CAAC,UAAU;EAC/B,CAAC,CACD,UAAU;CACd,CAAC;;;;AAKF,SAAgB,gBAAgB,SAAkB;AAChD,QAAO,sBAAsB,MAAM,QAAQ"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"editor-D4qoje1V.js","names":["KNOWN_EDITORS: Record<string, string>"],"sources":["../src/utils/editor.ts"],"sourcesContent":["import { spawn } from \"child_process\";\nimport { EditorLaunchError } from \"./errors.ts\";\n\nconst KNOWN_EDITORS: Record<string, string> = {\n vscode: \"code\",\n code: \"code\",\n cursor: \"cursor\",\n zed: \"zed\",\n sublime: \"subl\",\n subl: \"subl\",\n};\n\nexport function resolveEditorCommand(ide?: string): string {\n if (!ide) {\n return \"code\";\n }\n const normalized = ide.toLowerCase();\n return KNOWN_EDITORS[normalized] ?? ide;\n}\n\nexport async function openInEditor(\n command: string,\n filePath: string,\n): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const child = spawn(command, [filePath], {\n stdio: \"inherit\",\n });\n\n child.on(\"error\", (error) => {\n reject(new EditorLaunchError(command, error.message));\n });\n\n child.on(\"exit\", (code) => {\n if (code === 0 || code === null) {\n resolve();\n } else {\n reject(new EditorLaunchError(command, `Exited with code ${code}`));\n }\n });\n });\n}\n"],"mappings":";;;;AAGA,MAAMA,gBAAwC;CAC5C,QAAQ;CACR,MAAM;CACN,QAAQ;CACR,KAAK;CACL,SAAS;CACT,MAAM;CACP;AAED,SAAgB,qBAAqB,KAAsB;AACzD,KAAI,CAAC,IACH,QAAO;AAGT,QAAO,cADY,IAAI,aAAa,KACA;;AAGtC,eAAsB,aACpB,SACA,UACe;AACf,OAAM,IAAI,SAAe,SAAS,WAAW;EAC3C,MAAM,QAAQ,MAAM,SAAS,CAAC,SAAS,EAAE,EACvC,OAAO,WACR,CAAC;AAEF,QAAM,GAAG,UAAU,UAAU;AAC3B,UAAO,IAAI,kBAAkB,SAAS,MAAM,QAAQ,CAAC;IACrD;AAEF,QAAM,GAAG,SAAS,SAAS;AACzB,OAAI,SAAS,KAAK,SAAS,KACzB,UAAS;OAET,QAAO,IAAI,kBAAkB,SAAS,oBAAoB,OAAO,CAAC;IAEpE;GACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"errors-CAZ5k5YT.js","names":[],"sources":["../src/utils/errors.ts"],"sourcesContent":["/**\n * 自定义错误类型\n */\n\n/**\n * 基础错误类\n */\nexport class XlingError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"XlingError\";\n }\n}\n\n/**\n * 不支持的工具错误\n */\nexport class UnsupportedToolError extends XlingError {\n constructor(tool: string) {\n super(`Unsupported tool: ${tool}`);\n this.name = \"UnsupportedToolError\";\n }\n}\n\n/**\n * 无效的 scope 错误\n */\nexport class InvalidScopeError extends XlingError {\n constructor(scope: string) {\n super(`Invalid scope: ${scope}`);\n this.name = \"InvalidScopeError\";\n }\n}\n\n/**\n * 配置文件不存在错误\n */\nexport class ConfigFileNotFoundError extends XlingError {\n constructor(path: string) {\n super(`Config file not found: ${path}`);\n this.name = \"ConfigFileNotFoundError\";\n }\n}\n\n/**\n * 配置文件解析错误\n */\nexport class ConfigParseError extends XlingError {\n constructor(path: string, reason: string) {\n super(`Failed to parse config file ${path}: ${reason}`);\n this.name = \"ConfigParseError\";\n }\n}\n\n/**\n * Profile 不存在错误\n */\nexport class ProfileNotFoundError extends XlingError {\n constructor(profile: string) {\n super(`Profile not found: ${profile}`);\n this.name = \"ProfileNotFoundError\";\n }\n}\n\n/**\n * Settings 变体不存在错误\n */\nexport class SettingsVariantNotFoundError extends XlingError {\n constructor(variant: string) {\n super(`Settings variant not found: ${variant}`);\n this.name = \"SettingsVariantNotFoundError\";\n }\n}\n\n/**\n * 文件写入错误\n */\nexport class FileWriteError extends XlingError {\n constructor(path: string, reason: string) {\n super(`Failed to write file ${path}: ${reason}`);\n this.name = \"FileWriteError\";\n }\n}\n\n/**\n * 编辑器启动错误\n */\nexport class EditorLaunchError extends XlingError {\n constructor(editor: string, reason: string) {\n super(`Failed to launch editor ${editor}: ${reason}`);\n this.name = \"EditorLaunchError\";\n }\n}\n"],"mappings":";;;;;;;AAOA,IAAa,aAAb,cAAgC,MAAM;CACpC,YAAY,SAAiB;AAC3B,QAAM,QAAQ;AACd,OAAK,OAAO;;;;;;AAOhB,IAAa,uBAAb,cAA0C,WAAW;CACnD,YAAY,MAAc;AACxB,QAAM,qBAAqB,OAAO;AAClC,OAAK,OAAO;;;;;;AAOhB,IAAa,oBAAb,cAAuC,WAAW;CAChD,YAAY,OAAe;AACzB,QAAM,kBAAkB,QAAQ;AAChC,OAAK,OAAO;;;;;;AAOhB,IAAa,0BAAb,cAA6C,WAAW;CACtD,YAAY,MAAc;AACxB,QAAM,0BAA0B,OAAO;AACvC,OAAK,OAAO;;;;;;AAOhB,IAAa,mBAAb,cAAsC,WAAW;CAC/C,YAAY,MAAc,QAAgB;AACxC,QAAM,+BAA+B,KAAK,IAAI,SAAS;AACvD,OAAK,OAAO;;;;;;AAOhB,IAAa,uBAAb,cAA0C,WAAW;CACnD,YAAY,SAAiB;AAC3B,QAAM,sBAAsB,UAAU;AACtC,OAAK,OAAO;;;;;;AAOhB,IAAa,+BAAb,cAAkD,WAAW;CAC3D,YAAY,SAAiB;AAC3B,QAAM,+BAA+B,UAAU;AAC/C,OAAK,OAAO;;;;;;AAOhB,IAAa,iBAAb,cAAoC,WAAW;CAC7C,YAAY,MAAc,QAAgB;AACxC,QAAM,wBAAwB,KAAK,IAAI,SAAS;AAChD,OAAK,OAAO;;;;;;AAOhB,IAAa,oBAAb,cAAuC,WAAW;CAChD,YAAY,QAAgB,QAAgB;AAC1C,QAAM,2BAA2B,OAAO,IAAI,SAAS;AACrD,OAAK,OAAO"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"format-Cqecj3RS.js","names":["lines: string[]","dp: number[][]","i","j","parts: DiffPart[]","hunks: Hunk[]","currentHunk: Hunk | null","contextBuffer: string[]","active: Hunk"],"sources":["../src/utils/format.ts"],"sourcesContent":["/**\n * 输出格式化工具\n */\n\nimport Table from \"cli-table3\";\nimport type { SettingsFileEntry } from \"@/domain/types.ts\";\n\n/**\n * 格式化为 JSON 字符串\n */\nexport function formatJson(data: unknown, pretty = true): string {\n return JSON.stringify(data, null, pretty ? 2 : 0);\n}\n\n/**\n * 格式化为表格\n */\nexport function formatTable(data: Record<string, unknown>): string {\n const table = new Table({\n head: [\"Key\", \"Value\"],\n colWidths: [30, 50],\n wordWrap: true,\n });\n\n for (const [key, value] of Object.entries(data)) {\n table.push([key, formatValue(value)]);\n }\n\n return table.toString();\n}\n\n/**\n * 格式化 settings 文件清单\n */\nexport function formatFilesTable(files: SettingsFileEntry[]): string {\n const table = new Table({\n head: [\"Variant\", \"File\", \"Status\", \"Size\", \"Updated\"],\n colWidths: [15, 40, 12, 12, 26],\n wordWrap: true,\n });\n\n for (const file of files) {\n table.push([\n file.variant,\n file.path,\n formatStatus(file),\n formatBytes(file.size),\n formatTimestamp(file.lastModified),\n ]);\n }\n\n return table.toString();\n}\n\nexport function formatDiff(\n currentValue: unknown,\n nextValue: unknown,\n): string | null {\n const current = JSON.stringify(currentValue ?? {}, null, 2);\n const next = JSON.stringify(nextValue ?? {}, null, 2);\n\n if (current === next) {\n return null;\n }\n\n const parts = buildDiffParts(current.split(\"\\n\"), next.split(\"\\n\"));\n const hunks = buildUnifiedHunks(parts);\n\n const lines: string[] = [\"--- current\", \"+++ variant\"];\n for (const hunk of hunks) {\n lines.push(\n `@@ -${hunk.oldStart},${hunk.oldLines} +${hunk.newStart},${hunk.newLines} @@`,\n );\n lines.push(...hunk.lines);\n }\n\n return lines.map(colorizeDiffLine).join(\"\\n\");\n}\n\n/**\n * 格式化单个值\n */\nfunction formatValue(value: unknown): string {\n if (value === null) return \"null\";\n if (value === undefined) return \"undefined\";\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"boolean\")\n return String(value);\n if (Array.isArray(value)) return JSON.stringify(value);\n if (typeof value === \"object\") return JSON.stringify(value, null, 2);\n return String(value);\n}\n\nfunction formatStatus(file: SettingsFileEntry): string {\n if (file.active) {\n return file.exists ? \"active\" : \"missing\";\n }\n return file.exists ? \"available\" : \"missing\";\n}\n\nfunction formatBytes(size?: number): string {\n if (typeof size !== \"number\") {\n return \"-\";\n }\n\n const units = [\"B\", \"KB\", \"MB\", \"GB\"];\n let value = size;\n let unitIndex = 0;\n\n while (value >= 1024 && unitIndex < units.length - 1) {\n value /= 1024;\n unitIndex++;\n }\n\n const formatted =\n value >= 10 || value % 1 === 0 ? value.toFixed(0) : value.toFixed(1);\n return `${formatted} ${units[unitIndex]}`;\n}\n\nfunction formatTimestamp(date?: Date): string {\n if (!date) {\n return \"-\";\n }\n\n return new Intl.DateTimeFormat(undefined, {\n dateStyle: \"medium\",\n timeStyle: \"short\",\n }).format(date);\n}\n\nconst ANSI = {\n reset: \"\\x1b[0m\",\n red: \"\\x1b[31m\",\n green: \"\\x1b[32m\",\n yellow: \"\\x1b[33m\",\n cyan: \"\\x1b[36m\",\n dim: \"\\x1b[90m\",\n bold: \"\\x1b[1m\",\n};\n\nfunction supportsColor(): boolean {\n if (process.env.NO_COLOR) return false;\n if (process.env.FORCE_COLOR === \"0\") return false;\n return Boolean(process.stdout?.isTTY);\n}\n\nfunction colorizeDiffLine(line: string): string {\n if (!supportsColor()) {\n return line;\n }\n\n if (line.startsWith(\"@@\")) {\n return `${ANSI.cyan}${ANSI.bold}${line}${ANSI.reset}`;\n }\n if (line.startsWith(\"---\") || line.startsWith(\"+++\")) {\n return `${ANSI.yellow}${line}${ANSI.reset}`;\n }\n if (line.startsWith(\"+\")) {\n return `${ANSI.green}${line}${ANSI.reset}`;\n }\n if (line.startsWith(\"-\")) {\n return `${ANSI.red}${line}${ANSI.reset}`;\n }\n if (line.startsWith(\" \")) {\n return `${ANSI.dim}${line}${ANSI.reset}`;\n }\n return line;\n}\n\ntype DiffPart = {\n type: \"equal\" | \"insert\" | \"delete\";\n lines: string[];\n};\n\ntype Hunk = {\n oldStart: number;\n newStart: number;\n oldLines: number;\n newLines: number;\n lines: string[];\n};\n\nfunction buildDiffParts(oldLines: string[], newLines: string[]): DiffPart[] {\n const m = oldLines.length;\n const n = newLines.length;\n const dp: number[][] = Array.from({ length: m + 1 }, () =>\n Array.from({ length: n + 1 }, () => 0),\n );\n\n for (let i = m - 1; i >= 0; i--) {\n for (let j = n - 1; j >= 0; j--) {\n if (oldLines[i] === newLines[j]) {\n dp[i][j] = dp[i + 1][j + 1] + 1;\n } else {\n dp[i][j] = Math.max(dp[i + 1][j], dp[i][j + 1]);\n }\n }\n }\n\n const parts: DiffPart[] = [];\n const push = (type: DiffPart[\"type\"], value: string) => {\n const last = parts[parts.length - 1];\n if (last && last.type === type) {\n last.lines.push(value);\n } else {\n parts.push({ type, lines: [value] });\n }\n };\n\n let i = 0;\n let j = 0;\n\n while (i < m && j < n) {\n if (oldLines[i] === newLines[j]) {\n push(\"equal\", oldLines[i]);\n i++;\n j++;\n } else if (dp[i + 1][j] >= dp[i][j + 1]) {\n push(\"delete\", oldLines[i]);\n i++;\n } else {\n push(\"insert\", newLines[j]);\n j++;\n }\n }\n\n while (i < m) {\n push(\"delete\", oldLines[i++]);\n }\n while (j < n) {\n push(\"insert\", newLines[j++]);\n }\n\n return parts;\n}\n\nfunction buildUnifiedHunks(parts: DiffPart[]): Hunk[] {\n const context = 3;\n const hunks: Hunk[] = [];\n let oldLine = 1;\n let newLine = 1;\n let currentHunk: Hunk | null = null;\n let contextBuffer: string[] = [];\n\n const startHunk = () => {\n const oldStart = Math.max(oldLine - contextBuffer.length, 1);\n const newStart = Math.max(newLine - contextBuffer.length, 1);\n currentHunk = {\n oldStart,\n newStart,\n oldLines: contextBuffer.length,\n newLines: contextBuffer.length,\n lines: contextBuffer.map((line) => ` ${line}`),\n };\n contextBuffer = [];\n };\n\n const closeHunk = () => {\n if (currentHunk) {\n hunks.push(currentHunk);\n currentHunk = null;\n }\n };\n\n for (const part of parts) {\n if (part.type === \"equal\") {\n if (currentHunk !== null) {\n const active: Hunk = currentHunk;\n const leading = part.lines.slice(0, context);\n for (const line of leading) {\n active.lines.push(` ${line}`);\n active.oldLines++;\n active.newLines++;\n }\n oldLine += leading.length;\n newLine += leading.length;\n\n if (part.lines.length > context) {\n closeHunk();\n contextBuffer = part.lines.slice(part.lines.length - context);\n oldLine += part.lines.length - leading.length;\n newLine += part.lines.length - leading.length;\n } else {\n contextBuffer = [...leading].slice(-context);\n }\n } else {\n contextBuffer.push(...part.lines);\n if (contextBuffer.length > context) {\n contextBuffer.splice(0, contextBuffer.length - context);\n }\n oldLine += part.lines.length;\n newLine += part.lines.length;\n }\n continue;\n }\n\n if (!currentHunk) {\n startHunk();\n }\n\n if (!currentHunk) {\n throw new Error(\"Failed to initialize diff hunk\");\n }\n\n const active: Hunk = currentHunk;\n for (const line of part.lines) {\n if (part.type === \"delete\") {\n active.lines.push(`-${line}`);\n active.oldLines++;\n oldLine++;\n } else {\n active.lines.push(`+${line}`);\n active.newLines++;\n newLine++;\n }\n }\n }\n\n closeHunk();\n return hunks;\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"fsStore-i-3731TM.js","names":[],"sources":["../src/services/settings/fsStore.ts"],"sourcesContent":["/**\n * 文件系统存储工具\n */\n\nimport * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as os from \"os\";\nimport * as toml from \"@iarna/toml\";\nimport {\n ConfigFileNotFoundError,\n ConfigParseError,\n FileWriteError,\n} from \"@/utils/errors.ts\";\n\n/**\n * 解析 ~ 为用户主目录\n */\nexport function resolveHome(filepath: string): string {\n if (filepath.startsWith(\"~/\") || filepath === \"~\") {\n return path.join(os.homedir(), filepath.slice(1));\n }\n return filepath;\n}\n\n/**\n * 确保目录存在\n */\nexport function ensureDir(dirPath: string): void {\n const resolvedPath = resolveHome(dirPath);\n if (!fs.existsSync(resolvedPath)) {\n fs.mkdirSync(resolvedPath, { recursive: true });\n }\n}\n\n/**\n * 读取 JSON 文件\n */\nexport function readJSON(filepath: string): Record<string, unknown> {\n const resolvedPath = resolveHome(filepath);\n\n if (!fs.existsSync(resolvedPath)) {\n throw new ConfigFileNotFoundError(resolvedPath);\n }\n\n try {\n const content = fs.readFileSync(resolvedPath, \"utf-8\");\n return JSON.parse(content);\n } catch (error) {\n throw new ConfigParseError(resolvedPath, (error as Error).message);\n }\n}\n\n/**\n * 写入 JSON 文件\n */\nexport function writeJSON(\n filepath: string,\n data: Record<string, unknown>,\n backup = true,\n): void {\n const resolvedPath = resolveHome(filepath);\n\n // 确保目录存在\n ensureDir(path.dirname(resolvedPath));\n\n // 备份现有文件\n if (backup && fs.existsSync(resolvedPath)) {\n const backupPath = `${resolvedPath}.bak`;\n fs.copyFileSync(resolvedPath, backupPath);\n }\n\n try {\n // 原子写入:先写临时文件,再重命名\n const tempPath = `${resolvedPath}.tmp`;\n fs.writeFileSync(tempPath, JSON.stringify(data, null, 2), \"utf-8\");\n fs.renameSync(tempPath, resolvedPath);\n } catch (error) {\n throw new FileWriteError(resolvedPath, (error as Error).message);\n }\n}\n\n/**\n * 读取 TOML 文件\n */\nexport function readTOML(filepath: string): Record<string, unknown> {\n const resolvedPath = resolveHome(filepath);\n\n if (!fs.existsSync(resolvedPath)) {\n throw new ConfigFileNotFoundError(resolvedPath);\n }\n\n try {\n const content = fs.readFileSync(resolvedPath, \"utf-8\");\n return toml.parse(content) as Record<string, unknown>;\n } catch (error) {\n throw new ConfigParseError(resolvedPath, (error as Error).message);\n }\n}\n\n/**\n * 写入 TOML 文件\n */\nexport function writeTOML(\n filepath: string,\n data: Record<string, unknown>,\n backup = true,\n): void {\n const resolvedPath = resolveHome(filepath);\n\n // 确保目录存在\n ensureDir(path.dirname(resolvedPath));\n\n // 备份现有文件\n if (backup && fs.existsSync(resolvedPath)) {\n const backupPath = `${resolvedPath}.bak`;\n fs.copyFileSync(resolvedPath, backupPath);\n }\n\n try {\n // 原子写入\n const tempPath = `${resolvedPath}.tmp`;\n fs.writeFileSync(tempPath, toml.stringify(data as any), \"utf-8\");\n fs.renameSync(tempPath, resolvedPath);\n } catch (error) {\n throw new FileWriteError(resolvedPath, (error as Error).message);\n }\n}\n\n/**\n * 深度合并对象\n */\nexport function deepMerge(\n target: Record<string, unknown>,\n source: Record<string, unknown>,\n): Record<string, unknown> {\n const result = { ...target };\n\n for (const key in source) {\n if (Object.prototype.hasOwnProperty.call(source, key)) {\n const sourceValue = source[key];\n const targetValue = result[key];\n\n if (\n typeof sourceValue === \"object\" &&\n sourceValue !== null &&\n !Array.isArray(sourceValue) &&\n typeof targetValue === \"object\" &&\n targetValue !== null &&\n !Array.isArray(targetValue)\n ) {\n result[key] = deepMerge(\n targetValue as Record<string, unknown>,\n sourceValue as Record<string, unknown>,\n );\n } else {\n result[key] = sourceValue;\n }\n }\n }\n\n return result;\n}\n\n/**\n * 检查文件是否存在\n */\nexport function fileExists(filepath: string): boolean {\n const resolvedPath = resolveHome(filepath);\n return fs.existsSync(resolvedPath);\n}\n\n/**\n * 获取文件信息\n */\nexport function getFileInfo(filepath: string) {\n const resolvedPath = resolveHome(filepath);\n if (!fs.existsSync(resolvedPath)) {\n return null;\n }\n\n const stats = fs.statSync(resolvedPath);\n return {\n size: stats.size,\n lastModified: stats.mtime,\n };\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"gemini-aNNm-QGE.js","names":[],"sources":["../src/services/settings/adapters/gemini.ts"],"sourcesContent":["/**\n * Gemini CLI 适配器\n */\n\nimport type { Scope } from \"@/domain/types.ts\";\nimport { BaseAdapter } from \"./base.ts\";\nimport * as os from \"os\";\nimport * as path from \"path\";\n\n/**\n * Gemini CLI 配置适配器\n *\n * 配置文件路径:\n * - user: ~/.gemini/settings.json\n * - project: <cwd>/.gemini/settings.json\n * - system: 平台相关路径\n */\nexport class GeminiAdapter extends BaseAdapter {\n readonly toolId = \"gemini\" as const;\n\n /**\n * 解析配置文件路径\n */\n resolvePath(scope: Scope): string {\n switch (scope) {\n case \"user\":\n return \"~/.gemini/settings.json\";\n case \"project\":\n return \".gemini/settings.json\";\n case \"system\":\n return this.getSystemConfigPath();\n default:\n throw new Error(`Unsupported scope for Gemini: ${scope}`);\n }\n }\n\n /**\n * 验证 scope 是否有效\n */\n validateScope(scope: Scope): boolean {\n return [\"user\", \"project\", \"system\"].includes(scope);\n }\n\n /**\n * 获取系统级配置路径(跨平台)\n */\n private getSystemConfigPath(): string {\n const platform = os.platform();\n\n switch (platform) {\n case \"darwin\": // macOS\n return \"/Library/Application Support/Gemini/settings.json\";\n case \"win32\": // Windows\n return path.join(\n process.env.PROGRAMDATA || \"C:\\\\ProgramData\",\n \"Gemini\",\n \"settings.json\",\n );\n case \"linux\":\n return \"/etc/gemini/settings.json\";\n default:\n return \"/etc/gemini/settings.json\";\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAiBA,IAAa,gBAAb,cAAmC,YAAY;CAC7C,AAAS,SAAS;;;;CAKlB,YAAY,OAAsB;AAChC,UAAQ,OAAR;GACE,KAAK,OACH,QAAO;GACT,KAAK,UACH,QAAO;GACT,KAAK,SACH,QAAO,KAAK,qBAAqB;GACnC,QACE,OAAM,IAAI,MAAM,iCAAiC,QAAQ;;;;;;CAO/D,cAAc,OAAuB;AACnC,SAAO;GAAC;GAAQ;GAAW;GAAS,CAAC,SAAS,MAAM;;;;;CAMtD,AAAQ,sBAA8B;AAGpC,UAFiB,GAAG,UAAU,EAE9B;GACE,KAAK,SACH,QAAO;GACT,KAAK,QACH,QAAO,KAAK,KACV,QAAQ,IAAI,eAAe,mBAC3B,UACA,gBACD;GACH,KAAK,QACH,QAAO;GACT,QACE,QAAO"}
@@ -1,41 +0,0 @@
1
- import { d as ToolId, i as Scope, l as SettingsResult, n as InspectResult, s as SettingsListData, t as EditOptions, u as SwitchOptions } from "./types-BfNSo2rs.js";
2
-
3
- //#region src/domain/interfaces.d.ts
4
-
5
- /**
6
- * Settings 适配器接口
7
- * 所有工具适配器必须实现此接口(LSP 原则)
8
- */
9
- interface SettingsAdapter {
10
- /**
11
- * 工具标识符
12
- */
13
- readonly toolId: ToolId;
14
- /**
15
- * 列出指定 scope 的所有配置
16
- */
17
- list(scope: Scope): Promise<SettingsListData>;
18
- /**
19
- * 切换 profile(可选,仅 Codex 支持)
20
- */
21
- switchProfile?(scope: Scope, profile: string, options?: SwitchOptions): Promise<SettingsResult>;
22
- /**
23
- * 打开配置文件供编辑(可选)
24
- */
25
- edit?(scope: Scope, options: EditOptions): Promise<SettingsResult>;
26
- /**
27
- * 检查配置文件状态
28
- */
29
- inspect?(scope: Scope): Promise<InspectResult>;
30
- /**
31
- * 解析配置文件路径
32
- */
33
- resolvePath(scope: Scope): string;
34
- /**
35
- * 验证 scope 是否有效
36
- */
37
- validateScope(scope: Scope): boolean;
38
- }
39
- //#endregion
40
- export { SettingsAdapter as t };
41
- //# sourceMappingURL=interfaces-CriQW6hF.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"interfaces-CriQW6hF.d.ts","names":[],"sources":["../src/domain/interfaces.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAiCW,UAfM,eAAA,CAeN;EAEG;;;EAMC,SAAA,MAAA,EAnBI,MAmBJ;EAAgB;;;EAKb,IAAA,CAAA,KAAA,EAnBJ,KAmBI,CAAA,EAnBI,OAmBJ,CAnBY,gBAmBZ,CAAA;EAAgB;;;EAUX,aAAA,EAAA,KAAA,EAvBZ,KAuBY,EAAA,OAAA,EAAA,MAAA,EAAA,OAAA,CAAA,EArBT,aAqBS,CAAA,EApBlB,OAoBkB,CApBV,cAoBU,CAAA;EAAK;;;eAfb,gBAAgB,cAAc,QAAQ;;;;kBAKnC,QAAQ,QAAQ;;;;qBAKb;;;;uBAKE"}
package/dist/run.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"run.js","names":[],"sources":["../src/run.ts"],"sourcesContent":["#!/usr/bin/env node\n\n/**\n * xling CLI 入口点\n */\n\nimport { execute } from \"@oclif/core\";\n\nawait execute({ development: false, dir: import.meta.url });\n"],"mappings":";;;;;;;AAQA,MAAM,QAAQ;CAAE,aAAa;CAAO,KAAK,OAAO,KAAK;CAAK,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"claude.d.ts","names":[],"sources":["../../../../src/services/settings/adapters/claude.ts"],"sourcesContent":[],"mappings":";;;;;;AAgCA;;;;;;;;AAmEa,cAnEA,aAAA,SAAsB,WAAA,CAmEtB;EAAR,SAAA,MAAA,EAAA,QAAA;EAqEM;;;EAEN,IAAA,CAAA,KAAA,EApIwB,KAoIxB,CAAA,EApIgC,OAoIhC,CApIwC,gBAoIxC,CAAA;EA1I8B;;;qBAwCd;;;;uBAgBE;;;;uBAQZ,kCAEG,gBACT,QAAQ;cAqEF,gBACE,cACR,QAAQ"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"codex.d.ts","names":[],"sources":["../../../../src/services/settings/adapters/codex.ts"],"sourcesContent":[],"mappings":";;;;;;AAsBA;;;;;;;;AAgDa,cAhDA,YAAA,SAAqB,WAAA,CAgDrB;EAAR,SAAA,MAAA,EAAA,OAAA;EAuCiC;;;EAvFO,IAAA,CAAA,KAAA,EAMhB,KANgB,CAAA,EAMR,OANQ,CAMA,gBANA,CAAA;;;;qBAyBxB;;;;uBAYE;;;;uBAQZ,mCAEI,gBACV,QAAQ;;;;sCAuCyB;;;;4CAOM"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"gemini.d.ts","names":[],"sources":["../../../../src/services/settings/adapters/gemini.ts"],"sourcesContent":[],"mappings":";;;;;;AAiBA;;;;;;;;cAAa,aAAA,SAAsB,WAAA;;;;;qBAMd;;;;uBAgBE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"dispatcher.d.ts","names":[],"sources":["../../../src/services/settings/dispatcher.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;cAwBa,kBAAA;;;;;;mBAcY,kBAAkB,QAAQ;;;;;;;;2BAkExB;;;;uBAOJ"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"fsStore.d.ts","names":[],"sources":["../../../src/services/settings/fsStore.ts"],"sourcesContent":[],"mappings":";;AAiBA;AAUA;AAUA;AAkBA;AA6BA;AAkBgB,iBArFA,WAAA,CAuFF,QAAA,EAAA,MAAA,CAAA,EAAA,MAAA;AA2Bd;;;AAGG,iBA3Ga,SAAA,CA2Gb,OAAA,EAAA,MAAA,CAAA,EAAA,IAAA;;AAgCH;AAQA;iBAzIgB,QAAA,oBAA4B;;;;iBAkB5B,SAAA,yBAER;;;;iBA2BQ,QAAA,oBAA4B;;;;iBAkB5B,SAAA,yBAER;;;;iBA2BQ,SAAA,SACN,iCACA,0BACP;;;;iBAgCa,UAAA;;;;iBAQA,WAAA;;gBAAW"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"claudeDefault.d.ts","names":[],"sources":["../../../../src/services/settings/templates/claudeDefault.ts"],"sourcesContent":[],"mappings":";cAAa;EAAA,GAAA,EAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"types-BfNSo2rs.d.ts","names":[],"sources":["../src/domain/types.ts"],"sourcesContent":[],"mappings":";;AAIA;AACA;AACY,KAFA,MAAA,GAEa,QAAA,GAAA,OAAA,GAAA,QAAA;AACb,KAFA,KAAA,GAEY,MAAA,GAAA,SAAA,GAAA,OAAA,GAAA,QAAA;AAEP,KAHL,aAAA,GAGgB,MAAA,GAAA,MAAA,GAAA,gBAAA,GAAA,SAAA;AAKX,KAPL,YAAA,GAOkB,MAAA,GAAA,OAAA;AAKb,UAVA,WAAA,CAUiB;EAWtB,IAAA,CAAA,EAAA,MAAA;EAcK,GAAA,CAAA,EAAA,MAAA;;AAER,UAhCQ,aAAA,CAgCR;EACC,OAAA,CAAA,EAAA,OAAA;EAIC,MAAA,CAAA,EAAA,OAAA;;AACoB,UAjCd,iBAAA,CAiCc;EAMd,QAAA,EAAA,MAAA;EAYA,OAAA,EAAA,MAAA;;SA/CR;;;;iBAIQ;;KAGL,gBAAA;;WAGG;;;;SAKF;;;;;UAMI,eAAA;QACT;SACC;UACC;;;;WAIC;kBACO;;;;;UAMD,cAAA;;SAER;;;;;;;;;UAUQ,aAAA;;;;;iBAKA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"editor.d.ts","names":[],"sources":["../../src/utils/editor.ts"],"sourcesContent":[],"mappings":";iBAYgB,oBAAA;AAAA,iBAQM,YAAA,CARc,OAAA,EAAA,MAAA,EAAA,QAAA,EAAA,MAAA,CAAA,EAWjC,OAXiC,CAAA,IAAA,CAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"errors.d.ts","names":[],"sources":["../../src/utils/errors.ts"],"sourcesContent":[],"mappings":";;AAOA;AAUA;AAUA;AAUA;AAUA;AAUa,cAlDA,UAAA,SAAmB,KAAA,CAkDU;EAU7B,WAAA,CAAA,OAAA,EAAA,MAAA;AAUb;AAUA;;;cAtEa,oBAAA,SAA6B,UAAA;;;;;;cAU7B,iBAAA,SAA0B,UAAA;;;;;;cAU1B,uBAAA,SAAgC,UAAA;;;;;;cAUhC,gBAAA,SAAyB,UAAA;;;;;;cAUzB,oBAAA,SAA6B,UAAA;;;;;;cAU7B,4BAAA,SAAqC,UAAA;;;;;;cAUrC,cAAA,SAAuB,UAAA;;;;;;cAUvB,iBAAA,SAA0B,UAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"format.d.ts","names":[],"sources":["../../src/utils/format.ts"],"sourcesContent":[],"mappings":";;;;AAiBA;AAiBA;AAoBA;iBA5CgB,UAAA;;;;iBAOA,WAAA,OAAkB;;;;iBAiBlB,gBAAA,QAAwB;iBAoBxB,UAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"logger.d.ts","names":[],"sources":["../../src/utils/logger.ts"],"sourcesContent":[],"mappings":";;AAOA;AAUA;AAuCA;;;aAjDY,QAAA;;;;;;;;;cAUC,MAAA;;sBAGQ;kBAIH;;;;;;;;;cAgCL,QAAM"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"logger.js","names":[],"sources":["../../src/utils/logger.ts"],"sourcesContent":["/**\n * 日志工具\n */\n\n/**\n * 日志级别\n */\nexport enum LogLevel {\n DEBUG = 0,\n INFO = 1,\n WARN = 2,\n ERROR = 3,\n}\n\n/**\n * 简单的日志工具类\n */\nexport class Logger {\n private level: LogLevel;\n\n constructor(level: LogLevel = LogLevel.INFO) {\n this.level = level;\n }\n\n setLevel(level: LogLevel) {\n this.level = level;\n }\n\n debug(message: string, ...args: unknown[]) {\n if (this.level <= LogLevel.DEBUG) {\n console.debug(`[DEBUG] ${message}`, ...args);\n }\n }\n\n info(message: string, ...args: unknown[]) {\n if (this.level <= LogLevel.INFO) {\n console.info(`[INFO] ${message}`, ...args);\n }\n }\n\n warn(message: string, ...args: unknown[]) {\n if (this.level <= LogLevel.WARN) {\n console.warn(`[WARN] ${message}`, ...args);\n }\n }\n\n error(message: string, ...args: unknown[]) {\n if (this.level <= LogLevel.ERROR) {\n console.error(`[ERROR] ${message}`, ...args);\n }\n }\n}\n\n/**\n * 默认 logger 实例\n */\nexport const logger = new Logger();\n"],"mappings":";;;;;;;AAOA,IAAY,gDAAL;AACL;AACA;AACA;AACA;;;;;;AAMF,IAAa,SAAb,MAAoB;CAClB,AAAQ;CAER,YAAY,QAAkB,SAAS,MAAM;AAC3C,OAAK,QAAQ;;CAGf,SAAS,OAAiB;AACxB,OAAK,QAAQ;;CAGf,MAAM,SAAiB,GAAG,MAAiB;AACzC,MAAI,KAAK,SAAS,SAAS,MACzB,SAAQ,MAAM,WAAW,WAAW,GAAG,KAAK;;CAIhD,KAAK,SAAiB,GAAG,MAAiB;AACxC,MAAI,KAAK,SAAS,SAAS,KACzB,SAAQ,KAAK,UAAU,WAAW,GAAG,KAAK;;CAI9C,KAAK,SAAiB,GAAG,MAAiB;AACxC,MAAI,KAAK,SAAS,SAAS,KACzB,SAAQ,KAAK,UAAU,WAAW,GAAG,KAAK;;CAI9C,MAAM,SAAiB,GAAG,MAAiB;AACzC,MAAI,KAAK,SAAS,SAAS,MACzB,SAAQ,MAAM,WAAW,WAAW,GAAG,KAAK;;;;;;AAQlD,MAAa,SAAS,IAAI,QAAQ"}