easyai 1.7.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: easyai
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wade
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-11-05 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: claide
@@ -38,39 +38,19 @@ dependencies:
38
38
  - !ruby/object:Gem::Version
39
39
  version: '3.1'
40
40
  - !ruby/object:Gem::Dependency
41
- name: webrick
41
+ name: base64
42
42
  requirement: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: '1.9'
46
+ version: '0.2'
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '1.9'
54
- - !ruby/object:Gem::Dependency
55
- name: jpsclient
56
- requirement: !ruby/object:Gem::Requirement
57
- requirements:
58
- - - "~>"
59
- - !ruby/object:Gem::Version
60
- version: '1.4'
61
- - - ">="
62
- - !ruby/object:Gem::Version
63
- version: 1.4.0
64
- type: :runtime
65
- prerelease: false
66
- version_requirements: !ruby/object:Gem::Requirement
67
- requirements:
68
- - - "~>"
69
- - !ruby/object:Gem::Version
70
- version: '1.4'
71
- - - ">="
72
- - !ruby/object:Gem::Version
73
- version: 1.4.0
53
+ version: '0.2'
74
54
  - !ruby/object:Gem::Dependency
75
55
  name: bundler
76
56
  requirement: !ruby/object:Gem::Requirement
@@ -113,8 +93,10 @@ dependencies:
113
93
  - - "~>"
114
94
  - !ruby/object:Gem::Version
115
95
  version: '3.0'
116
- description: A CLI tool that simplifies running AI tools like Claude, Gemini, and
117
- GPT with environment configuration
96
+ description: |
97
+ EasyAI 是一个 Ruby CLI 包装器,为 Anthropic Claude、Google Gemini、OpenAI Codex 三家命令行工具提供统一入口。
98
+ v2.0 起聚焦单机本地化:无远程下发链路,通过单一 ~/.easyai/config.json 集中管理多家 CLI 与多平台凭证、代理;
99
+ 运行时仅向子进程注入环境变量,不污染当前 shell。
118
100
  email:
119
101
  - wade@example.com
120
102
  executables:
@@ -128,27 +110,30 @@ files:
128
110
  - bin/easyai
129
111
  - easyai.gemspec
130
112
  - lib/easyai.rb
131
- - lib/easyai/auth/authclaude.rb
132
- - lib/easyai/auth/jpsloginhelper.rb
133
113
  - lib/easyai/base/cross_platform.rb
134
114
  - lib/easyai/base/file_crypto.rb
115
+ - lib/easyai/base/secret_masker.rb
135
116
  - lib/easyai/base/system_info.rb
136
- - lib/easyai/base/system_keychain.rb
117
+ - lib/easyai/base/toml_sections.rb
137
118
  - lib/easyai/base/update_notifier.rb
138
119
  - lib/easyai/base/version_checker.rb
139
120
  - lib/easyai/command.rb
121
+ - lib/easyai/command/ai_tool_base.rb
122
+ - lib/easyai/command/backup.rb
123
+ - lib/easyai/command/backup/claude.rb
124
+ - lib/easyai/command/backup/codex.rb
140
125
  - lib/easyai/command/claude.rb
141
126
  - lib/easyai/command/clean.rb
142
- - lib/easyai/command/gemini.rb
143
- - lib/easyai/command/gpt.rb
127
+ - lib/easyai/command/codex.rb
128
+ - lib/easyai/command/restore.rb
129
+ - lib/easyai/command/restore/claude.rb
130
+ - lib/easyai/command/restore/codex.rb
144
131
  - lib/easyai/command/setup.rb
145
132
  - lib/easyai/command/update.rb
146
133
  - lib/easyai/command/utils.rb
147
134
  - lib/easyai/command/utils/decry.rb
148
135
  - lib/easyai/command/utils/encry.rb
149
- - lib/easyai/command/utils/export.rb
150
- - lib/easyai/config/config.rb
151
- - lib/easyai/config/easyai_config.rb
136
+ - lib/easyai/config/local_config.rb
152
137
  - lib/easyai/version.rb
153
138
  homepage: https://github.com/wade/easyai
154
139
  licenses:
@@ -161,14 +146,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
161
146
  requirements:
162
147
  - - ">="
163
148
  - !ruby/object:Gem::Version
164
- version: 2.7.0
149
+ version: 3.0.0
165
150
  required_rubygems_version: !ruby/object:Gem::Requirement
166
151
  requirements:
167
152
  - - ">="
168
153
  - !ruby/object:Gem::Version
169
154
  version: '0'
170
155
  requirements: []
171
- rubygems_version: 3.6.3
156
+ rubygems_version: 4.0.11
172
157
  specification_version: 4
173
- summary: Easy AI CLI tool wrapper
158
+ summary: Claude / Gemini / Codex 三家 AI CLI 的本地化统一入口
174
159
  test_files: []
@@ -1,519 +0,0 @@
1
- require 'json'
2
- require 'etc'
3
- require 'open3'
4
- require 'fileutils'
5
- require_relative '../base/system_info'
6
-
7
- module EasyAI
8
- module Auth
9
- class AuthClaude
10
- # 常量定义
11
- SERVICE_NAME = "Claude Code-credentials"
12
- TOKEN_KEY = "CLAUDE_CODE_OAUTH_TOKEN"
13
- ALT_TOKEN_KEY = "ANTHROPIC_AUTH_TOKEN"
14
- CLAUDE_JSON_PATH = File.expand_path("~/.claude.json")
15
-
16
- def self.configure(config, user_name = nil)
17
- return false unless config
18
-
19
- # 第一步:清理系统环境,确保干净的运行环境
20
- clean_system_environment
21
-
22
- # 检查认证配置优先级
23
- keychain_exists = macos? && config["key_chain"] && config["key_chain"]["claudeAiOauth"] && config["key_chain"]["service_name"]
24
- # 检查两种可能的令牌键
25
- env_token_exists = config["env"] && (config["env"][TOKEN_KEY] || config["env"][ALT_TOKEN_KEY])
26
-
27
- # 如果使用 Keychain,需要将令牌从 Keychain 读取到配置中
28
- if keychain_exists
29
- token_from_keychain = get_token_from_keychain(config["key_chain"]["service_name"])
30
- if token_from_keychain
31
- config["env"] ||= {}
32
- config["env"][TOKEN_KEY] = token_from_keychain
33
- end
34
- end
35
-
36
- # 根据优先级确定认证方法
37
- if keychain_exists
38
- configure_keychain(config)
39
- clean_env_variables
40
- elsif env_token_exists
41
- verify_token_config(config)
42
- clean_keychain if macos?
43
- else
44
- # 先检查环境变量中是否已有令牌
45
- token = check_env_tokens
46
-
47
- if token.nil? || token.empty?
48
- # 环境变量中没有,才提示用户输入
49
- token = prompt_for_token
50
- return false if token.nil? || token.empty?
51
- else
52
- log_verbose(" ✓ 使用环境变量中的令牌")
53
- end
54
-
55
- # 将令牌添加到配置中进行处理
56
- # 如果配置中已经有 ANTHROPIC_AUTH_TOKEN,使用该键;否则使用 CLAUDE_CODE_OAUTH_TOKEN
57
- config["env"] ||= {}
58
- if config["env"][ALT_TOKEN_KEY]
59
- config["env"][ALT_TOKEN_KEY] = token
60
- else
61
- config["env"][TOKEN_KEY] = token
62
- end
63
-
64
- verify_token_config(config)
65
- clean_keychain
66
- end
67
-
68
- # 更新 ~/.claude.json 文件
69
- update_claude_json(config) if config["claude_json"]
70
-
71
- # 配置代理设置
72
- configure_proxy(config) if config["claude_proxy"]
73
-
74
- true
75
- end
76
-
77
- private
78
-
79
- # 辅助方法
80
- def self.macos?
81
- Base::SystemInfo.macos?
82
- end
83
-
84
- def self.current_user
85
- Base::SystemInfo.current_user
86
- end
87
-
88
- def self.log_verbose(message)
89
- puts message if ENV['EASYAI_DEBUG'] || ENV['EASYAI_VERBOSE']
90
- end
91
-
92
- def self.log_debug(message)
93
- puts message if ENV['EASYAI_DEBUG']
94
- end
95
-
96
- # 通用的 shell 文件处理方法
97
- def self.process_shell_files(operation_name)
98
- shell_files = get_shell_files
99
-
100
- shell_files.each do |shell_file|
101
- next unless File.exist?(shell_file)
102
-
103
- begin
104
- content = File.read(shell_file)
105
- lines = content.split("\n", -1)
106
- lines.pop if lines.last == ""
107
-
108
- original_count = lines.length
109
- lines = yield(lines, shell_file)
110
- removed_count = original_count - lines.length
111
-
112
- if removed_count > 0
113
- File.write(shell_file, lines.join("\n") + "\n")
114
- log_verbose(" ✓ 已从 #{File.basename(shell_file)} 中清理 #{removed_count} 行#{operation_name}")
115
- end
116
- rescue => e
117
- log_debug(" ⚠ 处理 #{shell_file} 失败: #{e.message}")
118
- end
119
- end
120
- end
121
-
122
- def self.clean_system_environment
123
- log_verbose("🧹 清理系统环境...")
124
-
125
- # 1. 清理 ~/.claude.json 中的 oauthAccount
126
- clean_claude_json_oauth
127
-
128
- # 2. 清理 Keychain(仅 macOS)
129
- clean_keychain if macos?
130
-
131
- # 3. 清理环境变量中的 token
132
- clean_env_variables
133
-
134
- # 4. 清理环境变量中的代理设置
135
- clean_proxy_variables
136
-
137
- log_verbose(" ✓ 系统环境清理完成")
138
- end
139
-
140
- def self.clean_claude_json_oauth
141
- return unless File.exist?(CLAUDE_JSON_PATH)
142
-
143
- begin
144
- content = File.read(CLAUDE_JSON_PATH)
145
- config = JSON.parse(content)
146
-
147
- # 删除 oauthAccount 字段
148
- if config.delete("oauthAccount")
149
- # 写回文件
150
- File.write(CLAUDE_JSON_PATH, JSON.pretty_generate(config))
151
- log_verbose(" ✓ 已清理 ~/.claude.json 中的 oauthAccount")
152
- end
153
- rescue JSON::ParserError => e
154
- log_debug(" ⚠ 解析 ~/.claude.json 失败: #{e.message}")
155
- rescue => e
156
- log_debug(" ⚠ 清理 ~/.claude.json 失败: #{e.message}")
157
- end
158
- end
159
-
160
- def self.clean_proxy_variables
161
- process_shell_files("代理配置") do |lines, shell_file|
162
- remove_all_proxy_config(lines, shell_file)
163
- end
164
- end
165
-
166
- def self.get_token_from_keychain(service_name)
167
- return nil unless macos?
168
-
169
- cmd = [
170
- "security",
171
- "find-generic-password",
172
- "-a", current_user,
173
- "-s", service_name,
174
- "-w"
175
- ]
176
-
177
- begin
178
- stdout, stderr, status = Open3.capture3(*cmd)
179
-
180
- if status.success? && !stdout.strip.empty?
181
- # 解析 JSON 格式的密码
182
- credentials = JSON.parse(stdout.strip)
183
- return credentials["claudeAiOauth"]
184
- end
185
- rescue JSON::ParserError, StandardError
186
- # 如果不是 JSON 格式,尝试直接返回
187
- return stdout.strip if status.success? && !stdout.strip.empty?
188
- end
189
-
190
- nil
191
- end
192
-
193
- def self.configure_keychain(config)
194
- credentials = {
195
- "claudeAiOauth" => config["key_chain"]["claudeAiOauth"]
196
- }
197
-
198
- service_name = config["key_chain"]["service_name"]
199
- password = credentials.to_json
200
-
201
- cmd = [
202
- "security",
203
- "add-generic-password",
204
- "-a", current_user,
205
- "-s", service_name,
206
- "-l", service_name,
207
- "-w", password,
208
- "-U",
209
- "-T", ""
210
- ]
211
-
212
- system(*cmd)
213
-
214
- if $?.success?
215
- verify_keychain_entry(current_user, service_name)
216
- else
217
- puts "✗ 保存凭证到 Keychain 失败"
218
- return false
219
- end
220
-
221
- true
222
- end
223
-
224
- def self.verify_keychain_entry(account_name, service_name)
225
- verify_cmd = [
226
- "security",
227
- "find-generic-password",
228
- "-a", account_name,
229
- "-s", service_name
230
- ]
231
-
232
- unless system(*verify_cmd, out: File::NULL, err: File::NULL)
233
- puts "✗ 无法验证 Keychain 条目"
234
- end
235
- end
236
-
237
- def self.verify_token_config(config)
238
- # 检查两种可能的令牌键
239
- token = config["env"][TOKEN_KEY] || config["env"][ALT_TOKEN_KEY]
240
- return false unless token
241
-
242
- # 只验证令牌存在且不为空,不写入任何配置文件
243
- if token && !token.strip.empty?
244
- # 清理任何现有的环境配置文件中的令牌定义
245
- clean_env_variables
246
- return true
247
- else
248
- puts "✗ 令牌配置无效"
249
- return false
250
- end
251
- end
252
-
253
- def self.update_claude_json(config)
254
- begin
255
- # 读取现有文件或创建空哈希
256
- if File.exist?(CLAUDE_JSON_PATH)
257
- user_config = JSON.parse(File.read(CLAUDE_JSON_PATH))
258
- else
259
- user_config = {}
260
- end
261
-
262
- # 合并 claude_json 内容,过滤掉代理相关字段
263
- claude_config = config["claude_json"].dup
264
- claude_config.delete("claude_proxy")
265
- claude_config.delete("HTTP_PROXY")
266
- claude_config.delete("HTTPS_PROXY")
267
-
268
- user_config.merge!(claude_config)
269
-
270
- # 写回文件
271
- File.write(CLAUDE_JSON_PATH, JSON.pretty_generate(user_config))
272
-
273
- rescue JSON::ParserError => e
274
- puts "✗ 解析现有 ~/.claude.json 失败: #{e.message}"
275
- false
276
- rescue => e
277
- puts "✗ 更新 ~/.claude.json 失败: #{e.message}"
278
- false
279
- end
280
- end
281
-
282
- def self.configure_proxy(config)
283
- return unless config["claude_proxy"] && (config["claude_proxy"]["HTTP_PROXY"] || config["claude_proxy"]["HTTPS_PROXY"])
284
-
285
- http_proxy = config["claude_proxy"]["HTTP_PROXY"]
286
- https_proxy = config["claude_proxy"]["HTTPS_PROXY"]
287
-
288
- shell_files = get_shell_files
289
-
290
- shell_files.each do |shell_file|
291
- next unless File.exist?(shell_file)
292
-
293
- begin
294
- content = File.read(shell_file)
295
- lines = content.split("\n", -1)
296
- lines.pop if lines.last == ""
297
-
298
- # 移除所有现有的代理相关配置
299
- lines = remove_all_proxy_config(lines, shell_file)
300
-
301
- # 只添加代理别名/函数,不直接设置环境变量
302
- lines = add_proxy_aliases(lines, shell_file, http_proxy, https_proxy)
303
-
304
- # 写回文件
305
- File.write(shell_file, lines.join("\n") + "\n")
306
-
307
- rescue => e
308
- puts " ✗ 更新 #{shell_file} 失败: #{e.message}"
309
- end
310
- end
311
-
312
- # 显示代理配置完成信息
313
- puts "✅ 代理别名已配置 | claude_proxy / unclaude_proxy"
314
- end
315
-
316
- # 检查环境变量中的令牌
317
- def self.check_env_tokens
318
- # 优先使用 CLAUDE_CODE_OAUTH_TOKEN,其次是 ANTHROPIC_AUTH_TOKEN
319
- token = ENV[TOKEN_KEY] || ENV[ALT_TOKEN_KEY]
320
- token&.strip&.empty? ? nil : token
321
- end
322
-
323
- def self.prompt_for_token
324
- puts "请输入您的 CLAUDE_CODE_OAUTH_TOKEN:"
325
- print "> "
326
-
327
- begin
328
- # 简化输入处理,直接使用 STDIN
329
- STDIN.gets&.chomp
330
- rescue => e
331
- puts "✗ 无法读取输入: #{e.message}"
332
- puts " 请使用本地配置文件或 --user 参数"
333
- nil
334
- end
335
- end
336
-
337
- def self.clean_env_variables
338
- process_shell_files("令牌配置") do |lines, shell_file|
339
- patterns = get_token_patterns(shell_file)
340
- lines.reject { |line| patterns.any? { |pattern| line.match(pattern) } }
341
- end
342
- end
343
-
344
- def self.clean_keychain
345
- return unless macos?
346
-
347
- cmd = [
348
- "security",
349
- "delete-generic-password",
350
- "-a", current_user,
351
- "-s", SERVICE_NAME
352
- ]
353
-
354
- stdout, stderr, status = Open3.capture3(*cmd)
355
-
356
- if status.success?
357
- log_verbose(" ✓ 已清理 Keychain 中的 Claude Code 凭证")
358
- elsif !stderr.include?("could not be found")
359
- log_debug(" ⚠ 清理 Keychain 失败: #{stderr}")
360
- end
361
- end
362
-
363
- def self.get_shell_files
364
- Base::SystemInfo.shell_config_files
365
- end
366
-
367
- def self.get_token_patterns(shell_file)
368
- if shell_file.include?("config.fish")
369
- [
370
- /^set\s+-gx\s+#{Regexp.escape(TOKEN_KEY)}\s/,
371
- /^set\s+-x\s+#{Regexp.escape(TOKEN_KEY)}\s/,
372
- /^#set\s+-gx\s+#{Regexp.escape(TOKEN_KEY)}\s/
373
- ]
374
- else
375
- [
376
- /^export\s+#{Regexp.escape(TOKEN_KEY)}=/,
377
- /^#{Regexp.escape(TOKEN_KEY)}=/,
378
- /^#export\s+#{Regexp.escape(TOKEN_KEY)}=/
379
- ]
380
- end
381
- end
382
-
383
- def self.get_export_line(shell_file, token)
384
- if shell_file.include?("config.fish")
385
- "set -gx #{TOKEN_KEY} \"#{token}\""
386
- else
387
- "export #{TOKEN_KEY}=\"#{token}\""
388
- end
389
- end
390
-
391
- def self.remove_all_proxy_config(lines, shell_file)
392
- # 更全面的代理配置清理,包括所有可能的代理设置
393
- if shell_file.include?("config.fish")
394
- # Fish shell 代理配置清理
395
- lines.reject! { |line|
396
- # 清理环境变量设置
397
- line.match(/^set\s+-[gx]+\s+(HTTP_PROXY|HTTPS_PROXY|http_proxy|https_proxy|ALL_PROXY|all_proxy|NO_PROXY|no_proxy)\s/) ||
398
- line.match(/^export\s+(HTTP_PROXY|HTTPS_PROXY|http_proxy|https_proxy|ALL_PROXY|all_proxy|NO_PROXY|no_proxy)=/) ||
399
- # 清理别名
400
- line.match(/^alias\s+(claude_proxy|unclaude_proxy|proxy|unproxy)=/) ||
401
- # 清理函数
402
- line.match(/^function\s+(claude_proxy|unclaude_proxy|proxy|unproxy)/)
403
- }
404
-
405
- # 移除函数块
406
- in_function = false
407
- lines = lines.select do |line|
408
- if line.match(/^function\s+(claude_proxy|unclaude_proxy|proxy|unproxy)/)
409
- in_function = true
410
- false
411
- elsif in_function && line.strip == "end"
412
- in_function = false
413
- false
414
- elsif in_function
415
- false
416
- else
417
- true
418
- end
419
- end
420
- else
421
- # Bash/zsh 代理配置清理
422
- lines.reject! { |line|
423
- # 清理环境变量设置
424
- line.match(/^export\s+(HTTP_PROXY|HTTPS_PROXY|http_proxy|https_proxy|ALL_PROXY|all_proxy|NO_PROXY|no_proxy)=/) ||
425
- line.match(/^(HTTP_PROXY|HTTPS_PROXY|http_proxy|https_proxy|ALL_PROXY|all_proxy|NO_PROXY|no_proxy)=/) ||
426
- # 清理别名
427
- line.match(/^alias\s+(claude_proxy|unclaude_proxy|proxy|unproxy)=/) ||
428
- # 清理函数
429
- line.match(/^(claude_proxy|unclaude_proxy|proxy|unproxy)\(\)/) ||
430
- # 清理函数定义的另一种格式
431
- line.match(/^function\s+(claude_proxy|unclaude_proxy|proxy|unproxy)/)
432
- }
433
-
434
- # 移除函数块
435
- in_function = false
436
- function_depth = 0
437
- lines = lines.select do |line|
438
- if line.match(/^(claude_proxy|unclaude_proxy|proxy|unproxy)\(\)/) ||
439
- line.match(/^function\s+(claude_proxy|unclaude_proxy|proxy|unproxy)/)
440
- in_function = true
441
- function_depth = 0
442
- false
443
- elsif in_function
444
- function_depth += 1 if line.include?("{")
445
- if line.include?("}")
446
- function_depth -= 1
447
- if function_depth <= 0
448
- in_function = false
449
- false
450
- else
451
- false
452
- end
453
- else
454
- false
455
- end
456
- else
457
- true
458
- end
459
- end
460
- end
461
-
462
- lines
463
- end
464
-
465
- # remove_proxy_config 方法已被 remove_all_proxy_config 替代
466
- # remove_all_proxy_config 提供更全面的清理功能,包括 ALL_PROXY 和 NO_PROXY
467
-
468
- def self.add_proxy_aliases(lines, shell_file, http_proxy, https_proxy)
469
- if shell_file.include?("config.fish")
470
- # Fish shell - 只添加函数,不直接设置环境变量
471
- proxy_commands = []
472
- proxy_commands << ""
473
- proxy_commands << "function claude_proxy"
474
- if http_proxy
475
- proxy_commands << " set -gx HTTP_PROXY \"#{http_proxy}\""
476
- proxy_commands << " set -gx http_proxy \"#{http_proxy}\""
477
- end
478
- if https_proxy
479
- proxy_commands << " set -gx HTTPS_PROXY \"#{https_proxy}\""
480
- proxy_commands << " set -gx https_proxy \"#{https_proxy}\""
481
- end
482
- proxy_commands << " echo '代理已启用: HTTP_PROXY=#{http_proxy || 'not set'}, HTTPS_PROXY=#{https_proxy || 'not set'}'"
483
- proxy_commands << "end"
484
-
485
- proxy_commands << ""
486
- proxy_commands << "function unclaude_proxy"
487
- proxy_commands << " set -e HTTP_PROXY"
488
- proxy_commands << " set -e http_proxy"
489
- proxy_commands << " set -e HTTPS_PROXY"
490
- proxy_commands << " set -e https_proxy"
491
- proxy_commands << " echo '代理已禁用'"
492
- proxy_commands << "end"
493
-
494
- lines.concat(proxy_commands)
495
- else
496
- # Bash/zsh - 只添加别名,不直接设置环境变量
497
- proxy_exports = []
498
- if http_proxy
499
- proxy_exports << "export HTTP_PROXY=\"#{http_proxy}\""
500
- proxy_exports << "export http_proxy=\"#{http_proxy}\""
501
- end
502
- if https_proxy
503
- proxy_exports << "export HTTPS_PROXY=\"#{https_proxy}\""
504
- proxy_exports << "export https_proxy=\"#{https_proxy}\""
505
- end
506
-
507
- if proxy_exports.any?
508
- lines << ""
509
- lines << "alias claude_proxy='#{proxy_exports.join("; ")}; echo \"代理已启用: HTTP_PROXY=#{http_proxy || 'not set'}, HTTPS_PROXY=#{https_proxy || 'not set'}\"'"
510
- end
511
-
512
- lines << "alias unclaude_proxy='unset HTTP_PROXY http_proxy HTTPS_PROXY https_proxy; echo \"代理已禁用\"'"
513
- end
514
-
515
- lines
516
- end
517
- end
518
- end
519
- end