patchpal 0.1.5__tar.gz → 0.1.7__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.
- {patchpal-0.1.5/patchpal.egg-info → patchpal-0.1.7}/PKG-INFO +102 -1
- {patchpal-0.1.5 → patchpal-0.1.7}/README.md +101 -0
- {patchpal-0.1.5 → patchpal-0.1.7}/patchpal/__init__.py +1 -1
- {patchpal-0.1.5 → patchpal-0.1.7}/patchpal/agent.py +219 -0
- {patchpal-0.1.5 → patchpal-0.1.7}/patchpal/cli.py +16 -0
- {patchpal-0.1.5 → patchpal-0.1.7}/patchpal/system_prompt.md +12 -1
- {patchpal-0.1.5 → patchpal-0.1.7}/patchpal/tools.py +628 -0
- {patchpal-0.1.5 → patchpal-0.1.7/patchpal.egg-info}/PKG-INFO +102 -1
- {patchpal-0.1.5 → patchpal-0.1.7}/tests/test_agent.py +13 -3
- {patchpal-0.1.5 → patchpal-0.1.7}/tests/test_tools.py +597 -0
- {patchpal-0.1.5 → patchpal-0.1.7}/LICENSE +0 -0
- {patchpal-0.1.5 → patchpal-0.1.7}/MANIFEST.in +0 -0
- {patchpal-0.1.5 → patchpal-0.1.7}/patchpal/context.py +0 -0
- {patchpal-0.1.5 → patchpal-0.1.7}/patchpal/permissions.py +0 -0
- {patchpal-0.1.5 → patchpal-0.1.7}/patchpal/skills.py +0 -0
- {patchpal-0.1.5 → patchpal-0.1.7}/patchpal.egg-info/SOURCES.txt +0 -0
- {patchpal-0.1.5 → patchpal-0.1.7}/patchpal.egg-info/dependency_links.txt +0 -0
- {patchpal-0.1.5 → patchpal-0.1.7}/patchpal.egg-info/entry_points.txt +0 -0
- {patchpal-0.1.5 → patchpal-0.1.7}/patchpal.egg-info/requires.txt +0 -0
- {patchpal-0.1.5 → patchpal-0.1.7}/patchpal.egg-info/top_level.txt +0 -0
- {patchpal-0.1.5 → patchpal-0.1.7}/pyproject.toml +0 -0
- {patchpal-0.1.5 → patchpal-0.1.7}/setup.cfg +0 -0
- {patchpal-0.1.5 → patchpal-0.1.7}/tests/test_cli.py +0 -0
- {patchpal-0.1.5 → patchpal-0.1.7}/tests/test_context.py +0 -0
- {patchpal-0.1.5 → patchpal-0.1.7}/tests/test_guardrails.py +0 -0
- {patchpal-0.1.5 → patchpal-0.1.7}/tests/test_operational_safety.py +0 -0
- {patchpal-0.1.5 → patchpal-0.1.7}/tests/test_skills.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: patchpal
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
4
4
|
Summary: A lean Claude Code clone in pure Python
|
|
5
5
|
Author: PatchPal Contributors
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -121,6 +121,10 @@ The agent has the following tools:
|
|
|
121
121
|
|
|
122
122
|
### File Operations
|
|
123
123
|
- **read_file**: Read contents of files in the repository
|
|
124
|
+
- **read_lines**: Read specific line ranges from a file without loading the entire file
|
|
125
|
+
- Example: `read_lines("app.py", 100, 150)` - read lines 100-150
|
|
126
|
+
- More efficient than read_file when you only need a few lines
|
|
127
|
+
- Useful for viewing code sections, error context, or specific regions of large files
|
|
124
128
|
- **list_files**: List all files in the repository
|
|
125
129
|
- **get_file_info**: Get detailed metadata for file(s) - size, modification time, type
|
|
126
130
|
- Supports single files: `get_file_info("file.txt")`
|
|
@@ -143,6 +147,29 @@ The agent has the following tools:
|
|
|
143
147
|
- **apply_patch**: Modify files by providing complete new content
|
|
144
148
|
- **run_shell**: Execute shell commands (requires user permission; privilege escalation blocked)
|
|
145
149
|
|
|
150
|
+
### Task Planning (TODO System)
|
|
151
|
+
- **todo_add**: Add a new task to break down complex work into manageable subtasks
|
|
152
|
+
- Example: `todo_add("Implement authentication", details="Use JWT tokens")`
|
|
153
|
+
- Each task gets a unique ID for tracking
|
|
154
|
+
- **todo_list**: Show all tasks with their status and progress
|
|
155
|
+
- Example: `todo_list()` - show pending tasks only
|
|
156
|
+
- Example: `todo_list(show_completed=True)` - show all tasks including completed
|
|
157
|
+
- **todo_complete**: Mark a task as done
|
|
158
|
+
- Example: `todo_complete(1)` - mark task #1 as completed
|
|
159
|
+
- **todo_update**: Update task description or details
|
|
160
|
+
- Example: `todo_update(1, description="Implement OAuth2 authentication")`
|
|
161
|
+
- **todo_remove**: Remove a task from the list
|
|
162
|
+
- Example: `todo_remove(1)` - remove task #1
|
|
163
|
+
- **todo_clear**: Clear completed tasks or start fresh
|
|
164
|
+
- Example: `todo_clear()` - clear completed tasks only
|
|
165
|
+
- Example: `todo_clear(completed_only=False)` - clear all tasks
|
|
166
|
+
|
|
167
|
+
### User Interaction
|
|
168
|
+
- **ask_user**: Ask the user a question during task execution
|
|
169
|
+
- Example: `ask_user("Which database should I use?", options=["PostgreSQL", "MySQL", "SQLite"])`
|
|
170
|
+
- Useful for clarifying requirements, getting decisions, or gathering additional information
|
|
171
|
+
- Supports multiple choice options or free-form answers
|
|
172
|
+
|
|
146
173
|
### Git Operations (No Permission Required)
|
|
147
174
|
- **git_status**: Show modified, staged, and untracked files
|
|
148
175
|
- **git_diff**: Show changes in working directory or staged area
|
|
@@ -513,6 +540,80 @@ When web tools are disabled:
|
|
|
513
540
|
patchpal --help
|
|
514
541
|
```
|
|
515
542
|
|
|
543
|
+
### Maximum Security Mode
|
|
544
|
+
|
|
545
|
+
For maximum security and control, you can require permission for **all** operations including read operations:
|
|
546
|
+
|
|
547
|
+
```bash
|
|
548
|
+
patchpal --require-permission-for-all
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
When enabled, the agent will prompt for permission before:
|
|
552
|
+
- **Read operations**: `read_file`, `list_files`, `get_file_info`, `find_files`, `tree`, `grep_code`, `git_status`, `git_diff`, `git_log`
|
|
553
|
+
- **Write operations**: `edit_file`, `apply_patch` (always require permission)
|
|
554
|
+
- **Shell commands**: `run_shell` (always requires permission)
|
|
555
|
+
- **Web operations**: `web_search`, `web_fetch` (always require permission)
|
|
556
|
+
|
|
557
|
+
**Granular session permissions:**
|
|
558
|
+
When you grant permission for read operations, you can choose to grant it for:
|
|
559
|
+
- **This specific operation only** (option 1)
|
|
560
|
+
- **This specific file/pattern for the session** (option 2) - e.g., grant permission to read `config.py` for the session, but still prompt for other files
|
|
561
|
+
- **Cancel the operation** (option 3)
|
|
562
|
+
|
|
563
|
+
This provides fine-grained control over what the agent can access during the session.
|
|
564
|
+
|
|
565
|
+
**Use cases:**
|
|
566
|
+
- Working with highly sensitive codebases
|
|
567
|
+
- Security audits where every operation must be reviewed
|
|
568
|
+
- Training/demonstration purposes where you want to see exactly what the agent does
|
|
569
|
+
- Untrusted environments where you want complete control
|
|
570
|
+
|
|
571
|
+
**Example session:**
|
|
572
|
+
```bash
|
|
573
|
+
$ patchpal --require-permission-for-all
|
|
574
|
+
================================================================================
|
|
575
|
+
PatchPal - Claude Code–inspired coding and automation assistant
|
|
576
|
+
================================================================================
|
|
577
|
+
|
|
578
|
+
Using model: anthropic/claude-sonnet-4-5
|
|
579
|
+
🔒 Permission required for ALL operations (including reads)
|
|
580
|
+
|
|
581
|
+
You: Read config.py and database.py
|
|
582
|
+
|
|
583
|
+
================================================================================
|
|
584
|
+
Read File
|
|
585
|
+
--------------------------------------------------------------------------------
|
|
586
|
+
Read: config.py
|
|
587
|
+
--------------------------------------------------------------------------------
|
|
588
|
+
|
|
589
|
+
Do you want to proceed?
|
|
590
|
+
1. Yes
|
|
591
|
+
2. Yes, and don't ask again this session for 'config.py'
|
|
592
|
+
3. No, and tell me what to do differently
|
|
593
|
+
|
|
594
|
+
Choice [1-3]: 2
|
|
595
|
+
|
|
596
|
+
# Agent reads config.py, then prompts for database.py
|
|
597
|
+
|
|
598
|
+
================================================================================
|
|
599
|
+
Read File
|
|
600
|
+
--------------------------------------------------------------------------------
|
|
601
|
+
Read: database.py
|
|
602
|
+
--------------------------------------------------------------------------------
|
|
603
|
+
|
|
604
|
+
Do you want to proceed?
|
|
605
|
+
1. Yes
|
|
606
|
+
2. Yes, and don't ask again this session for 'database.py'
|
|
607
|
+
3. No, and tell me what to do differently
|
|
608
|
+
|
|
609
|
+
Choice [1-3]: 1
|
|
610
|
+
|
|
611
|
+
# Agent reads database.py, but will prompt again if it tries to read it later
|
|
612
|
+
# Won't prompt again for config.py since you chose option 2
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
**Note:** This mode is separate from and overrides `PATCHPAL_REQUIRE_PERMISSION=false`. Even if you've disabled the standard permission system, `--require-permission-for-all` will still prompt for all operations.
|
|
616
|
+
|
|
516
617
|
## Usage
|
|
517
618
|
|
|
518
619
|
Simply run the `patchpal` command and type your requests interactively:
|
|
@@ -84,6 +84,10 @@ The agent has the following tools:
|
|
|
84
84
|
|
|
85
85
|
### File Operations
|
|
86
86
|
- **read_file**: Read contents of files in the repository
|
|
87
|
+
- **read_lines**: Read specific line ranges from a file without loading the entire file
|
|
88
|
+
- Example: `read_lines("app.py", 100, 150)` - read lines 100-150
|
|
89
|
+
- More efficient than read_file when you only need a few lines
|
|
90
|
+
- Useful for viewing code sections, error context, or specific regions of large files
|
|
87
91
|
- **list_files**: List all files in the repository
|
|
88
92
|
- **get_file_info**: Get detailed metadata for file(s) - size, modification time, type
|
|
89
93
|
- Supports single files: `get_file_info("file.txt")`
|
|
@@ -106,6 +110,29 @@ The agent has the following tools:
|
|
|
106
110
|
- **apply_patch**: Modify files by providing complete new content
|
|
107
111
|
- **run_shell**: Execute shell commands (requires user permission; privilege escalation blocked)
|
|
108
112
|
|
|
113
|
+
### Task Planning (TODO System)
|
|
114
|
+
- **todo_add**: Add a new task to break down complex work into manageable subtasks
|
|
115
|
+
- Example: `todo_add("Implement authentication", details="Use JWT tokens")`
|
|
116
|
+
- Each task gets a unique ID for tracking
|
|
117
|
+
- **todo_list**: Show all tasks with their status and progress
|
|
118
|
+
- Example: `todo_list()` - show pending tasks only
|
|
119
|
+
- Example: `todo_list(show_completed=True)` - show all tasks including completed
|
|
120
|
+
- **todo_complete**: Mark a task as done
|
|
121
|
+
- Example: `todo_complete(1)` - mark task #1 as completed
|
|
122
|
+
- **todo_update**: Update task description or details
|
|
123
|
+
- Example: `todo_update(1, description="Implement OAuth2 authentication")`
|
|
124
|
+
- **todo_remove**: Remove a task from the list
|
|
125
|
+
- Example: `todo_remove(1)` - remove task #1
|
|
126
|
+
- **todo_clear**: Clear completed tasks or start fresh
|
|
127
|
+
- Example: `todo_clear()` - clear completed tasks only
|
|
128
|
+
- Example: `todo_clear(completed_only=False)` - clear all tasks
|
|
129
|
+
|
|
130
|
+
### User Interaction
|
|
131
|
+
- **ask_user**: Ask the user a question during task execution
|
|
132
|
+
- Example: `ask_user("Which database should I use?", options=["PostgreSQL", "MySQL", "SQLite"])`
|
|
133
|
+
- Useful for clarifying requirements, getting decisions, or gathering additional information
|
|
134
|
+
- Supports multiple choice options or free-form answers
|
|
135
|
+
|
|
109
136
|
### Git Operations (No Permission Required)
|
|
110
137
|
- **git_status**: Show modified, staged, and untracked files
|
|
111
138
|
- **git_diff**: Show changes in working directory or staged area
|
|
@@ -476,6 +503,80 @@ When web tools are disabled:
|
|
|
476
503
|
patchpal --help
|
|
477
504
|
```
|
|
478
505
|
|
|
506
|
+
### Maximum Security Mode
|
|
507
|
+
|
|
508
|
+
For maximum security and control, you can require permission for **all** operations including read operations:
|
|
509
|
+
|
|
510
|
+
```bash
|
|
511
|
+
patchpal --require-permission-for-all
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
When enabled, the agent will prompt for permission before:
|
|
515
|
+
- **Read operations**: `read_file`, `list_files`, `get_file_info`, `find_files`, `tree`, `grep_code`, `git_status`, `git_diff`, `git_log`
|
|
516
|
+
- **Write operations**: `edit_file`, `apply_patch` (always require permission)
|
|
517
|
+
- **Shell commands**: `run_shell` (always requires permission)
|
|
518
|
+
- **Web operations**: `web_search`, `web_fetch` (always require permission)
|
|
519
|
+
|
|
520
|
+
**Granular session permissions:**
|
|
521
|
+
When you grant permission for read operations, you can choose to grant it for:
|
|
522
|
+
- **This specific operation only** (option 1)
|
|
523
|
+
- **This specific file/pattern for the session** (option 2) - e.g., grant permission to read `config.py` for the session, but still prompt for other files
|
|
524
|
+
- **Cancel the operation** (option 3)
|
|
525
|
+
|
|
526
|
+
This provides fine-grained control over what the agent can access during the session.
|
|
527
|
+
|
|
528
|
+
**Use cases:**
|
|
529
|
+
- Working with highly sensitive codebases
|
|
530
|
+
- Security audits where every operation must be reviewed
|
|
531
|
+
- Training/demonstration purposes where you want to see exactly what the agent does
|
|
532
|
+
- Untrusted environments where you want complete control
|
|
533
|
+
|
|
534
|
+
**Example session:**
|
|
535
|
+
```bash
|
|
536
|
+
$ patchpal --require-permission-for-all
|
|
537
|
+
================================================================================
|
|
538
|
+
PatchPal - Claude Code–inspired coding and automation assistant
|
|
539
|
+
================================================================================
|
|
540
|
+
|
|
541
|
+
Using model: anthropic/claude-sonnet-4-5
|
|
542
|
+
🔒 Permission required for ALL operations (including reads)
|
|
543
|
+
|
|
544
|
+
You: Read config.py and database.py
|
|
545
|
+
|
|
546
|
+
================================================================================
|
|
547
|
+
Read File
|
|
548
|
+
--------------------------------------------------------------------------------
|
|
549
|
+
Read: config.py
|
|
550
|
+
--------------------------------------------------------------------------------
|
|
551
|
+
|
|
552
|
+
Do you want to proceed?
|
|
553
|
+
1. Yes
|
|
554
|
+
2. Yes, and don't ask again this session for 'config.py'
|
|
555
|
+
3. No, and tell me what to do differently
|
|
556
|
+
|
|
557
|
+
Choice [1-3]: 2
|
|
558
|
+
|
|
559
|
+
# Agent reads config.py, then prompts for database.py
|
|
560
|
+
|
|
561
|
+
================================================================================
|
|
562
|
+
Read File
|
|
563
|
+
--------------------------------------------------------------------------------
|
|
564
|
+
Read: database.py
|
|
565
|
+
--------------------------------------------------------------------------------
|
|
566
|
+
|
|
567
|
+
Do you want to proceed?
|
|
568
|
+
1. Yes
|
|
569
|
+
2. Yes, and don't ask again this session for 'database.py'
|
|
570
|
+
3. No, and tell me what to do differently
|
|
571
|
+
|
|
572
|
+
Choice [1-3]: 1
|
|
573
|
+
|
|
574
|
+
# Agent reads database.py, but will prompt again if it tries to read it later
|
|
575
|
+
# Won't prompt again for config.py since you chose option 2
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
**Note:** This mode is separate from and overrides `PATCHPAL_REQUIRE_PERMISSION=false`. Even if you've disabled the standard permission system, `--require-permission-for-all` will still prompt for all operations.
|
|
579
|
+
|
|
479
580
|
## Usage
|
|
480
581
|
|
|
481
582
|
Simply run the `patchpal` command and type your requests interactively:
|
|
@@ -14,6 +14,7 @@ from rich.markdown import Markdown
|
|
|
14
14
|
from patchpal.context import ContextManager
|
|
15
15
|
from patchpal.tools import (
|
|
16
16
|
apply_patch,
|
|
17
|
+
ask_user,
|
|
17
18
|
edit_file,
|
|
18
19
|
find_files,
|
|
19
20
|
get_file_info,
|
|
@@ -24,7 +25,14 @@ from patchpal.tools import (
|
|
|
24
25
|
list_files,
|
|
25
26
|
list_skills,
|
|
26
27
|
read_file,
|
|
28
|
+
read_lines,
|
|
27
29
|
run_shell,
|
|
30
|
+
todo_add,
|
|
31
|
+
todo_clear,
|
|
32
|
+
todo_complete,
|
|
33
|
+
todo_list,
|
|
34
|
+
todo_remove,
|
|
35
|
+
todo_update,
|
|
28
36
|
tree,
|
|
29
37
|
use_skill,
|
|
30
38
|
web_fetch,
|
|
@@ -104,6 +112,31 @@ TOOLS = [
|
|
|
104
112
|
},
|
|
105
113
|
},
|
|
106
114
|
},
|
|
115
|
+
{
|
|
116
|
+
"type": "function",
|
|
117
|
+
"function": {
|
|
118
|
+
"name": "read_lines",
|
|
119
|
+
"description": "Read specific lines from a file without loading the entire file. Useful for viewing code sections, error context, or specific regions of large files. More efficient than read_file when you only need a few lines.",
|
|
120
|
+
"parameters": {
|
|
121
|
+
"type": "object",
|
|
122
|
+
"properties": {
|
|
123
|
+
"path": {
|
|
124
|
+
"type": "string",
|
|
125
|
+
"description": "Path to the file - can be relative to repository root or an absolute path",
|
|
126
|
+
},
|
|
127
|
+
"start_line": {
|
|
128
|
+
"type": "integer",
|
|
129
|
+
"description": "Starting line number (1-indexed)",
|
|
130
|
+
},
|
|
131
|
+
"end_line": {
|
|
132
|
+
"type": "integer",
|
|
133
|
+
"description": "Ending line number (inclusive, 1-indexed). If omitted, reads only start_line",
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
"required": ["path", "start_line"],
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
},
|
|
107
140
|
{
|
|
108
141
|
"type": "function",
|
|
109
142
|
"function": {
|
|
@@ -368,6 +401,142 @@ TOOLS = [
|
|
|
368
401
|
},
|
|
369
402
|
},
|
|
370
403
|
},
|
|
404
|
+
{
|
|
405
|
+
"type": "function",
|
|
406
|
+
"function": {
|
|
407
|
+
"name": "todo_add",
|
|
408
|
+
"description": "Add a new task to the TODO list. Use this to break down complex tasks into manageable subtasks. Essential for planning multi-step work.",
|
|
409
|
+
"parameters": {
|
|
410
|
+
"type": "object",
|
|
411
|
+
"properties": {
|
|
412
|
+
"description": {
|
|
413
|
+
"type": "string",
|
|
414
|
+
"description": "Brief task description (one line)",
|
|
415
|
+
},
|
|
416
|
+
"details": {
|
|
417
|
+
"type": "string",
|
|
418
|
+
"description": "Optional detailed notes about the task",
|
|
419
|
+
},
|
|
420
|
+
},
|
|
421
|
+
"required": ["description"],
|
|
422
|
+
},
|
|
423
|
+
},
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
"type": "function",
|
|
427
|
+
"function": {
|
|
428
|
+
"name": "todo_list",
|
|
429
|
+
"description": "List all tasks in the TODO list with their status and progress.",
|
|
430
|
+
"parameters": {
|
|
431
|
+
"type": "object",
|
|
432
|
+
"properties": {
|
|
433
|
+
"show_completed": {
|
|
434
|
+
"type": "boolean",
|
|
435
|
+
"description": "If true, show completed tasks; if false, show only pending tasks (default: false)",
|
|
436
|
+
},
|
|
437
|
+
},
|
|
438
|
+
"required": [],
|
|
439
|
+
},
|
|
440
|
+
},
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
"type": "function",
|
|
444
|
+
"function": {
|
|
445
|
+
"name": "todo_complete",
|
|
446
|
+
"description": "Mark a task as completed.",
|
|
447
|
+
"parameters": {
|
|
448
|
+
"type": "object",
|
|
449
|
+
"properties": {
|
|
450
|
+
"task_id": {
|
|
451
|
+
"type": "integer",
|
|
452
|
+
"description": "The ID of the task to complete",
|
|
453
|
+
},
|
|
454
|
+
},
|
|
455
|
+
"required": ["task_id"],
|
|
456
|
+
},
|
|
457
|
+
},
|
|
458
|
+
},
|
|
459
|
+
{
|
|
460
|
+
"type": "function",
|
|
461
|
+
"function": {
|
|
462
|
+
"name": "todo_update",
|
|
463
|
+
"description": "Update a task's description or details.",
|
|
464
|
+
"parameters": {
|
|
465
|
+
"type": "object",
|
|
466
|
+
"properties": {
|
|
467
|
+
"task_id": {
|
|
468
|
+
"type": "integer",
|
|
469
|
+
"description": "The ID of the task to update",
|
|
470
|
+
},
|
|
471
|
+
"description": {
|
|
472
|
+
"type": "string",
|
|
473
|
+
"description": "New description (optional)",
|
|
474
|
+
},
|
|
475
|
+
"details": {
|
|
476
|
+
"type": "string",
|
|
477
|
+
"description": "New details (optional)",
|
|
478
|
+
},
|
|
479
|
+
},
|
|
480
|
+
"required": ["task_id"],
|
|
481
|
+
},
|
|
482
|
+
},
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
"type": "function",
|
|
486
|
+
"function": {
|
|
487
|
+
"name": "todo_remove",
|
|
488
|
+
"description": "Remove a task from the TODO list.",
|
|
489
|
+
"parameters": {
|
|
490
|
+
"type": "object",
|
|
491
|
+
"properties": {
|
|
492
|
+
"task_id": {
|
|
493
|
+
"type": "integer",
|
|
494
|
+
"description": "The ID of the task to remove",
|
|
495
|
+
},
|
|
496
|
+
},
|
|
497
|
+
"required": ["task_id"],
|
|
498
|
+
},
|
|
499
|
+
},
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
"type": "function",
|
|
503
|
+
"function": {
|
|
504
|
+
"name": "todo_clear",
|
|
505
|
+
"description": "Clear tasks from the TODO list (completed tasks only by default, or all tasks).",
|
|
506
|
+
"parameters": {
|
|
507
|
+
"type": "object",
|
|
508
|
+
"properties": {
|
|
509
|
+
"completed_only": {
|
|
510
|
+
"type": "boolean",
|
|
511
|
+
"description": "If true, clear only completed tasks; if false, clear all tasks (default: true)",
|
|
512
|
+
},
|
|
513
|
+
},
|
|
514
|
+
"required": [],
|
|
515
|
+
},
|
|
516
|
+
},
|
|
517
|
+
},
|
|
518
|
+
{
|
|
519
|
+
"type": "function",
|
|
520
|
+
"function": {
|
|
521
|
+
"name": "ask_user",
|
|
522
|
+
"description": "Ask the user a question and wait for their response. Use this to clarify requirements, get decisions, or gather additional information during task execution.",
|
|
523
|
+
"parameters": {
|
|
524
|
+
"type": "object",
|
|
525
|
+
"properties": {
|
|
526
|
+
"question": {
|
|
527
|
+
"type": "string",
|
|
528
|
+
"description": "The question to ask the user",
|
|
529
|
+
},
|
|
530
|
+
"options": {
|
|
531
|
+
"type": "array",
|
|
532
|
+
"items": {"type": "string"},
|
|
533
|
+
"description": "Optional list of predefined answer choices (e.g., ['yes', 'no', 'skip']). User can select from these or provide custom answer.",
|
|
534
|
+
},
|
|
535
|
+
},
|
|
536
|
+
"required": ["question"],
|
|
537
|
+
},
|
|
538
|
+
},
|
|
539
|
+
},
|
|
371
540
|
{
|
|
372
541
|
"type": "function",
|
|
373
542
|
"function": {
|
|
@@ -387,6 +556,7 @@ TOOLS = [
|
|
|
387
556
|
# Map tool names to functions
|
|
388
557
|
TOOL_FUNCTIONS = {
|
|
389
558
|
"read_file": read_file,
|
|
559
|
+
"read_lines": read_lines,
|
|
390
560
|
"list_files": list_files,
|
|
391
561
|
"get_file_info": get_file_info,
|
|
392
562
|
"find_files": find_files,
|
|
@@ -401,6 +571,13 @@ TOOL_FUNCTIONS = {
|
|
|
401
571
|
"web_fetch": web_fetch,
|
|
402
572
|
"list_skills": list_skills,
|
|
403
573
|
"use_skill": use_skill,
|
|
574
|
+
"todo_add": todo_add,
|
|
575
|
+
"todo_list": todo_list,
|
|
576
|
+
"todo_complete": todo_complete,
|
|
577
|
+
"todo_update": todo_update,
|
|
578
|
+
"todo_remove": todo_remove,
|
|
579
|
+
"todo_clear": todo_clear,
|
|
580
|
+
"ask_user": ask_user,
|
|
404
581
|
"run_shell": run_shell,
|
|
405
582
|
}
|
|
406
583
|
|
|
@@ -792,6 +969,13 @@ class PatchPalAgent:
|
|
|
792
969
|
f"\033[2m📖 Reading: {tool_args.get('path', '')}\033[0m",
|
|
793
970
|
flush=True,
|
|
794
971
|
)
|
|
972
|
+
elif tool_name == "read_lines":
|
|
973
|
+
start = tool_args.get("start_line", "")
|
|
974
|
+
end = tool_args.get("end_line", start)
|
|
975
|
+
print(
|
|
976
|
+
f"\033[2m📖 Reading lines {start}-{end}: {tool_args.get('path', '')}\033[0m",
|
|
977
|
+
flush=True,
|
|
978
|
+
)
|
|
795
979
|
elif tool_name == "list_files":
|
|
796
980
|
print("\033[2m📁 Listing files...\033[0m", flush=True)
|
|
797
981
|
elif tool_name == "get_file_info":
|
|
@@ -855,6 +1039,41 @@ class PatchPalAgent:
|
|
|
855
1039
|
f"\033[2m⚡ Running: {tool_args.get('cmd', '')}\033[0m",
|
|
856
1040
|
flush=True,
|
|
857
1041
|
)
|
|
1042
|
+
elif tool_name == "todo_add":
|
|
1043
|
+
print(
|
|
1044
|
+
f"\033[2m✅ Adding TODO: {tool_args.get('description', '')[:50]}\033[0m",
|
|
1045
|
+
flush=True,
|
|
1046
|
+
)
|
|
1047
|
+
elif tool_name == "todo_list":
|
|
1048
|
+
print("\033[2m📋 Listing TODO tasks...\033[0m", flush=True)
|
|
1049
|
+
elif tool_name == "todo_complete":
|
|
1050
|
+
print(
|
|
1051
|
+
f"\033[2m✓ Completing task #{tool_args.get('task_id', '')}\033[0m",
|
|
1052
|
+
flush=True,
|
|
1053
|
+
)
|
|
1054
|
+
elif tool_name == "todo_update":
|
|
1055
|
+
print(
|
|
1056
|
+
f"\033[2m📝 Updating task #{tool_args.get('task_id', '')}\033[0m",
|
|
1057
|
+
flush=True,
|
|
1058
|
+
)
|
|
1059
|
+
elif tool_name == "todo_remove":
|
|
1060
|
+
print(
|
|
1061
|
+
f"\033[2m🗑️ Removing task #{tool_args.get('task_id', '')}\033[0m",
|
|
1062
|
+
flush=True,
|
|
1063
|
+
)
|
|
1064
|
+
elif tool_name == "todo_clear":
|
|
1065
|
+
clear_type = (
|
|
1066
|
+
"completed" if tool_args.get("completed_only", True) else "all"
|
|
1067
|
+
)
|
|
1068
|
+
print(
|
|
1069
|
+
f"\033[2m🧹 Clearing {clear_type} TODO tasks...\033[0m",
|
|
1070
|
+
flush=True,
|
|
1071
|
+
)
|
|
1072
|
+
elif tool_name == "ask_user":
|
|
1073
|
+
print(
|
|
1074
|
+
"\033[2m❓ Asking user a question...\033[0m",
|
|
1075
|
+
flush=True,
|
|
1076
|
+
)
|
|
858
1077
|
|
|
859
1078
|
# Execute the tool (permission checks happen inside the tool)
|
|
860
1079
|
try:
|
|
@@ -194,8 +194,20 @@ Supported models: Any LiteLLM-supported model
|
|
|
194
194
|
help="LiteLLM model identifier (e.g., openai/gpt-4o, anthropic/claude-opus-4, ollama_chat/llama3.1). "
|
|
195
195
|
"Can also be set via PATCHPAL_MODEL environment variable.",
|
|
196
196
|
)
|
|
197
|
+
parser.add_argument(
|
|
198
|
+
"--require-permission-for-all",
|
|
199
|
+
action="store_true",
|
|
200
|
+
help="Require permission for ALL operations including read operations (read_file, list_files, etc.). "
|
|
201
|
+
"Use this for maximum security when you want to review every operation the agent performs.",
|
|
202
|
+
)
|
|
197
203
|
args = parser.parse_args()
|
|
198
204
|
|
|
205
|
+
# Set the require-permission-for-all flag if specified
|
|
206
|
+
if args.require_permission_for_all:
|
|
207
|
+
from patchpal.tools import set_require_permission_for_all
|
|
208
|
+
|
|
209
|
+
set_require_permission_for_all(True)
|
|
210
|
+
|
|
199
211
|
# Determine model to use (priority: CLI arg > env var > default)
|
|
200
212
|
model_id = args.model or os.getenv("PATCHPAL_MODEL") or "anthropic/claude-sonnet-4-5"
|
|
201
213
|
|
|
@@ -226,6 +238,10 @@ Supported models: Any LiteLLM-supported model
|
|
|
226
238
|
print("=" * 80)
|
|
227
239
|
print(f"\nUsing model: {model_id}")
|
|
228
240
|
|
|
241
|
+
# Show require-permission-for-all indicator if active
|
|
242
|
+
if args.require_permission_for_all:
|
|
243
|
+
print("\033[1;33m🔒 Permission required for ALL operations (including reads)\033[0m")
|
|
244
|
+
|
|
229
245
|
# Show custom prompt indicator if set
|
|
230
246
|
custom_prompt_path = os.getenv("PATCHPAL_SYSTEM_PROMPT")
|
|
231
247
|
if custom_prompt_path:
|
|
@@ -8,6 +8,7 @@ Today is {current_date}. Current time is {current_time}.
|
|
|
8
8
|
# Available Tools
|
|
9
9
|
|
|
10
10
|
- **read_file**: Read any file on the system (repository files, /etc configs, logs, etc.) - sensitive files blocked for safety
|
|
11
|
+
- **read_lines**: Read specific line ranges from a file without loading the entire file (efficient for large files or viewing code sections)
|
|
11
12
|
- **list_files**: List all files in the repository (repository-only)
|
|
12
13
|
- **get_file_info**: Get metadata for any file(s) - size, type, modified time (supports globs like '*.py', '/etc/*.conf')
|
|
13
14
|
- **find_files**: Find files by name pattern using glob wildcards in repository (e.g., '*.py', 'test_*.txt')
|
|
@@ -30,7 +31,7 @@ You are a LOCAL CODE ASSISTANT with flexible file access. Security model (inspir
|
|
|
30
31
|
|
|
31
32
|
Your tools are organized into:
|
|
32
33
|
|
|
33
|
-
- **File navigation/reading**: read_file (system-wide), list_files (repo-only), find_files (repo-only), tree (system-wide), get_file_info (system-wide)
|
|
34
|
+
- **File navigation/reading**: read_file (system-wide), read_lines (system-wide), list_files (repo-only), find_files (repo-only), tree (system-wide), get_file_info (system-wide)
|
|
34
35
|
- **Code search**: grep_code (repo-only)
|
|
35
36
|
- **File modification**: edit_file, apply_patch (repo files; outside requires permission)
|
|
36
37
|
- **Git operations**: git_status, git_diff, git_log (read-only, no permission needed)
|
|
@@ -102,6 +103,7 @@ The user will primarily request software engineering tasks like solving bugs, ad
|
|
|
102
103
|
- Use find_files to locate specific files by name pattern in repository (e.g., '*.py', 'test_*.txt')
|
|
103
104
|
- Use get_file_info to check file metadata anywhere (supports globs like '/etc/*.conf')
|
|
104
105
|
- Use read_file to examine any file on the system (repository, configs, logs, etc.)
|
|
106
|
+
- Use read_lines to read specific line ranges from files (more efficient for large files)
|
|
105
107
|
- Use grep_code to search for patterns in repository file contents
|
|
106
108
|
- For system file exploration (outside repository):
|
|
107
109
|
- Use tree for directory listing (e.g., tree("/etc") to list /etc)
|
|
@@ -111,6 +113,15 @@ The user will primarily request software engineering tasks like solving bugs, ad
|
|
|
111
113
|
- Use edit_file for small, targeted changes (repository files; outside requires permission)
|
|
112
114
|
- Use apply_patch for larger changes or rewriting significant portions
|
|
113
115
|
- Use git_status, git_diff, git_log to understand repository state (no permission needed){web_usage}
|
|
116
|
+
- For complex multi-step tasks:
|
|
117
|
+
- Use todo_add to break down work into manageable subtasks
|
|
118
|
+
- Use todo_list to check progress and see what's next
|
|
119
|
+
- Use todo_complete when finishing each task
|
|
120
|
+
- This helps track progress and ensures nothing is forgotten
|
|
121
|
+
- Use ask_user to clarify requirements, get decisions, or gather information during execution
|
|
122
|
+
- Ask when user intent is ambiguous
|
|
123
|
+
- Get preferences on implementation choices
|
|
124
|
+
- Confirm before making significant architectural decisions
|
|
114
125
|
- Use run_shell when no dedicated tool exists (requires permission)
|
|
115
126
|
- Never use run_shell for repository file operations - dedicated tools are available
|
|
116
127
|
|