jarvis-ai-assistant 0.2.4__py3-none-any.whl → 0.2.6__py3-none-any.whl

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.
@@ -2,6 +2,7 @@
2
2
  import hashlib
3
3
  import json
4
4
  import os
5
+ import platform
5
6
  import signal
6
7
  import subprocess
7
8
  import sys
@@ -11,6 +12,11 @@ from typing import Any, Callable, Dict, List, Optional
11
12
  from datetime import datetime
12
13
 
13
14
  import yaml # type: ignore
15
+ from rich.align import Align
16
+ from rich.console import Group, RenderableType
17
+ from rich.panel import Panel
18
+ from rich.table import Table
19
+ from rich.text import Text
14
20
 
15
21
  from jarvis import __version__
16
22
  from jarvis.jarvis_utils.config import (
@@ -24,6 +30,35 @@ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
24
30
 
25
31
  g_config_file = None
26
32
 
33
+ COMMAND_MAPPING = {
34
+ # jarvis主命令
35
+ "jvs": "jarvis",
36
+ # 代码代理
37
+ "jca": "jarvis-code-agent",
38
+ # 智能shell
39
+ "jss": "jarvis-smart-shell",
40
+ # 平台管理
41
+ "jpm": "jarvis-platform-manager",
42
+ # Git提交
43
+ "jgc": "jarvis-git-commit",
44
+ # 代码审查
45
+ "jcr": "jarvis-code-review",
46
+ # Git压缩
47
+ "jgs": "jarvis-git-squash",
48
+ # 多代理
49
+ "jma": "jarvis-multi-agent",
50
+ # 代理
51
+ "ja": "jarvis-agent",
52
+ # 工具
53
+ "jt": "jarvis-tool",
54
+ # 方法论
55
+ "jm": "jarvis-methodology",
56
+ # RAG
57
+ "jrg": "jarvis-rag",
58
+ # 统计
59
+ "jst": "jarvis-stats",
60
+ }
61
+
27
62
 
28
63
  def _setup_signal_handler() -> None:
29
64
  """设置SIGINT信号处理函数"""
@@ -79,15 +114,20 @@ def _check_git_updates() -> bool:
79
114
 
80
115
  def _show_usage_stats() -> None:
81
116
  """显示Jarvis使用统计信息"""
117
+ from jarvis.jarvis_utils.output import OutputType, PrettyOutput
118
+
82
119
  try:
83
- from jarvis.jarvis_stats.stats import StatsManager
84
- from jarvis.jarvis_utils.output import OutputType, PrettyOutput
85
120
  from datetime import datetime
86
121
 
87
- stats_manager = StatsManager()
122
+ from rich.console import Console, Group
123
+ from rich.panel import Panel
124
+ from rich.table import Table
125
+ from rich.text import Text
126
+
127
+ from jarvis.jarvis_stats.stats import StatsManager
88
128
 
89
129
  # 获取所有可用的指标
90
- all_metrics = stats_manager.list_metrics()
130
+ all_metrics = StatsManager.list_metrics()
91
131
 
92
132
  # 根据指标名称和标签自动分类
93
133
  categorized_stats: Dict[str, Dict[str, Any]] = {
@@ -96,12 +136,13 @@ def _show_usage_stats() -> None:
96
136
  "lines": {"title": "📊 代码行数", "metrics": {}, "suffix": "行"},
97
137
  "commit": {"title": "💾 提交统计", "metrics": {}, "suffix": "个"},
98
138
  "command": {"title": "📱 命令使用", "metrics": {}, "suffix": "次"},
139
+ "adoption": {"title": "🎯 采纳情况", "metrics": {}, "suffix": ""},
99
140
  }
100
141
 
101
142
  # 遍历所有指标,获取统计数据
102
143
  for metric in all_metrics:
103
144
  # 获取该指标的所有数据
104
- stats_data = stats_manager.get_stats(
145
+ stats_data = StatsManager.get_stats(
105
146
  metric_name=metric,
106
147
  start_time=datetime(2000, 1, 1),
107
148
  end_time=datetime.now(),
@@ -137,6 +178,50 @@ def _show_usage_stats() -> None:
137
178
  elif group == "command":
138
179
  categorized_stats["command"]["metrics"][metric] = int(total)
139
180
 
181
+ # 合并长短命令的历史统计数据
182
+ command_stats = categorized_stats["command"]["metrics"]
183
+ if command_stats:
184
+ merged_stats: Dict[str, int] = {}
185
+ for metric, count in command_stats.items():
186
+ long_command = COMMAND_MAPPING.get(metric, metric)
187
+ merged_stats[long_command] = merged_stats.get(long_command, 0) + count
188
+ categorized_stats["command"]["metrics"] = merged_stats
189
+
190
+ # 计算采纳率并添加到统计中
191
+ commit_stats = categorized_stats["commit"]["metrics"]
192
+ # 尝试多种可能的指标名称
193
+ generated_commits = commit_stats.get(
194
+ "commits_generated", commit_stats.get("commit_generated", 0)
195
+ )
196
+ accepted_commits = commit_stats.get(
197
+ "commits_accepted",
198
+ commit_stats.get("commit_accepted", commit_stats.get("commit_adopted", 0)),
199
+ )
200
+ rejected_commits = commit_stats.get(
201
+ "commits_rejected", commit_stats.get("commit_rejected", 0)
202
+ )
203
+
204
+ # 如果有 generated 和 accepted,则使用这两个计算采纳率
205
+ if generated_commits > 0 and accepted_commits > 0:
206
+ adoption_rate = (accepted_commits / generated_commits) * 100
207
+ categorized_stats["adoption"]["metrics"][
208
+ "adoption_rate"
209
+ ] = f"{adoption_rate:.1f}%"
210
+ categorized_stats["adoption"]["metrics"][
211
+ "commits_status"
212
+ ] = f"{accepted_commits}/{generated_commits}"
213
+ elif accepted_commits > 0 or rejected_commits > 0:
214
+ # 否则使用 accepted 和 rejected 计算
215
+ total_commits = accepted_commits + rejected_commits
216
+ if total_commits > 0:
217
+ adoption_rate = (accepted_commits / total_commits) * 100
218
+ categorized_stats["adoption"]["metrics"][
219
+ "adoption_rate"
220
+ ] = f"{adoption_rate:.1f}%"
221
+ categorized_stats["adoption"]["metrics"][
222
+ "commits_status"
223
+ ] = f"{accepted_commits}/{total_commits}"
224
+
140
225
  # 构建输出
141
226
  has_data = False
142
227
  stats_output = []
@@ -148,18 +233,73 @@ def _show_usage_stats() -> None:
148
233
 
149
234
  # 显示统计信息
150
235
  if has_data:
151
- # 构建统计信息字符串
152
- stats_lines = ["📊 Jarvis 使用统计"]
153
-
236
+ # 1. 创建统计表格
237
+ from rich import box
238
+
239
+ table = Table(
240
+ show_header=True,
241
+ header_style="bold magenta",
242
+ title="📊 Jarvis 使用统计",
243
+ title_justify="center",
244
+ box=box.ROUNDED,
245
+ padding=(0, 1),
246
+ )
247
+ table.add_column("分类", style="cyan", no_wrap=True, width=12)
248
+ table.add_column("指标", style="white", width=20)
249
+ table.add_column("数量", style="green", justify="right", width=10)
250
+ table.add_column("分类", style="cyan", no_wrap=True, width=12)
251
+ table.add_column("指标", style="white", width=20)
252
+ table.add_column("数量", style="green", justify="right", width=10)
253
+
254
+ # 收集所有要显示的数据
255
+ all_rows = []
154
256
  for title, stats, suffix in stats_output:
155
257
  if stats:
156
- stats_lines.append(f"\n{title}:")
157
- for metric, count in sorted(
158
- stats.items(), key=lambda x: x[1], reverse=True
159
- ):
160
- # 美化指标名称
258
+ sorted_stats = sorted(
259
+ stats.items(), key=lambda item: item[1], reverse=True
260
+ )
261
+ for i, (metric, count) in enumerate(sorted_stats):
161
262
  display_name = metric.replace("_", " ").title()
162
- stats_lines.append(f" • {display_name}: {count:,} {suffix}")
263
+ category_title = title if i == 0 else ""
264
+ # 处理不同类型的count值
265
+ if isinstance(count, (int, float)):
266
+ count_str = f"{count:,} {suffix}"
267
+ else:
268
+ # 对于字符串类型的count(如百分比或比率),直接使用
269
+ count_str = str(count)
270
+ all_rows.append((category_title, display_name, count_str))
271
+
272
+ # 以3行2列的方式添加数据
273
+ has_content = len(all_rows) > 0
274
+ # 计算需要多少行来显示所有数据
275
+ total_rows = len(all_rows)
276
+ rows_needed = (total_rows + 1) // 2 # 向上取整,因为是2列布局
277
+
278
+ for i in range(rows_needed):
279
+ left_idx = i
280
+ right_idx = i + rows_needed
281
+
282
+ if left_idx < len(all_rows):
283
+ left_row = all_rows[left_idx]
284
+ else:
285
+ left_row = ("", "", "")
286
+
287
+ if right_idx < len(all_rows):
288
+ right_row = all_rows[right_idx]
289
+ else:
290
+ right_row = ("", "", "")
291
+
292
+ table.add_row(
293
+ left_row[0],
294
+ left_row[1],
295
+ left_row[2],
296
+ right_row[0],
297
+ right_row[1],
298
+ right_row[2],
299
+ )
300
+
301
+ # 2. 创建总结面板
302
+ summary_content = []
163
303
 
164
304
  # 总结统计
165
305
  total_tools = sum(
@@ -175,80 +315,135 @@ def _show_usage_stats() -> None:
175
315
  for metric, count in stats.items()
176
316
  )
177
317
 
178
- if total_tools > 0 or total_changes > 0:
179
- stats_lines.append(
180
- f"\n📈 总计: 工具调用 {total_tools:,} 次, 代码修改 {total_changes:,} 次"
181
- )
182
-
183
- # 计算节省的时间
184
- # 基于经验估算:
185
- # - 每次工具调用平均节省5分钟(相比手动操作)
186
- # - 每行代码修改平均节省60秒(考虑思考、编写、测试时间)
187
- # - 每次提交平均节省15分钟(考虑整理、描述、检查时间)
188
- # - 每个命令调用平均节省5分钟(相比手动执行)
189
-
190
- time_saved_minutes = 0
191
-
192
- # 工具调用节省的时间
193
- time_saved_minutes += total_tools * 5
194
-
195
- # 代码行数节省的时间(每行修改节省60秒)
196
- total_lines = sum(
197
- count
198
- for title, stats, _ in stats_output
199
- if "代码行数" in title
200
- for metric, count in stats.items()
318
+ # 统计代码行数
319
+ lines_stats = categorized_stats["lines"]["metrics"]
320
+ total_lines_added = lines_stats.get(
321
+ "code_lines_inserted", lines_stats.get("code_lines_added", 0)
201
322
  )
202
- time_saved_minutes += total_lines * 1 # 60秒 = 1分钟
323
+ total_lines_deleted = lines_stats.get("code_lines_deleted", 0)
324
+ total_lines_modified = total_lines_added + total_lines_deleted
203
325
 
204
- # 提交节省的时间
205
- total_commits = sum(
206
- count
207
- for title, stats, _ in stats_output
208
- if "提交统计" in title
209
- for metric, count in stats.items()
210
- )
211
- time_saved_minutes += total_commits * 15
326
+ if total_tools > 0 or total_changes > 0 or total_lines_modified > 0:
327
+ parts = []
328
+ if total_tools > 0:
329
+ parts.append(f"工具调用 {total_tools:,} 次")
330
+ if total_changes > 0:
331
+ parts.append(f"代码修改 {total_changes:,} 次")
332
+ if total_lines_modified > 0:
333
+ parts.append(f"代码行数 {total_lines_modified:,} 行")
212
334
 
213
- # 命令调用节省的时间
214
- total_commands = sum(
215
- count
216
- for title, stats, _ in stats_output
217
- if "命令使用" in title
218
- for metric, count in stats.items()
219
- )
220
- time_saved_minutes += total_commands * 5
221
-
222
- # 转换为更友好的格式
223
- if time_saved_minutes > 0:
224
- hours = int(time_saved_minutes // 60)
225
- minutes = int(time_saved_minutes % 60)
226
-
227
- if hours > 24:
228
- days = hours // 24
229
- remaining_hours = hours % 24
230
- time_str = f"{days} 天 {remaining_hours} 小时 {minutes} 分钟"
231
- elif hours > 0:
335
+ if parts:
336
+ summary_content.append(f"📈 总计: {', '.join(parts)}")
337
+
338
+ # 计算节省的时间
339
+ time_saved_seconds = 0
340
+ tool_stats = categorized_stats["tool"]["metrics"]
341
+ code_agent_changes = categorized_stats["code"]["metrics"]
342
+ lines_stats = categorized_stats["lines"]["metrics"]
343
+ # commit_stats is already defined above
344
+ command_stats = categorized_stats["command"]["metrics"]
345
+
346
+ # 统一的工具使用时间估算(每次调用节省2分钟)
347
+ DEFAULT_TOOL_TIME_SAVINGS = 2 * 60 # 秒
348
+
349
+ # 计算所有工具的时间节省
350
+ for tool_name, count in tool_stats.items():
351
+ time_saved_seconds += count * DEFAULT_TOOL_TIME_SAVINGS
352
+
353
+ # 其他类型的时间计算
354
+ total_code_agent_calls = sum(code_agent_changes.values())
355
+ time_saved_seconds += total_code_agent_calls * 10 * 60
356
+ time_saved_seconds += lines_stats.get("code_lines_added", 0) * 0.8 * 60
357
+ time_saved_seconds += lines_stats.get("code_lines_deleted", 0) * 0.2 * 60
358
+ time_saved_seconds += sum(commit_stats.values()) * 10 * 60
359
+ time_saved_seconds += sum(command_stats.values()) * 1 * 60
360
+
361
+ time_str = ""
362
+ hours = 0
363
+ if time_saved_seconds > 0:
364
+ total_minutes = int(time_saved_seconds / 60)
365
+ seconds = int(time_saved_seconds % 60)
366
+ hours = total_minutes // 60
367
+ minutes = total_minutes % 60
368
+ # 只显示小时和分钟
369
+ if hours > 0:
232
370
  time_str = f"{hours} 小时 {minutes} 分钟"
371
+ elif total_minutes > 0:
372
+ time_str = f"{minutes} 分钟 {seconds} 秒"
233
373
  else:
234
- time_str = f"{minutes} 分钟"
235
-
236
- stats_lines.append(f"\n⏱️ 节省时间: 约 {time_str}")
237
-
238
- # 根据节省的时间给出鼓励信息
239
- if hours >= 100:
240
- stats_lines.append(
241
- "🎉 您已经通过 Jarvis 节省了超过100小时的开发时间!"
242
- )
243
- elif hours >= 40:
244
- stats_lines.append("🚀 相当于节省了一整周的工作时间!")
245
- elif hours >= 8:
246
- stats_lines.append("💪 相当于节省了一个工作日的时间!")
374
+ time_str = f"{seconds} "
375
+
376
+ if summary_content:
377
+ summary_content.append("") # Add a separator line
378
+ summary_content.append(f"⏱️ 节省时间: 约 {time_str}")
379
+
380
+ encouragement = ""
381
+ # 计算各级时间单位
382
+ total_work_days = hours // 8 # 总工作日数
383
+ work_years = total_work_days // 240 # 每年约240个工作日
384
+ remaining_days_after_years = total_work_days % 240
385
+ work_months = remaining_days_after_years // 20 # 每月约20个工作日
386
+ remaining_days_after_months = remaining_days_after_years % 20
387
+ work_days = remaining_days_after_months
388
+ remaining_hours = int(hours % 8) # 剩余不足一个工作日的小时数
389
+
390
+ # 构建时间描述
391
+ time_parts = []
392
+ if work_years > 0:
393
+ time_parts.append(f"{work_years} 年")
394
+ if work_months > 0:
395
+ time_parts.append(f"{work_months} 个月")
396
+ if work_days > 0:
397
+ time_parts.append(f"{work_days} 个工作日")
398
+ if remaining_hours > 0:
399
+ time_parts.append(f"{remaining_hours} 小时")
400
+
401
+ if time_parts:
402
+ time_description = "、".join(time_parts)
403
+ if work_years >= 1:
404
+ encouragement = (
405
+ f"🎉 相当于节省了 {time_description} 的工作时间!"
406
+ )
407
+ elif work_months >= 1:
408
+ encouragement = (
409
+ f"🚀 相当于节省了 {time_description} 的工作时间!"
410
+ )
411
+ elif work_days >= 1:
412
+ encouragement = (
413
+ f"💪 相当于节省了 {time_description} 的工作时间!"
414
+ )
415
+ else:
416
+ encouragement = (
417
+ f"✨ 相当于节省了 {time_description} 的工作时间!"
418
+ )
247
419
  elif hours >= 1:
248
- stats_lines.append(" 积少成多,继续保持!")
249
-
250
- # 一次性输出所有统计信息
251
- PrettyOutput.print("\n".join(stats_lines), OutputType.INFO)
420
+ encouragement = f" 相当于节省了 {int(hours)} 小时的工作时间,积少成多,继续保持!"
421
+ if encouragement:
422
+ summary_content.append(encouragement)
423
+
424
+ # 3. 组合并打印
425
+ render_items: List[RenderableType] = []
426
+ if has_content:
427
+ # 居中显示表格
428
+ centered_table = Align.center(table)
429
+ render_items.append(centered_table)
430
+
431
+ if summary_content:
432
+ summary_panel = Panel(
433
+ Text("\n".join(summary_content), justify="left"),
434
+ title="✨ 总体表现 ✨",
435
+ title_align="center",
436
+ border_style="green",
437
+ expand=False,
438
+ )
439
+ # 居中显示面板
440
+ centered_panel = Align.center(summary_panel)
441
+ render_items.append(centered_panel)
442
+
443
+ if render_items:
444
+ console = Console()
445
+ render_group = Group(*render_items)
446
+ console.print(render_group)
252
447
  except Exception as e:
253
448
  # 输出错误信息以便调试
254
449
  import traceback
@@ -310,7 +505,9 @@ def load_config():
310
505
  if schema_path.exists():
311
506
  try:
312
507
  config_file_path.parent.mkdir(parents=True, exist_ok=True)
313
- generate_default_config(str(schema_path), str(config_file_path))
508
+ generate_default_config(
509
+ str(schema_path.absolute()), str(config_file_path)
510
+ )
314
511
  PrettyOutput.print(
315
512
  f"已生成默认配置文件: {config_file_path}", OutputType.INFO
316
513
  )
@@ -427,7 +624,7 @@ def generate_default_config(schema_path: str, output_path: str) -> None:
427
624
 
428
625
  default_config = _generate_from_schema(schema)
429
626
 
430
- content = f"# yaml-language-server: $schema={schema}\n"
627
+ content = f"# yaml-language-server: $schema={schema_path}\n"
431
628
  content += yaml.dump(default_config, allow_unicode=True, sort_keys=False)
432
629
 
433
630
  with open(output_path, "w", encoding="utf-8") as f:
@@ -573,9 +770,14 @@ def count_cmd_usage() -> None:
573
770
  cmd_path = sys.argv[0]
574
771
  cmd_name = os.path.basename(cmd_path)
575
772
 
773
+ # 如果是短命令,映射到长命令
774
+ if cmd_name in COMMAND_MAPPING:
775
+ metric_name = COMMAND_MAPPING[cmd_name]
776
+ else:
777
+ metric_name = cmd_name
778
+
576
779
  # 使用 StatsManager 记录命令使用统计
577
- stats_manager = StatsManager()
578
- stats_manager.increment(cmd_name, group="command")
780
+ StatsManager.increment(metric_name, group="command")
579
781
 
580
782
 
581
783
  def is_context_overflow(
@@ -603,7 +805,7 @@ def get_loc_stats() -> str:
603
805
 
604
806
 
605
807
  def copy_to_clipboard(text: str) -> None:
606
- """将文本复制到剪贴板,依次尝试xselxclip (非阻塞)
808
+ """将文本复制到剪贴板,支持Windows、macOSLinux
607
809
 
608
810
  参数:
609
811
  text: 要复制的文本
@@ -611,41 +813,80 @@ def copy_to_clipboard(text: str) -> None:
611
813
  print("--- 剪贴板内容开始 ---")
612
814
  print(text)
613
815
  print("--- 剪贴板内容结束 ---")
614
- # 尝试使用 xsel
615
- try:
616
- process = subprocess.Popen(
617
- ["xsel", "-b", "-i"],
618
- stdin=subprocess.PIPE,
619
- stdout=subprocess.DEVNULL,
620
- stderr=subprocess.DEVNULL,
621
- )
622
- if process.stdin:
623
- process.stdin.write(text.encode("utf-8"))
624
- process.stdin.close()
625
- return
626
- except FileNotFoundError:
627
- pass # xsel 未安装,继续尝试下一个
628
- except Exception as e:
629
- PrettyOutput.print(f"使用xsel时出错: {e}", OutputType.WARNING)
630
816
 
631
- # 尝试使用 xclip
632
- try:
633
- process = subprocess.Popen(
634
- ["xclip", "-selection", "clipboard"],
635
- stdin=subprocess.PIPE,
636
- stdout=subprocess.DEVNULL,
637
- stderr=subprocess.DEVNULL,
638
- )
639
- if process.stdin:
640
- process.stdin.write(text.encode("utf-8"))
641
- process.stdin.close()
642
- return
643
- except FileNotFoundError:
644
- PrettyOutput.print(
645
- "xsel 和 xclip 均未安装, 无法复制到剪贴板", OutputType.WARNING
646
- )
647
- except Exception as e:
648
- PrettyOutput.print(f"使用xclip时出错: {e}", OutputType.WARNING)
817
+ system = platform.system()
818
+
819
+ # Windows系统
820
+ if system == "Windows":
821
+ try:
822
+ # 使用Windows的clip命令
823
+ process = subprocess.Popen(
824
+ ["clip"],
825
+ stdin=subprocess.PIPE,
826
+ stdout=subprocess.DEVNULL,
827
+ stderr=subprocess.DEVNULL,
828
+ shell=True,
829
+ )
830
+ if process.stdin:
831
+ process.stdin.write(text.encode("utf-8"))
832
+ process.stdin.close()
833
+ return
834
+ except Exception as e:
835
+ PrettyOutput.print(f"使用Windows clip命令时出错: {e}", OutputType.WARNING)
836
+
837
+ # macOS系统
838
+ elif system == "Darwin":
839
+ try:
840
+ process = subprocess.Popen(
841
+ ["pbcopy"],
842
+ stdin=subprocess.PIPE,
843
+ stdout=subprocess.DEVNULL,
844
+ stderr=subprocess.DEVNULL,
845
+ )
846
+ if process.stdin:
847
+ process.stdin.write(text.encode("utf-8"))
848
+ process.stdin.close()
849
+ return
850
+ except Exception as e:
851
+ PrettyOutput.print(f"使用macOS pbcopy命令时出错: {e}", OutputType.WARNING)
852
+
853
+ # Linux系统
854
+ else:
855
+ # 尝试使用 xsel
856
+ try:
857
+ process = subprocess.Popen(
858
+ ["xsel", "-b", "-i"],
859
+ stdin=subprocess.PIPE,
860
+ stdout=subprocess.DEVNULL,
861
+ stderr=subprocess.DEVNULL,
862
+ )
863
+ if process.stdin:
864
+ process.stdin.write(text.encode("utf-8"))
865
+ process.stdin.close()
866
+ return
867
+ except FileNotFoundError:
868
+ pass # xsel 未安装,继续尝试下一个
869
+ except Exception as e:
870
+ PrettyOutput.print(f"使用xsel时出错: {e}", OutputType.WARNING)
871
+
872
+ # 尝试使用 xclip
873
+ try:
874
+ process = subprocess.Popen(
875
+ ["xclip", "-selection", "clipboard"],
876
+ stdin=subprocess.PIPE,
877
+ stdout=subprocess.DEVNULL,
878
+ stderr=subprocess.DEVNULL,
879
+ )
880
+ if process.stdin:
881
+ process.stdin.write(text.encode("utf-8"))
882
+ process.stdin.close()
883
+ return
884
+ except FileNotFoundError:
885
+ PrettyOutput.print(
886
+ "xsel 和 xclip 均未安装, 无法复制到剪贴板", OutputType.WARNING
887
+ )
888
+ except Exception as e:
889
+ PrettyOutput.print(f"使用xclip时出错: {e}", OutputType.WARNING)
649
890
 
650
891
 
651
892
  def _pull_git_repo(repo_path: Path, repo_type: str):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: jarvis-ai-assistant
3
- Version: 0.2.4
3
+ Version: 0.2.6
4
4
  Summary: Jarvis: An AI assistant that uses tools to interact with the system
5
5
  Home-page: https://github.com/skyfireitdiy/Jarvis
6
6
  Author: skyfire
@@ -60,6 +60,7 @@ Requires-Dist: lxml==6.0.0
60
60
  Requires-Dist: markdownify>=1.1.0
61
61
  Requires-Dist: typer
62
62
  Requires-Dist: pathspec
63
+ Requires-Dist: plotext==5.2.8
63
64
  Provides-Extra: dev
64
65
  Requires-Dist: pytest; extra == "dev"
65
66
  Requires-Dist: black; extra == "dev"
@@ -180,15 +181,23 @@ Jarvis 正是为这种工作流而设计的工具。它通过无缝的命令行
180
181
 
181
182
  ### 系统要求
182
183
  - **Linux**: 完全支持。
183
- - **Windows**: 未经充分测试,建议在 [WSL](https://docs.microsoft.com/en-us/windows/wsl/install) 中使用。
184
+ - **Windows**: 完全支持(需要 PowerShell)。
184
185
 
185
186
  ### 安装
186
187
 
187
188
  #### 一键安装 (推荐)
188
189
  只需一行命令即可完成所有安装和配置:
190
+
191
+ **Linux/macOS:**
189
192
  ```bash
190
193
  bash -c "$(curl -fsSL https://raw.githubusercontent.com/skyfireitdiy/Jarvis/main/scripts/install.sh)"
191
194
  ```
195
+
196
+ **Windows (PowerShell):**
197
+ ```powershell
198
+ iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/skyfireitdiy/Jarvis/main/scripts/install.ps1'))
199
+ ```
200
+
192
201
  > 该脚本会自动检测Python环境、克隆项目、安装依赖并设置好路径。
193
202
 
194
203
  #### 手动安装