minion-code 0.1.0__py3-none-any.whl → 0.1.1__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.
- examples/cli_entrypoint.py +60 -0
- examples/{agent_with_todos.py → components/agent_with_todos.py} +58 -47
- examples/{message_response_children_demo.py → components/message_response_children_demo.py} +61 -55
- examples/components/messages_component.py +199 -0
- examples/file_freshness_example.py +22 -22
- examples/file_watching_example.py +32 -26
- examples/interruptible_tui.py +921 -3
- examples/repl_tui.py +129 -0
- examples/skills/example_usage.py +57 -0
- examples/start.py +173 -0
- minion_code/__init__.py +1 -1
- minion_code/acp_server/__init__.py +34 -0
- minion_code/acp_server/agent.py +539 -0
- minion_code/acp_server/hooks.py +354 -0
- minion_code/acp_server/main.py +194 -0
- minion_code/acp_server/permissions.py +142 -0
- minion_code/acp_server/test_client.py +104 -0
- minion_code/adapters/__init__.py +22 -0
- minion_code/adapters/output_adapter.py +207 -0
- minion_code/adapters/rich_adapter.py +169 -0
- minion_code/adapters/textual_adapter.py +254 -0
- minion_code/agents/__init__.py +2 -2
- minion_code/agents/code_agent.py +517 -104
- minion_code/agents/hooks.py +378 -0
- minion_code/cli.py +538 -429
- minion_code/cli_simple.py +665 -0
- minion_code/commands/__init__.py +136 -29
- minion_code/commands/clear_command.py +19 -46
- minion_code/commands/help_command.py +33 -49
- minion_code/commands/history_command.py +37 -55
- minion_code/commands/model_command.py +194 -0
- minion_code/commands/quit_command.py +9 -12
- minion_code/commands/resume_command.py +181 -0
- minion_code/commands/skill_command.py +89 -0
- minion_code/commands/status_command.py +48 -73
- minion_code/commands/tools_command.py +54 -52
- minion_code/commands/version_command.py +34 -69
- minion_code/components/ConfirmDialog.py +430 -0
- minion_code/components/Message.py +318 -97
- minion_code/components/MessageResponse.py +30 -29
- minion_code/components/Messages.py +351 -0
- minion_code/components/PromptInput.py +499 -245
- minion_code/components/__init__.py +24 -17
- minion_code/const.py +7 -0
- minion_code/screens/REPL.py +1453 -469
- minion_code/screens/__init__.py +1 -1
- minion_code/services/__init__.py +20 -20
- minion_code/services/event_system.py +19 -14
- minion_code/services/file_freshness_service.py +223 -170
- minion_code/skills/__init__.py +25 -0
- minion_code/skills/skill.py +128 -0
- minion_code/skills/skill_loader.py +198 -0
- minion_code/skills/skill_registry.py +177 -0
- minion_code/subagents/__init__.py +31 -0
- minion_code/subagents/builtin/__init__.py +30 -0
- minion_code/subagents/builtin/claude_code_guide.py +32 -0
- minion_code/subagents/builtin/explore.py +36 -0
- minion_code/subagents/builtin/general_purpose.py +19 -0
- minion_code/subagents/builtin/plan.py +61 -0
- minion_code/subagents/subagent.py +116 -0
- minion_code/subagents/subagent_loader.py +147 -0
- minion_code/subagents/subagent_registry.py +151 -0
- minion_code/tools/__init__.py +8 -2
- minion_code/tools/bash_tool.py +16 -3
- minion_code/tools/file_edit_tool.py +201 -104
- minion_code/tools/file_read_tool.py +183 -26
- minion_code/tools/file_write_tool.py +17 -3
- minion_code/tools/glob_tool.py +23 -2
- minion_code/tools/grep_tool.py +229 -21
- minion_code/tools/ls_tool.py +28 -3
- minion_code/tools/multi_edit_tool.py +89 -84
- minion_code/tools/python_interpreter_tool.py +9 -1
- minion_code/tools/skill_tool.py +210 -0
- minion_code/tools/task_tool.py +287 -0
- minion_code/tools/todo_read_tool.py +28 -24
- minion_code/tools/todo_write_tool.py +82 -65
- minion_code/{types.py → type_defs.py} +15 -2
- minion_code/utils/__init__.py +45 -17
- minion_code/utils/config.py +610 -0
- minion_code/utils/history.py +114 -0
- minion_code/utils/logs.py +53 -0
- minion_code/utils/mcp_loader.py +153 -55
- minion_code/utils/output_truncator.py +233 -0
- minion_code/utils/session_storage.py +369 -0
- minion_code/utils/todo_file_utils.py +26 -22
- minion_code/utils/todo_storage.py +43 -33
- minion_code/web/__init__.py +9 -0
- minion_code/web/adapters/__init__.py +5 -0
- minion_code/web/adapters/web_adapter.py +524 -0
- minion_code/web/api/__init__.py +7 -0
- minion_code/web/api/chat.py +277 -0
- minion_code/web/api/interactions.py +136 -0
- minion_code/web/api/sessions.py +135 -0
- minion_code/web/server.py +149 -0
- minion_code/web/services/__init__.py +5 -0
- minion_code/web/services/session_manager.py +420 -0
- minion_code-0.1.1.dist-info/METADATA +475 -0
- minion_code-0.1.1.dist-info/RECORD +111 -0
- {minion_code-0.1.0.dist-info → minion_code-0.1.1.dist-info}/WHEEL +1 -1
- minion_code-0.1.1.dist-info/entry_points.txt +6 -0
- tests/test_adapter.py +67 -0
- tests/test_adapter_simple.py +79 -0
- tests/test_file_read_tool.py +144 -0
- tests/test_readonly_tools.py +0 -2
- tests/test_skills.py +441 -0
- examples/advance_tui.py +0 -508
- examples/rich_example.py +0 -4
- examples/simple_file_watching.py +0 -57
- examples/simple_tui.py +0 -267
- examples/simple_usage.py +0 -69
- minion_code-0.1.0.dist-info/METADATA +0 -350
- minion_code-0.1.0.dist-info/RECORD +0 -59
- minion_code-0.1.0.dist-info/entry_points.txt +0 -4
- {minion_code-0.1.0.dist-info → minion_code-0.1.1.dist-info}/licenses/LICENSE +0 -0
- {minion_code-0.1.0.dist-info → minion_code-0.1.1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Hook system for MinionCodeAgent.
|
|
5
|
+
|
|
6
|
+
Re-exports base hooks from minion framework and provides
|
|
7
|
+
minion-code specific hook implementations.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import logging
|
|
11
|
+
from typing import Any, Dict, List, Optional, Union, Callable, Set
|
|
12
|
+
|
|
13
|
+
# Re-export base types from minion framework
|
|
14
|
+
from minion.main.tool_hooks import (
|
|
15
|
+
PermissionDecision,
|
|
16
|
+
PreToolUseResult,
|
|
17
|
+
PostToolUseResult,
|
|
18
|
+
ToolCallInfo,
|
|
19
|
+
PreToolUseHook,
|
|
20
|
+
PostToolUseHook,
|
|
21
|
+
HookMatcher,
|
|
22
|
+
PostHookMatcher,
|
|
23
|
+
HookConfig,
|
|
24
|
+
ToolHooks,
|
|
25
|
+
NoOpToolHooks,
|
|
26
|
+
HookedTool,
|
|
27
|
+
wrap_tools_with_hooks,
|
|
28
|
+
create_auto_accept_hook,
|
|
29
|
+
create_auto_deny_hook,
|
|
30
|
+
create_dangerous_command_check_hook,
|
|
31
|
+
create_logging_hook,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
logger = logging.getLogger(__name__)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# ============================================================================
|
|
38
|
+
# Spinner Controller for CLI
|
|
39
|
+
# ============================================================================
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class SpinnerController:
|
|
43
|
+
"""
|
|
44
|
+
Controller to pause/resume spinners during user prompts.
|
|
45
|
+
|
|
46
|
+
Usage:
|
|
47
|
+
controller = SpinnerController()
|
|
48
|
+
hook = create_cli_confirm_hook(spinner_controller=controller)
|
|
49
|
+
|
|
50
|
+
# In your main loop:
|
|
51
|
+
with Progress(...) as progress:
|
|
52
|
+
controller.set_progress(progress)
|
|
53
|
+
# ... run agent ...
|
|
54
|
+
controller.clear_progress()
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
def __init__(self):
|
|
58
|
+
self._progress = None
|
|
59
|
+
self._is_paused = False
|
|
60
|
+
|
|
61
|
+
def set_progress(self, progress: Any) -> None:
|
|
62
|
+
"""Set the current Progress instance."""
|
|
63
|
+
self._progress = progress
|
|
64
|
+
self._is_paused = False
|
|
65
|
+
|
|
66
|
+
def clear_progress(self) -> None:
|
|
67
|
+
"""Clear the current Progress instance."""
|
|
68
|
+
self._progress = None
|
|
69
|
+
self._is_paused = False
|
|
70
|
+
|
|
71
|
+
def pause(self) -> None:
|
|
72
|
+
"""Pause the spinner (stop the progress display)."""
|
|
73
|
+
if self._progress and not self._is_paused:
|
|
74
|
+
try:
|
|
75
|
+
self._progress.stop()
|
|
76
|
+
self._is_paused = True
|
|
77
|
+
except Exception as e:
|
|
78
|
+
logger.debug(f"Failed to pause spinner: {e}")
|
|
79
|
+
|
|
80
|
+
def resume(self) -> None:
|
|
81
|
+
"""Resume the spinner (start the progress display)."""
|
|
82
|
+
if self._progress and self._is_paused:
|
|
83
|
+
try:
|
|
84
|
+
self._progress.start()
|
|
85
|
+
self._is_paused = False
|
|
86
|
+
except Exception as e:
|
|
87
|
+
logger.debug(f"Failed to resume spinner: {e}")
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
# ============================================================================
|
|
91
|
+
# minion-code Specific Hook Implementations
|
|
92
|
+
# ============================================================================
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _format_tool_input(tool_name: str, tool_input: Dict[str, Any]) -> str:
|
|
96
|
+
"""Format tool input for display in confirmation dialog."""
|
|
97
|
+
if tool_name == "bash":
|
|
98
|
+
return f"Command: {tool_input.get('command', '')}"
|
|
99
|
+
|
|
100
|
+
if tool_name in ("file_write", "file_edit"):
|
|
101
|
+
path = tool_input.get("file_path", tool_input.get("path", ""))
|
|
102
|
+
return f"File: {path}"
|
|
103
|
+
|
|
104
|
+
if tool_name == "file_read":
|
|
105
|
+
return f"File: {tool_input.get('file_path', '')}"
|
|
106
|
+
|
|
107
|
+
if tool_name == "Task":
|
|
108
|
+
desc = tool_input.get("description", "")
|
|
109
|
+
prompt = tool_input.get("prompt", "")
|
|
110
|
+
subagent = tool_input.get("subagent_type", "general-purpose")
|
|
111
|
+
# Truncate prompt if too long
|
|
112
|
+
if len(prompt) > 200:
|
|
113
|
+
prompt = prompt[:200] + "..."
|
|
114
|
+
return f"Subagent: {subagent}\nDescription: {desc}\nPrompt: {prompt}"
|
|
115
|
+
|
|
116
|
+
# Default: show all parameters (excluding internal ones like 'state')
|
|
117
|
+
parts = []
|
|
118
|
+
skip_keys = {"state"} # Internal parameters to hide
|
|
119
|
+
for key, value in tool_input.items():
|
|
120
|
+
if key in skip_keys:
|
|
121
|
+
continue
|
|
122
|
+
if isinstance(value, str) and len(value) > 100:
|
|
123
|
+
value = value[:100] + "..."
|
|
124
|
+
parts.append(f"{key}: {value}")
|
|
125
|
+
|
|
126
|
+
return "\n".join(parts) if parts else "(no parameters)"
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def create_confirm_writes_hook(
|
|
130
|
+
adapter: Any, # OutputAdapter
|
|
131
|
+
tools_registry: Optional[Dict[str, Any]] = None,
|
|
132
|
+
skip_readonly: bool = True,
|
|
133
|
+
) -> PreToolUseHook:
|
|
134
|
+
"""
|
|
135
|
+
Create a hook that requests user confirmation for non-readonly tools.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
adapter: OutputAdapter instance with confirm() method
|
|
139
|
+
tools_registry: Optional dict mapping tool names to tool instances
|
|
140
|
+
skip_readonly: If True, auto-accept readonly tools without confirmation
|
|
141
|
+
"""
|
|
142
|
+
|
|
143
|
+
async def confirm_writes(
|
|
144
|
+
tool_name: str, tool_input: Dict[str, Any], tool_use_id: str
|
|
145
|
+
) -> PreToolUseResult:
|
|
146
|
+
# Skip readonly tools
|
|
147
|
+
if skip_readonly:
|
|
148
|
+
# Known readonly tools (hardcoded list)
|
|
149
|
+
# Task is readonly because subagents have their own permission control
|
|
150
|
+
readonly_tools = {
|
|
151
|
+
"file_read",
|
|
152
|
+
"glob",
|
|
153
|
+
"grep",
|
|
154
|
+
"ls",
|
|
155
|
+
"web_fetch",
|
|
156
|
+
"web_search",
|
|
157
|
+
"todo_read",
|
|
158
|
+
"Task",
|
|
159
|
+
}
|
|
160
|
+
if tool_name in readonly_tools:
|
|
161
|
+
return PreToolUseResult(decision=PermissionDecision.ACCEPT)
|
|
162
|
+
|
|
163
|
+
# Check if tool is readonly from registry
|
|
164
|
+
if tools_registry:
|
|
165
|
+
tool = tools_registry.get(tool_name)
|
|
166
|
+
if tool and getattr(tool, "readonly", False):
|
|
167
|
+
return PreToolUseResult(decision=PermissionDecision.ACCEPT)
|
|
168
|
+
|
|
169
|
+
# Format tool input for display
|
|
170
|
+
input_summary = _format_tool_input(tool_name, tool_input)
|
|
171
|
+
|
|
172
|
+
# Request confirmation
|
|
173
|
+
try:
|
|
174
|
+
confirmed = await adapter.confirm(
|
|
175
|
+
message=f"Allow {tool_name}?\n{input_summary}",
|
|
176
|
+
title="Tool Permission",
|
|
177
|
+
resource_type="tool",
|
|
178
|
+
resource_name=tool_name,
|
|
179
|
+
resource_args=tool_input,
|
|
180
|
+
)
|
|
181
|
+
except Exception as e:
|
|
182
|
+
logger.error(f"Error during confirmation: {e}")
|
|
183
|
+
return PreToolUseResult(
|
|
184
|
+
decision=PermissionDecision.DENY, reason=f"Confirmation error: {e}"
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
if confirmed:
|
|
188
|
+
return PreToolUseResult(decision=PermissionDecision.ACCEPT)
|
|
189
|
+
else:
|
|
190
|
+
return PreToolUseResult(
|
|
191
|
+
decision=PermissionDecision.DENY, reason="User denied permission"
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
return confirm_writes
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def create_cli_confirm_hook(
|
|
198
|
+
allowed_tools: Optional[Set[str]] = None,
|
|
199
|
+
session_allowed: Optional[Set[str]] = None,
|
|
200
|
+
console: Optional[Any] = None,
|
|
201
|
+
spinner_controller: Optional[SpinnerController] = None,
|
|
202
|
+
) -> PreToolUseHook:
|
|
203
|
+
"""
|
|
204
|
+
Create a hook that prompts for confirmation in CLI/terminal.
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
allowed_tools: Set of tool names that are always allowed (persistent)
|
|
208
|
+
session_allowed: Set of tool names allowed for this session only
|
|
209
|
+
console: Optional Rich Console for better formatting
|
|
210
|
+
spinner_controller: Optional SpinnerController to pause spinner during prompts
|
|
211
|
+
"""
|
|
212
|
+
if allowed_tools is None:
|
|
213
|
+
allowed_tools = set()
|
|
214
|
+
if session_allowed is None:
|
|
215
|
+
session_allowed = set()
|
|
216
|
+
|
|
217
|
+
# Task is readonly because subagents have their own permission control
|
|
218
|
+
readonly_tools = {
|
|
219
|
+
"file_read",
|
|
220
|
+
"glob",
|
|
221
|
+
"grep",
|
|
222
|
+
"ls",
|
|
223
|
+
"web_fetch",
|
|
224
|
+
"web_search",
|
|
225
|
+
"todo_read",
|
|
226
|
+
"Task",
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
# Use Rich console if provided, otherwise create one
|
|
230
|
+
if console is None:
|
|
231
|
+
from rich.console import Console
|
|
232
|
+
|
|
233
|
+
console = Console()
|
|
234
|
+
|
|
235
|
+
async def cli_confirm(
|
|
236
|
+
tool_name: str, tool_input: Dict[str, Any], tool_use_id: str
|
|
237
|
+
) -> PreToolUseResult:
|
|
238
|
+
# Skip readonly tools
|
|
239
|
+
if tool_name in readonly_tools:
|
|
240
|
+
return PreToolUseResult(decision=PermissionDecision.ACCEPT)
|
|
241
|
+
|
|
242
|
+
if tool_name in allowed_tools or tool_name in session_allowed:
|
|
243
|
+
return PreToolUseResult(decision=PermissionDecision.ACCEPT)
|
|
244
|
+
|
|
245
|
+
input_summary = _format_tool_input(tool_name, tool_input)
|
|
246
|
+
|
|
247
|
+
# Pause spinner before prompting user
|
|
248
|
+
if spinner_controller:
|
|
249
|
+
spinner_controller.pause()
|
|
250
|
+
|
|
251
|
+
try:
|
|
252
|
+
# Use Rich console to print
|
|
253
|
+
console.print()
|
|
254
|
+
console.print(f"[bold yellow]{'='*60}[/]")
|
|
255
|
+
console.print(f"[bold cyan]🔧 Tool: {tool_name}[/]")
|
|
256
|
+
console.print(f"[bold yellow]{'='*60}[/]")
|
|
257
|
+
console.print(input_summary)
|
|
258
|
+
console.print(f"[bold yellow]{'='*60}[/]")
|
|
259
|
+
console.print("[dim]Options:[/]")
|
|
260
|
+
console.print(" [green][y][/] Yes, allow this once")
|
|
261
|
+
console.print(" [red][n][/] No, deny")
|
|
262
|
+
console.print(" [yellow][a][/] Always allow this tool (session)")
|
|
263
|
+
console.print(" [blue][A][/] Always allow this tool (permanent)")
|
|
264
|
+
|
|
265
|
+
try:
|
|
266
|
+
# Don't lowercase - we need to distinguish 'a' from 'A'
|
|
267
|
+
response = console.input("[bold]Allow? [y/n/a/A]: [/]").strip()
|
|
268
|
+
except (EOFError, KeyboardInterrupt):
|
|
269
|
+
return PreToolUseResult(
|
|
270
|
+
decision=PermissionDecision.DENY, reason="User cancelled"
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
if response.lower() == "y":
|
|
274
|
+
return PreToolUseResult(decision=PermissionDecision.ACCEPT)
|
|
275
|
+
elif response == "a": # Session allow (lowercase only)
|
|
276
|
+
session_allowed.add(tool_name)
|
|
277
|
+
logger.info(f"Tool '{tool_name}' allowed for this session")
|
|
278
|
+
return PreToolUseResult(decision=PermissionDecision.ACCEPT)
|
|
279
|
+
elif response == "A": # Permanent allow (uppercase only)
|
|
280
|
+
allowed_tools.add(tool_name)
|
|
281
|
+
logger.info(f"Tool '{tool_name}' permanently allowed")
|
|
282
|
+
return PreToolUseResult(decision=PermissionDecision.ACCEPT)
|
|
283
|
+
else:
|
|
284
|
+
return PreToolUseResult(
|
|
285
|
+
decision=PermissionDecision.DENY, reason="User denied permission"
|
|
286
|
+
)
|
|
287
|
+
finally:
|
|
288
|
+
# Resume spinner after user responds
|
|
289
|
+
if spinner_controller:
|
|
290
|
+
spinner_controller.resume()
|
|
291
|
+
|
|
292
|
+
return cli_confirm
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def create_cli_hooks(
|
|
296
|
+
auto_accept: bool = False,
|
|
297
|
+
spinner_controller: Optional[SpinnerController] = None,
|
|
298
|
+
console: Optional[Any] = None,
|
|
299
|
+
) -> HookConfig:
|
|
300
|
+
"""
|
|
301
|
+
Create hook configuration for CLI usage.
|
|
302
|
+
|
|
303
|
+
Args:
|
|
304
|
+
auto_accept: If True, auto-accept all tools (no confirmation prompts)
|
|
305
|
+
spinner_controller: Optional SpinnerController to pause spinner during prompts
|
|
306
|
+
console: Optional Rich Console for output
|
|
307
|
+
"""
|
|
308
|
+
if auto_accept:
|
|
309
|
+
return create_autonomous_hooks()
|
|
310
|
+
|
|
311
|
+
return HookConfig(
|
|
312
|
+
pre_tool_use=[
|
|
313
|
+
HookMatcher("bash", create_dangerous_command_check_hook()),
|
|
314
|
+
HookMatcher(
|
|
315
|
+
"*",
|
|
316
|
+
create_cli_confirm_hook(
|
|
317
|
+
spinner_controller=spinner_controller,
|
|
318
|
+
console=console,
|
|
319
|
+
),
|
|
320
|
+
),
|
|
321
|
+
]
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
def create_default_hooks(adapter: Any) -> HookConfig:
|
|
326
|
+
"""
|
|
327
|
+
Create default hook configuration with:
|
|
328
|
+
- Dangerous command blocking for bash
|
|
329
|
+
- User confirmation for write operations
|
|
330
|
+
"""
|
|
331
|
+
return HookConfig(
|
|
332
|
+
pre_tool_use=[
|
|
333
|
+
HookMatcher("bash", create_dangerous_command_check_hook()),
|
|
334
|
+
HookMatcher("*", create_confirm_writes_hook(adapter)),
|
|
335
|
+
]
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def create_autonomous_hooks() -> HookConfig:
|
|
340
|
+
"""
|
|
341
|
+
Create hook configuration for autonomous/unattended mode.
|
|
342
|
+
Blocks dangerous commands but auto-accepts everything else.
|
|
343
|
+
"""
|
|
344
|
+
return HookConfig(
|
|
345
|
+
pre_tool_use=[
|
|
346
|
+
HookMatcher("bash", create_dangerous_command_check_hook()),
|
|
347
|
+
HookMatcher("*", create_auto_accept_hook()),
|
|
348
|
+
]
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
__all__ = [
|
|
353
|
+
# Re-exported from minion.main.tool_hooks
|
|
354
|
+
"PermissionDecision",
|
|
355
|
+
"PreToolUseResult",
|
|
356
|
+
"PostToolUseResult",
|
|
357
|
+
"ToolCallInfo",
|
|
358
|
+
"PreToolUseHook",
|
|
359
|
+
"PostToolUseHook",
|
|
360
|
+
"HookMatcher",
|
|
361
|
+
"PostHookMatcher",
|
|
362
|
+
"HookConfig",
|
|
363
|
+
"ToolHooks",
|
|
364
|
+
"NoOpToolHooks",
|
|
365
|
+
"HookedTool",
|
|
366
|
+
"wrap_tools_with_hooks",
|
|
367
|
+
"create_auto_accept_hook",
|
|
368
|
+
"create_auto_deny_hook",
|
|
369
|
+
"create_dangerous_command_check_hook",
|
|
370
|
+
"create_logging_hook",
|
|
371
|
+
# minion-code specific
|
|
372
|
+
"SpinnerController",
|
|
373
|
+
"create_confirm_writes_hook",
|
|
374
|
+
"create_cli_confirm_hook",
|
|
375
|
+
"create_cli_hooks",
|
|
376
|
+
"create_default_hooks",
|
|
377
|
+
"create_autonomous_hooks",
|
|
378
|
+
]
|