ata-coder 2.4.3__tar.gz → 2.4.4__tar.gz

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 (139) hide show
  1. {ata_coder-2.4.3/ata_coder.egg-info → ata_coder-2.4.4}/PKG-INFO +15 -1
  2. {ata_coder-2.4.3 → ata_coder-2.4.4}/README.md +14 -0
  3. {ata_coder-2.4.3 → ata_coder-2.4.4}/agent_compact.py +11 -4
  4. {ata_coder-2.4.3 → ata_coder-2.4.4/ata_coder.egg-info}/PKG-INFO +15 -1
  5. {ata_coder-2.4.3 → ata_coder-2.4.4}/config.py +7 -2
  6. {ata_coder-2.4.3 → ata_coder-2.4.4}/git_workflow.py +9 -7
  7. {ata_coder-2.4.3 → ata_coder-2.4.4}/main.py +1 -1
  8. {ata_coder-2.4.3 → ata_coder-2.4.4}/mcp_client.py +25 -3
  9. {ata_coder-2.4.3 → ata_coder-2.4.4}/pyproject.toml +1 -1
  10. {ata_coder-2.4.3 → ata_coder-2.4.4}/safety_guard.py +47 -32
  11. {ata_coder-2.4.3 → ata_coder-2.4.4}/server.py +128 -35
  12. {ata_coder-2.4.3 → ata_coder-2.4.4}/server_session.py +233 -178
  13. {ata_coder-2.4.3 → ata_coder-2.4.4}/server_shell.py +8 -2
  14. {ata_coder-2.4.3 → ata_coder-2.4.4}/settings.py +139 -2
  15. {ata_coder-2.4.3 → ata_coder-2.4.4}/setup_wizard.py +1 -1
  16. {ata_coder-2.4.3 → ata_coder-2.4.4}/tools/executor.py +6 -3
  17. {ata_coder-2.4.3 → ata_coder-2.4.4}/utils.py +7 -4
  18. {ata_coder-2.4.3 → ata_coder-2.4.4}/LICENSE +0 -0
  19. {ata_coder-2.4.3 → ata_coder-2.4.4}/MANIFEST.in +0 -0
  20. {ata_coder-2.4.3 → ata_coder-2.4.4}/__init__.py +0 -0
  21. {ata_coder-2.4.3 → ata_coder-2.4.4}/agent.py +0 -0
  22. {ata_coder-2.4.3 → ata_coder-2.4.4}/agent_controller.py +0 -0
  23. {ata_coder-2.4.3 → ata_coder-2.4.4}/agent_extension.py +0 -0
  24. {ata_coder-2.4.3 → ata_coder-2.4.4}/agent_routing.py +0 -0
  25. {ata_coder-2.4.3 → ata_coder-2.4.4}/agent_subsystems.py +0 -0
  26. {ata_coder-2.4.3 → ata_coder-2.4.4}/agent_tools.py +0 -0
  27. {ata_coder-2.4.3 → ata_coder-2.4.4}/agent_undo.py +0 -0
  28. {ata_coder-2.4.3 → ata_coder-2.4.4}/anthropic_client.py +0 -0
  29. {ata_coder-2.4.3 → ata_coder-2.4.4}/ata_coder.egg-info/SOURCES.txt +0 -0
  30. {ata_coder-2.4.3 → ata_coder-2.4.4}/ata_coder.egg-info/dependency_links.txt +0 -0
  31. {ata_coder-2.4.3 → ata_coder-2.4.4}/ata_coder.egg-info/entry_points.txt +0 -0
  32. {ata_coder-2.4.3 → ata_coder-2.4.4}/ata_coder.egg-info/requires.txt +0 -0
  33. {ata_coder-2.4.3 → ata_coder-2.4.4}/ata_coder.egg-info/top_level.txt +0 -0
  34. {ata_coder-2.4.3 → ata_coder-2.4.4}/change_tracker.py +0 -0
  35. {ata_coder-2.4.3 → ata_coder-2.4.4}/clawd_integration.py +0 -0
  36. {ata_coder-2.4.3 → ata_coder-2.4.4}/commands/__init__.py +0 -0
  37. {ata_coder-2.4.3 → ata_coder-2.4.4}/commands/_core.py +0 -0
  38. {ata_coder-2.4.3 → ata_coder-2.4.4}/commands/_safety.py +0 -0
  39. {ata_coder-2.4.3 → ata_coder-2.4.4}/commands/_settings.py +0 -0
  40. {ata_coder-2.4.3 → ata_coder-2.4.4}/commands/_workflow.py +0 -0
  41. {ata_coder-2.4.3 → ata_coder-2.4.4}/core/__init__.py +0 -0
  42. {ata_coder-2.4.3 → ata_coder-2.4.4}/core/events.py +0 -0
  43. {ata_coder-2.4.3 → ata_coder-2.4.4}/core/queue.py +0 -0
  44. {ata_coder-2.4.3 → ata_coder-2.4.4}/core/state.py +0 -0
  45. {ata_coder-2.4.3 → ata_coder-2.4.4}/event_queue.py +0 -0
  46. {ata_coder-2.4.3 → ata_coder-2.4.4}/extension.py +0 -0
  47. {ata_coder-2.4.3 → ata_coder-2.4.4}/extensions/__init__.py +0 -0
  48. {ata_coder-2.4.3 → ata_coder-2.4.4}/extensions/hello_skill.py +0 -0
  49. {ata_coder-2.4.3 → ata_coder-2.4.4}/fool_proof.py +0 -0
  50. {ata_coder-2.4.3 → ata_coder-2.4.4}/gui.py +0 -0
  51. {ata_coder-2.4.3 → ata_coder-2.4.4}/llm_client.py +0 -0
  52. {ata_coder-2.4.3 → ata_coder-2.4.4}/memory.py +0 -0
  53. {ata_coder-2.4.3 → ata_coder-2.4.4}/model_registry.py +0 -0
  54. {ata_coder-2.4.3 → ata_coder-2.4.4}/model_router.py +0 -0
  55. {ata_coder-2.4.3 → ata_coder-2.4.4}/permissions.py +0 -0
  56. {ata_coder-2.4.3 → ata_coder-2.4.4}/privilege.py +0 -0
  57. {ata_coder-2.4.3 → ata_coder-2.4.4}/project.py +0 -0
  58. {ata_coder-2.4.3 → ata_coder-2.4.4}/prompt_template.py +0 -0
  59. {ata_coder-2.4.3 → ata_coder-2.4.4}/prompts/auto-mode.md +0 -0
  60. {ata_coder-2.4.3 → ata_coder-2.4.4}/prompts/coding-rules.md +0 -0
  61. {ata_coder-2.4.3 → ata_coder-2.4.4}/prompts/execution-guardrails.md +0 -0
  62. {ata_coder-2.4.3 → ata_coder-2.4.4}/prompts/memory-system.md +0 -0
  63. {ata_coder-2.4.3 → ata_coder-2.4.4}/prompts/output-style.md +0 -0
  64. {ata_coder-2.4.3 → ata_coder-2.4.4}/prompts/safety.md +0 -0
  65. {ata_coder-2.4.3 → ata_coder-2.4.4}/prompts/slash-commands.md +0 -0
  66. {ata_coder-2.4.3 → ata_coder-2.4.4}/prompts/sub-agents.md +0 -0
  67. {ata_coder-2.4.3 → ata_coder-2.4.4}/prompts/system-reminders.md +0 -0
  68. {ata_coder-2.4.3 → ata_coder-2.4.4}/prompts/system.md +0 -0
  69. {ata_coder-2.4.3 → ata_coder-2.4.4}/prompts/tool-policy.md +0 -0
  70. {ata_coder-2.4.3 → ata_coder-2.4.4}/repl_theme.py +0 -0
  71. {ata_coder-2.4.3 → ata_coder-2.4.4}/repl_tracker.py +0 -0
  72. {ata_coder-2.4.3 → ata_coder-2.4.4}/repl_ui.py +0 -0
  73. {ata_coder-2.4.3 → ata_coder-2.4.4}/self_correct.py +0 -0
  74. {ata_coder-2.4.3 → ata_coder-2.4.4}/session.py +0 -0
  75. {ata_coder-2.4.3 → ata_coder-2.4.4}/setup.cfg +0 -0
  76. {ata_coder-2.4.3 → ata_coder-2.4.4}/skill_extension.py +0 -0
  77. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills/architect/SKILL.md +0 -0
  78. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills/code-reviewer/SKILL.md +0 -0
  79. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills/codecraft/SKILL.md +0 -0
  80. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills/debugger/SKILL.md +0 -0
  81. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills/doc-writer/SKILL.md +0 -0
  82. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills/general-coder/SKILL.md +0 -0
  83. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills/math-calculator/README.md +0 -0
  84. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills/math-calculator/SKILL.md +0 -0
  85. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills/math-calculator/handler.py +0 -0
  86. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills/math-calculator/prompts/system.md +0 -0
  87. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills/math-calculator/requirements.txt +0 -0
  88. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills/math-calculator/resources/constants.json +0 -0
  89. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills/math-calculator/tests/test_handler.py +0 -0
  90. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills/security-auditor/SKILL.md +0 -0
  91. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills/test-writer/SKILL.md +0 -0
  92. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills/weather-skill/README.md +0 -0
  93. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills/weather-skill/handler.py +0 -0
  94. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills/weather-skill/manifest.json +0 -0
  95. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills/weather-skill/prompts/system_prompt.txt +0 -0
  96. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills/weather-skill/prompts/user_prompt_template.txt +0 -0
  97. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills/weather-skill/requirements.txt +0 -0
  98. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills/weather-skill/resources/city_list.json +0 -0
  99. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills/weather-skill/resources/error_messages.json +0 -0
  100. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills/weather-skill/tests/test_handler.py +0 -0
  101. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills/weather-skill/weather_utils.py +0 -0
  102. {ata_coder-2.4.3 → ata_coder-2.4.4}/skills.py +0 -0
  103. {ata_coder-2.4.3 → ata_coder-2.4.4}/sub_agent.py +0 -0
  104. {ata_coder-2.4.3 → ata_coder-2.4.4}/sub_agent_manager.py +0 -0
  105. {ata_coder-2.4.3 → ata_coder-2.4.4}/system_prompt_builder.py +0 -0
  106. {ata_coder-2.4.3 → ata_coder-2.4.4}/task_planner.py +0 -0
  107. {ata_coder-2.4.3 → ata_coder-2.4.4}/terminal.py +0 -0
  108. {ata_coder-2.4.3 → ata_coder-2.4.4}/tests/test_agent.py +0 -0
  109. {ata_coder-2.4.3 → ata_coder-2.4.4}/tests/test_change_tracker.py +0 -0
  110. {ata_coder-2.4.3 → ata_coder-2.4.4}/tests/test_config.py +0 -0
  111. {ata_coder-2.4.3 → ata_coder-2.4.4}/tests/test_event_queue.py +0 -0
  112. {ata_coder-2.4.3 → ata_coder-2.4.4}/tests/test_extension.py +0 -0
  113. {ata_coder-2.4.3 → ata_coder-2.4.4}/tests/test_fibonacci.py +0 -0
  114. {ata_coder-2.4.3 → ata_coder-2.4.4}/tests/test_fool_proof.py +0 -0
  115. {ata_coder-2.4.3 → ata_coder-2.4.4}/tests/test_llm_client.py +0 -0
  116. {ata_coder-2.4.3 → ata_coder-2.4.4}/tests/test_memory.py +0 -0
  117. {ata_coder-2.4.3 → ata_coder-2.4.4}/tests/test_model_registry.py +0 -0
  118. {ata_coder-2.4.3 → ata_coder-2.4.4}/tests/test_permissions.py +0 -0
  119. {ata_coder-2.4.3 → ata_coder-2.4.4}/tests/test_privilege.py +0 -0
  120. {ata_coder-2.4.3 → ata_coder-2.4.4}/tests/test_prompt_template.py +0 -0
  121. {ata_coder-2.4.3 → ata_coder-2.4.4}/tests/test_safety_guard.py +0 -0
  122. {ata_coder-2.4.3 → ata_coder-2.4.4}/tests/test_server.py +0 -0
  123. {ata_coder-2.4.3 → ata_coder-2.4.4}/tests/test_skill_handlers.py +0 -0
  124. {ata_coder-2.4.3 → ata_coder-2.4.4}/tests/test_sub_agent.py +0 -0
  125. {ata_coder-2.4.3 → ata_coder-2.4.4}/tests/test_tools.py +0 -0
  126. {ata_coder-2.4.3 → ata_coder-2.4.4}/token_counter.py +0 -0
  127. {ata_coder-2.4.3 → ata_coder-2.4.4}/tools/__init__.py +0 -0
  128. {ata_coder-2.4.3 → ata_coder-2.4.4}/tools/definitions.py +0 -0
  129. {ata_coder-2.4.3 → ata_coder-2.4.4}/tools/result.py +0 -0
  130. {ata_coder-2.4.3 → ata_coder-2.4.4}/tools/strategy.py +0 -0
  131. {ata_coder-2.4.3 → ata_coder-2.4.4}/tools/subagent.py +0 -0
  132. {ata_coder-2.4.3 → ata_coder-2.4.4}/tools/web.py +0 -0
  133. {ata_coder-2.4.3 → ata_coder-2.4.4}/types.py +0 -0
  134. {ata_coder-2.4.3 → ata_coder-2.4.4}/web/css/style.css +0 -0
  135. {ata_coder-2.4.3 → ata_coder-2.4.4}/web/index.html +0 -0
  136. {ata_coder-2.4.3 → ata_coder-2.4.4}/web/js/app.js +0 -0
  137. {ata_coder-2.4.3 → ata_coder-2.4.4}/web/package-lock.json +0 -0
  138. {ata_coder-2.4.3 → ata_coder-2.4.4}/web/package.json +0 -0
  139. {ata_coder-2.4.3 → ata_coder-2.4.4}/web/tsconfig.json +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ata-coder
3
- Version: 2.4.3
3
+ Version: 2.4.4
4
4
  Summary: ATA Coder — AI-powered coding assistant
5
5
  Author: ATA Coder Team
6
6
  License-Expression: MIT
@@ -51,6 +51,10 @@ Dynamic: license-file
51
51
 
52
52
  ATA Coder is a CLI AI coding assistant compatible with OpenAI and Anthropic APIs. It runs on a **single-threaded asyncio event loop** — no threads, no race conditions, low memory. Features deterministic AST-based code editing, sub-agent pool, MCP support, and a built-in HTTP API server.
53
53
 
54
+ ```bash
55
+ pip install ata-coder
56
+ ```
57
+
54
58
  ### Architecture (v2.3.3)
55
59
 
56
60
  ```
@@ -95,7 +99,12 @@ asyncio Event Loop (single-threaded)
95
99
  ### Quick Start
96
100
 
97
101
  ```bash
102
+ # Install from PyPI (recommended)
103
+ pip install ata-coder
104
+
105
+ # Or install from source (development)
98
106
  pip install -e .
107
+
99
108
  ata # Interactive REPL
100
109
  ata run "Add type hints" # Single task
101
110
  ata server --port 8080 # HTTP API server
@@ -558,7 +567,12 @@ asyncio 事件循环(单线程)
558
567
  ### 快速开始
559
568
 
560
569
  ```bash
570
+ # 从 PyPI 安装(推荐)
571
+ pip install ata-coder
572
+
573
+ # 或从源码安装(开发模式)
561
574
  pip install -e .
575
+
562
576
  ata # 交互模式
563
577
  ata run "添加类型注解" # 单任务
564
578
  ata server --port 8080 # API 服务
@@ -28,6 +28,10 @@
28
28
 
29
29
  ATA Coder is a CLI AI coding assistant compatible with OpenAI and Anthropic APIs. It runs on a **single-threaded asyncio event loop** — no threads, no race conditions, low memory. Features deterministic AST-based code editing, sub-agent pool, MCP support, and a built-in HTTP API server.
30
30
 
31
+ ```bash
32
+ pip install ata-coder
33
+ ```
34
+
31
35
  ### Architecture (v2.3.3)
32
36
 
33
37
  ```
@@ -72,7 +76,12 @@ asyncio Event Loop (single-threaded)
72
76
  ### Quick Start
73
77
 
74
78
  ```bash
79
+ # Install from PyPI (recommended)
80
+ pip install ata-coder
81
+
82
+ # Or install from source (development)
75
83
  pip install -e .
84
+
76
85
  ata # Interactive REPL
77
86
  ata run "Add type hints" # Single task
78
87
  ata server --port 8080 # HTTP API server
@@ -535,7 +544,12 @@ asyncio 事件循环(单线程)
535
544
  ### 快速开始
536
545
 
537
546
  ```bash
547
+ # 从 PyPI 安装(推荐)
548
+ pip install ata-coder
549
+
550
+ # 或从源码安装(开发模式)
538
551
  pip install -e .
552
+
539
553
  ata # 交互模式
540
554
  ata run "添加类型注解" # 单任务
541
555
  ata server --port 8080 # API 服务
@@ -4,6 +4,7 @@ import json
4
4
  import logging
5
5
 
6
6
  from .types import Message
7
+ from .token_counter import TokenCounter
7
8
  from .clawd_integration import get_clawd
8
9
  from .model_router import get_subagent_model
9
10
  logger = logging.getLogger(__name__)
@@ -35,7 +36,11 @@ class CompactionMixin:
35
36
  recent_tokens = 0
36
37
  for msg in reversed(all_but_system):
37
38
  msg_tokens = self._estimate_message_tokens(msg)
38
- if recent_tokens + msg_tokens > self.RECENT_TOKEN_BUDGET and recent:
39
+ if recent_tokens + msg_tokens > self.RECENT_TOKEN_BUDGET:
40
+ if not recent:
41
+ # Single huge message — include it anyway but stop after
42
+ recent.insert(0, msg)
43
+ recent_tokens += msg_tokens
39
44
  break
40
45
  recent.insert(0, msg)
41
46
  recent_tokens += msg_tokens
@@ -79,8 +84,11 @@ class CompactionMixin:
79
84
  recent_tokens = 0
80
85
  for msg in reversed(all_but_system):
81
86
  msg_tokens = self._estimate_message_tokens(msg)
82
- if recent_tokens + msg_tokens > self.RECENT_TOKEN_BUDGET and recent:
83
- # Stop — we've filled the recent budget
87
+ if recent_tokens + msg_tokens > self.RECENT_TOKEN_BUDGET:
88
+ if not recent:
89
+ # Single huge message — include it anyway but stop after
90
+ recent.insert(0, msg)
91
+ recent_tokens += msg_tokens
84
92
  break
85
93
  recent.insert(0, msg)
86
94
  recent_tokens += msg_tokens
@@ -120,7 +128,6 @@ class CompactionMixin:
120
128
 
121
129
  def _estimate_message_tokens(self, msg: Message) -> int:
122
130
  """Rough token estimate for a single message (via TokenCounter)."""
123
- from .token_counter import TokenCounter
124
131
  model = getattr(self.llm.config, 'model', '')
125
132
  return TokenCounter.for_model(model).count_tokens([msg])
126
133
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ata-coder
3
- Version: 2.4.3
3
+ Version: 2.4.4
4
4
  Summary: ATA Coder — AI-powered coding assistant
5
5
  Author: ATA Coder Team
6
6
  License-Expression: MIT
@@ -51,6 +51,10 @@ Dynamic: license-file
51
51
 
52
52
  ATA Coder is a CLI AI coding assistant compatible with OpenAI and Anthropic APIs. It runs on a **single-threaded asyncio event loop** — no threads, no race conditions, low memory. Features deterministic AST-based code editing, sub-agent pool, MCP support, and a built-in HTTP API server.
53
53
 
54
+ ```bash
55
+ pip install ata-coder
56
+ ```
57
+
54
58
  ### Architecture (v2.3.3)
55
59
 
56
60
  ```
@@ -95,7 +99,12 @@ asyncio Event Loop (single-threaded)
95
99
  ### Quick Start
96
100
 
97
101
  ```bash
102
+ # Install from PyPI (recommended)
103
+ pip install ata-coder
104
+
105
+ # Or install from source (development)
98
106
  pip install -e .
107
+
99
108
  ata # Interactive REPL
100
109
  ata run "Add type hints" # Single task
101
110
  ata server --port 8080 # HTTP API server
@@ -558,7 +567,12 @@ asyncio 事件循环(单线程)
558
567
  ### 快速开始
559
568
 
560
569
  ```bash
570
+ # 从 PyPI 安装(推荐)
571
+ pip install ata-coder
572
+
573
+ # 或从源码安装(开发模式)
561
574
  pip install -e .
575
+
562
576
  ata # 交互模式
563
577
  ata run "添加类型注解" # 单任务
564
578
  ata server --port 8080 # API 服务
@@ -176,7 +176,7 @@ class AppConfig:
176
176
 
177
177
  llm: LLMConfig = field(default_factory=LLMConfig)
178
178
  agent: AgentConfig = field(default_factory=AgentConfig)
179
- effort: str = field(default_factory=lambda: _from_settings("effort_level", "medium"))
179
+ effort: str = field(default_factory=lambda: (_from_settings("effort_level") or "medium"))
180
180
 
181
181
  @classmethod
182
182
  def load(cls) -> "AppConfig":
@@ -246,7 +246,12 @@ def _safe_temperature() -> float:
246
246
 
247
247
 
248
248
  def _settings_api_key() -> str:
249
- return _from_settings("api_key", "")
249
+ """Resolve API key with tiered fallback (OS keychain → env vars → settings.json)."""
250
+ try:
251
+ from .settings import resolve_api_key
252
+ return resolve_api_key()
253
+ except ImportError:
254
+ return _from_settings("api_key", "")
250
255
 
251
256
 
252
257
  def _settings_base_url() -> str:
@@ -134,13 +134,15 @@ class GitWorkflow:
134
134
  status.modified += 1
135
135
  status.clean = (status.staged == 0 and status.modified == 0 and status.untracked == 0)
136
136
 
137
- # Ahead/behind
138
- _, ahead_str, _ = _run_git(["rev-list", "--count", "@{u}..HEAD"], self.cwd, timeout=10)
139
- if ahead_str and ahead_str.isdigit():
140
- status.ahead = int(ahead_str)
141
- _, behind_str, _ = _run_git(["rev-list", "--count", "HEAD..@{u}"], self.cwd, timeout=10)
142
- if behind_str and behind_str.isdigit():
143
- status.behind = int(behind_str)
137
+ # Ahead/behind — only if upstream is configured
138
+ has_upstream, _, _ = _run_git(["rev-parse", "--abbrev-ref", "@{u}"], self.cwd, timeout=10)
139
+ if has_upstream == 0:
140
+ _, ahead_str, _ = _run_git(["rev-list", "--count", "@{u}..HEAD"], self.cwd, timeout=10)
141
+ if ahead_str and ahead_str.isdigit():
142
+ status.ahead = int(ahead_str)
143
+ _, behind_str, _ = _run_git(["rev-list", "--count", "HEAD..@{u}"], self.cwd, timeout=10)
144
+ if behind_str and behind_str.isdigit():
145
+ status.behind = int(behind_str)
144
146
 
145
147
  # Last commit
146
148
  _, last, _ = _run_git(["log", "-1", "--format=%h %s"], self.cwd)
@@ -44,7 +44,7 @@ if sys.platform == 'win32':
44
44
  _patched_init.__ata_patched__ = True
45
45
  _sp.Popen.__init__ = _patched_init
46
46
 
47
- __version__ = "2.4.3"
47
+ __version__ = "2.4.4"
48
48
 
49
49
  import asyncio
50
50
  import logging
@@ -995,6 +995,25 @@ class MCPClient:
995
995
  """Register a callback for health check failures."""
996
996
  self._on_health_fail = callback
997
997
 
998
+ async def reconnect_server(self, name: str) -> bool:
999
+ """Attempt to reconnect a failed MCP server. Returns True on success."""
1000
+ conn = self._connections.get(name)
1001
+ if not conn:
1002
+ return False
1003
+ logger.info("[%s] Attempting reconnection...", name)
1004
+ try:
1005
+ await conn.stop()
1006
+ except Exception:
1007
+ pass
1008
+ try:
1009
+ await conn.start()
1010
+ self._register_server_tools(name, conn)
1011
+ logger.info("[%s] Reconnected successfully", name)
1012
+ return True
1013
+ except Exception as e:
1014
+ logger.warning("[%s] Reconnection failed: %s", name, e)
1015
+ return False
1016
+
998
1017
  def start_health_monitor(self, interval: float = 60.0) -> None:
999
1018
  """Start periodic health checks (ping every N seconds)."""
1000
1019
  if self._health_running:
@@ -1021,16 +1040,19 @@ class MCPClient:
1021
1040
  break
1022
1041
  for name, conn in list(self._connections.items()):
1023
1042
  try:
1024
- if not await conn.ping(timeout=10):
1025
- logger.warning("[%s] Health check failed: no response", name)
1043
+ alive = await conn.ping(timeout=10)
1044
+ if not alive:
1045
+ logger.warning("[%s] Health check failed — attempting reconnect", name)
1026
1046
  if self._on_health_fail:
1027
1047
  self._on_health_fail(name)
1048
+ await self.reconnect_server(name)
1028
1049
  except asyncio.CancelledError:
1029
1050
  raise
1030
1051
  except Exception as e:
1031
- logger.warning("[%s] Health check error: %s", name, e)
1052
+ logger.warning("[%s] Health check error: %s — attempting reconnect", name, e)
1032
1053
  if self._on_health_fail:
1033
1054
  self._on_health_fail(name)
1055
+ await self.reconnect_server(name)
1034
1056
 
1035
1057
  # ── Properties ──────────────────────────────────────────────────────────
1036
1058
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ata-coder"
7
- version = "2.4.3"
7
+ version = "2.4.4"
8
8
  description = "ATA Coder — AI-powered coding assistant"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -98,63 +98,78 @@ PROTECTED_PATHS = [
98
98
 
99
99
  # Destructive shell command patterns
100
100
  DESTRUCTIVE_PATTERNS = [
101
- # System destruction
102
- (r"rm\s+-r\w*\s*-?f\w*\s+/(?:\s|$)", RiskLevel.CRITICAL, "Recursive delete of root filesystem"),
103
- (r"rm\s+-r\w*\s*-?f\w*\s+~", RiskLevel.CRITICAL, "Recursive delete of home directory"),
104
- (r"rm\s+-r\w*\s*-?f\w*\s+\$HOME", RiskLevel.CRITICAL, "Recursive delete of home directory"),
101
+ # System destruction — cover common bypasses (/*, / *, wildcards, etc.)
102
+ (r"\brm\s+.*-r\w*\s*-?f\w*\s+/(?:\s|\*|$)", RiskLevel.CRITICAL, "Recursive delete of root filesystem"),
103
+ (r"\brm\s+.*-r\w*\s*-?f\w*\s+/\s*\*", RiskLevel.CRITICAL, "Recursive delete of root filesystem (/*)"),
104
+ (r"\brm\s+.*-r\w*\s*-?f\w*\s+/\s+\*", RiskLevel.CRITICAL, "Recursive delete of root filesystem (/ *)"),
105
+ (r"\brm\s+.*-r\w*\s*-?f\w*\s+~", RiskLevel.CRITICAL, "Recursive delete of home directory"),
106
+ (r"\brm\s+.*-r\w*\s*-?f\w*\s+\$HOME", RiskLevel.CRITICAL, "Recursive delete of home directory"),
107
+ (r"\bfind\s+/.*-delete\b", RiskLevel.CRITICAL, "Recursive delete of root via find"),
108
+ (r"\bfind\s+/\s+.*-delete\b", RiskLevel.CRITICAL, "Recursive delete of root via find"),
109
+ (r"\bfind\s+/.*-exec\s+rm\b", RiskLevel.CRITICAL, "Recursive delete via find -exec rm"),
110
+ (r"\bfind\s+/\s+.*-exec\s+rm\b", RiskLevel.CRITICAL, "Recursive delete of root via find -exec rm"),
105
111
  (r"mkfs\.", RiskLevel.CRITICAL, "Filesystem format"),
106
- (r"dd\s+if=", RiskLevel.CRITICAL, "Raw disk write (dd)"),
107
- (r"dd\s+of=", RiskLevel.CRITICAL, "Raw disk write (dd of=)"),
112
+ (r"\bdd\s+if=", RiskLevel.CRITICAL, "Raw disk write (dd)"),
113
+ (r"\bdd\s+of=", RiskLevel.CRITICAL, "Raw disk write (dd of=)"),
108
114
  (r">\s*/dev/sd", RiskLevel.CRITICAL, "Direct disk write"),
109
115
  (r">\s*/dev/nvme", RiskLevel.CRITICAL, "Direct NVMe write"),
110
- (r"find\s+.*-delete", RiskLevel.DANGER, "Recursive delete via find"),
111
- (r"shred\s+", RiskLevel.DANGER, "Secure file deletion"),
116
+ (r"\bshred\s+", RiskLevel.DANGER, "Secure file deletion"),
112
117
  (r"\$\(.*\)", RiskLevel.CAUTION, "Command substitution detected"),
113
118
  (r"`[^`]+`", RiskLevel.CAUTION, "Backtick command substitution detected"),
114
119
  (r"chmod\s+777\s+/", RiskLevel.CRITICAL, "World-writable root"),
115
120
  (r"chmod\s+-R\s+777\s+/", RiskLevel.CRITICAL, "World-writable root recursive"),
116
121
 
117
122
  # System control
118
- (r"shutdown", RiskLevel.DANGER, "System shutdown"),
119
- (r"reboot", RiskLevel.DANGER, "System reboot"),
120
- (r"systemctl\s+stop", RiskLevel.DANGER, "Stop system service"),
121
- (r"systemctl\s+disable", RiskLevel.DANGER, "Disable system service"),
122
- (r"killall", RiskLevel.DANGER, "Kill all processes"),
123
- (r"pkill", RiskLevel.DANGER, "Kill processes by pattern"),
123
+ (r"\bshutdown\b", RiskLevel.DANGER, "System shutdown"),
124
+ (r"\breboot\b", RiskLevel.DANGER, "System reboot"),
125
+ (r"\bsystemctl\s+stop\b", RiskLevel.DANGER, "Stop system service"),
126
+ (r"\bsystemctl\s+disable\b", RiskLevel.DANGER, "Disable system service"),
127
+ (r"\bkillall\b", RiskLevel.DANGER, "Kill all processes"),
128
+ (r"\bpkill\b", RiskLevel.DANGER, "Kill processes by pattern"),
124
129
 
125
130
  # Git danger
126
- (r"git\s+push\s+--force", RiskLevel.DANGER, "Force push"),
127
- (r"git\s+push\s+-f", RiskLevel.DANGER, "Force push"),
128
- (r"git\s+reset\s+--hard", RiskLevel.DANGER, "Hard reset — loses changes"),
129
- (r"git\s+clean\s+-fdx", RiskLevel.DANGER, "Remove all untracked files"),
131
+ (r"\bgit\s+push\s+--force\b", RiskLevel.DANGER, "Force push"),
132
+ (r"\bgit\s+push\s+-f\b", RiskLevel.DANGER, "Force push"),
133
+ (r"\bgit\s+reset\s+--hard\b", RiskLevel.DANGER, "Hard reset — loses changes"),
134
+ (r"\bgit\s+clean\s+-fdx\b", RiskLevel.DANGER, "Remove all untracked files"),
130
135
 
131
136
  # Network danger
132
- (r"curl.*\|\s*(ba)?sh", RiskLevel.DANGER, "Pipe curl to shell"),
133
- (r"wget.*\|\s*(ba)?sh", RiskLevel.DANGER, "Pipe wget to shell"),
134
- (r"nc\s+-l", RiskLevel.CAUTION, "Open network listener"),
137
+ (r"\bcurl\b.*\|\s*(ba)?sh\b", RiskLevel.DANGER, "Pipe curl to shell"),
138
+ (r"\bwget\b.*\|\s*(ba)?sh\b", RiskLevel.DANGER, "Pipe wget to shell"),
139
+ (r"\bnc\s+-l\b", RiskLevel.CAUTION, "Open network listener"),
135
140
 
136
141
  # Fork bomb
137
142
  (r":\(\)\s*\{", RiskLevel.CRITICAL, "Fork bomb pattern"),
138
143
 
139
144
  # Database danger
140
- (r"DROP\s+(TABLE|DATABASE)", RiskLevel.DANGER, "SQL DROP operation"),
141
- (r"TRUNCATE\s+(TABLE\s+)?", RiskLevel.DANGER, "SQL TRUNCATE operation"),
142
- (r"DELETE\s+FROM\s+\w+\s+WHERE", RiskLevel.CAUTION, "SQL DELETE with condition"),
143
- (r"DELETE\s+FROM\s+\w+\s*;", RiskLevel.DANGER, "SQL DELETE without WHERE"),
145
+ (r"\bDROP\s+(TABLE|DATABASE)\b", RiskLevel.DANGER, "SQL DROP operation"),
146
+ (r"\bTRUNCATE\s+(TABLE\s+)?", RiskLevel.DANGER, "SQL TRUNCATE operation"),
147
+ (r"\bDELETE\s+FROM\s+\w+\s+WHERE\b", RiskLevel.CAUTION, "SQL DELETE with condition"),
148
+ (r"\bDELETE\s+FROM\s+\w+\s*;", RiskLevel.DANGER, "SQL DELETE without WHERE"),
144
149
 
145
150
  # Package manager danger
146
- (r"(pip|npm|gem|cargo)\s+(uninstall|remove)", RiskLevel.CAUTION, "Package removal"),
151
+ (r"\b(pip|npm|gem|cargo)\s+(uninstall|remove)\b", RiskLevel.CAUTION, "Package removal"),
147
152
 
148
153
  # Permission changes
149
- (r"chmod\s+777", RiskLevel.CAUTION, "Make file world-writable"),
150
- (r"chown\s+root", RiskLevel.DANGER, "Change owner to root"),
154
+ (r"\bchmod\s+777\b", RiskLevel.CAUTION, "Make file world-writable"),
155
+ (r"\bchown\s+root\b", RiskLevel.DANGER, "Change owner to root"),
151
156
 
152
157
  # Encoded / obfuscated commands (common bypass techniques)
153
- (r"base64\s+(-d|--decode)", RiskLevel.CAUTION, "Base64 decode — possible obfuscated command"),
158
+ (r"\bbase64\s+(-d|--decode)\b", RiskLevel.CAUTION, "Base64 decode — possible obfuscated command"),
154
159
  (r"\bIEX\s*\([^)]*\)", RiskLevel.DANGER, "PowerShell Invoke-Expression (IEX) — remote code execution risk"),
155
- (r"Invoke-Expression", RiskLevel.DANGER, "PowerShell Invoke-Expression — remote code execution risk"),
156
- (r"Invoke-WebRequest", RiskLevel.CAUTION, "PowerShell Invoke-WebRequest — fetches remote content"),
157
- (r"Invoke-RestMethod", RiskLevel.CAUTION, "PowerShell Invoke-RestMethod — fetches remote content"),
160
+ (r"\bInvoke-Expression\b", RiskLevel.DANGER, "PowerShell Invoke-Expression — remote code execution risk"),
161
+ (r"\bInvoke-WebRequest\b", RiskLevel.CAUTION, "PowerShell Invoke-WebRequest — fetches remote content"),
162
+ (r"\bInvoke-RestMethod\b", RiskLevel.CAUTION, "PowerShell Invoke-RestMethod — fetches remote content"),
163
+ # Additional PowerShell bypass techniques
164
+ (r"\bStart-Process\s+.*-Verb\s+RunAs\b", RiskLevel.DANGER, "PowerShell elevated execution"),
165
+ (r"\[\s*System\.Net\.WebClient\s*\]", RiskLevel.DANGER, "PowerShell WebClient — remote download"),
166
+ (r"\[\s*System\.Reflection\.Assembly\s*\]", RiskLevel.DANGER, "PowerShell reflection assembly load"),
167
+
168
+ # Additional bypass techniques
169
+ (r"\beval\s+.*\$", RiskLevel.CAUTION, "Eval with variable — possible code injection"),
170
+ (r"\bxargs\s+.*\brm\b", RiskLevel.DANGER, "xargs with rm — mass delete"),
171
+ (r">\s*/etc/", RiskLevel.CRITICAL, "Write to /etc/"),
172
+ (r">\s*/boot/", RiskLevel.CRITICAL, "Write to /boot/"),
158
173
  ]
159
174
 
160
175
  # Suspicious file extensions (writing these is unusual for a code agent)