easyai 1.0.3 → 1.0.5
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/easyai.gemspec +1 -0
- data/lib/easyai/auth/jpslogin.rb +189 -5
- data/lib/easyai/command/claude.rb +0 -8
- data/lib/easyai/version.rb +1 -1
- metadata +15 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 764f51642d04ee3ba299d468f3d09cc6064899605910fdca6568c536de330e0e
|
4
|
+
data.tar.gz: 29d920f541d56356ee766d87f349ee6e2459b9d5a6fdaede676d9457079bf4f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 68b0aaec2f2996bf44c808d2e1266f47e4fc624a5194e1a29569b942ca35abfc9cd393baf3b29a5c6263798d591dd5b570d1b289e20da0fc30d05cb419f4ad92
|
7
|
+
data.tar.gz: 816988a6ec0d2414ee5823621febfb7c28fa7607484f85436b8014a3eb0bab31b2d316e6f342f3939f066f7087bd443dcda9eab1d4302e9a9ca20bb4c2202dd6
|
data/easyai.gemspec
CHANGED
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_dependency 'claide', '~> 1.0'
|
22
22
|
spec.add_dependency 'colored2', '~> 3.1'
|
23
|
+
spec.add_dependency 'webrick', '~> 1.7'
|
23
24
|
|
24
25
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
25
26
|
spec.add_development_dependency 'rake', '~> 13.0'
|
data/lib/easyai/auth/jpslogin.rb
CHANGED
@@ -164,13 +164,27 @@ module EasyAI
|
|
164
164
|
def start_callback_server
|
165
165
|
code = nil
|
166
166
|
|
167
|
+
# 检查并处理端口占用
|
168
|
+
unless ensure_port_available(@server_port)
|
169
|
+
puts "✗ 无法使用端口 #{@server_port},登录失败"
|
170
|
+
return nil
|
171
|
+
end
|
172
|
+
|
167
173
|
puts "启动本地服务器,监听端口 #{@server_port}..."
|
168
174
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
175
|
+
begin
|
176
|
+
server = WEBrick::HTTPServer.new(
|
177
|
+
Port: @server_port,
|
178
|
+
Logger: WEBrick::Log.new("/dev/null"),
|
179
|
+
AccessLog: []
|
180
|
+
)
|
181
|
+
rescue Errno::EADDRINUSE
|
182
|
+
puts "✗ 端口 #{@server_port} 仍被占用,无法启动服务器"
|
183
|
+
return nil
|
184
|
+
rescue => e
|
185
|
+
puts "✗ 启动服务器失败: #{e.message}"
|
186
|
+
return nil
|
187
|
+
end
|
174
188
|
|
175
189
|
# 处理根路径的请求
|
176
190
|
server.mount_proc '/' do |req, res|
|
@@ -379,6 +393,176 @@ module EasyAI
|
|
379
393
|
</html>
|
380
394
|
HTML
|
381
395
|
end
|
396
|
+
|
397
|
+
# 确保端口可用,处理端口占用问题
|
398
|
+
def ensure_port_available(port)
|
399
|
+
return true unless port_occupied?(port)
|
400
|
+
|
401
|
+
puts "⚠️ 端口 #{port} 被占用,正在检查占用进程..."
|
402
|
+
|
403
|
+
# 获取占用端口的进程信息
|
404
|
+
process_info = get_port_process_info(port)
|
405
|
+
|
406
|
+
if process_info.nil?
|
407
|
+
puts "✗ 无法获取端口占用信息"
|
408
|
+
return false
|
409
|
+
end
|
410
|
+
|
411
|
+
puts "占用进程信息:"
|
412
|
+
puts " PID: #{process_info[:pid]}"
|
413
|
+
puts " 进程名: #{process_info[:name]}"
|
414
|
+
puts " 命令: #{process_info[:command]}"
|
415
|
+
|
416
|
+
# 检查是否是自己的进程(可能是之前未正常关闭的实例)
|
417
|
+
if process_info[:name].include?('ruby') && process_info[:command].include?('easyai')
|
418
|
+
puts "检测到可能是 EasyAI 之前的遗留进程"
|
419
|
+
if ask_user_kill_process?
|
420
|
+
return kill_process_by_pid(process_info[:pid])
|
421
|
+
end
|
422
|
+
else
|
423
|
+
puts "端口被其他应用程序占用"
|
424
|
+
if ask_user_kill_process?
|
425
|
+
return kill_process_by_pid(process_info[:pid])
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
return false
|
430
|
+
end
|
431
|
+
|
432
|
+
# 检查端口是否被占用
|
433
|
+
def port_occupied?(port)
|
434
|
+
require 'socket'
|
435
|
+
|
436
|
+
begin
|
437
|
+
server = TCPServer.new('127.0.0.1', port)
|
438
|
+
server.close
|
439
|
+
false # 端口未被占用
|
440
|
+
rescue Errno::EADDRINUSE
|
441
|
+
true # 端口被占用
|
442
|
+
rescue => e
|
443
|
+
puts "⚠️ 检查端口时出错: #{e.message}"
|
444
|
+
true # 出错时假设端口被占用,避免冲突
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
# 获取占用指定端口的进程信息
|
449
|
+
def get_port_process_info(port)
|
450
|
+
begin
|
451
|
+
# macOS/Linux 使用 lsof 命令
|
452
|
+
if system('which lsof > /dev/null 2>&1')
|
453
|
+
output = `lsof -ti :#{port} 2>/dev/null`.strip
|
454
|
+
return nil if output.empty?
|
455
|
+
|
456
|
+
pid = output.split("\n").first
|
457
|
+
return nil if pid.nil? || pid.empty?
|
458
|
+
|
459
|
+
# 获取进程详细信息
|
460
|
+
ps_output = `ps -p #{pid} -o pid,comm,args 2>/dev/null`.lines
|
461
|
+
return nil if ps_output.length < 2
|
462
|
+
|
463
|
+
process_line = ps_output[1].strip
|
464
|
+
parts = process_line.split(/\s+/, 3)
|
465
|
+
|
466
|
+
return {
|
467
|
+
pid: parts[0],
|
468
|
+
name: parts[1] || 'unknown',
|
469
|
+
command: parts[2] || 'unknown'
|
470
|
+
}
|
471
|
+
end
|
472
|
+
|
473
|
+
# Windows 使用 netstat 命令
|
474
|
+
if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
|
475
|
+
output = `netstat -ano | findstr :#{port}`.strip
|
476
|
+
return nil if output.empty?
|
477
|
+
|
478
|
+
lines = output.split("\n")
|
479
|
+
listening_line = lines.find { |line| line.include?('LISTENING') }
|
480
|
+
return nil unless listening_line
|
481
|
+
|
482
|
+
pid = listening_line.split.last
|
483
|
+
return nil if pid.nil? || pid.empty?
|
484
|
+
|
485
|
+
# 获取进程名称
|
486
|
+
task_output = `tasklist /FI "PID eq #{pid}" /FO CSV /NH 2>nul`.strip
|
487
|
+
if !task_output.empty?
|
488
|
+
process_name = task_output.split(',').first.gsub('"', '')
|
489
|
+
return {
|
490
|
+
pid: pid,
|
491
|
+
name: process_name,
|
492
|
+
command: process_name
|
493
|
+
}
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
497
|
+
return nil
|
498
|
+
rescue => e
|
499
|
+
puts "获取进程信息时出错: #{e.message}"
|
500
|
+
return nil
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
# 询问用户是否终止占用端口的进程
|
505
|
+
def ask_user_kill_process?
|
506
|
+
puts "\n是否终止占用端口的进程?"
|
507
|
+
puts " y/yes - 终止进程并继续 (可能影响其他应用)"
|
508
|
+
puts " n/no - 取消登录 (默认)"
|
509
|
+
print "> "
|
510
|
+
|
511
|
+
begin
|
512
|
+
response = STDIN.gets&.chomp&.downcase
|
513
|
+
return ['y', 'yes'].include?(response)
|
514
|
+
rescue Interrupt
|
515
|
+
puts "\n\n用户中断操作"
|
516
|
+
return false
|
517
|
+
rescue => e
|
518
|
+
puts "无法读取用户输入: #{e.message}"
|
519
|
+
return false
|
520
|
+
end
|
521
|
+
end
|
522
|
+
|
523
|
+
# 根据 PID 终止进程
|
524
|
+
def kill_process_by_pid(pid)
|
525
|
+
return false if pid.nil? || pid.empty?
|
526
|
+
|
527
|
+
begin
|
528
|
+
puts "正在终止进程 #{pid}..."
|
529
|
+
|
530
|
+
# 跨平台的进程终止命令
|
531
|
+
if RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
|
532
|
+
# Windows
|
533
|
+
success = system("taskkill /PID #{pid} /F >nul 2>&1")
|
534
|
+
else
|
535
|
+
# macOS/Linux - 先尝试优雅终止,再强制终止
|
536
|
+
success = system("kill -TERM #{pid} 2>/dev/null")
|
537
|
+
sleep(2)
|
538
|
+
# 检查进程是否还存在
|
539
|
+
if system("kill -0 #{pid} 2>/dev/null")
|
540
|
+
puts "优雅终止失败,使用强制终止..."
|
541
|
+
success = system("kill -KILL #{pid} 2>/dev/null")
|
542
|
+
end
|
543
|
+
end
|
544
|
+
|
545
|
+
if success
|
546
|
+
puts "✓ 进程 #{pid} 已终止"
|
547
|
+
sleep(1) # 等待端口释放
|
548
|
+
|
549
|
+
# 再次检查端口是否可用
|
550
|
+
unless port_occupied?(@server_port)
|
551
|
+
puts "✓ 端口 #{@server_port} 现在可用"
|
552
|
+
return true
|
553
|
+
else
|
554
|
+
puts "⚠️ 端口仍被占用,可能需要等待更长时间"
|
555
|
+
return false
|
556
|
+
end
|
557
|
+
else
|
558
|
+
puts "✗ 终止进程失败,可能需要管理员权限"
|
559
|
+
return false
|
560
|
+
end
|
561
|
+
rescue => e
|
562
|
+
puts "终止进程时出错: #{e.message}"
|
563
|
+
return false
|
564
|
+
end
|
565
|
+
end
|
382
566
|
end
|
383
567
|
end
|
384
568
|
end
|
@@ -62,9 +62,6 @@ module EasyAI
|
|
62
62
|
begin
|
63
63
|
# 在非verbose模式下显示简洁的更新提醒
|
64
64
|
Base::UpdateNotifier.maybe_show_notification unless @verbose_mode
|
65
|
-
|
66
|
-
# 美化的启动信息
|
67
|
-
print_header
|
68
65
|
|
69
66
|
# 首先尝试从远程下载配置
|
70
67
|
remote_config = nil
|
@@ -128,11 +125,6 @@ module EasyAI
|
|
128
125
|
|
129
126
|
private
|
130
127
|
|
131
|
-
def print_header
|
132
|
-
puts "\n╔#{'═' * 58}╗"
|
133
|
-
puts "║#{'EasyAI Claude CLI 启动器'.center(58)}║"
|
134
|
-
puts "╚#{'═' * 58}╝\n"
|
135
|
-
end
|
136
128
|
|
137
129
|
def print_status(icon_text, detail = nil)
|
138
130
|
if detail
|
data/lib/easyai/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: easyai
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wade
|
@@ -37,6 +37,20 @@ dependencies:
|
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
39
|
version: '3.1'
|
40
|
+
- !ruby/object:Gem::Dependency
|
41
|
+
name: webrick
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.7'
|
47
|
+
type: :runtime
|
48
|
+
prerelease: false
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.7'
|
40
54
|
- !ruby/object:Gem::Dependency
|
41
55
|
name: bundler
|
42
56
|
requirement: !ruby/object:Gem::Requirement
|