ata-coder 2.4.2__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.
- ata_coder/__init__.py +1 -0
- ata_coder/agent.py +874 -0
- ata_coder/agent_compact.py +190 -0
- ata_coder/agent_controller.py +218 -0
- ata_coder/agent_extension.py +69 -0
- ata_coder/agent_routing.py +105 -0
- ata_coder/agent_subsystems.py +72 -0
- ata_coder/agent_tools.py +318 -0
- ata_coder/agent_undo.py +63 -0
- ata_coder/anthropic_client.py +465 -0
- ata_coder/change_tracker.py +368 -0
- ata_coder/clawd_integration.py +574 -0
- ata_coder/commands/__init__.py +128 -0
- ata_coder/commands/_core.py +184 -0
- ata_coder/commands/_safety.py +95 -0
- ata_coder/commands/_settings.py +241 -0
- ata_coder/commands/_workflow.py +451 -0
- ata_coder/commands.py +974 -0
- ata_coder/config.py +257 -0
- ata_coder/core/__init__.py +35 -0
- ata_coder/core/events.py +73 -0
- ata_coder/core/queue.py +85 -0
- ata_coder/core/state.py +17 -0
- ata_coder/event_queue.py +5 -0
- ata_coder/extension.py +654 -0
- ata_coder/extensions/__init__.py +1 -0
- ata_coder/extensions/hello_skill.py +47 -0
- ata_coder/fool_proof.py +295 -0
- ata_coder/git_workflow.py +371 -0
- ata_coder/gui.py +511 -0
- ata_coder/llm_client.py +543 -0
- ata_coder/main.py +814 -0
- ata_coder/mcp_client.py +1095 -0
- ata_coder/memory.py +539 -0
- ata_coder/model_registry.py +134 -0
- ata_coder/model_router.py +105 -0
- ata_coder/permissions.py +274 -0
- ata_coder/privilege.py +464 -0
- ata_coder/project.py +273 -0
- ata_coder/prompt_template.py +423 -0
- ata_coder/prompts/auto-mode.md +7 -0
- ata_coder/prompts/coding-rules.md +40 -0
- ata_coder/prompts/execution-guardrails.md +14 -0
- ata_coder/prompts/memory-system.md +24 -0
- ata_coder/prompts/output-style.md +23 -0
- ata_coder/prompts/safety.md +17 -0
- ata_coder/prompts/slash-commands.md +24 -0
- ata_coder/prompts/sub-agents.md +38 -0
- ata_coder/prompts/system-reminders.md +17 -0
- ata_coder/prompts/system.md +105 -0
- ata_coder/prompts/tool-policy.md +46 -0
- ata_coder/repl_theme.py +99 -0
- ata_coder/repl_tracker.py +89 -0
- ata_coder/repl_ui.py +1214 -0
- ata_coder/safety_guard.py +434 -0
- ata_coder/self_correct.py +346 -0
- ata_coder/server.py +882 -0
- ata_coder/server_session.py +159 -0
- ata_coder/server_shell.py +129 -0
- ata_coder/session.py +431 -0
- ata_coder/settings.py +439 -0
- ata_coder/setup_wizard.py +136 -0
- ata_coder/skill_extension.py +92 -0
- ata_coder/skills/architect/SKILL.md +42 -0
- ata_coder/skills/code-reviewer/SKILL.md +37 -0
- ata_coder/skills/codecraft/SKILL.md +452 -0
- ata_coder/skills/debugger/SKILL.md +45 -0
- ata_coder/skills/doc-writer/SKILL.md +36 -0
- ata_coder/skills/general-coder/SKILL.md +76 -0
- ata_coder/skills/math-calculator/README.md +40 -0
- ata_coder/skills/math-calculator/SKILL.md +59 -0
- ata_coder/skills/math-calculator/handler.py +103 -0
- ata_coder/skills/math-calculator/prompts/system.md +8 -0
- ata_coder/skills/math-calculator/requirements.txt +2 -0
- ata_coder/skills/math-calculator/resources/constants.json +8 -0
- ata_coder/skills/math-calculator/tests/test_handler.py +53 -0
- ata_coder/skills/security-auditor/SKILL.md +40 -0
- ata_coder/skills/test-writer/SKILL.md +36 -0
- ata_coder/skills/weather-skill/README.md +45 -0
- ata_coder/skills/weather-skill/handler.py +76 -0
- ata_coder/skills/weather-skill/manifest.json +48 -0
- ata_coder/skills/weather-skill/prompts/system_prompt.txt +9 -0
- ata_coder/skills/weather-skill/prompts/user_prompt_template.txt +3 -0
- ata_coder/skills/weather-skill/requirements.txt +1 -0
- ata_coder/skills/weather-skill/resources/city_list.json +17 -0
- ata_coder/skills/weather-skill/resources/error_messages.json +7 -0
- ata_coder/skills/weather-skill/tests/test_handler.py +28 -0
- ata_coder/skills/weather-skill/weather_utils.py +50 -0
- ata_coder/skills.py +1014 -0
- ata_coder/sub_agent.py +273 -0
- ata_coder/sub_agent_manager.py +203 -0
- ata_coder/system_prompt_builder.py +146 -0
- ata_coder/task_planner.py +391 -0
- ata_coder/terminal.py +318 -0
- ata_coder/test_runner.py +219 -0
- ata_coder/thread_supervisor.py +195 -0
- ata_coder/tool_defs.py +335 -0
- ata_coder/tools/__init__.py +11 -0
- ata_coder/tools/definitions.py +335 -0
- ata_coder/tools/executor.py +1036 -0
- ata_coder/tools/result.py +26 -0
- ata_coder/tools/subagent.py +332 -0
- ata_coder/tools/web.py +361 -0
- ata_coder/tools.py +1576 -0
- ata_coder/types.py +92 -0
- ata_coder/utils.py +113 -0
- ata_coder/web/css/style.css +180 -0
- ata_coder/web/index.html +84 -0
- ata_coder/web/js/app.js +489 -0
- ata_coder/web/package-lock.json +25 -0
- ata_coder/web/package.json +10 -0
- ata_coder/web/tsconfig.json +13 -0
- ata_coder-2.4.2.dist-info/METADATA +799 -0
- ata_coder-2.4.2.dist-info/RECORD +118 -0
- ata_coder-2.4.2.dist-info/WHEEL +5 -0
- ata_coder-2.4.2.dist-info/entry_points.txt +2 -0
- ata_coder-2.4.2.dist-info/licenses/LICENSE +21 -0
- ata_coder-2.4.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: general-coder
|
|
3
|
+
description: General-purpose coding assistant. Writes, debugs, refactors, and explains code.
|
|
4
|
+
triggers:
|
|
5
|
+
- code
|
|
6
|
+
- write
|
|
7
|
+
- implement
|
|
8
|
+
- fix
|
|
9
|
+
- add
|
|
10
|
+
- change
|
|
11
|
+
- refactor
|
|
12
|
+
- build
|
|
13
|
+
- create
|
|
14
|
+
- 写
|
|
15
|
+
- 改
|
|
16
|
+
- 修
|
|
17
|
+
- 加
|
|
18
|
+
- 实现
|
|
19
|
+
tools: []
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
You are an **expert software engineer** embedded in a coding agent. Your job is to understand the user's intent, navigate the codebase, make precise changes, verify them, and communicate clearly.
|
|
23
|
+
|
|
24
|
+
## Workflow
|
|
25
|
+
|
|
26
|
+
1. **Understand** — read relevant files before acting. Never guess file contents.
|
|
27
|
+
2. **Plan** — outline your approach before writing code. For complex tasks, break into subtasks.
|
|
28
|
+
3. **Execute** — make minimal, surgical edits. One logical change per edit.
|
|
29
|
+
4. **Verify** — run tests, check the build, or validate manually if applicable.
|
|
30
|
+
5. **Explain** — summarize what you did, why, and any important caveats.
|
|
31
|
+
|
|
32
|
+
## Code Quality
|
|
33
|
+
|
|
34
|
+
- **Match existing style** — naming, indentation, comment density, import ordering
|
|
35
|
+
- **Prefer readability** over cleverness. Code is read more than written.
|
|
36
|
+
- **One logical change** per edit. Don't mix unrelated fixes.
|
|
37
|
+
- **Add tests** when the codebase has an existing test framework.
|
|
38
|
+
- **Handle edge cases** — null/empty inputs, error paths, boundary conditions.
|
|
39
|
+
|
|
40
|
+
## Communication
|
|
41
|
+
|
|
42
|
+
Your responses should be clear, structured, and easy to scan:
|
|
43
|
+
|
|
44
|
+
- **Use `**bold**` generously** for key terms, file names, function names, and important conclusions. Bold text draws the reader's eye to what matters most.
|
|
45
|
+
- **Use `file_path:line_number` references** — they're clickable and help the user jump to code.
|
|
46
|
+
- **Use emojis sparingly** to mark sections: 🐛 for bugs, ⚡ for performance, 🔒 for security, ✅ for completed items.
|
|
47
|
+
- **Keep it concise.** Say what you found, what you changed, and why. Don't write novels.
|
|
48
|
+
- **If blocked**, say so directly and suggest next steps. Don't silently give up.
|
|
49
|
+
- **Use bullet lists** for multiple points, **code blocks** for code, **tables** for comparisons.
|
|
50
|
+
|
|
51
|
+
### Response Structure (for complex tasks)
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
## Summary
|
|
55
|
+
**What** was done and **why**
|
|
56
|
+
|
|
57
|
+
## Changes
|
|
58
|
+
- `file.py:42` — **specific change** with reason
|
|
59
|
+
- `other.py:10` — **another change** with reason
|
|
60
|
+
|
|
61
|
+
## Verification
|
|
62
|
+
**How** you confirmed it works (tests run, manual check, etc.)
|
|
63
|
+
|
|
64
|
+
## Notes (optional)
|
|
65
|
+
Any caveats, follow-ups, or things the user should know.
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Rules
|
|
69
|
+
|
|
70
|
+
1. **Read before edit** — never guess file contents.
|
|
71
|
+
2. **Surgical edits** — change only what's needed. Don't refactor what isn't broken.
|
|
72
|
+
3. **Tool failures** — read the error, diagnose, retry with a fix. Don't just report failure.
|
|
73
|
+
4. **No destructive ops** — never run `rm -rf`, `DROP TABLE`, `git push --force`, etc. unless explicitly asked.
|
|
74
|
+
5. **Use dedicated tools** — prefer `grep`/`glob` over shell `find`/`grep`. Use `edit_file` for precise edits.
|
|
75
|
+
6. **Verify your work** — after making changes, confirm they compile/run/pass tests.
|
|
76
|
+
7. **Report faithfully** — if tests fail, show the output. If you skipped a step, say so.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Math Calculator Skill
|
|
2
|
+
|
|
3
|
+
Safely evaluate mathematical expressions with configurable precision.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from ata_coder.skills import get_skill_manager
|
|
9
|
+
|
|
10
|
+
mgr = get_skill_manager()
|
|
11
|
+
result = mgr.execute_skill("math-calculator", {
|
|
12
|
+
"expression": "2 + 3 * 4",
|
|
13
|
+
"precision": 2,
|
|
14
|
+
})
|
|
15
|
+
print(result) # {"success": True, "result": 14, ...}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Parameters
|
|
19
|
+
|
|
20
|
+
| Name | Type | Required | Default | Description |
|
|
21
|
+
|------|------|----------|---------|-------------|
|
|
22
|
+
| expression | string | yes | — | Math expression |
|
|
23
|
+
| precision | integer | no | 6 | Decimal places |
|
|
24
|
+
| format | string | no | number | `number` or `steps` |
|
|
25
|
+
|
|
26
|
+
## Supported Operations
|
|
27
|
+
|
|
28
|
+
- Arithmetic: `+ - * / ** %`
|
|
29
|
+
- Functions: `sqrt sin cos tan log abs round`
|
|
30
|
+
- Constants: `pi e`
|
|
31
|
+
|
|
32
|
+
## Security
|
|
33
|
+
|
|
34
|
+
Input is sanitized against code injection. Expressions over 500 chars are rejected.
|
|
35
|
+
|
|
36
|
+
## Testing
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pytest tests/
|
|
40
|
+
```
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: math-calculator
|
|
3
|
+
version: "1.0.0"
|
|
4
|
+
description: Safely evaluate mathematical expressions with configurable precision
|
|
5
|
+
type: skill
|
|
6
|
+
call:
|
|
7
|
+
function: calculate
|
|
8
|
+
parameters:
|
|
9
|
+
expression:
|
|
10
|
+
type: string
|
|
11
|
+
description: "Mathematical expression to evaluate (e.g., '2 + 3 * 4')"
|
|
12
|
+
required: true
|
|
13
|
+
precision:
|
|
14
|
+
type: integer
|
|
15
|
+
description: "Number of decimal places in result"
|
|
16
|
+
default: 6
|
|
17
|
+
format:
|
|
18
|
+
type: string
|
|
19
|
+
description: "Output format: 'number' or 'steps' (show intermediate steps)"
|
|
20
|
+
default: number
|
|
21
|
+
output:
|
|
22
|
+
format: json
|
|
23
|
+
schema:
|
|
24
|
+
result:
|
|
25
|
+
type: number
|
|
26
|
+
description: "The computed result"
|
|
27
|
+
expression:
|
|
28
|
+
type: string
|
|
29
|
+
description: "The original expression"
|
|
30
|
+
precision:
|
|
31
|
+
type: integer
|
|
32
|
+
description: "Precision used"
|
|
33
|
+
permissions:
|
|
34
|
+
network: false
|
|
35
|
+
filesystem: none
|
|
36
|
+
allowed_commands: []
|
|
37
|
+
tags: [math, utility, calculator]
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
# Math Calculator
|
|
41
|
+
|
|
42
|
+
You are a precise mathematical calculator. When asked to compute an expression:
|
|
43
|
+
|
|
44
|
+
1. Parse the expression carefully, respecting operator precedence
|
|
45
|
+
2. Evaluate step by step if format='steps'
|
|
46
|
+
3. Return the result to the specified precision
|
|
47
|
+
|
|
48
|
+
## Supported Operations
|
|
49
|
+
|
|
50
|
+
- Basic: +, -, *, /, ** (power), % (modulo)
|
|
51
|
+
- Functions: sqrt, sin, cos, tan, log, abs, round
|
|
52
|
+
- Constants: pi, e
|
|
53
|
+
|
|
54
|
+
## Important
|
|
55
|
+
|
|
56
|
+
- Never execute shell commands to calculate
|
|
57
|
+
- Use Python's `math` module internally
|
|
58
|
+
- Sanitize input — reject expressions over 500 characters
|
|
59
|
+
- For security, only allow safe mathematical expressions (no `__import__`, `eval` injection, etc.)
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""Math Calculator Skill — safe expression evaluation."""
|
|
3
|
+
|
|
4
|
+
import math
|
|
5
|
+
import re
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# Allowed builtins for safe evaluation
|
|
10
|
+
_SAFE_BUILTINS = {
|
|
11
|
+
"abs": abs, "round": round, "int": int, "float": float,
|
|
12
|
+
"max": max, "min": min, "sum": sum, "pow": pow,
|
|
13
|
+
"len": len, "range": range, "list": list, "tuple": tuple,
|
|
14
|
+
}
|
|
15
|
+
_SAFE_MATH = {
|
|
16
|
+
"sqrt": math.sqrt, "sin": math.sin, "cos": math.cos,
|
|
17
|
+
"tan": math.tan, "log": math.log, "log10": math.log10,
|
|
18
|
+
"log2": math.log2, "exp": math.exp, "pi": math.pi, "e": math.e,
|
|
19
|
+
"ceil": math.ceil, "floor": math.floor, "degrees": math.degrees,
|
|
20
|
+
"radians": math.radians, "asin": math.asin, "acos": math.acos,
|
|
21
|
+
"atan": math.atan, "sinh": math.sinh, "cosh": math.cosh,
|
|
22
|
+
"tanh": math.tanh, "fabs": math.fabs, "factorial": math.factorial,
|
|
23
|
+
"gcd": math.gcd, "trunc": math.trunc, "modf": math.modf,
|
|
24
|
+
"isclose": math.isclose,
|
|
25
|
+
}
|
|
26
|
+
_SAFE_NAMES = {**_SAFE_BUILTINS, **_SAFE_MATH}
|
|
27
|
+
|
|
28
|
+
# Regex for sanitizing expressions
|
|
29
|
+
_UNSAFE_PATTERNS = [
|
|
30
|
+
r"__", # dunder attributes
|
|
31
|
+
r"import", # imports
|
|
32
|
+
r"exec\s*\(", # exec()
|
|
33
|
+
r"eval\s*\(", # recursive eval
|
|
34
|
+
r"open\s*\(", # file open
|
|
35
|
+
r"os\.", # os module
|
|
36
|
+
r"sys\.", # sys module
|
|
37
|
+
r"subprocess", # subprocess
|
|
38
|
+
r"lambda", # lambda (can create arbitrary code)
|
|
39
|
+
r"globals?\s*\(", # globals()
|
|
40
|
+
r"locals?\s*\(", # locals()
|
|
41
|
+
r"getattr\s*\(", # getattr()
|
|
42
|
+
r"setattr\s*\(", # setattr()
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def run(input_data: dict[str, Any]) -> dict[str, Any]:
|
|
47
|
+
"""
|
|
48
|
+
Evaluate a mathematical expression safely.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
input_data: {"expression": str, "precision": int = 6, "format": str = "number"}
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
{"success": bool, "result": number|null, "expression": str, "error": str|null}
|
|
55
|
+
"""
|
|
56
|
+
expression = input_data.get("expression", "").strip()
|
|
57
|
+
precision = input_data.get("precision", 6)
|
|
58
|
+
output_format = input_data.get("format", "number")
|
|
59
|
+
|
|
60
|
+
# Validate
|
|
61
|
+
if not expression:
|
|
62
|
+
return _error("No expression provided", expression, 400)
|
|
63
|
+
|
|
64
|
+
if len(expression) > 500:
|
|
65
|
+
return _error("Expression too long (>500 chars)", expression, 400)
|
|
66
|
+
|
|
67
|
+
# Sanitize — check for unsafe patterns
|
|
68
|
+
lowered = expression.lower()
|
|
69
|
+
for pattern in _UNSAFE_PATTERNS:
|
|
70
|
+
if re.search(pattern, lowered):
|
|
71
|
+
return _error(f"Unsafe pattern detected: {pattern}", expression, 403)
|
|
72
|
+
|
|
73
|
+
# Evaluate safely
|
|
74
|
+
try:
|
|
75
|
+
result = eval(expression, {"__builtins__": {}}, _SAFE_NAMES)
|
|
76
|
+
except SyntaxError as e:
|
|
77
|
+
return _error(f"Syntax error: {e}", expression, 400)
|
|
78
|
+
except ZeroDivisionError:
|
|
79
|
+
return _error("Division by zero", expression, 400)
|
|
80
|
+
except Exception as e:
|
|
81
|
+
return _error(f"Evaluation error: {type(e).__name__}: {e}", expression, 400)
|
|
82
|
+
|
|
83
|
+
# Format
|
|
84
|
+
if isinstance(result, float):
|
|
85
|
+
result = round(result, precision)
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
"success": True,
|
|
89
|
+
"result": result,
|
|
90
|
+
"expression": expression,
|
|
91
|
+
"precision": precision,
|
|
92
|
+
"error": None,
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _error(msg: str, expr: str, code: int) -> dict[str, Any]:
|
|
97
|
+
return {
|
|
98
|
+
"success": False,
|
|
99
|
+
"result": None,
|
|
100
|
+
"expression": expr,
|
|
101
|
+
"error": msg,
|
|
102
|
+
"status_code": code,
|
|
103
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
You are a precise mathematical calculator.
|
|
2
|
+
|
|
3
|
+
Rules:
|
|
4
|
+
- Parse expressions respecting standard operator precedence (PEMDAS)
|
|
5
|
+
- Use Python's math module internally
|
|
6
|
+
- Return results rounded to the requested precision
|
|
7
|
+
- Reject any expression containing non-mathematical operations
|
|
8
|
+
- If format='steps', show each intermediate step
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""Tests for math-calculator handler."""
|
|
3
|
+
|
|
4
|
+
import sys
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
# Add parent to path so we can import handler
|
|
8
|
+
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
9
|
+
from handler import run
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_basic_addition():
|
|
13
|
+
result = run({"expression": "2 + 3"})
|
|
14
|
+
assert result["success"]
|
|
15
|
+
assert result["result"] == 5
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_precedence():
|
|
19
|
+
result = run({"expression": "2 + 3 * 4"})
|
|
20
|
+
assert result["success"]
|
|
21
|
+
assert result["result"] == 14
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_sqrt():
|
|
25
|
+
result = run({"expression": "sqrt(16)"})
|
|
26
|
+
assert result["success"]
|
|
27
|
+
assert result["result"] == 4.0
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def test_empty_expression():
|
|
31
|
+
result = run({"expression": ""})
|
|
32
|
+
assert not result["success"]
|
|
33
|
+
assert result["status_code"] == 400
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_unsafe_import():
|
|
37
|
+
result = run({"expression": "__import__('os')"})
|
|
38
|
+
assert not result["success"]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_unsafe_eval():
|
|
42
|
+
result = run({"expression": "eval('1+1')"})
|
|
43
|
+
assert not result["success"]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def test_division_by_zero():
|
|
47
|
+
result = run({"expression": "1/0"})
|
|
48
|
+
assert not result["success"]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_long_expression():
|
|
52
|
+
result = run({"expression": "1+" * 300})
|
|
53
|
+
assert not result["success"]
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: security-auditor
|
|
3
|
+
description: Security-focused code auditor. Finds vulnerabilities, hardcoded secrets, and unsafe patterns.
|
|
4
|
+
triggers:
|
|
5
|
+
- security audit
|
|
6
|
+
- security review
|
|
7
|
+
- hardcoded key
|
|
8
|
+
- vulnerability
|
|
9
|
+
- CVE
|
|
10
|
+
- 安全
|
|
11
|
+
- 漏洞
|
|
12
|
+
- secret
|
|
13
|
+
- password
|
|
14
|
+
- token leak
|
|
15
|
+
tools: []
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
You are a security engineer performing a code audit. Find real vulnerabilities, not theoretical ones.
|
|
19
|
+
|
|
20
|
+
## Audit Checklist
|
|
21
|
+
1. **Secrets exposure** — API keys, tokens, passwords in code or config
|
|
22
|
+
2. **Injection risks** — SQL, command, code injection vectors
|
|
23
|
+
3. **Authentication** — weak or missing auth, session issues
|
|
24
|
+
4. **Authorization** — missing access controls, privilege escalation
|
|
25
|
+
5. **Data exposure** — sensitive data in logs, errors, or client-side
|
|
26
|
+
6. **Dependencies** — known vulnerable packages (check versions)
|
|
27
|
+
7. **Crypto** — weak algorithms, hardcoded keys, bad random
|
|
28
|
+
|
|
29
|
+
## Output Format
|
|
30
|
+
For each finding:
|
|
31
|
+
- **Severity**: critical / high / medium / low
|
|
32
|
+
- **Location**: file:line
|
|
33
|
+
- **Finding**: what the vulnerability is
|
|
34
|
+
- **Exploit**: how it could be exploited
|
|
35
|
+
- **Fix**: concrete remediation
|
|
36
|
+
|
|
37
|
+
## Rules
|
|
38
|
+
- Only report findings you can confirm from the code
|
|
39
|
+
- Prioritize exploitable issues over theoretical ones
|
|
40
|
+
- If no serious issues found, say so — don't invent problems
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test-writer
|
|
3
|
+
description: Writes unit tests, integration tests, and test fixtures. Follows testing best practices.
|
|
4
|
+
triggers:
|
|
5
|
+
- test
|
|
6
|
+
- unit test
|
|
7
|
+
- spec
|
|
8
|
+
- coverage
|
|
9
|
+
- pytest
|
|
10
|
+
- jest
|
|
11
|
+
- vitest
|
|
12
|
+
- 测试
|
|
13
|
+
- 写测试
|
|
14
|
+
tools: []
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
You are a test engineer. Write tests that matter, not tests that inflate coverage numbers.
|
|
18
|
+
|
|
19
|
+
## Principles
|
|
20
|
+
- **Test behavior, not implementation** — what it does, not how
|
|
21
|
+
- **AAA pattern** — Arrange, Act, Assert
|
|
22
|
+
- **One concept per test** — clear failure messages
|
|
23
|
+
- **Deterministic** — no flaky tests, no random without seeds
|
|
24
|
+
- **Fast** — unit tests in milliseconds
|
|
25
|
+
|
|
26
|
+
## Coverage Targets
|
|
27
|
+
- Happy path (expected case)
|
|
28
|
+
- Edge cases (empty, null, boundary)
|
|
29
|
+
- Error cases (invalid input, failures)
|
|
30
|
+
- Integration boundaries (DB, API, FS)
|
|
31
|
+
|
|
32
|
+
## Process
|
|
33
|
+
1. Detect the project's test framework
|
|
34
|
+
2. Study existing test style
|
|
35
|
+
3. Write tests following the same conventions
|
|
36
|
+
4. Run them to confirm they pass
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Weather Skill
|
|
2
|
+
|
|
3
|
+
Query real-time weather for cities worldwide using the free Open-Meteo API (no API key required).
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```python
|
|
8
|
+
from ata_coder.skills import get_skill_manager
|
|
9
|
+
mgr = get_skill_manager()
|
|
10
|
+
result = mgr.execute_skill("weather-skill", {
|
|
11
|
+
"city": "Tokyo",
|
|
12
|
+
"units": "celsius",
|
|
13
|
+
"forecast_days": 3,
|
|
14
|
+
})
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Parameters
|
|
18
|
+
|
|
19
|
+
| Name | Type | Required | Default | Description |
|
|
20
|
+
|------|------|----------|---------|-------------|
|
|
21
|
+
| city | string | yes | — | City name |
|
|
22
|
+
| units | string | no | celsius | `celsius` or `fahrenheit` |
|
|
23
|
+
| forecast_days | integer | no | 1 | 1-7 days |
|
|
24
|
+
|
|
25
|
+
## Response Format
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"success": true,
|
|
30
|
+
"result": {
|
|
31
|
+
"city": "Tokyo",
|
|
32
|
+
"country": "Japan",
|
|
33
|
+
"temperature": "22.5°C",
|
|
34
|
+
"windspeed": "12 km/h",
|
|
35
|
+
"conditions": "Clear sky",
|
|
36
|
+
"humidity": "N/A (free API limitation)"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install -r requirements.txt
|
|
45
|
+
```
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""Weather Skill — query weather via Open-Meteo API (free, no API key)."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
import httpx
|
|
7
|
+
except ImportError:
|
|
8
|
+
httpx = None
|
|
9
|
+
|
|
10
|
+
from utils import load_city_coords, format_weather_response, GEO_URL, WEATHER_URL
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def run(input_data: dict[str, Any]) -> dict[str, Any]:
|
|
14
|
+
"""
|
|
15
|
+
Get weather for a city.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
input_data: {"city": str, "units": str = "celsius", "forecast_days": int = 1}
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
{"success": bool, "result": dict|null, "error": str|null}
|
|
22
|
+
"""
|
|
23
|
+
city = input_data.get("city", "").strip()
|
|
24
|
+
units = input_data.get("units", "celsius")
|
|
25
|
+
forecast_days = min(max(int(input_data.get("forecast_days", 1)), 1), 7)
|
|
26
|
+
|
|
27
|
+
if not city:
|
|
28
|
+
return {"success": False, "result": None, "error": "City name required"}
|
|
29
|
+
|
|
30
|
+
# Look up coordinates from local resource
|
|
31
|
+
cities = load_city_coords()
|
|
32
|
+
coords = cities.get(city.lower())
|
|
33
|
+
if not coords:
|
|
34
|
+
# Try geocoding API
|
|
35
|
+
coords = _geocode_city(city)
|
|
36
|
+
if not coords:
|
|
37
|
+
return {
|
|
38
|
+
"success": False, "result": None,
|
|
39
|
+
"error": f"City not found: {city}",
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
lat, lon = coords["lat"], coords["lon"]
|
|
43
|
+
|
|
44
|
+
# Fetch weather
|
|
45
|
+
if httpx is None:
|
|
46
|
+
return {"success": False, "result": None, "error": "httpx not installed"}
|
|
47
|
+
try:
|
|
48
|
+
params = {
|
|
49
|
+
"latitude": lat, "longitude": lon,
|
|
50
|
+
"current_weather": "true",
|
|
51
|
+
"forecast_days": forecast_days,
|
|
52
|
+
"temperature_unit": "celsius" if units == "celsius" else "fahrenheit",
|
|
53
|
+
}
|
|
54
|
+
resp = httpx.get(WEATHER_URL, params=params, timeout=10.0)
|
|
55
|
+
resp.raise_for_status()
|
|
56
|
+
data = resp.json()
|
|
57
|
+
except Exception as e:
|
|
58
|
+
return {"success": False, "result": None, "error": f"API error: {e}"}
|
|
59
|
+
|
|
60
|
+
return format_weather_response(city, coords.get("country", ""), data, units)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _geocode_city(city: str) -> dict | None:
|
|
64
|
+
"""Fallback: geocode city name via Open-Meteo Geocoding API."""
|
|
65
|
+
if httpx is None:
|
|
66
|
+
return None
|
|
67
|
+
try:
|
|
68
|
+
resp = httpx.get(GEO_URL, params={"name": city, "count": 1}, timeout=5.0)
|
|
69
|
+
resp.raise_for_status()
|
|
70
|
+
results = resp.json().get("results", [])
|
|
71
|
+
if results:
|
|
72
|
+
r = results[0]
|
|
73
|
+
return {"lat": r["latitude"], "lon": r["longitude"], "country": r.get("country", "")}
|
|
74
|
+
except Exception:
|
|
75
|
+
pass
|
|
76
|
+
return None
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "weather-skill",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Query weather information for cities worldwide via Open-Meteo API",
|
|
5
|
+
"type": "skill",
|
|
6
|
+
"author": "ATA Coder Team",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"call": {
|
|
9
|
+
"function": "get_weather",
|
|
10
|
+
"parameters": {
|
|
11
|
+
"city": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"description": "City name (e.g., 'Beijing', 'Tokyo', 'London')",
|
|
14
|
+
"required": true
|
|
15
|
+
},
|
|
16
|
+
"units": {
|
|
17
|
+
"type": "string",
|
|
18
|
+
"description": "Temperature unit: 'celsius' or 'fahrenheit'",
|
|
19
|
+
"default": "celsius"
|
|
20
|
+
},
|
|
21
|
+
"forecast_days": {
|
|
22
|
+
"type": "integer",
|
|
23
|
+
"description": "Number of forecast days (1-7)",
|
|
24
|
+
"default": 1
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"output": {
|
|
29
|
+
"format": "json",
|
|
30
|
+
"schema": {
|
|
31
|
+
"city": "string",
|
|
32
|
+
"country": "string",
|
|
33
|
+
"temperature": "number",
|
|
34
|
+
"humidity": "number",
|
|
35
|
+
"conditions": "string",
|
|
36
|
+
"forecast": "array"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"permissions": {
|
|
40
|
+
"network": true,
|
|
41
|
+
"filesystem": "read_only",
|
|
42
|
+
"allowed_domains": ["api.open-meteo.com", "geocoding-api.open-meteo.com"],
|
|
43
|
+
"allowed_commands": []
|
|
44
|
+
},
|
|
45
|
+
"triggers": ["weather", "temperature", "forecast", "天气", "气温", "预报"],
|
|
46
|
+
"tags": ["weather", "utility", "api"],
|
|
47
|
+
"dependencies": []
|
|
48
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
You are a weather information assistant. When asked about weather:
|
|
2
|
+
|
|
3
|
+
1. Use the get_weather function to query real-time data
|
|
4
|
+
2. Present results in a clear, structured format
|
|
5
|
+
3. Include temperature, conditions, and wind speed
|
|
6
|
+
4. If the city is not found, suggest the user check spelling
|
|
7
|
+
5. For forecasts, present each day clearly
|
|
8
|
+
|
|
9
|
+
Always use the Open-Meteo API (free, no key required).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
httpx>=0.27.0
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"beijing": {"lat": 39.9042, "lon": 116.4074, "country": "China"},
|
|
3
|
+
"shanghai": {"lat": 31.2304, "lon": 121.4737, "country": "China"},
|
|
4
|
+
"guangzhou": {"lat": 23.1291, "lon": 113.2644, "country": "China"},
|
|
5
|
+
"shenzhen": {"lat": 22.5431, "lon": 114.0579, "country": "China"},
|
|
6
|
+
"tokyo": {"lat": 35.6762, "lon": 139.6503, "country": "Japan"},
|
|
7
|
+
"osaka": {"lat": 34.6937, "lon": 135.5023, "country": "Japan"},
|
|
8
|
+
"seoul": {"lat": 37.5665, "lon": 126.9780, "country": "South Korea"},
|
|
9
|
+
"singapore": {"lat": 1.3521, "lon": 103.8198, "country": "Singapore"},
|
|
10
|
+
"london": {"lat": 51.5074, "lon": -0.1278, "country": "United Kingdom"},
|
|
11
|
+
"paris": {"lat": 48.8566, "lon": 2.3522, "country": "France"},
|
|
12
|
+
"new york": {"lat": 40.7128, "lon": -74.0060, "country": "United States"},
|
|
13
|
+
"san francisco": {"lat": 37.7749, "lon": -122.4194, "country": "United States"},
|
|
14
|
+
"sydney": {"lat": -33.8688, "lon": 151.2093, "country": "Australia"},
|
|
15
|
+
"berlin": {"lat": 52.5200, "lon": 13.4050, "country": "Germany"},
|
|
16
|
+
"moscow": {"lat": 55.7558, "lon": 37.6173, "country": "Russia"}
|
|
17
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"city_not_found": "City '{{city}}' not found. Check spelling or try a nearby major city.",
|
|
3
|
+
"api_error": "Weather service temporarily unavailable ({{detail}}). Try again later.",
|
|
4
|
+
"no_network": "Network access required for weather queries.",
|
|
5
|
+
"invalid_units": "Units must be 'celsius' or 'fahrenheit', got '{{units}}'.",
|
|
6
|
+
"forecast_range": "Forecast days must be between 1 and 7, got {{days}}."
|
|
7
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Tests for weather-skill handler (unit tests, no network)."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
6
|
+
|
|
7
|
+
from handler import run
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_missing_city():
|
|
11
|
+
result = run({"city": ""})
|
|
12
|
+
assert not result["success"]
|
|
13
|
+
assert "City name required" in result["error"]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_unknown_city_no_network():
|
|
17
|
+
"""Without httpx installed, unknown cities should fail gracefully."""
|
|
18
|
+
result = run({"city": "asdfghjkl"})
|
|
19
|
+
assert not result["success"]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def test_known_city_no_httpx():
|
|
23
|
+
"""With city_list.json but no httpx, should report httpx missing."""
|
|
24
|
+
result = run({"city": "Beijing"})
|
|
25
|
+
# Either finds coords in city_list but fails on httpx,
|
|
26
|
+
# or succeeds if httpx is installed
|
|
27
|
+
if not result["success"]:
|
|
28
|
+
assert "httpx" in result.get("error", "").lower() or "city" in result.get("error", "").lower()
|