hop-claude 1.0.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.
Files changed (65) hide show
  1. package/CHANGELOG.md +316 -0
  2. package/README.md +574 -0
  3. package/SECURITY.md +280 -0
  4. package/bin/cli.js +6 -0
  5. package/dist/cli.d.ts +6 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +147 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/config/config-manager.d.ts +88 -0
  10. package/dist/config/config-manager.d.ts.map +1 -0
  11. package/dist/config/config-manager.js +334 -0
  12. package/dist/config/config-manager.js.map +1 -0
  13. package/dist/config/encryption-v2.d.ts +51 -0
  14. package/dist/config/encryption-v2.d.ts.map +1 -0
  15. package/dist/config/encryption-v2.js +93 -0
  16. package/dist/config/encryption-v2.js.map +1 -0
  17. package/dist/config/encryption.d.ts +36 -0
  18. package/dist/config/encryption.d.ts.map +1 -0
  19. package/dist/config/encryption.js +72 -0
  20. package/dist/config/encryption.js.map +1 -0
  21. package/dist/config/keychain.d.ts +56 -0
  22. package/dist/config/keychain.d.ts.map +1 -0
  23. package/dist/config/keychain.js +112 -0
  24. package/dist/config/keychain.js.map +1 -0
  25. package/dist/config/storage.d.ts +32 -0
  26. package/dist/config/storage.d.ts.map +1 -0
  27. package/dist/config/storage.js +87 -0
  28. package/dist/config/storage.js.map +1 -0
  29. package/dist/config/validator.d.ts +9 -0
  30. package/dist/config/validator.d.ts.map +1 -0
  31. package/dist/config/validator.js +53 -0
  32. package/dist/config/validator.js.map +1 -0
  33. package/dist/index.d.ts +2 -0
  34. package/dist/index.d.ts.map +1 -0
  35. package/dist/index.js +10 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/types/index.d.ts +38 -0
  38. package/dist/types/index.d.ts.map +1 -0
  39. package/dist/types/index.js +2 -0
  40. package/dist/types/index.js.map +1 -0
  41. package/dist/ui/display.d.ts +25 -0
  42. package/dist/ui/display.d.ts.map +1 -0
  43. package/dist/ui/display.js +39 -0
  44. package/dist/ui/display.js.map +1 -0
  45. package/dist/ui/prompts.d.ts +52 -0
  46. package/dist/ui/prompts.d.ts.map +1 -0
  47. package/dist/ui/prompts.js +339 -0
  48. package/dist/ui/prompts.js.map +1 -0
  49. package/dist/utils/backup.d.ts +14 -0
  50. package/dist/utils/backup.d.ts.map +1 -0
  51. package/dist/utils/backup.js +27 -0
  52. package/dist/utils/backup.js.map +1 -0
  53. package/dist/utils/claude-launcher.d.ts +8 -0
  54. package/dist/utils/claude-launcher.d.ts.map +1 -0
  55. package/dist/utils/claude-launcher.js +68 -0
  56. package/dist/utils/claude-launcher.js.map +1 -0
  57. package/dist/utils/migration.d.ts +18 -0
  58. package/dist/utils/migration.d.ts.map +1 -0
  59. package/dist/utils/migration.js +176 -0
  60. package/dist/utils/migration.js.map +1 -0
  61. package/dist/utils/platform.d.ts +19 -0
  62. package/dist/utils/platform.d.ts.map +1 -0
  63. package/dist/utils/platform.js +91 -0
  64. package/dist/utils/platform.js.map +1 -0
  65. package/package.json +54 -0
@@ -0,0 +1,56 @@
1
+ /**
2
+ * KeychainManager:使用 OS 密钥链存储 API Keys
3
+ * - macOS: Keychain
4
+ * - Windows: Credential Manager
5
+ * - Linux: libsecret
6
+ *
7
+ * 优点:
8
+ * - 最安全:密钥不写入磁盘,由 OS 管理
9
+ * - 自动加密:OS 级别的加密保护
10
+ * - 统一管理:与系统密钥链集成
11
+ *
12
+ * 缺点:
13
+ * - 不可移植:无法跨机器导出
14
+ */
15
+ export declare class KeychainManager {
16
+ private static readonly SERVICE_NAME;
17
+ /**
18
+ * 检查 keychain 是否可用
19
+ * @returns keychain 是否可用
20
+ */
21
+ static isAvailable(): Promise<boolean>;
22
+ /**
23
+ * 存储 API Key 到密钥链
24
+ * @param profileName profile 名称
25
+ * @param apiKey API Key 明文
26
+ */
27
+ setAPIKey(profileName: string, apiKey: string): Promise<void>;
28
+ /**
29
+ * 从密钥链读取 API Key
30
+ * @param profileName profile 名称
31
+ * @returns API Key 明文,如果不存在则返回 null
32
+ */
33
+ getAPIKey(profileName: string): Promise<string | null>;
34
+ /**
35
+ * 从密钥链删除 API Key
36
+ * @param profileName profile 名称
37
+ * @returns 是否成功删除
38
+ */
39
+ deleteAPIKey(profileName: string): Promise<boolean>;
40
+ /**
41
+ * 列出密钥链中所有的 profile
42
+ * @returns profile 名称列表
43
+ */
44
+ listProfiles(): Promise<string[]>;
45
+ /**
46
+ * 清除所有存储的 API Keys
47
+ */
48
+ clearAll(): Promise<void>;
49
+ /**
50
+ * 部分隐藏 API Key(用于显示)
51
+ * @param apiKey API Key
52
+ * @returns 部分隐藏的 API Key,如:sk-ant-***xyz
53
+ */
54
+ maskApiKey(apiKey: string): string;
55
+ }
56
+ //# sourceMappingURL=keychain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keychain.d.ts","sourceRoot":"","sources":["../../src/config/keychain.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;GAaG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAgB;IAEpD;;;OAGG;WACU,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAY5C;;;;OAIG;IACG,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IASnE;;;;OAIG;IACG,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAS5D;;;;OAIG;IACG,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IASzD;;;OAGG;IACG,YAAY,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAUvC;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAO/B;;;;OAIG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;CAOnC"}
@@ -0,0 +1,112 @@
1
+ import * as keytar from 'keytar';
2
+ /**
3
+ * KeychainManager:使用 OS 密钥链存储 API Keys
4
+ * - macOS: Keychain
5
+ * - Windows: Credential Manager
6
+ * - Linux: libsecret
7
+ *
8
+ * 优点:
9
+ * - 最安全:密钥不写入磁盘,由 OS 管理
10
+ * - 自动加密:OS 级别的加密保护
11
+ * - 统一管理:与系统密钥链集成
12
+ *
13
+ * 缺点:
14
+ * - 不可移植:无法跨机器导出
15
+ */
16
+ export class KeychainManager {
17
+ static SERVICE_NAME = 'hop-claude';
18
+ /**
19
+ * 检查 keychain 是否可用
20
+ * @returns keychain 是否可用
21
+ */
22
+ static async isAvailable() {
23
+ try {
24
+ // 尝试写入测试值
25
+ await keytar.setPassword(KeychainManager.SERVICE_NAME, '__test__', 'test');
26
+ await keytar.deletePassword(KeychainManager.SERVICE_NAME, '__test__');
27
+ return true;
28
+ }
29
+ catch (error) {
30
+ console.warn('Keychain not available:', error instanceof Error ? error.message : String(error));
31
+ return false;
32
+ }
33
+ }
34
+ /**
35
+ * 存储 API Key 到密钥链
36
+ * @param profileName profile 名称
37
+ * @param apiKey API Key 明文
38
+ */
39
+ async setAPIKey(profileName, apiKey) {
40
+ try {
41
+ await keytar.setPassword(KeychainManager.SERVICE_NAME, profileName, apiKey);
42
+ }
43
+ catch (error) {
44
+ const err = error instanceof Error ? error : new Error(String(error));
45
+ throw new Error(`Failed to store API key in keychain: ${err.message}`);
46
+ }
47
+ }
48
+ /**
49
+ * 从密钥链读取 API Key
50
+ * @param profileName profile 名称
51
+ * @returns API Key 明文,如果不存在则返回 null
52
+ */
53
+ async getAPIKey(profileName) {
54
+ try {
55
+ return await keytar.getPassword(KeychainManager.SERVICE_NAME, profileName);
56
+ }
57
+ catch (error) {
58
+ const err = error instanceof Error ? error : new Error(String(error));
59
+ throw new Error(`Failed to retrieve API key from keychain: ${err.message}`);
60
+ }
61
+ }
62
+ /**
63
+ * 从密钥链删除 API Key
64
+ * @param profileName profile 名称
65
+ * @returns 是否成功删除
66
+ */
67
+ async deleteAPIKey(profileName) {
68
+ try {
69
+ return await keytar.deletePassword(KeychainManager.SERVICE_NAME, profileName);
70
+ }
71
+ catch (error) {
72
+ const err = error instanceof Error ? error : new Error(String(error));
73
+ throw new Error(`Failed to delete API key from keychain: ${err.message}`);
74
+ }
75
+ }
76
+ /**
77
+ * 列出密钥链中所有的 profile
78
+ * @returns profile 名称列表
79
+ */
80
+ async listProfiles() {
81
+ try {
82
+ const credentials = await keytar.findCredentials(KeychainManager.SERVICE_NAME);
83
+ return credentials.map(cred => cred.account);
84
+ }
85
+ catch (error) {
86
+ const err = error instanceof Error ? error : new Error(String(error));
87
+ throw new Error(`Failed to list profiles from keychain: ${err.message}`);
88
+ }
89
+ }
90
+ /**
91
+ * 清除所有存储的 API Keys
92
+ */
93
+ async clearAll() {
94
+ const profiles = await this.listProfiles();
95
+ for (const profile of profiles) {
96
+ await this.deleteAPIKey(profile);
97
+ }
98
+ }
99
+ /**
100
+ * 部分隐藏 API Key(用于显示)
101
+ * @param apiKey API Key
102
+ * @returns 部分隐藏的 API Key,如:sk-ant-***xyz
103
+ */
104
+ maskApiKey(apiKey) {
105
+ if (!apiKey || apiKey.length < 8)
106
+ return '***';
107
+ const prefix = apiKey.slice(0, 6);
108
+ const suffix = apiKey.slice(-3);
109
+ return `${prefix}***${suffix}`;
110
+ }
111
+ }
112
+ //# sourceMappingURL=keychain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keychain.js","sourceRoot":"","sources":["../../src/config/keychain.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { ConfigStore } from '../types/index.js';
2
+ /**
3
+ * 配置文件存储类
4
+ */
5
+ export declare class ConfigStorage {
6
+ private configDir;
7
+ private configFile;
8
+ constructor();
9
+ /**
10
+ * 确保配置目录存在并设置正确权限
11
+ */
12
+ ensureConfigDir(): Promise<void>;
13
+ /**
14
+ * 读取配置文件
15
+ * @returns 配置对象,如果文件不存在则返回 null
16
+ */
17
+ read(): Promise<ConfigStore | null>;
18
+ /**
19
+ * 写入配置文件
20
+ * @param config 配置对象
21
+ */
22
+ write(config: ConfigStore): Promise<void>;
23
+ /**
24
+ * 获取配置文件路径
25
+ */
26
+ getConfigPath(): string;
27
+ /**
28
+ * 获取配置目录路径
29
+ */
30
+ getConfigDir(): string;
31
+ }
32
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/config/storage.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAS;;IAO3B;;OAEG;IACG,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAItC;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAazC;;;OAGG;IACG,KAAK,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAwC/C;;OAEG;IACH,aAAa,IAAI,MAAM;IAIvB;;OAEG;IACH,YAAY,IAAI,MAAM;CAGvB"}
@@ -0,0 +1,87 @@
1
+ import fs from 'fs/promises';
2
+ import path from 'path';
3
+ import lockfile from 'proper-lockfile';
4
+ import { getConfigDir, ensureSecureDirectory, setSecureFilePermissions } from '../utils/platform.js';
5
+ /**
6
+ * 配置文件存储类
7
+ */
8
+ export class ConfigStorage {
9
+ configDir;
10
+ configFile;
11
+ constructor() {
12
+ this.configDir = getConfigDir();
13
+ this.configFile = path.join(this.configDir, 'config.json');
14
+ }
15
+ /**
16
+ * 确保配置目录存在并设置正确权限
17
+ */
18
+ async ensureConfigDir() {
19
+ await ensureSecureDirectory(this.configDir);
20
+ }
21
+ /**
22
+ * 读取配置文件
23
+ * @returns 配置对象,如果文件不存在则返回 null
24
+ */
25
+ async read() {
26
+ try {
27
+ const data = await fs.readFile(this.configFile, 'utf8');
28
+ return JSON.parse(data);
29
+ }
30
+ catch (error) {
31
+ // 检查是否为文件不存在错误
32
+ if (error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT') {
33
+ return null;
34
+ }
35
+ throw error;
36
+ }
37
+ }
38
+ /**
39
+ * 写入配置文件
40
+ * @param config 配置对象
41
+ */
42
+ async write(config) {
43
+ await this.ensureConfigDir();
44
+ // 使用文件锁防止并发写入冲突
45
+ let release;
46
+ try {
47
+ // 如果文件不存在,先创建空文件以便加锁
48
+ try {
49
+ await fs.access(this.configFile);
50
+ }
51
+ catch {
52
+ await fs.writeFile(this.configFile, '{}', 'utf8');
53
+ }
54
+ // 获取文件锁(最多重试 5 次,每次等待 200ms)
55
+ release = await lockfile.lock(this.configFile, {
56
+ retries: {
57
+ retries: 5,
58
+ minTimeout: 200,
59
+ maxTimeout: 1000,
60
+ },
61
+ });
62
+ // 写入配置
63
+ await fs.writeFile(this.configFile, JSON.stringify(config, null, 2), 'utf8');
64
+ // 设置文件权限(仅所有者可读写)
65
+ await setSecureFilePermissions(this.configFile);
66
+ }
67
+ finally {
68
+ // 释放锁
69
+ if (release) {
70
+ await release();
71
+ }
72
+ }
73
+ }
74
+ /**
75
+ * 获取配置文件路径
76
+ */
77
+ getConfigPath() {
78
+ return this.configFile;
79
+ }
80
+ /**
81
+ * 获取配置目录路径
82
+ */
83
+ getConfigDir() {
84
+ return this.configDir;
85
+ }
86
+ }
87
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/config/storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,QAAQ,MAAM,iBAAiB,CAAC;AAEvC,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAErG;;GAEG;AACH,MAAM,OAAO,aAAa;IAChB,SAAS,CAAS;IAClB,UAAU,CAAS;IAE3B;QACE,IAAI,CAAC,SAAS,GAAG,YAAY,EAAE,CAAC;QAChC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IAC7D,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe;QACnB,MAAM,qBAAqB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC9C,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,IAAI;QACR,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;YACxD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,eAAe;YACf,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBACrF,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,KAAK,CAAC,MAAmB;QAC7B,MAAM,IAAI,CAAC,eAAe,EAAE,CAAC;QAE7B,gBAAgB;QAChB,IAAI,OAA0C,CAAC;QAE/C,IAAI,CAAC;YACH,qBAAqB;YACrB,IAAI,CAAC;gBACH,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACnC,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;YACpD,CAAC;YAED,6BAA6B;YAC7B,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE;gBAC7C,OAAO,EAAE;oBACP,OAAO,EAAE,CAAC;oBACV,UAAU,EAAE,GAAG;oBACf,UAAU,EAAE,IAAI;iBACjB;aACF,CAAC,CAAC;YAEH,OAAO;YACP,MAAM,EAAE,CAAC,SAAS,CAChB,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAC/B,MAAM,CACP,CAAC;YAEF,kBAAkB;YAClB,MAAM,wBAAwB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAClD,CAAC;gBAAS,CAAC;YACT,MAAM;YACN,IAAI,OAAO,EAAE,CAAC;gBACZ,MAAM,OAAO,EAAE,CAAC;YAClB,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,aAAa;QACX,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,YAAY;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;CACF"}
@@ -0,0 +1,9 @@
1
+ import type { ValidationResult } from '../types/index.js';
2
+ /**
3
+ * 验证 API Key 是否有效
4
+ * @param apiKey API Key
5
+ * @param baseUrl 可选的自定义 Base URL
6
+ * @returns 验证结果
7
+ */
8
+ export declare function validateApiKey(apiKey: string, baseUrl?: string): Promise<ValidationResult>;
9
+ //# sourceMappingURL=validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/config/validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAE1D;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,GACf,OAAO,CAAC,gBAAgB,CAAC,CAkD3B"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * 验证 API Key 是否有效
3
+ * @param apiKey API Key
4
+ * @param baseUrl 可选的自定义 Base URL
5
+ * @returns 验证结果
6
+ */
7
+ export async function validateApiKey(apiKey, baseUrl) {
8
+ if (!apiKey || apiKey.trim().length === 0) {
9
+ return { valid: false, error: 'API Key cannot be empty' };
10
+ }
11
+ const url = baseUrl
12
+ ? `${baseUrl.replace(/\/$/, '')}/v1/messages`
13
+ : 'https://api.anthropic.com/v1/messages';
14
+ try {
15
+ // 发送一个最小的测试请求
16
+ const response = await fetch(url, {
17
+ method: 'POST',
18
+ headers: {
19
+ 'Content-Type': 'application/json',
20
+ 'x-api-key': apiKey,
21
+ 'anthropic-version': '2023-06-01',
22
+ },
23
+ body: JSON.stringify({
24
+ model: 'claude-3-haiku-20240307',
25
+ max_tokens: 1,
26
+ messages: [{ role: 'user', content: 'Hi' }],
27
+ }),
28
+ });
29
+ // 检查响应状态
30
+ if (response.status === 401) {
31
+ return { valid: false, error: 'Invalid API Key' };
32
+ }
33
+ if (response.status === 403) {
34
+ return { valid: false, error: 'API Key does not have permission' };
35
+ }
36
+ // 200 或其他非错误状态都认为 API Key 有效
37
+ if (response.ok || response.status === 400) {
38
+ return { valid: true };
39
+ }
40
+ // 其他错误
41
+ const errorText = await response.text();
42
+ return { valid: false, error: `API request failed: ${response.status} ${errorText}` };
43
+ }
44
+ catch (error) {
45
+ // 网络错误或其他异常
46
+ const err = error instanceof Error ? error : new Error(String(error));
47
+ if (err.message.includes('fetch')) {
48
+ return { valid: false, error: 'Network error: Unable to reach API endpoint' };
49
+ }
50
+ return { valid: false, error: `Validation error: ${err.message}` };
51
+ }
52
+ }
53
+ //# sourceMappingURL=validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/config/validator.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAc,EACd,OAAgB;IAEhB,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1C,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC;IAC5D,CAAC;IAED,MAAM,GAAG,GAAG,OAAO;QACjB,CAAC,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,cAAc;QAC7C,CAAC,CAAC,uCAAuC,CAAC;IAE5C,IAAI,CAAC;QACH,cAAc;QACd,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,WAAW,EAAE,MAAM;gBACnB,mBAAmB,EAAE,YAAY;aAClC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK,EAAE,yBAAyB;gBAChC,UAAU,EAAE,CAAC;gBACb,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;aAC5C,CAAC;SACH,CAAC,CAAC;QAEH,SAAS;QACT,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5B,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC;QACpD,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5B,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,kCAAkC,EAAE,CAAC;QACrE,CAAC;QAED,6BAA6B;QAC7B,IAAI,QAAQ,CAAC,EAAE,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC3C,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACzB,CAAC;QAED,OAAO;QACP,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACxC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,uBAAuB,QAAQ,CAAC,MAAM,IAAI,SAAS,EAAE,EAAE,CAAC;IACxF,CAAC;IAAC,OAAO,KAAc,EAAE,CAAC;QACxB,YAAY;QACZ,MAAM,GAAG,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACtE,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YAClC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,6CAA6C,EAAE,CAAC;QAChF,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,qBAAqB,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;IACrE,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ import { createCLI } from './cli.js';
2
+ async function main() {
3
+ const program = await createCLI();
4
+ await program.parseAsync(process.argv);
5
+ }
6
+ main().catch((err) => {
7
+ console.error('Error:', err.message);
8
+ process.exit(1);
9
+ });
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAErC,KAAK,UAAU,IAAI;IACjB,MAAM,OAAO,GAAG,MAAM,SAAS,EAAE,CAAC;IAClC,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * 加密模式
3
+ * - legacy: 旧版机器绑定加密(已弃用,但保持向后兼容)
4
+ * - keychain: OS 密钥链存储(推荐,最安全)
5
+ * - passphrase: 用户密码加密(可移植)
6
+ */
7
+ export type EncryptionMode = 'legacy' | 'keychain' | 'passphrase';
8
+ export interface ProfileConfig {
9
+ domain: string;
10
+ apiKey: string;
11
+ baseUrl?: string;
12
+ proxy?: string;
13
+ disableNonessentialTraffic?: boolean;
14
+ createdAt: number;
15
+ updatedAt: number;
16
+ }
17
+ export interface ConfigStore {
18
+ version: string;
19
+ currentProfile: string;
20
+ profiles: ProfileConfig[];
21
+ encryptionSalt?: string;
22
+ encryptionMode?: EncryptionMode;
23
+ }
24
+ export interface DecryptedProfile extends Omit<ProfileConfig, 'apiKey'> {
25
+ apiKey: string;
26
+ }
27
+ export interface EnvironmentVariables {
28
+ ANTHROPIC_API_KEY?: string;
29
+ ANTHROPIC_BASE_URL?: string;
30
+ HTTP_PROXY?: string;
31
+ HTTPS_PROXY?: string;
32
+ CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC?: string;
33
+ }
34
+ export interface ValidationResult {
35
+ valid: boolean;
36
+ error?: string;
37
+ }
38
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,UAAU,GAAG,YAAY,CAAC;AAElE,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED,MAAM,WAAW,gBAAiB,SAAQ,IAAI,CAAC,aAAa,EAAE,QAAQ,CAAC;IACrE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wCAAwC,CAAC,EAAE,MAAM,CAAC;CACnD;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * 显示标题
3
+ */
4
+ export declare function displayTitle(title: string): void;
5
+ /**
6
+ * 显示成功消息
7
+ */
8
+ export declare function displaySuccess(message: string): void;
9
+ /**
10
+ * 显示错误消息
11
+ */
12
+ export declare function displayError(message: string): void;
13
+ /**
14
+ * 显示警告消息
15
+ */
16
+ export declare function displayWarning(message: string): void;
17
+ /**
18
+ * 显示信息消息
19
+ */
20
+ export declare function displayInfo(label: string, value: string | undefined, defaultText?: string): void;
21
+ /**
22
+ * 显示普通消息
23
+ */
24
+ export declare function displayMessage(message: string): void;
25
+ //# sourceMappingURL=display.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display.d.ts","sourceRoot":"","sources":["../../src/ui/display.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAEhD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAEpD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAElD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAEpD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,WAAW,GAAE,MAAoB,GAAG,IAAI,CAG7G;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAEpD"}
@@ -0,0 +1,39 @@
1
+ import chalk from 'chalk';
2
+ /**
3
+ * 显示标题
4
+ */
5
+ export function displayTitle(title) {
6
+ console.log(chalk.bold(`\n${title}\n`));
7
+ }
8
+ /**
9
+ * 显示成功消息
10
+ */
11
+ export function displaySuccess(message) {
12
+ console.log(chalk.green(`✓ ${message}`));
13
+ }
14
+ /**
15
+ * 显示错误消息
16
+ */
17
+ export function displayError(message) {
18
+ console.error(chalk.red(`✗ ${message}`));
19
+ }
20
+ /**
21
+ * 显示警告消息
22
+ */
23
+ export function displayWarning(message) {
24
+ console.log(chalk.yellow(`⚠ ${message}`));
25
+ }
26
+ /**
27
+ * 显示信息消息
28
+ */
29
+ export function displayInfo(label, value, defaultText = '(default)') {
30
+ const displayValue = value || chalk.gray(defaultText);
31
+ console.log(` ${label}: ${displayValue}`);
32
+ }
33
+ /**
34
+ * 显示普通消息
35
+ */
36
+ export function displayMessage(message) {
37
+ console.log(message);
38
+ }
39
+ //# sourceMappingURL=display.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display.js","sourceRoot":"","sources":["../../src/ui/display.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC;AAC1C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,KAAyB,EAAE,cAAsB,WAAW;IACrG,MAAM,YAAY,GAAG,KAAK,IAAI,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACtD,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,KAAK,YAAY,EAAE,CAAC,CAAC;AAC7C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AACvB,CAAC"}
@@ -0,0 +1,52 @@
1
+ import { ConfigManager } from '../config/config-manager.js';
2
+ import type { ProfileConfig } from '../types/index.js';
3
+ /**
4
+ * 交互式 UI 类
5
+ */
6
+ export declare class InteractiveUI {
7
+ private configManager;
8
+ constructor(configManager: ConfigManager);
9
+ /**
10
+ * 显示当前配置并询问是否修改
11
+ */
12
+ showCurrentAndAsk(): Promise<boolean>;
13
+ /**
14
+ * 配置管理主界面
15
+ */
16
+ manageConfiguration(): Promise<void>;
17
+ /**
18
+ * 选择 profile
19
+ */
20
+ selectProfile(profiles: Array<ProfileConfig & {
21
+ maskedApiKey: string;
22
+ }>): Promise<void>;
23
+ /**
24
+ * 创建新 profile
25
+ */
26
+ createProfile(): Promise<void>;
27
+ /**
28
+ * 编辑 profile
29
+ */
30
+ editProfile(profiles: Array<ProfileConfig & {
31
+ maskedApiKey: string;
32
+ }>): Promise<void>;
33
+ /**
34
+ * 删除 profile
35
+ */
36
+ deleteProfile(profiles: Array<ProfileConfig & {
37
+ maskedApiKey: string;
38
+ }>): Promise<void>;
39
+ /**
40
+ * 列出所有配置
41
+ */
42
+ listConfigurations(): Promise<void>;
43
+ /**
44
+ * 导出配置
45
+ */
46
+ exportConfiguration(): Promise<void>;
47
+ /**
48
+ * 导入配置
49
+ */
50
+ importConfiguration(): Promise<void>;
51
+ }
52
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/ui/prompts.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAG5D,OAAO,KAAK,EAAoB,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGzE;;GAEG;AACH,qBAAa,aAAa;IACZ,OAAO,CAAC,aAAa;gBAAb,aAAa,EAAE,aAAa;IAEhD;;OAEG;IACG,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC;IAuC3C;;OAEG;IACG,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAwC1C;;OAEG;IACG,aAAa,CAAC,QAAQ,EAAE,KAAK,CAAC,aAAa,GAAG;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB7F;;OAEG;IACG,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;IAgFpC;;OAEG;IACG,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC,aAAa,GAAG;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAsD3F;;OAEG;IACG,aAAa,CAAC,QAAQ,EAAE,KAAK,CAAC,aAAa,GAAG;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IA0B7F;;OAEG;IACG,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC;IAwBzC;;OAEG;IACG,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB1C;;OAEG;IACG,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;CA6B3C"}