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.
- checksums.yaml +4 -4
- data/AGENTS.md +10 -8
- data/CLAUDE.md +221 -126
- data/README.md +176 -36
- data/easyai.gemspec +12 -9
- data/lib/easyai/base/secret_masker.rb +39 -0
- data/lib/easyai/base/system_info.rb +17 -203
- data/lib/easyai/base/toml_sections.rb +105 -0
- data/lib/easyai/command/ai_tool_base.rb +228 -0
- data/lib/easyai/command/backup/claude.rb +140 -0
- data/lib/easyai/command/backup/codex.rb +206 -0
- data/lib/easyai/command/backup.rb +26 -0
- data/lib/easyai/command/claude.rb +75 -357
- data/lib/easyai/command/clean.rb +88 -395
- data/lib/easyai/command/codex.rb +269 -0
- data/lib/easyai/command/restore/claude.rb +150 -0
- data/lib/easyai/command/restore/codex.rb +165 -0
- data/lib/easyai/command/restore.rb +27 -0
- data/lib/easyai/command/setup.rb +524 -375
- data/lib/easyai/command/update.rb +39 -188
- data/lib/easyai/command/utils.rb +2 -7
- data/lib/easyai/command.rb +1 -3
- data/lib/easyai/config/local_config.rb +190 -0
- data/lib/easyai/version.rb +1 -1
- data/lib/easyai.rb +29 -36
- metadata +23 -38
- data/lib/easyai/auth/authclaude.rb +0 -519
- data/lib/easyai/auth/jpsloginhelper.rb +0 -98
- data/lib/easyai/base/system_keychain.rb +0 -283
- data/lib/easyai/command/gemini.rb +0 -56
- data/lib/easyai/command/gpt.rb +0 -259
- data/lib/easyai/command/utils/export.rb +0 -263
- data/lib/easyai/config/config.rb +0 -357
- data/lib/easyai/config/easyai_config.rb +0 -258
data/lib/easyai/command/clean.rb
CHANGED
|
@@ -1,451 +1,144 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
3
|
require 'fileutils'
|
|
4
|
-
require '
|
|
5
|
-
|
|
6
|
-
require_relative '../base/system_info'
|
|
4
|
+
require 'colored2'
|
|
5
|
+
require_relative '../command'
|
|
7
6
|
|
|
8
7
|
module EasyAI
|
|
9
8
|
class Command
|
|
9
|
+
# 清理 AI CLI 自身在本地产生的缓存与配置目录。
|
|
10
|
+
#
|
|
11
|
+
# 设计要点(详见 docs/设计文档.md §2.6):
|
|
12
|
+
# - 仅清理两家 AI CLI(claude / codex)的缓存路径
|
|
13
|
+
# - 不会触碰 ~/.easyai/config.json(重置 EasyAI 自身配置请用 easyai setup --reset)
|
|
14
|
+
# - --force 跳过确认;--dry-run 仅打印
|
|
15
|
+
# - 删除时遇到 Errno::EACCES 继续删余下项;最终如有失败项以退出码 1 退出
|
|
10
16
|
class Clean < Command
|
|
11
|
-
self.summary = '清理AI
|
|
17
|
+
self.summary = '清理 AI CLI 自身缓存(不影响 EasyAI 配置)'
|
|
12
18
|
self.description = <<-DESC
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
支持清理:
|
|
19
|
+
清理 claude / codex 各自在本地产生的缓存目录与配置文件。
|
|
16
20
|
|
|
17
|
-
|
|
21
|
+
支持范围:
|
|
22
|
+
* claude → ~/.claude、~/.claude.json、~/.config/claude
|
|
23
|
+
* codex → ~/.codex、~/.config/codex
|
|
24
|
+
* all → 上述全部
|
|
18
25
|
|
|
19
|
-
|
|
26
|
+
使用示例:
|
|
20
27
|
|
|
21
|
-
|
|
28
|
+
$ easyai clean # 默认清理 claude
|
|
29
|
+
$ easyai clean codex # 清理 codex
|
|
30
|
+
$ easyai clean all # 清理三家 AI CLI 缓存
|
|
31
|
+
$ easyai clean all --dry-run # 仅打印将要删除的路径
|
|
32
|
+
$ easyai clean all --force # 跳过确认提示
|
|
22
33
|
|
|
23
|
-
|
|
34
|
+
注意:本命令不会动 ~/.easyai/config.json;如需重置 EasyAI 自身配置请使用:
|
|
24
35
|
|
|
25
|
-
|
|
36
|
+
$ easyai setup --reset
|
|
37
|
+
DESC
|
|
26
38
|
|
|
27
|
-
|
|
39
|
+
VALID_TOOLS = %w[claude codex all].freeze
|
|
28
40
|
|
|
29
|
-
|
|
41
|
+
# AI CLI 自身的缓存路径表(不含 ~/.easyai/config.json)
|
|
42
|
+
CACHE_PATHS = {
|
|
43
|
+
'claude' => %w[~/.claude ~/.claude.json ~/.config/claude],
|
|
44
|
+
'codex' => %w[~/.codex ~/.config/codex]
|
|
45
|
+
}.freeze
|
|
30
46
|
|
|
31
|
-
|
|
32
|
-
DESC
|
|
47
|
+
self.arguments = [CLAide::Argument.new('TOOL', false)]
|
|
33
48
|
|
|
34
49
|
def self.options
|
|
35
50
|
[
|
|
36
|
-
['--force',
|
|
37
|
-
['--dry-run', '
|
|
51
|
+
['--force', '跳过确认提示,直接删除'],
|
|
52
|
+
['--dry-run', '仅打印将要删除的路径,不真正删除']
|
|
38
53
|
].concat(super)
|
|
39
54
|
end
|
|
40
55
|
|
|
41
56
|
def initialize(argv)
|
|
42
|
-
@
|
|
43
|
-
@force
|
|
57
|
+
@tool = (argv.shift_argument || 'claude').to_s.downcase
|
|
58
|
+
@force = argv.flag?('force')
|
|
44
59
|
@dry_run = argv.flag?('dry-run')
|
|
45
60
|
super
|
|
46
61
|
end
|
|
47
62
|
|
|
48
63
|
def validate!
|
|
49
64
|
super
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
help! "不支持的工具名称: #{@tool_name}。支持的工具: #{valid_tools.join(', ')}"
|
|
65
|
+
unless VALID_TOOLS.include?(@tool)
|
|
66
|
+
help! "不支持的工具:#{@tool}。可选值:#{VALID_TOOLS.join(' / ')}"
|
|
53
67
|
end
|
|
54
|
-
@tool_name = @tool_name.downcase
|
|
55
68
|
end
|
|
56
69
|
|
|
57
70
|
def run
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
# 预览模式或确认
|
|
62
|
-
if @dry_run
|
|
63
|
-
puts "📋 预览模式 - 以下项目将被清理:"
|
|
64
|
-
preview_cleanup
|
|
65
|
-
return
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
unless @force
|
|
69
|
-
puts "⚠️ 警告:此操作将删除以下配置信息:"
|
|
70
|
-
preview_cleanup
|
|
71
|
-
puts
|
|
72
|
-
print "确认继续清理?(y/N): "
|
|
73
|
-
confirmation = STDIN.gets.chomp.downcase
|
|
74
|
-
unless confirmation == 'y' || confirmation == 'yes'
|
|
75
|
-
puts "❌ 清理操作已取消"
|
|
76
|
-
return
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
puts "🧹 开始清理配置..."
|
|
81
|
-
perform_cleanup
|
|
82
|
-
puts "✅ 清理完成"
|
|
83
|
-
end
|
|
71
|
+
targets = collect_targets(@tool)
|
|
72
|
+
existing = targets.select { |path| File.exist?(path) || File.symlink?(path) }
|
|
84
73
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
case @tool_name
|
|
89
|
-
when 'claude'
|
|
90
|
-
preview_claude_cleanup
|
|
91
|
-
when 'gemini'
|
|
92
|
-
preview_gemini_cleanup
|
|
93
|
-
when 'openai'
|
|
94
|
-
preview_openai_cleanup
|
|
95
|
-
when 'all'
|
|
96
|
-
preview_claude_cleanup
|
|
97
|
-
preview_gemini_cleanup
|
|
98
|
-
preview_openai_cleanup
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
def perform_cleanup
|
|
103
|
-
case @tool_name
|
|
104
|
-
when 'claude'
|
|
105
|
-
clean_claude
|
|
106
|
-
when 'gemini'
|
|
107
|
-
clean_gemini
|
|
108
|
-
when 'openai'
|
|
109
|
-
clean_openai
|
|
110
|
-
when 'all'
|
|
111
|
-
clean_claude
|
|
112
|
-
clean_gemini
|
|
113
|
-
clean_openai
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
def preview_claude_cleanup
|
|
118
|
-
puts "📌 Claude 配置(由 easyai claude 命令设置的项目):"
|
|
119
|
-
|
|
120
|
-
# 本地配置文件 - easyai 自己的配置,不是 authclaude.rb 设置的
|
|
121
|
-
config_file = File.expand_path('~/.easyai/config.yml')
|
|
122
|
-
if File.exist?(config_file)
|
|
123
|
-
config = YAML.load_file(config_file) rescue {}
|
|
124
|
-
if config && config['claude_token']
|
|
125
|
-
puts " • 本地配置文件: #{config_file} (claude_token)"
|
|
126
|
-
end
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
# Claude JSON 配置文件 - authclaude.rb 中 update_claude_json 设置的
|
|
130
|
-
claude_file = File.expand_path('~/.claude.json')
|
|
131
|
-
if File.exist?(claude_file) && has_claude_json_config?(claude_file)
|
|
132
|
-
puts " • Claude配置文件: #{claude_file} (由远程配置合并的内容)"
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
# Shell 配置文件中的代理别名 - authclaude.rb 中 configure_proxy 设置的
|
|
136
|
-
shell_files = get_shell_files
|
|
137
|
-
shell_files.each do |shell_file|
|
|
138
|
-
if File.exist?(shell_file) && has_claude_proxy_config?(shell_file)
|
|
139
|
-
puts " • Shell代理配置: #{shell_file} (claude_proxy, unclaude_proxy 别名)"
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
# Keychain 认证信息 - authclaude.rb 中 configure_keychain 设置的
|
|
144
|
-
if Base::SystemInfo.macos?
|
|
145
|
-
keychain_entries = get_claude_keychain_entries
|
|
146
|
-
keychain_entries.each do |service_name|
|
|
147
|
-
puts " • macOS Keychain: #{service_name} (Claude认证信息)"
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
puts
|
|
152
|
-
end
|
|
153
|
-
|
|
154
|
-
def preview_gemini_cleanup
|
|
155
|
-
puts "📌 Gemini 配置:"
|
|
156
|
-
|
|
157
|
-
# 本地配置文件
|
|
158
|
-
config_file = File.expand_path('~/.easyai/config.yml')
|
|
159
|
-
if File.exist?(config_file)
|
|
160
|
-
puts " • 本地配置文件: #{config_file} (gemini_token)"
|
|
74
|
+
if existing.empty?
|
|
75
|
+
puts "未找到 #{display_label(@tool)} 的缓存路径,无需清理".cyan
|
|
76
|
+
return
|
|
161
77
|
end
|
|
162
|
-
|
|
163
|
-
puts
|
|
164
|
-
end
|
|
165
78
|
|
|
166
|
-
|
|
167
|
-
puts "
|
|
168
|
-
|
|
169
|
-
# 本地配置文件
|
|
170
|
-
config_file = File.expand_path('~/.easyai/config.yml')
|
|
171
|
-
if File.exist?(config_file)
|
|
172
|
-
puts " • 本地配置文件: #{config_file} (openai_token)"
|
|
173
|
-
end
|
|
174
|
-
|
|
79
|
+
puts "将清理以下路径(#{display_label(@tool)}):".cyan
|
|
80
|
+
existing.each { |path| puts " • #{path}" }
|
|
175
81
|
puts
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
def clean_claude
|
|
179
|
-
puts "🧹 清理Claude配置..."
|
|
180
|
-
|
|
181
|
-
# 清理本地配置文件中的Claude令牌
|
|
182
|
-
clean_local_config('claude_token')
|
|
183
|
-
|
|
184
|
-
# 清理 ~/.claude.json
|
|
185
|
-
clean_claude_json
|
|
186
|
-
|
|
187
|
-
# 清理Shell配置文件
|
|
188
|
-
clean_shell_config_claude
|
|
189
|
-
|
|
190
|
-
# 清理Keychain
|
|
191
|
-
clean_keychain_claude
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
def clean_gemini
|
|
195
|
-
puts "🧹 清理Gemini配置..."
|
|
196
|
-
clean_local_config('gemini_token')
|
|
197
|
-
end
|
|
198
82
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
def clean_local_config(key)
|
|
205
|
-
config_file = File.expand_path('~/.easyai/config.yml')
|
|
206
|
-
return unless File.exist?(config_file)
|
|
207
|
-
|
|
208
|
-
begin
|
|
209
|
-
config = YAML.load_file(config_file) || {}
|
|
210
|
-
if config.key?(key)
|
|
211
|
-
config.delete(key)
|
|
212
|
-
File.write(config_file, config.to_yaml)
|
|
213
|
-
puts " ✓ 已清理本地配置文件中的 #{key}"
|
|
214
|
-
|
|
215
|
-
# 如果配置文件为空,删除整个配置目录
|
|
216
|
-
if config.empty?
|
|
217
|
-
config_dir = File.dirname(config_file)
|
|
218
|
-
FileUtils.rm_rf(config_dir)
|
|
219
|
-
puts " ✓ 已删除空配置目录: #{config_dir}"
|
|
220
|
-
end
|
|
221
|
-
end
|
|
222
|
-
rescue => e
|
|
223
|
-
puts " ✗ 清理本地配置失败: #{e.message}"
|
|
224
|
-
end
|
|
225
|
-
end
|
|
226
|
-
|
|
227
|
-
def clean_claude_json
|
|
228
|
-
claude_file = File.expand_path('~/.claude.json')
|
|
229
|
-
return unless File.exist?(claude_file)
|
|
230
|
-
|
|
231
|
-
begin
|
|
232
|
-
# 不是完全删除文件,而是恢复到只包含默认字段的状态
|
|
233
|
-
# 因为 Claude Code 会自动重新创建基本配置
|
|
234
|
-
content = JSON.parse(File.read(claude_file))
|
|
235
|
-
|
|
236
|
-
# 保留默认字段,删除由 authclaude.rb update_claude_json 方法添加的配置
|
|
237
|
-
default_fields = %w[installMethod autoUpdates userID fallbackAvailableWarningThreshold projects tipsHistory]
|
|
238
|
-
cleaned_content = content.select { |key, _| default_fields.include?(key) }
|
|
239
|
-
|
|
240
|
-
if cleaned_content != content
|
|
241
|
-
File.write(claude_file, JSON.pretty_generate(cleaned_content))
|
|
242
|
-
puts " ✓ 已清理Claude配置文件中的远程配置内容: #{claude_file}"
|
|
243
|
-
end
|
|
244
|
-
rescue JSON::ParserError => e
|
|
245
|
-
puts " ✗ 解析Claude配置文件失败: #{e.message}"
|
|
246
|
-
rescue => e
|
|
247
|
-
puts " ✗ 清理Claude配置文件失败: #{e.message}"
|
|
83
|
+
if @dry_run
|
|
84
|
+
puts "已启用 --dry-run,未执行实际删除。".yellow
|
|
85
|
+
return
|
|
248
86
|
end
|
|
249
|
-
end
|
|
250
87
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
begin
|
|
258
|
-
content = File.read(shell_file)
|
|
259
|
-
original_content = content.dup
|
|
260
|
-
lines = content.split("\n", -1)
|
|
261
|
-
lines.pop if lines.last == ""
|
|
262
|
-
|
|
263
|
-
# 只清理由 authclaude.rb 添加的代理配置(claude_proxy 和 unclaude_proxy)
|
|
264
|
-
# 不清理 CLAUDE_CODE_OAUTH_TOKEN,因为那不是 authclaude.rb 设置的
|
|
265
|
-
lines = remove_claude_proxy_config(lines, shell_file)
|
|
266
|
-
|
|
267
|
-
if lines.join("\n") + "\n" != original_content
|
|
268
|
-
File.write(shell_file, lines.join("\n") + "\n")
|
|
269
|
-
puts " ✓ 已清理Shell代理配置: #{shell_file}"
|
|
270
|
-
end
|
|
271
|
-
rescue => e
|
|
272
|
-
puts " ✗ 清理Shell配置失败 #{shell_file}: #{e.message}"
|
|
88
|
+
unless @force
|
|
89
|
+
print "确认继续删除以上路径?(y/N): "
|
|
90
|
+
answer = ($stdin.gets || '').strip.downcase
|
|
91
|
+
unless %w[y yes].include?(answer)
|
|
92
|
+
puts "已取消".yellow
|
|
93
|
+
return
|
|
273
94
|
end
|
|
274
95
|
end
|
|
275
|
-
end
|
|
276
96
|
|
|
277
|
-
|
|
278
|
-
return unless Base::SystemInfo.macos?
|
|
97
|
+
failures = perform_delete(existing)
|
|
279
98
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
if keychain_entries.empty?
|
|
284
|
-
# 检查默认的 Claude Code-credentials
|
|
285
|
-
service_name = "Claude Code-credentials"
|
|
286
|
-
cmd = ["security", "delete-generic-password", "-a", account_name, "-s", service_name]
|
|
287
|
-
stdout, stderr, status = Open3.capture3(*cmd)
|
|
288
|
-
|
|
289
|
-
if status.success?
|
|
290
|
-
puts " ✓ 已清理Keychain: #{service_name}"
|
|
291
|
-
elsif !stderr.include?("could not be found")
|
|
292
|
-
puts " ✗ 清理Keychain失败: #{stderr}"
|
|
293
|
-
end
|
|
99
|
+
if failures.empty?
|
|
100
|
+
puts "✓ 清理完成".green
|
|
294
101
|
else
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
cmd = ["security", "delete-generic-password", "-a", account_name, "-s", service_name]
|
|
298
|
-
stdout, stderr, status = Open3.capture3(*cmd)
|
|
299
|
-
|
|
300
|
-
if status.success?
|
|
301
|
-
puts " ✓ 已清理Keychain: #{service_name}"
|
|
302
|
-
elsif !stderr.include?("could not be found")
|
|
303
|
-
puts " ✗ 清理Keychain失败 #{service_name}: #{stderr}"
|
|
304
|
-
end
|
|
305
|
-
end
|
|
102
|
+
puts "⚠ 清理完成,但有 #{failures.size} 项失败".yellow
|
|
103
|
+
exit 1
|
|
306
104
|
end
|
|
105
|
+
rescue Interrupt
|
|
106
|
+
puts
|
|
107
|
+
puts "已取消".yellow
|
|
108
|
+
exit 130
|
|
307
109
|
end
|
|
308
110
|
|
|
309
|
-
|
|
310
|
-
return false unless File.exist?(claude_file)
|
|
311
|
-
|
|
312
|
-
begin
|
|
313
|
-
content = JSON.parse(File.read(claude_file))
|
|
314
|
-
# 检查是否有非默认的配置项(排除 Claude Code 自动生成的默认字段)
|
|
315
|
-
default_fields = %w[installMethod autoUpdates userID fallbackAvailableWarningThreshold projects tipsHistory]
|
|
316
|
-
has_custom_config = content.keys.any? { |key| !default_fields.include?(key) }
|
|
317
|
-
return has_custom_config
|
|
318
|
-
rescue JSON::ParserError, StandardError
|
|
319
|
-
return false
|
|
320
|
-
end
|
|
321
|
-
end
|
|
111
|
+
private
|
|
322
112
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
113
|
+
# @param tool [String]
|
|
114
|
+
# @return [Array<String>] expand 后的绝对路径列表
|
|
115
|
+
def collect_targets(tool)
|
|
116
|
+
keys = tool == 'all' ? CACHE_PATHS.keys : [tool]
|
|
117
|
+
keys.flat_map { |key| CACHE_PATHS.fetch(key, []) }.map { |p| File.expand_path(p) }
|
|
328
118
|
end
|
|
329
119
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
"claude",
|
|
345
|
-
"anthropic-claude",
|
|
346
|
-
"anthropic",
|
|
347
|
-
]
|
|
348
|
-
|
|
349
|
-
# 逐个检查已知的服务名,避免使用 dump-keychain
|
|
350
|
-
possible_services.each do |service_name|
|
|
351
|
-
# 使用 find-generic-password 检查条目是否存在
|
|
352
|
-
# 不使用 -w 选项,只检查是否存在,不获取密码内容
|
|
353
|
-
cmd = ["security", "find-generic-password", "-a", account_name, "-s", service_name]
|
|
354
|
-
stdout, stderr, status = Open3.capture3(*cmd)
|
|
355
|
-
|
|
356
|
-
# 如果命令成功(返回码0),说明条目存在
|
|
357
|
-
if status.success?
|
|
358
|
-
entries << service_name
|
|
120
|
+
# @param paths [Array<String>]
|
|
121
|
+
# @return [Array<String>] 删除失败的路径列表
|
|
122
|
+
def perform_delete(paths)
|
|
123
|
+
failures = []
|
|
124
|
+
paths.each do |path|
|
|
125
|
+
begin
|
|
126
|
+
FileUtils.rm_rf(path, secure: true)
|
|
127
|
+
puts " ✓ #{path}".green
|
|
128
|
+
rescue Errno::EACCES => e
|
|
129
|
+
failures << path
|
|
130
|
+
puts " ✗ #{path}: 权限不足(#{e.message})".red
|
|
131
|
+
rescue StandardError => e
|
|
132
|
+
failures << path
|
|
133
|
+
puts " ✗ #{path}: #{e.message}".red
|
|
359
134
|
end
|
|
360
135
|
end
|
|
361
|
-
|
|
362
|
-
# 额外检查:使用 list-keychains 安全地获取钥匙串列表
|
|
363
|
-
# 但不解密内容,只是查看是否有相关条目
|
|
364
|
-
# 注意:这个方法更安全,不会触发密码提示
|
|
365
|
-
|
|
366
|
-
entries.uniq
|
|
367
|
-
end
|
|
368
|
-
|
|
369
|
-
def get_shell_files
|
|
370
|
-
shell_files = []
|
|
371
|
-
current_shell = Base::SystemInfo.current_shell
|
|
372
|
-
|
|
373
|
-
case current_shell
|
|
374
|
-
when 'zsh'
|
|
375
|
-
shell_files << File.expand_path("~/.zshrc")
|
|
376
|
-
when 'bash'
|
|
377
|
-
bash_profile = File.expand_path("~/.bash_profile")
|
|
378
|
-
bashrc = File.expand_path("~/.bashrc")
|
|
379
|
-
shell_files << (File.exist?(bash_profile) ? bash_profile : bashrc)
|
|
380
|
-
when 'fish'
|
|
381
|
-
fish_config = File.expand_path("~/.config/fish/config.fish")
|
|
382
|
-
shell_files << fish_config
|
|
383
|
-
else
|
|
384
|
-
shell_files << File.expand_path("~/.profile")
|
|
385
|
-
end
|
|
386
|
-
|
|
387
|
-
# 总是添加 ~/.profile 作为备份
|
|
388
|
-
profile_file = File.expand_path("~/.profile")
|
|
389
|
-
shell_files << profile_file unless shell_files.include?(profile_file)
|
|
390
|
-
|
|
391
|
-
shell_files
|
|
136
|
+
failures
|
|
392
137
|
end
|
|
393
138
|
|
|
394
|
-
def
|
|
395
|
-
|
|
396
|
-
# 这是 authclaude.rb 中 configure_proxy 方法添加的内容
|
|
397
|
-
if shell_file.include?("config.fish")
|
|
398
|
-
# Fish shell - 移除代理相关的别名/函数
|
|
399
|
-
lines.reject! { |line|
|
|
400
|
-
line.match(/^alias\s+claude_proxy=/) ||
|
|
401
|
-
line.match(/^alias\s+unclaude_proxy=/) ||
|
|
402
|
-
line.match(/^function\s+(claude_proxy|unclaude_proxy)/)
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
# 移除函数块
|
|
406
|
-
in_function = false
|
|
407
|
-
lines.select do |line|
|
|
408
|
-
if line.match(/^function\s+(claude_proxy|unclaude_proxy)/)
|
|
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
|
-
line.match(/^alias\s+(claude_proxy|unclaude_proxy)=/) ||
|
|
424
|
-
line.match(/^(claude_proxy|unclaude_proxy)\(\)/)
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
# 移除函数块
|
|
428
|
-
in_function = false
|
|
429
|
-
function_depth = 0
|
|
430
|
-
lines.select do |line|
|
|
431
|
-
if line.match(/^(claude_proxy|unclaude_proxy)\(\)/)
|
|
432
|
-
in_function = true
|
|
433
|
-
function_depth = 0
|
|
434
|
-
false
|
|
435
|
-
elsif in_function
|
|
436
|
-
function_depth += 1 if line.include?("{")
|
|
437
|
-
if line.include?("}")
|
|
438
|
-
function_depth -= 1
|
|
439
|
-
in_function = false if function_depth <= 0
|
|
440
|
-
end
|
|
441
|
-
false
|
|
442
|
-
else
|
|
443
|
-
true
|
|
444
|
-
end
|
|
445
|
-
end
|
|
446
|
-
end
|
|
139
|
+
def display_label(tool)
|
|
140
|
+
tool == 'all' ? '全部 AI CLI' : tool
|
|
447
141
|
end
|
|
448
|
-
|
|
449
142
|
end
|
|
450
143
|
end
|
|
451
|
-
end
|
|
144
|
+
end
|