Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion codetide/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ async def from_path(

codeTide._add_results_to_codebase(results)
codeTide._resolve_files_dependencies()
logger.info(f"\n{CODETIDE_ASCII_ART}\nInitialized with {len(results)} files processed in {time.time() - st:.2f}s")
print(f"\n{CODETIDE_ASCII_ART}\n")
logger.info(f"Initialized with {len(results)} files processed in {time.time() - st:.2f}s")

return codeTide

Expand Down
5 changes: 4 additions & 1 deletion codetide/agents/tide/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ async def _stage(self)->str:
for path in self.changed_paths:
index.add(path)

index.write()

staged_diff = await self.get_git_diff_staged_simple(self.tide.rootpath)
staged_diff = staged_diff.strip()
return staged_diff if staged_diff else "No files were staged. Nothing to commit. Tell the user to request some changes so there is something to commit"
Expand Down Expand Up @@ -275,7 +277,8 @@ def _(event):
# 2. Create a prompt session with the custom key bindings
session = PromptSession(key_bindings=bindings)

_logger.logger.info(f"\n{AGENT_TIDE_ASCII_ART}\nReady to surf. Press ESC to exit.\n")
print(f"\n{AGENT_TIDE_ASCII_ART}\n")
_logger.logger.info("Ready to surf. Press ESC to exit.")
try:
while True:
try:
Expand Down
14 changes: 6 additions & 8 deletions codetide/agents/tide/consts.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
AGENT_TIDE_ASCII_ART = """

█████╗ ██████╗ ███████╗███╗ ██╗████████╗ ████████╗██╗██████╗ ███████╗
██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝ ╚══██╔══╝██║██╔══██╗██╔════╝
███████║██║ ███╗█████╗ ██╔██╗ ██║ ██║ ██║ ██║██║ ██║█████╗
██╔══██║██║ ██║██╔══╝ ██║╚██╗██║ ██║ ██║ ██║██║ ██║██╔══╝
██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║ ██║ ██║██████╔╝███████╗
╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝╚═════╝ ╚══════╝

\033[1;38;5;25m█████╗ ██████╗ ███████╗███╗ ██╗████████╗ ████████╗██╗██████╗ ███████╗\033[0m
\033[1;38;5;33m██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝ ╚══██╔══╝██║██╔══██╗██╔════╝\033[0m
\033[1;38;5;39m███████║██║ ███╗█████╗ ██╔██╗ ██║ ██║ ██║ ██║██║ ██║█████╗\033[0m
\033[1;38;5;45m██╔══██║██║ ██║██╔══╝ ██║╚██╗██║ ██║ ██║ ██║██║ ██║██╔══╝\033[0m
\033[1;38;5;51m██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║ ██║ ██║██████╔╝███████╗\033[0m
\033[1;38;5;255m╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚═╝ ╚═╝╚═════╝ ╚══════╝\033[0m
"""
4 changes: 2 additions & 2 deletions codetide/agents/tide/ui/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,8 @@ async def agent_loop(message: Optional[cl.Message]=None, codeIdentifiers: Option
break

await stream_processor.process_chunk(chunk)


await asyncio.sleep(0.5)
if agent_tide_ui.agent_tide.steps:
cl.user_session.set("latest_step_message", msg)
msg.actions = [
Expand Down Expand Up @@ -355,7 +356,6 @@ async def agent_loop(message: Optional[cl.Message]=None, codeIdentifiers: Option
chat_history.append({"role": "assistant", "content": msg.content})
await agent_tide_ui.add_to_history(msg.content)

await asyncio.sleep(0.5)
if agent_tide_ui.agent_tide._has_patch:
choice = await cl.AskActionMessage(
content="AgentTide is asking you to review the Patch before applying it.",
Expand Down
12 changes: 6 additions & 6 deletions codetide/agents/tide/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,24 +57,24 @@ def parse_patch_blocks(text: str, multiple: bool = True) -> Union[str, List[str]

def parse_commit_blocks(text: str, multiple: bool = True) -> Union[str, List[str], None]:
"""
Extract content between *** Begin Patch and *** End Patch markers (inclusive),
Extract content between *** Begin Commit and *** End Commit markers (exclusive),
ensuring that both markers are at zero indentation (start of line, no leading spaces).

Args:
text: Full input text containing one or more patch blocks.
multiple: If True, return a list of all patch blocks. If False, return the first match.
text: Full input text containing one or more commit blocks.
multiple: If True, return a list of all commit blocks. If False, return the first match.

Returns:
A string (single patch), list of strings (multiple patches), or None if not found.
A string (single commit), list of strings (multiple commits), or None if not found.
"""

pattern = r"(?m)^(\*\*\* Begin Commit[\s\S]*?^\*\*\* End Commit)$"
pattern = r"(?m)^\*\*\* Begin Commit\n([\s\S]*?)^\*\*\* End Commit$"
matches = re.findall(pattern, text)

if not matches:
return None

return matches if multiple else matches[0]
return matches if multiple else matches[0].strip()

def parse_steps_markdown(md: str):
steps = []
Expand Down
14 changes: 6 additions & 8 deletions codetide/core/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,12 +92,10 @@
DEFAULT_BYTES_CONTENT_PLACEHOLDERS = "< suppressed bytes content >"

CODETIDE_ASCII_ART = """

███████╗ ██████╗ ██████╗ ███████╗████████╗██╗██████╗ ███████╗
██╔════╝██╔═══██╗██╔══██╗██╔════╝╚══██╔══╝██║██╔══██╗██╔════╝
██║ ██║ ██║██║ ██║█████╗ ██║ ██║██║ ██║█████╗
██║ ██║ ██║██║ ██║██╔══╝ ██║ ██║██║ ██║██╔══╝
╚██████╗╚██████╔╝██████╔╝███████╗ ██║ ██║██████╔╝███████╗
╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚═╝ ╚═╝╚═════╝ ╚══════╝

\033[1;38;5;25m███████╗ ██████╗ ██████╗ ███████╗████████╗██╗██████╗ ███████╗\033[0m
\033[1;38;5;33m██╔════╝██╔═══██╗██╔══██╗██╔════╝╚══██╔══╝██║██╔══██╗██╔════╝\033[0m
\033[1;38;5;39m██║ ██║ ██║██║ ██║█████╗ ██║ ██║██║ ██║█████╗\033[0m
\033[1;38;5;45m██║ ██║ ██║██║ ██║██╔══╝ ██║ ██║██║ ██║██╔══╝\033[0m
\033[1;38;5;51m╚██████╗╚██████╔╝██████╔╝███████╗ ██║ ██║██████╔╝███████╗\033[0m
\033[1;38;5;255m ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚═╝ ╚═╝╚═════╝ ╚══════╝\033[0m
"""
6 changes: 3 additions & 3 deletions codetide/mcp/tools/patch_code/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# --------------------------------------------------------------------------- #
# User-facing API
# --------------------------------------------------------------------------- #
def text_to_patch(text: str, orig: Dict[str, str]) -> Tuple[Patch, int]:
def text_to_patch(text: str, orig: Dict[str, str], rootpath: Optional[pathlib.Path]=None) -> Tuple[Patch, int]:
"""Improved version with better splitlines handling."""
lines = text.splitlines()

Expand All @@ -37,7 +37,7 @@ def text_to_patch(text: str, orig: Dict[str, str]) -> Tuple[Patch, int]:
if not lines or not Parser._norm(lines[-1]) == "*** End Patch":
raise DiffError(f"Invalid patch text - must end with '*** End Patch'. Found: '{lines[-1] if lines else 'empty'}'")

parser = Parser(current_files=orig, lines=lines, index=1)
parser = Parser(current_files=orig, lines=lines, index=1, rootpath=rootpath)
parser.parse()
return parser.patch, parser.fuzz

Expand Down Expand Up @@ -138,7 +138,7 @@ def process_patch(
path = str(root_path / path)
orig_files[path] = open_fn(path)

patch, _fuzz = text_to_patch(text, orig_files)
patch, _fuzz = text_to_patch(text, orig_files, rootpath=root_path)
commit = patch_to_commit(patch, orig_files)

apply_commit(commit, write_fn, remove_fn, exists_fn)
Expand Down
4 changes: 4 additions & 0 deletions codetide/mcp/tools/patch_code/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from typing import Dict, List, Optional, Tuple, Union
from dataclasses import dataclass, field
from pathlib import Path

# --------------------------------------------------------------------------- #
# Helper functions for parsing update chunks
Expand Down Expand Up @@ -218,6 +219,7 @@ class Parser:
index: int = 0
patch: Patch = field(default_factory=Patch)
fuzz: int = 0
rootpath: Optional[Path]=None

def _cur_line(self) -> str:
if self.index >= len(self.lines):
Expand Down Expand Up @@ -261,6 +263,8 @@ def parse(self) -> None:
while not self.is_done(("*** End Patch",)):
# ---------- UPDATE ---------- #
if path := self.read_str("*** Update File: "):
if self.rootpath is not None:
path = str(self.rootpath / path)
if path in self.patch.actions:
raise DiffError(f"Duplicate update for file: {path}")
move_to = self.read_str("*** Move to: ")
Expand Down
2 changes: 1 addition & 1 deletion examples/hf_demo_space/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,7 @@ async def agent_loop(message: Optional[cl.Message]=None, codeIdentifiers: Option

await stream_processor.process_chunk(chunk)

await asyncio.sleep(0.5)
if agent_tide_ui.agent_tide.steps:
cl.user_session.set("latest_step_message", msg)
msg.actions = [
Expand Down Expand Up @@ -397,7 +398,6 @@ async def agent_loop(message: Optional[cl.Message]=None, codeIdentifiers: Option
chat_history.append({"role": "assistant", "content": msg.content})
await agent_tide_ui.add_to_history(msg.content)

await asyncio.sleep(0.5)
if agent_tide_ui.agent_tide._has_patch:
choice = await cl.AskActionMessage(
content="AgentTide is asking you to review the Patch before applying it.",
Expand Down