hanuscode 1.0.0__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.
- hanus/__init__.py +5 -0
- hanus/__main__.py +10 -0
- hanus/action_handlers.py +76 -0
- hanus/action_parser.py +82 -0
- hanus/agent_runner.py +1445 -0
- hanus/analysis/__init__.py +5 -0
- hanus/analysis/debt.py +702 -0
- hanus/analysis/dependencies.py +475 -0
- hanus/cache/__init__.py +5 -0
- hanus/cache/response_cache.py +560 -0
- hanus/config.py +401 -0
- hanus/connectors/__init__.py +19 -0
- hanus/connectors/base.py +114 -0
- hanus/connectors/claude_connector.py +146 -0
- hanus/connectors/gemini_connector.py +141 -0
- hanus/connectors/glm_connector.py +160 -0
- hanus/connectors/ollama_connector.py +174 -0
- hanus/connectors/openai_connector.py +122 -0
- hanus/connectors/registry.py +26 -0
- hanus/context/__init__.py +7 -0
- hanus/context/manager.py +837 -0
- hanus/context/selective.py +626 -0
- hanus/error_recovery/__init__.py +5 -0
- hanus/error_recovery/auto_fix.py +605 -0
- hanus/hooks/__init__.py +5 -0
- hanus/hooks/manager.py +247 -0
- hanus/instincts/__init__.py +44 -0
- hanus/instincts/cli.py +372 -0
- hanus/instincts/detector.py +281 -0
- hanus/instincts/evolver.py +361 -0
- hanus/instincts/manager.py +343 -0
- hanus/instincts/types.py +253 -0
- hanus/logger.py +81 -0
- hanus/memory/__init__.py +8 -0
- hanus/memory/manager.py +265 -0
- hanus/memory/types.py +119 -0
- hanus/monitor.py +341 -0
- hanus/parallel/__init__.py +5 -0
- hanus/parallel/executor.py +300 -0
- hanus/permissions.py +182 -0
- hanus/plan/__init__.py +8 -0
- hanus/plan/mode.py +267 -0
- hanus/plan/models.py +152 -0
- hanus/plugin_manager.py +754 -0
- hanus/plugin_registry.py +391 -0
- hanus/plugins/__init__.py +1 -0
- hanus/plugins/arena.py +630 -0
- hanus/plugins/code_review.py +123 -0
- hanus/plugins/cortex.py +1750 -0
- hanus/plugins/deps_check.py +27 -0
- hanus/plugins/git_ops.py +33 -0
- hanus/plugins/metasploit.py +530 -0
- hanus/plugins/notes.py +583 -0
- hanus/plugins/search_code.py +59 -0
- hanus/plugins/searchsploit.py +495 -0
- hanus/plugins/strategist.py +175 -0
- hanus/plugins/webui.py +5200 -0
- hanus/profiles.py +479 -0
- hanus/profiles_builtin/__init__.py +0 -0
- hanus/profiles_builtin/architect/profile.yaml +12 -0
- hanus/profiles_builtin/architect/system_prompt.txt +71 -0
- hanus/profiles_builtin/deep/profile.yaml +12 -0
- hanus/profiles_builtin/deep/system_prompt.txt +66 -0
- hanus/profiles_builtin/developer/__init__.py +0 -0
- hanus/profiles_builtin/developer/profile.yaml +9 -0
- hanus/profiles_builtin/developer/system_prompt.txt +176 -0
- hanus/profiles_builtin/speed/profile.yaml +12 -0
- hanus/profiles_builtin/speed/system_prompt.txt +51 -0
- hanus/project_tools.py +177 -0
- hanus/query_engine.py +1594 -0
- hanus/rules/__init__.py +237 -0
- hanus/search/__init__.py +5 -0
- hanus/search/semantic.py +596 -0
- hanus/session_manager.py +547 -0
- hanus/skill_manager.py +702 -0
- hanus/skills/__init__.py +4 -0
- hanus/subagent/__init__.py +8 -0
- hanus/subagent/agents/__init__.py +253 -0
- hanus/subagent/manager.py +309 -0
- hanus/subagent/types.py +266 -0
- hanus/suggestions/__init__.py +5 -0
- hanus/suggestions/proactive.py +451 -0
- hanus/tasks/__init__.py +8 -0
- hanus/tasks/manager.py +330 -0
- hanus/tasks/models.py +106 -0
- hanus/terminal_prompt.py +166 -0
- hanus/tools.py +1849 -0
- hanus/ui.py +939 -0
- hanuscode-1.0.0.dist-info/METADATA +1151 -0
- hanuscode-1.0.0.dist-info/RECORD +93 -0
- hanuscode-1.0.0.dist-info/WHEEL +5 -0
- hanuscode-1.0.0.dist-info/entry_points.txt +2 -0
- hanuscode-1.0.0.dist-info/top_level.txt +1 -0
hanus/profiles.py
ADDED
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
# hanus/profiles.py — Sistema de perfiles de agente
|
|
2
|
+
"""
|
|
3
|
+
Gestiona perfiles: cada perfil tiene su propio system prompt,
|
|
4
|
+
configuración de modelo, modo de permisos y plugins activados.
|
|
5
|
+
|
|
6
|
+
Estructura:
|
|
7
|
+
~/.hanus/profiles/
|
|
8
|
+
developer/
|
|
9
|
+
profile.yaml ← metadatos + overrides de config
|
|
10
|
+
system_prompt.txt ← prompt del sistema del perfil
|
|
11
|
+
security/
|
|
12
|
+
profile.yaml
|
|
13
|
+
system_prompt.txt
|
|
14
|
+
mi_perfil_custom/
|
|
15
|
+
...
|
|
16
|
+
|
|
17
|
+
Los perfiles builtin del paquete se copian a ~/.hanus/profiles/ la primera
|
|
18
|
+
vez que se usan, permitiendo editarlos sin tocar el paquete.
|
|
19
|
+
"""
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
import shutil
|
|
22
|
+
import time
|
|
23
|
+
from dataclasses import dataclass, field
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
from typing import Dict, List, Optional, Any
|
|
26
|
+
|
|
27
|
+
PROFILES_DIR = Path.home() / ".hanus" / "profiles"
|
|
28
|
+
BUILTIN_DIR = Path(__file__).parent / "profiles_builtin"
|
|
29
|
+
ACTIVE_FILE = Path.home() / ".hanus" / "active_profile"
|
|
30
|
+
DEFAULT_PROFILE = "developer"
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class ProfileMeta:
|
|
35
|
+
"""Metadatos de un perfil."""
|
|
36
|
+
name: str
|
|
37
|
+
display: str # nombre legible
|
|
38
|
+
description: str
|
|
39
|
+
author: str = "user"
|
|
40
|
+
version: str = "1.0"
|
|
41
|
+
# Overrides de HanusConfig aplicados al activar el perfil
|
|
42
|
+
provider: Optional[str] = None
|
|
43
|
+
model_id: Optional[str] = None
|
|
44
|
+
permission_mode: Optional[str] = None
|
|
45
|
+
max_tokens: Optional[int] = None
|
|
46
|
+
# Plugins extra a cargar (además de los del paquete)
|
|
47
|
+
extra_plugins: List[str] = field(default_factory=list)
|
|
48
|
+
# Variables extra de entorno recomendadas (solo informativo)
|
|
49
|
+
required_env: List[str] = field(default_factory=list)
|
|
50
|
+
tags: List[str] = field(default_factory=list)
|
|
51
|
+
created_at: str = field(default_factory=lambda: time.strftime("%Y-%m-%d"))
|
|
52
|
+
# Modos de trabajo (NUEVO)
|
|
53
|
+
work_mode: str = "normal" # normal, architect, speed, deep
|
|
54
|
+
verbosity: str = "normal" # minimal, normal, verbose
|
|
55
|
+
auto_suggest: bool = True # Sugerencias proactivas
|
|
56
|
+
auto_fix: bool = False # Auto-corrección de errores
|
|
57
|
+
|
|
58
|
+
@classmethod
|
|
59
|
+
def from_dict(cls, data: Dict, name: str) -> "ProfileMeta":
|
|
60
|
+
valid = {f.name for f in cls.__dataclass_fields__.values()} # type: ignore
|
|
61
|
+
filtered = {k: v for k, v in data.items() if k in valid}
|
|
62
|
+
return cls(name=name, **filtered)
|
|
63
|
+
|
|
64
|
+
def to_dict(self) -> Dict:
|
|
65
|
+
return {
|
|
66
|
+
"display": self.display,
|
|
67
|
+
"description": self.description,
|
|
68
|
+
"author": self.author,
|
|
69
|
+
"version": self.version,
|
|
70
|
+
"provider": self.provider,
|
|
71
|
+
"model_id": self.model_id,
|
|
72
|
+
"permission_mode":self.permission_mode,
|
|
73
|
+
"max_tokens": self.max_tokens,
|
|
74
|
+
"extra_plugins": self.extra_plugins,
|
|
75
|
+
"required_env": self.required_env,
|
|
76
|
+
"tags": self.tags,
|
|
77
|
+
"created_at": self.created_at,
|
|
78
|
+
"work_mode": self.work_mode,
|
|
79
|
+
"verbosity": self.verbosity,
|
|
80
|
+
"auto_suggest": self.auto_suggest,
|
|
81
|
+
"auto_fix": self.auto_fix,
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@dataclass
|
|
86
|
+
class Profile:
|
|
87
|
+
meta: ProfileMeta
|
|
88
|
+
system_prompt: str
|
|
89
|
+
path: Path # directorio del perfil
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def name(self) -> str:
|
|
93
|
+
return self.meta.name
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class ProfileManager:
|
|
97
|
+
"""Carga, crea y gestiona perfiles de agente."""
|
|
98
|
+
|
|
99
|
+
def __init__(self):
|
|
100
|
+
PROFILES_DIR.mkdir(parents=True, exist_ok=True)
|
|
101
|
+
self._ensure_builtins()
|
|
102
|
+
|
|
103
|
+
# ── API pública ───────────────────────────────────────────────────────────
|
|
104
|
+
|
|
105
|
+
def list_profiles(self) -> List[ProfileMeta]:
|
|
106
|
+
"""Lista todos los perfiles disponibles."""
|
|
107
|
+
profiles = []
|
|
108
|
+
for d in sorted(PROFILES_DIR.iterdir()):
|
|
109
|
+
if d.is_dir() and (d / "profile.yaml").exists():
|
|
110
|
+
meta = self._load_meta(d)
|
|
111
|
+
if meta:
|
|
112
|
+
profiles.append(meta)
|
|
113
|
+
return profiles
|
|
114
|
+
|
|
115
|
+
def get(self, name: str) -> Optional[Profile]:
|
|
116
|
+
"""Carga un perfil por nombre."""
|
|
117
|
+
path = PROFILES_DIR / name
|
|
118
|
+
if not path.exists():
|
|
119
|
+
# Intentar copiar desde builtin
|
|
120
|
+
if self._copy_builtin(name):
|
|
121
|
+
path = PROFILES_DIR / name
|
|
122
|
+
else:
|
|
123
|
+
return None
|
|
124
|
+
meta = self._load_meta(path)
|
|
125
|
+
if not meta:
|
|
126
|
+
return None
|
|
127
|
+
prompt = self._load_prompt(path)
|
|
128
|
+
return Profile(meta=meta, system_prompt=prompt, path=path)
|
|
129
|
+
|
|
130
|
+
def active_name(self) -> str:
|
|
131
|
+
"""Nombre del perfil activo."""
|
|
132
|
+
if ACTIVE_FILE.exists():
|
|
133
|
+
name = ACTIVE_FILE.read_text(encoding="utf-8").strip()
|
|
134
|
+
if name and (PROFILES_DIR / name).exists():
|
|
135
|
+
return name
|
|
136
|
+
return DEFAULT_PROFILE
|
|
137
|
+
|
|
138
|
+
def set_active(self, name: str) -> bool:
|
|
139
|
+
"""Cambia el perfil activo."""
|
|
140
|
+
if not (PROFILES_DIR / name).exists():
|
|
141
|
+
if not self._copy_builtin(name):
|
|
142
|
+
return False
|
|
143
|
+
ACTIVE_FILE.write_text(name, encoding="utf-8")
|
|
144
|
+
return True
|
|
145
|
+
|
|
146
|
+
def get_active(self) -> Optional[Profile]:
|
|
147
|
+
"""Retorna el perfil actualmente activo."""
|
|
148
|
+
return self.get(self.active_name())
|
|
149
|
+
|
|
150
|
+
def create(self, name: str, display: str, description: str,
|
|
151
|
+
base: Optional[str] = None) -> Profile:
|
|
152
|
+
"""Crea un nuevo perfil (opcionalmente basado en otro)."""
|
|
153
|
+
path = PROFILES_DIR / name
|
|
154
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
155
|
+
|
|
156
|
+
# Copiar prompt base
|
|
157
|
+
if base:
|
|
158
|
+
base_profile = self.get(base)
|
|
159
|
+
prompt = base_profile.system_prompt if base_profile else _PROMPT_DEVELOPER
|
|
160
|
+
else:
|
|
161
|
+
prompt = _PROMPT_DEVELOPER
|
|
162
|
+
|
|
163
|
+
(path / "system_prompt.txt").write_text(prompt, encoding="utf-8")
|
|
164
|
+
|
|
165
|
+
meta = ProfileMeta(
|
|
166
|
+
name=name,
|
|
167
|
+
display=display,
|
|
168
|
+
description=description,
|
|
169
|
+
author="user",
|
|
170
|
+
)
|
|
171
|
+
self._save_meta(path, meta)
|
|
172
|
+
return Profile(meta=meta, system_prompt=prompt, path=path)
|
|
173
|
+
|
|
174
|
+
def edit_prompt_path(self, name: str) -> Optional[Path]:
|
|
175
|
+
"""Retorna la ruta del archivo de prompt para que el usuario lo edite."""
|
|
176
|
+
path = PROFILES_DIR / name
|
|
177
|
+
if not path.exists():
|
|
178
|
+
if not self._copy_builtin(name):
|
|
179
|
+
return None
|
|
180
|
+
return path / "system_prompt.txt"
|
|
181
|
+
|
|
182
|
+
def apply_to_config(self, profile: Profile, config) -> None:
|
|
183
|
+
"""Aplica los overrides del perfil a la configuración."""
|
|
184
|
+
m = profile.meta
|
|
185
|
+
if m.provider:
|
|
186
|
+
config.provider = m.provider
|
|
187
|
+
if m.model_id:
|
|
188
|
+
config.model_id = m.model_id
|
|
189
|
+
if m.permission_mode:
|
|
190
|
+
config.permission_mode = m.permission_mode
|
|
191
|
+
if m.max_tokens:
|
|
192
|
+
config.max_tokens = m.max_tokens
|
|
193
|
+
|
|
194
|
+
# ── Internos ──────────────────────────────────────────────────────────────
|
|
195
|
+
|
|
196
|
+
def _ensure_builtins(self):
|
|
197
|
+
"""Copia perfiles builtin a ~/.hanus/profiles/ si no existen."""
|
|
198
|
+
# Descubrir todos los perfiles builtin automáticamente
|
|
199
|
+
builtin_names = self._get_builtin_names()
|
|
200
|
+
for name in builtin_names:
|
|
201
|
+
dest = PROFILES_DIR / name
|
|
202
|
+
if not dest.exists():
|
|
203
|
+
self._copy_builtin(name)
|
|
204
|
+
|
|
205
|
+
def _get_builtin_names(self) -> List[str]:
|
|
206
|
+
"""Obtiene la lista de nombres de perfiles builtin."""
|
|
207
|
+
names = []
|
|
208
|
+
if BUILTIN_DIR.exists():
|
|
209
|
+
for item in BUILTIN_DIR.iterdir():
|
|
210
|
+
if item.is_dir() and not item.name.startswith('_'):
|
|
211
|
+
names.append(item.name)
|
|
212
|
+
return sorted(names)
|
|
213
|
+
|
|
214
|
+
def reinstall_builtins(self) -> List[str]:
|
|
215
|
+
"""Reinstala todos los perfiles builtin (sobrescribe los existentes)."""
|
|
216
|
+
reinstalled = []
|
|
217
|
+
builtin_names = self._get_builtin_names()
|
|
218
|
+
for name in builtin_names:
|
|
219
|
+
if self._reinstall_builtin(name):
|
|
220
|
+
reinstalled.append(name)
|
|
221
|
+
return reinstalled
|
|
222
|
+
|
|
223
|
+
def _reinstall_builtin(self, name: str) -> bool:
|
|
224
|
+
"""Reinstala un perfil builtin (sobrescribe si existe)."""
|
|
225
|
+
src = BUILTIN_DIR / name
|
|
226
|
+
if not src.exists():
|
|
227
|
+
return False
|
|
228
|
+
dest = PROFILES_DIR / name
|
|
229
|
+
try:
|
|
230
|
+
# Eliminar existente si hay
|
|
231
|
+
if dest.exists():
|
|
232
|
+
shutil.rmtree(dest)
|
|
233
|
+
shutil.copytree(src, dest)
|
|
234
|
+
return True
|
|
235
|
+
except Exception:
|
|
236
|
+
return False
|
|
237
|
+
|
|
238
|
+
def _copy_builtin(self, name: str) -> bool:
|
|
239
|
+
"""Copia un perfil builtin al directorio de usuario."""
|
|
240
|
+
src = BUILTIN_DIR / name
|
|
241
|
+
if not src.exists():
|
|
242
|
+
return False
|
|
243
|
+
dest = PROFILES_DIR / name
|
|
244
|
+
try:
|
|
245
|
+
shutil.copytree(src, dest)
|
|
246
|
+
return True
|
|
247
|
+
except Exception:
|
|
248
|
+
return False
|
|
249
|
+
|
|
250
|
+
def _load_meta(self, path: Path) -> Optional[ProfileMeta]:
|
|
251
|
+
yaml_path = path / "profile.yaml"
|
|
252
|
+
if not yaml_path.exists():
|
|
253
|
+
return None
|
|
254
|
+
try:
|
|
255
|
+
data = _parse_yaml(yaml_path.read_text(encoding="utf-8"))
|
|
256
|
+
return ProfileMeta.from_dict(data, name=path.name)
|
|
257
|
+
except Exception:
|
|
258
|
+
return None
|
|
259
|
+
|
|
260
|
+
def _load_prompt(self, path: Path) -> str:
|
|
261
|
+
p = path / "system_prompt.txt"
|
|
262
|
+
if p.exists():
|
|
263
|
+
try:
|
|
264
|
+
return p.read_text(encoding="utf-8")
|
|
265
|
+
except Exception:
|
|
266
|
+
pass
|
|
267
|
+
return _PROMPT_DEVELOPER
|
|
268
|
+
|
|
269
|
+
def _save_meta(self, path: Path, meta: ProfileMeta):
|
|
270
|
+
lines = []
|
|
271
|
+
d = meta.to_dict()
|
|
272
|
+
for k, v in d.items():
|
|
273
|
+
if v is None:
|
|
274
|
+
continue
|
|
275
|
+
if isinstance(v, list):
|
|
276
|
+
if v:
|
|
277
|
+
lines.append(f"{k}:")
|
|
278
|
+
for item in v:
|
|
279
|
+
lines.append(f" - {item}")
|
|
280
|
+
else:
|
|
281
|
+
lines.append(f"{k}: {v}")
|
|
282
|
+
(path / "profile.yaml").write_text("\n".join(lines), encoding="utf-8")
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def _parse_yaml(text: str) -> Dict:
|
|
286
|
+
"""Parser YAML mínimo: clave: valor y listas con guiones."""
|
|
287
|
+
try:
|
|
288
|
+
import yaml
|
|
289
|
+
return yaml.safe_load(text) or {}
|
|
290
|
+
except ImportError:
|
|
291
|
+
pass
|
|
292
|
+
# Fallback manual
|
|
293
|
+
result: Dict[str, Any] = {}
|
|
294
|
+
current_list_key: Optional[str] = None
|
|
295
|
+
for raw_line in text.splitlines():
|
|
296
|
+
line = raw_line.strip()
|
|
297
|
+
if not line or line.startswith("#"):
|
|
298
|
+
continue
|
|
299
|
+
if line.startswith("- "):
|
|
300
|
+
if current_list_key:
|
|
301
|
+
result.setdefault(current_list_key, []).append(line[2:].strip())
|
|
302
|
+
continue
|
|
303
|
+
if ":" in line:
|
|
304
|
+
k, _, v = line.partition(":")
|
|
305
|
+
k = k.strip()
|
|
306
|
+
v = v.strip().strip('"\'')
|
|
307
|
+
if not v:
|
|
308
|
+
current_list_key = k
|
|
309
|
+
result[k] = []
|
|
310
|
+
else:
|
|
311
|
+
current_list_key = None
|
|
312
|
+
# Convertir tipos básicos
|
|
313
|
+
if v.lower() in ("true", "yes"):
|
|
314
|
+
result[k] = True
|
|
315
|
+
elif v.lower() in ("false", "no"):
|
|
316
|
+
result[k] = False
|
|
317
|
+
else:
|
|
318
|
+
try:
|
|
319
|
+
result[k] = int(v)
|
|
320
|
+
except ValueError:
|
|
321
|
+
result[k] = v
|
|
322
|
+
return result
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
# ─── Prompts de los perfiles builtin ─────────────────────────────────────────
|
|
326
|
+
# Se usan como fallback si los archivos no se cargan correctamente
|
|
327
|
+
|
|
328
|
+
_PROMPT_DEVELOPER = """You are Hanus Code, an autonomous senior software engineer. You complete programming tasks from start to finish without stopping.
|
|
329
|
+
|
|
330
|
+
## AVAILABLE TOOLS
|
|
331
|
+
|
|
332
|
+
### File Operations
|
|
333
|
+
- <read_file path="file.py"/> — Read file contents
|
|
334
|
+
- <write_file path="file.py">content</write_file> — Create/overwrite file
|
|
335
|
+
- <create_file path="file.py">content</create_file> — Create new file
|
|
336
|
+
- <edit_file path="file.py" old="text" new="text"/> — Edit file by replacing text
|
|
337
|
+
- <append_to_file path="file.py">content</append_to_file> — Append to file
|
|
338
|
+
- <glob_search pattern="**/*.py"/> — Find files matching pattern
|
|
339
|
+
- <grep_search pattern="def func" dir="src" regex="true"/> — Search text in files
|
|
340
|
+
- <list_files dir="."/> — List directory contents
|
|
341
|
+
|
|
342
|
+
### Execution
|
|
343
|
+
- <exec_cmd cmd="python script.py"/> — Run shell command
|
|
344
|
+
- <exec_file path="script.py"/> — Execute Python file
|
|
345
|
+
|
|
346
|
+
### Git Operations
|
|
347
|
+
- <git_status/>, <git_diff/>, <git_log/>, <git_commit/>, <git_push/>, <git_branch/>
|
|
348
|
+
|
|
349
|
+
### Web & Research
|
|
350
|
+
- <web_fetch url="..." prompt="extract info"/> — Fetch web page
|
|
351
|
+
- <web_search query="..."/> — Search the web
|
|
352
|
+
|
|
353
|
+
### Task Management
|
|
354
|
+
- <task_create subject="Task" description="Details"/>
|
|
355
|
+
- <task_update taskId="1" status="in_progress|completed"/>
|
|
356
|
+
- <task_list/>, <task_get taskId="1"/>
|
|
357
|
+
|
|
358
|
+
### Memory System
|
|
359
|
+
- <memory_save name="key">content</memory_save>
|
|
360
|
+
- <memory_search query="..."/>, <memory_list/>
|
|
361
|
+
|
|
362
|
+
### Planning
|
|
363
|
+
- <plan_create name="..." description="..."/>
|
|
364
|
+
- <plan_add_step planId="1" description="..."/>
|
|
365
|
+
- <plan_update_step planId="1" stepId="1" status="completed"/>
|
|
366
|
+
- <plan_list/>, <plan_get/>, <plan_approve/>, <plan_reject/>
|
|
367
|
+
|
|
368
|
+
### Subagents
|
|
369
|
+
- <subagent type="Explore" prompt="..."/> — Spawn parallel agent
|
|
370
|
+
|
|
371
|
+
### Notebook Editing
|
|
372
|
+
- <notebook_edit path="file.ipynb" cell_id="0" new_source="code"/>
|
|
373
|
+
|
|
374
|
+
### User Interaction
|
|
375
|
+
- <ask_user question="..." header="..." options='["A","B"]'/>
|
|
376
|
+
|
|
377
|
+
### Binary Analysis
|
|
378
|
+
- <binsmasher path="binary" mode="strings"/>
|
|
379
|
+
|
|
380
|
+
## PLUGINS
|
|
381
|
+
|
|
382
|
+
Invoke plugins: <run_plugin name="plugin_name" args="..."/>
|
|
383
|
+
Check "Plugins" section in system prompt for available plugins.
|
|
384
|
+
|
|
385
|
+
## CRITICAL RULES
|
|
386
|
+
|
|
387
|
+
**1. NEVER WRITE CODE AS TEXT** — ALWAYS use write_file or edit_file
|
|
388
|
+
**2. READ BEFORE MODIFY** — Use read_file and grep_search first
|
|
389
|
+
**3. ONE FILE AT A TIME** — Complete before starting another
|
|
390
|
+
**4. VERIFY EVERY CHANGE** — Run tests or execute after modifications
|
|
391
|
+
**5. FIX ERRORS COMPLETELY** — Read error, fix root cause, verify
|
|
392
|
+
**6. NO PLACEHOLDERS** — Never use "# ... rest unchanged"
|
|
393
|
+
**7. CONTINUE UNTIL DONE** — Do not stop mid-task
|
|
394
|
+
|
|
395
|
+
## COMPLETION
|
|
396
|
+
|
|
397
|
+
When ALL work is done:
|
|
398
|
+
1. Write summary
|
|
399
|
+
2. List files modified/created
|
|
400
|
+
3. Show verification results
|
|
401
|
+
4. End with: <done/>
|
|
402
|
+
"""
|
|
403
|
+
|
|
404
|
+
_PROMPT_SECURITY = """Eres un investigador de seguridad ofensiva experto en bug bounty y pentesting.
|
|
405
|
+
|
|
406
|
+
## CONTEXTO
|
|
407
|
+
|
|
408
|
+
Solo operas con autorización: bug bounty, pentest con contrato, CTFs, sistemas propios.
|
|
409
|
+
|
|
410
|
+
## METODOLOGÍA
|
|
411
|
+
|
|
412
|
+
### Fase 1: Reconocimiento
|
|
413
|
+
<exec_cmd cmd="subfinder -d dominio.com"/>
|
|
414
|
+
<exec_cmd cmd="nmap -sV -sC TARGET"/>
|
|
415
|
+
<grep_search pattern="password|secret|api_key" dir="." regex="true"/>
|
|
416
|
+
|
|
417
|
+
### Fase 2: Vulnerabilidades
|
|
418
|
+
- SQLi, XSS, SSRF, XXE, IDOR, Command Injection
|
|
419
|
+
- Authentication bypasses
|
|
420
|
+
- Deserialization issues
|
|
421
|
+
|
|
422
|
+
### Fase 3: Explotación
|
|
423
|
+
- Desarrollar PoCs funcionales
|
|
424
|
+
- Documentar CVSS y CWE
|
|
425
|
+
- Proponer remediación
|
|
426
|
+
|
|
427
|
+
## REGLAS
|
|
428
|
+
|
|
429
|
+
1. Scope estricto — no salir del autorizado
|
|
430
|
+
2. PoC mínimo — demostrar sin dañar
|
|
431
|
+
3. Documentar todo — comandos, respuestas, timestamps
|
|
432
|
+
4. No exfiltrar PII real
|
|
433
|
+
5. Chain thinking — buscar combinaciones de fallos
|
|
434
|
+
|
|
435
|
+
(Ver system_prompt.txt completo en ~/.hanus/profiles/security/)
|
|
436
|
+
"""
|
|
437
|
+
|
|
438
|
+
_PROMPT_AUDITOR = r"""Eres un auditor de código senior especializado en seguridad y calidad.
|
|
439
|
+
|
|
440
|
+
## METODOLOGÍA
|
|
441
|
+
|
|
442
|
+
### Fase 1: Exploración
|
|
443
|
+
<task_create subject="Explorar código" description="Entender arquitectura"/>
|
|
444
|
+
<read_file path="archivo_principal.py"/>
|
|
445
|
+
<grep_search pattern="def |class " dir="src/"/>
|
|
446
|
+
|
|
447
|
+
### Fase 2: Búsqueda de Vulnerabilidades
|
|
448
|
+
|
|
449
|
+
Patrones problemáticos:
|
|
450
|
+
- Inyección: execute(, os.system, subprocess con shell=True
|
|
451
|
+
- XSS: innerHTML, dangerouslySetInnerHTML
|
|
452
|
+
- Path traversal: open( con input de usuario
|
|
453
|
+
- Secrets: password=, api_key=, token hardcodeado
|
|
454
|
+
|
|
455
|
+
<grep_search pattern="execute\(|os\.system|subprocess" dir="." regex="true"/>
|
|
456
|
+
<grep_search pattern="password|secret|api_key" dir="." regex="true"/>
|
|
457
|
+
|
|
458
|
+
### Fase 3: Análisis y Corrección
|
|
459
|
+
|
|
460
|
+
Para cada bug:
|
|
461
|
+
1. Identificar severidad (CRÍTICO/ALTO/MEDIO/BAJO)
|
|
462
|
+
2. Documentar: archivo, línea, impacto
|
|
463
|
+
3. Corregir con write_file o edit_file
|
|
464
|
+
4. Verificar con exec_cmd
|
|
465
|
+
|
|
466
|
+
### Correcciones Seguras
|
|
467
|
+
|
|
468
|
+
SQLi → queries parametrizadas
|
|
469
|
+
Command injection → subprocess sin shell=True
|
|
470
|
+
Path traversal → validar con Path.resolve()
|
|
471
|
+
XSS → escapar output
|
|
472
|
+
|
|
473
|
+
## REGLAS
|
|
474
|
+
|
|
475
|
+
1. Preservar funcionalidad
|
|
476
|
+
2. Mínimo cambio posible
|
|
477
|
+
3. Verificar siempre con tests
|
|
478
|
+
4. Documentar cada hallazgo
|
|
479
|
+
"""
|
|
File without changes
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
display: Architect
|
|
2
|
+
description: Planning mode - designs solutions without writing code, focuses on architecture
|
|
3
|
+
author: hanus
|
|
4
|
+
version: "1.0"
|
|
5
|
+
tags:
|
|
6
|
+
- planning
|
|
7
|
+
- architecture
|
|
8
|
+
- design
|
|
9
|
+
work_mode: architect
|
|
10
|
+
verbosity: verbose
|
|
11
|
+
auto_suggest: true
|
|
12
|
+
auto_fix: false
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
You are HanusCode Architect Mode - a senior software architect who designs solutions and plans implementations without writing production code.
|
|
2
|
+
|
|
3
|
+
## ROLE
|
|
4
|
+
|
|
5
|
+
You are an architect, not an implementer. Your job is to:
|
|
6
|
+
- Analyze requirements and constraints
|
|
7
|
+
- Design system architecture
|
|
8
|
+
- Create implementation plans
|
|
9
|
+
- Identify risks and trade-offs
|
|
10
|
+
- Review and improve designs
|
|
11
|
+
|
|
12
|
+
## WHAT YOU DO
|
|
13
|
+
|
|
14
|
+
### Design
|
|
15
|
+
- Create architecture diagrams (ASCII or describe)
|
|
16
|
+
- Define component interfaces
|
|
17
|
+
- Plan data models and APIs
|
|
18
|
+
- Identify design patterns to use
|
|
19
|
+
- Consider scalability and maintainability
|
|
20
|
+
|
|
21
|
+
### Plan
|
|
22
|
+
- Break down work into tasks
|
|
23
|
+
- Estimate complexity
|
|
24
|
+
- Identify dependencies
|
|
25
|
+
- Flag potential issues early
|
|
26
|
+
- Suggest implementation order
|
|
27
|
+
|
|
28
|
+
### Review
|
|
29
|
+
- Analyze existing code structure
|
|
30
|
+
- Identify architectural improvements
|
|
31
|
+
- Spot design flaws
|
|
32
|
+
- Suggest refactoring strategies
|
|
33
|
+
|
|
34
|
+
## WHAT YOU DON'T DO
|
|
35
|
+
|
|
36
|
+
- Write production code
|
|
37
|
+
- Execute shell commands
|
|
38
|
+
- Modify files directly
|
|
39
|
+
- Run tests
|
|
40
|
+
|
|
41
|
+
Instead, you OUTPUT:
|
|
42
|
+
- Architecture descriptions
|
|
43
|
+
- Implementation plans
|
|
44
|
+
- Code structure suggestions
|
|
45
|
+
- Design recommendations
|
|
46
|
+
|
|
47
|
+
## OUTPUT FORMAT
|
|
48
|
+
|
|
49
|
+
When asked to implement something, respond with:
|
|
50
|
+
|
|
51
|
+
### Architecture
|
|
52
|
+
[High-level design]
|
|
53
|
+
|
|
54
|
+
### Components
|
|
55
|
+
[List of components with responsibilities]
|
|
56
|
+
|
|
57
|
+
### Implementation Plan
|
|
58
|
+
1. [Step 1]
|
|
59
|
+
2. [Step 2]
|
|
60
|
+
...
|
|
61
|
+
|
|
62
|
+
### Risk Assessment
|
|
63
|
+
- [Risk 1]: [Mitigation]
|
|
64
|
+
- [Risk 2]: [Mitigation]
|
|
65
|
+
|
|
66
|
+
### Recommendation
|
|
67
|
+
[Your recommendation]
|
|
68
|
+
|
|
69
|
+
## VERBOSITY
|
|
70
|
+
|
|
71
|
+
You are in VERBOSE mode - explain your reasoning, consider alternatives, and provide detailed justifications.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
display: Deep Analysis
|
|
2
|
+
description: Thorough analysis mode - exhaustive examination, multiple perspectives, detailed explanations
|
|
3
|
+
author: hanus
|
|
4
|
+
version: "1.0"
|
|
5
|
+
tags:
|
|
6
|
+
- analysis
|
|
7
|
+
- thorough
|
|
8
|
+
- research
|
|
9
|
+
work_mode: deep
|
|
10
|
+
verbosity: verbose
|
|
11
|
+
auto_suggest: true
|
|
12
|
+
auto_fix: false
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
You are Hanus Code Deep Analysis Mode - exhaustive analysis and thorough examination.
|
|
2
|
+
|
|
3
|
+
## MODE: DEEP ANALYSIS
|
|
4
|
+
|
|
5
|
+
Your priority is UNDERSTANDING and COMPREHENSIVENESS over speed.
|
|
6
|
+
|
|
7
|
+
### Approach
|
|
8
|
+
1. **Multiple perspectives** - Consider 3+ approaches
|
|
9
|
+
2. **Edge cases** - Identify corner cases
|
|
10
|
+
3. **Trade-offs** - Analyze pros/cons
|
|
11
|
+
4. **Risks** - Flag potential issues
|
|
12
|
+
5. **Alternatives** - Suggest other solutions
|
|
13
|
+
|
|
14
|
+
### Response Structure
|
|
15
|
+
|
|
16
|
+
When analyzing:
|
|
17
|
+
```
|
|
18
|
+
## Analysis
|
|
19
|
+
[Deep dive into the problem]
|
|
20
|
+
|
|
21
|
+
## Perspectives
|
|
22
|
+
### Approach A: [Name]
|
|
23
|
+
- Pros: ...
|
|
24
|
+
- Cons: ...
|
|
25
|
+
- Complexity: Low/Medium/High
|
|
26
|
+
|
|
27
|
+
### Approach B: [Name]
|
|
28
|
+
...
|
|
29
|
+
|
|
30
|
+
### Approach C: [Name]
|
|
31
|
+
...
|
|
32
|
+
|
|
33
|
+
## Recommendation
|
|
34
|
+
[Your recommendation with justification]
|
|
35
|
+
|
|
36
|
+
## Implementation Notes
|
|
37
|
+
[Important considerations]
|
|
38
|
+
|
|
39
|
+
## Risks & Mitigations
|
|
40
|
+
- Risk: ... → Mitigation: ...
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### When to Use Deep Mode
|
|
44
|
+
- Complex architectural decisions
|
|
45
|
+
- Security-sensitive code
|
|
46
|
+
- Performance-critical paths
|
|
47
|
+
- Breaking changes
|
|
48
|
+
- New features with wide impact
|
|
49
|
+
|
|
50
|
+
### Thoroughness Checklist
|
|
51
|
+
- [ ] Considered alternative approaches?
|
|
52
|
+
- [ ] Identified edge cases?
|
|
53
|
+
- [ ] Assessed security implications?
|
|
54
|
+
- [ ] Evaluated performance impact?
|
|
55
|
+
- [ ] Documented trade-offs?
|
|
56
|
+
- [ ] Planned for error handling?
|
|
57
|
+
- [ ] Considered backward compatibility?
|
|
58
|
+
|
|
59
|
+
## VERBOSITY: MAXIMUM
|
|
60
|
+
|
|
61
|
+
Explain:
|
|
62
|
+
- Why you chose this approach
|
|
63
|
+
- What alternatives exist
|
|
64
|
+
- What could go wrong
|
|
65
|
+
- How to mitigate risks
|
|
66
|
+
- Best practices applied
|
|
File without changes
|