Skip to content

Commit f57a1cc

Browse files
committed
✨ code exec
1 parent ecbdbb2 commit f57a1cc

File tree

5 files changed

+221
-119
lines changed

5 files changed

+221
-119
lines changed

dymo-code.spec

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@ block_cipher = None
1212
# Get the project root
1313
project_root = Path(SPECPATH)
1414

15+
# Check for icon file and report status
16+
icon_path = project_root / 'docs' / 'images' / 'icon.ico'
17+
icon_exists = icon_path.exists()
18+
print(f"[BUILD INFO] Project root: {project_root}")
19+
print(f"[BUILD INFO] Icon path: {icon_path}")
20+
print(f"[BUILD INFO] Icon exists: {icon_exists}")
21+
if icon_exists:
22+
print(f"[BUILD INFO] Icon size: {icon_path.stat().st_size} bytes")
23+
else:
24+
print(f"[BUILD WARNING] Icon file not found! The executable will have no icon.")
25+
1526
# Get certifi certificate path for SSL support
1627
try:
1728
import certifi
@@ -134,5 +145,5 @@ exe = EXE(
134145
target_arch=None,
135146
codesign_identity=None,
136147
entitlements_file=None,
137-
icon=str(project_root / 'docs' / 'images' / 'icon.ico') if (project_root / 'docs' / 'images' / 'icon.ico').exists() else None,
148+
icon=str(icon_path) if icon_exists else None,
138149
)

src/config.py

Lines changed: 92 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -341,108 +341,98 @@ def items(self):
341341
# System Prompt
342342
# ═══════════════════════════════════════════════════════════════════════════════
343343

344-
SYSTEM_PROMPT = """You are a helpful AI coding assistant running in a terminal environment. You are concise, precise, and focused on helping users with their tasks.
345-
346-
## CRITICAL RULES
347-
348-
### 1. TASK DIVISION - BREAK DOWN COMPLEX REQUESTS
349-
350-
**IMPORTANT:** When you receive a complex request that involves multiple steps or creating a complete project, you MUST use the `spawn_agents` tool to divide the work into manageable tasks.
351-
352-
**CRITICAL LIMITS:**
353-
- Maximum 5 tasks per spawn_agents call
354-
- If you need more than 5 tasks, work in BATCHES (call spawn_agents multiple times)
355-
- Group related items into single tasks (e.g., "Create 5 sorting algorithm files" instead of 5 separate tasks)
356-
357-
**When to use `spawn_agents`:**
358-
- Initializing a complete project (Astro, React, Next.js, etc.)
359-
- Creating multiple files or components
360-
- Tasks with 3+ distinct steps
361-
- Building features that require setup, implementation, and configuration
362-
363-
**How to divide tasks:**
364-
1. Analyze the request and identify logical subtasks
365-
2. Group similar items (e.g., all sorting algorithms = 1 task, all search algorithms = 1 task)
366-
3. Maximum 5 tasks per call - if more needed, execute in batches
367-
4. Use `sequential: true` when tasks depend on each other
368-
369-
**Example - "Create an algorithm repository with 30 algorithms":**
370-
WRONG: 30 separate tasks (exceeds limit)
371-
CORRECT: Group by category into 5 or fewer tasks:
372-
- Task 1: "Create 8 sorting algorithm files (bubble, merge, quick, heap, insertion, selection, radix, shell)"
373-
- Task 2: "Create 7 search algorithm files (binary, linear, jump, interpolation, exponential, fibonacci, ternary)"
374-
- Task 3: "Create 8 graph algorithm files (dijkstra, BFS, DFS, bellman-ford, floyd-warshall, kruskal, prim, a-star)"
375-
- Task 4: "Create 7 data structure files (binary-trees, linked-lists, hash-tables, stacks-queues, avl-trees, red-black-trees, tries)"
376-
377-
**Example - "Initialize an Astro project with a search feature":**
378-
- Task 1: "Initialize Astro project with TypeScript and install dependencies"
379-
- Task 2: "Create layout and base components"
380-
- Task 3: "Create search component with fuse.js"
381-
- Task 4: "Create example algorithm pages"
382-
- Task 5: "Configure routing and final setup"
383-
384-
**Benefits:**
385-
- Prevents context exhaustion in a single prompt
386-
- Respects system limits (max 5 tasks)
387-
- Each task gets full attention
388-
- Easier to track progress and debug
389-
390-
### 2. COMPLETE THE USER'S REQUEST - NO MORE, NO LESS
391-
392-
Do exactly what the user asks:
393-
- If user says "create a file" → Create the file with `create_file`. Done.
394-
- If user says "create a folder and a file" → Create both. Done.
395-
- If user says "create and run" → Create the file AND run it.
396-
397-
**DO NOT automatically run code after creating it** unless the user specifically asks to run it.
398-
399-
### 3. USE TOOLS, DON'T SHOW CODE
400-
401-
When asked to CREATE a file:
402-
- Use `create_file` tool - don't just display code as text
403-
- The diff display will show the user what was created
404-
405-
### 4. YOUR AVAILABLE TOOLS
406-
407-
| Tool Name | When to Use |
408-
|-----------|-------------|
409-
| `list_files_in_dir` | List files/folders in a directory |
410-
| `read_file` | Read content of a file |
411-
| `create_folder` | Create a new directory |
412-
| `create_file` | Create or write a file |
413-
| `move_path` | Move or rename a file/folder |
414-
| `delete_path` | Delete a file/folder (asks for confirmation) |
415-
| `run_command` | Execute a system command |
416-
| `spawn_agents` | Divide complex tasks into subtasks |
417-
418-
**Use these exact names. No prefixes like "repo_browser." etc.**
419-
420-
### 5. WHEN TO RUN CODE
421-
422-
**RUN code ONLY when:**
423-
- User explicitly says "run", "execute", "test", or "try"
424-
- User asks to see output/results
425-
426-
**DO NOT automatically run code when:**
427-
- User just says "create a file"
428-
- User says "make a script"
429-
- User says "write code for X"
430-
431-
### 6. CODE QUALITY
432-
433-
When writing code:
434-
- Write complete, working code
435-
- Follow language best practices
436-
- Python: Don't put newlines inside f-strings
437-
438-
### 7. RESPONDING TO REQUESTS
439-
440-
Keep responses brief after tool use:
441-
- "Created `filename.py`" - done
442-
- Don't repeat the entire file content
443-
- Don't explain every line unless asked
444-
445-
## Environment
344+
SYSTEM_PROMPT = """You are an expert AI coding assistant with direct access to the user's system through tools. Your primary mode of operation is ACTION, not description.
345+
346+
## CORE PRINCIPLES
347+
348+
### 1. ACT, DON'T JUST DESCRIBE
349+
- When asked to do something → USE TOOLS to do it
350+
- Don't explain what you "would do" → DO IT
351+
- Don't show code in chat → CREATE files with tools
352+
- The user can see results through tool outputs
353+
354+
### 2. SOLVE PROBLEMS COMPLETELY
355+
When given a task:
356+
1. **Understand** - Read relevant files if needed
357+
2. **Plan** - Break down into steps (use spawn_agents for complex tasks)
358+
3. **Execute** - Use tools to implement the solution
359+
4. **Verify** - Run/test to confirm it works
360+
5. **Iterate** - If something fails, FIX IT and try again
361+
362+
**NEVER give up after one failure.** Debug, fix, and retry.
363+
364+
### 3. VERIFY YOUR WORK
365+
After making changes:
366+
- Run the code to check for errors
367+
- Read the file to confirm changes were applied
368+
- Test the functionality if possible
369+
- If something breaks, investigate and fix it
370+
371+
### 4. ITERATE UNTIL SUCCESS
372+
- Error in code? → Read the error, fix it, run again
373+
- File not created? → Check the path, try again
374+
- Test failed? → Debug, modify, retest
375+
- Keep iterating until the task is COMPLETE
376+
377+
## TOOLS AVAILABLE
378+
379+
| Tool | Purpose |
380+
|------|---------|
381+
| `list_files_in_dir` | Explore directory structure |
382+
| `read_file` | Read file contents |
383+
| `create_folder` | Create directories |
384+
| `create_file` | Create or modify files |
385+
| `move_path` | Rename or move files |
386+
| `delete_path` | Remove files (with confirmation) |
387+
| `run_command` | Execute shell commands (output streams in real-time) |
388+
| `spawn_agents` | Divide complex tasks (max 5 subtasks) |
389+
| `glob_search` | Find files by pattern |
390+
| `grep_search` | Search file contents |
391+
| `web_search` | Search the internet |
392+
| `fetch_url` | Get web page content |
393+
394+
## TASK DIVISION (spawn_agents)
395+
396+
For complex tasks with 3+ steps:
397+
- Use `spawn_agents` to parallelize work
398+
- Maximum 5 tasks per call (batch if needed)
399+
- Group related items (e.g., "Create all sorting algorithms")
400+
- Use `sequential: true` for dependent tasks
401+
402+
**Example - "Create an algorithm repository":**
403+
- Task 1: "Create sorting algorithm files (bubble, merge, quick, heap)"
404+
- Task 2: "Create search algorithm files (binary, linear, jump)"
405+
- Task 3: "Create graph algorithm files (dijkstra, BFS, DFS)"
406+
407+
## RESPONSE STYLE
408+
409+
- **Brief after actions**: "Created `file.py`" - done
410+
- **Don't repeat file contents** unless asked
411+
- **Don't over-explain** - the user sees tool results
412+
- **Be direct**: Do what's asked, no more, no less
413+
414+
## ERROR HANDLING
415+
416+
When something fails:
417+
1. Read the error message carefully
418+
2. Identify the root cause
419+
3. Fix the issue
420+
4. Run again to verify
421+
5. Repeat until resolved
422+
423+
**Example workflow:**
424+
```
425+
User: "Create a Python script that fetches weather data and run it"
426+
427+
Your approach:
428+
1. create_file → weather.py with API code
429+
2. run_command → python weather.py
430+
3. If error → read error, fix code, run again
431+
4. If missing module → run_command pip install X, then retry
432+
5. Continue until it works or you've exhausted options
433+
```
434+
435+
## ENVIRONMENT
446436
- OS: {os_info}
447437
- Working Directory: {cwd}
448438
"""

src/tools.py

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,10 @@ def create_file(file_path: str = "", content: str = "") -> str:
211211
return f"Error: {str(e)}"
212212

213213

214-
def run_command(command: str = "") -> str:
215-
"""Execute a shell command and return output"""
216-
if not command: return "Error: command is required"
214+
def run_command(command: str = "", timeout: int = 300) -> str:
215+
"""Execute a shell command with real-time output streaming"""
216+
if not command:
217+
return "Error: command is required"
217218

218219
# Check command permissions before executing
219220
try:
@@ -223,22 +224,55 @@ def run_command(command: str = "") -> str:
223224
except ImportError:
224225
pass # If module not available, allow execution
225226

227+
from .ui import StreamingConsole
228+
229+
# Truncate command for title display
230+
display_cmd = command[:60] + "..." if len(command) > 60 else command
231+
232+
console_display = StreamingConsole(title=display_cmd)
233+
console_display.start()
234+
235+
output_lines = []
236+
exit_code = 0
237+
226238
try:
227-
result = subprocess.run(
239+
# Use Popen for streaming output
240+
process = subprocess.Popen(
228241
command,
229242
shell=True,
230-
capture_output=True,
243+
stdout=subprocess.PIPE,
244+
stderr=subprocess.STDOUT, # Merge stderr into stdout for proper ordering
231245
text=True,
232-
timeout=30,
233-
cwd=os.getcwd()
246+
bufsize=1, # Line buffered
247+
cwd=os.getcwd(),
248+
env={**os.environ, 'PYTHONUNBUFFERED': '1'} # Force unbuffered Python
234249
)
235-
output = ""
236-
if result.stdout: output += result.stdout
237-
if result.stderr: output += f"\n[stderr]\n{result.stderr}" if output else result.stderr
238-
if result.returncode != 0: output += f"\n[exit code: {result.returncode}]"
239-
return output.strip() if output.strip() else "(No output)"
240-
except subprocess.TimeoutExpired: return "Error: Command timed out after 30 seconds."
241-
except Exception as e: return f"Error: {str(e)}"
250+
251+
# Read output line by line as it's produced
252+
for line in iter(process.stdout.readline, ''):
253+
if line:
254+
output_lines.append(line)
255+
console_display.append(line)
256+
257+
process.wait(timeout=timeout)
258+
exit_code = process.returncode
259+
260+
except subprocess.TimeoutExpired:
261+
process.kill()
262+
console_display.append("[Command timed out!]")
263+
exit_code = -1
264+
except Exception as e:
265+
console_display.append(f"[Error: {str(e)}]")
266+
exit_code = -1
267+
268+
console_display.finish(exit_code)
269+
270+
# Return complete output for tool result
271+
result = ''.join(output_lines)
272+
if exit_code != 0:
273+
result += f"\n[exit code: {exit_code}]"
274+
275+
return result.strip() if result.strip() else "(No output)"
242276

243277

244278
def move_path(source: str = "", destination: str = "") -> str:

src/ui.py

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1048,4 +1048,71 @@ def print_keybindings():
10481048
console.print(table)
10491049
console.print()
10501050

1051-
except ImportError: console.print(f"\n[{COLORS['error']}]Keybinding system not available.[/]\n")
1051+
except ImportError: console.print(f"\n[{COLORS['error']}]Keybinding system not available.[/]\n")
1052+
1053+
1054+
# ═══════════════════════════════════════════════════════════════════════════════
1055+
# Streaming Console for Real-Time Command Output
1056+
# ═══════════════════════════════════════════════════════════════════════════════
1057+
1058+
class StreamingConsole:
1059+
"""Live updating console panel for command output with ANSI color support"""
1060+
1061+
def __init__(self, title: str = "Console", max_lines: int = 100):
1062+
self.title = title
1063+
self.lines = []
1064+
self.live = None
1065+
self.max_lines = max_lines
1066+
self.exit_code = None
1067+
1068+
def start(self):
1069+
"""Start the live display"""
1070+
from rich.live import Live
1071+
self.live = Live(
1072+
self._render(),
1073+
console=console,
1074+
refresh_per_second=15,
1075+
transient=True # Will be replaced by final static panel
1076+
)
1077+
self.live.start()
1078+
1079+
def append(self, line: str):
1080+
"""Append a line of output"""
1081+
self.lines.append(line.rstrip('\n\r'))
1082+
# Keep last N lines for scrollback
1083+
if len(self.lines) > self.max_lines:
1084+
self.lines = self.lines[-self.max_lines:]
1085+
if self.live:
1086+
self.live.update(self._render())
1087+
1088+
def _render(self):
1089+
"""Render the panel with current output"""
1090+
# Use Text.from_ansi to preserve colors from command output
1091+
if self.lines:
1092+
content = '\n'.join(self.lines)
1093+
text = Text.from_ansi(content)
1094+
else:
1095+
text = Text("Waiting for output...", style=f"dim {COLORS['muted']}")
1096+
1097+
# Title with exit code if finished
1098+
title = f"[bold cyan]$ {self.title}[/bold cyan]"
1099+
if self.exit_code is not None:
1100+
code_style = COLORS['success'] if self.exit_code == 0 else COLORS['error']
1101+
title += f" [{code_style}](exit: {self.exit_code})[/{code_style}]"
1102+
1103+
return Panel(
1104+
text,
1105+
title=title,
1106+
title_align="left",
1107+
border_style=COLORS['muted'],
1108+
box=ROUNDED,
1109+
padding=(0, 1)
1110+
)
1111+
1112+
def finish(self, exit_code: int):
1113+
"""Finish streaming and show final static panel"""
1114+
self.exit_code = exit_code
1115+
if self.live:
1116+
self.live.stop()
1117+
# Print final static panel that persists
1118+
console.print(self._render())

static-api/version.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"version": "0.0.0.24"
2+
"version": "0.0.0.25"
33
}

0 commit comments

Comments
 (0)