Skip to content

Commit 0ba6f21

Browse files
groksrcphernandezclaude
authored
fix: Windows CLI Unicode encoding errors (#411)
Signed-off-by: phernandez <paul@basicmachines.co> Signed-off-by: Claude <noreply@anthropic.com> Signed-off-by: Paul Hernandez <60959+phernandez@users.noreply.github.com> Co-authored-by: phernandez <paul@basicmachines.co> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Paul Hernandez <60959+phernandez@users.noreply.github.com>
1 parent 0b3272a commit 0ba6f21

14 files changed

Lines changed: 63 additions & 59 deletions

File tree

.github/workflows/claude-code-review.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,12 @@ jobs:
7171
- [ ] Proper error handling and logging
7272
- [ ] Performance considerations addressed
7373
- [ ] No sensitive data in logs or commits
74+
75+
## Compatability
76+
- [ ] File path comparisons must be windows compatible
77+
- [ ] Avoid using emojis and unicode characters in console and log output
7478
7579
Read the CLAUDE.md file for detailed project context. For each checklist item, verify if it's satisfied and comment on any that need attention. Use inline comments for specific code issues and post a summary with checklist results.
7680
7781
# Allow broader tool access for thorough code review
7882
claude_args: '--allowed-tools "Bash(gh pr:*),Bash(gh issue:*),Bash(gh api:*),Bash(git log:*),Bash(git show:*),Read,Grep,Glob"'
79-

src/basic_memory/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""basic-memory - Local-first knowledge management combining Zettelkasten with knowledge graphs"""
22

33
# Package version - updated by release automation
4-
__version__ = "0.15.2"
4+
__version__ = "0.15.3.dev42+36149d6"
55

66
# API version for FastAPI - independent of package version
77
__api_version__ = "v0"

src/basic_memory/cli/auth.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def display_user_instructions(self, device_response: dict) -> None:
7777
verification_uri = device_response["verification_uri"]
7878
verification_uri_complete = device_response.get("verification_uri_complete")
7979

80-
console.print("\n[bold blue]🔐 Authentication Required[/bold blue]")
80+
console.print("\n[bold blue]Authentication Required[/bold blue]")
8181
console.print("\nTo authenticate, please visit:")
8282
console.print(f"[bold cyan]{verification_uri}[/bold cyan]")
8383
console.print(f"\nAnd enter this code: [bold yellow]{user_code}[/bold yellow]")
@@ -171,7 +171,7 @@ def save_tokens(self, tokens: dict) -> None:
171171
# Secure the token file
172172
os.chmod(self.token_file, 0o600)
173173

174-
console.print(f"[green]Tokens saved to {self.token_file}[/green]")
174+
console.print(f"[green]Tokens saved to {self.token_file}[/green]")
175175

176176
def load_tokens(self) -> dict | None:
177177
"""Load tokens from .bm-auth.json file."""
@@ -233,7 +233,7 @@ async def get_valid_token(self) -> str | None:
233233
if new_tokens:
234234
# Save new tokens (may include rotated refresh token)
235235
self.save_tokens(new_tokens)
236-
console.print("[green]Token refreshed successfully[/green]")
236+
console.print("[green]Token refreshed successfully[/green]")
237237
return new_tokens["access_token"]
238238
else:
239239
console.print("[yellow]Token refresh failed. Please run 'login' again.[/yellow]")
@@ -265,13 +265,13 @@ async def login(self) -> bool:
265265
# Step 4: Save tokens
266266
self.save_tokens(tokens)
267267

268-
console.print("\n[green]Successfully authenticated with Basic Memory Cloud![/green]")
268+
console.print("\n[green]Successfully authenticated with Basic Memory Cloud![/green]")
269269
return True
270270

271271
def logout(self) -> None:
272272
"""Remove stored authentication tokens."""
273273
if self.token_file.exists():
274274
self.token_file.unlink()
275-
console.print("[green]Logged out successfully[/green]")
275+
console.print("[green]Logged out successfully[/green]")
276276
else:
277277
console.print("[yellow]No stored authentication found[/yellow]")

src/basic_memory/cli/commands/cloud/core_commands.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,11 @@ async def _login():
5252
config.cloud_mode = True
5353
config_manager.save_config(config)
5454

55-
console.print("[green]Cloud mode enabled[/green]")
55+
console.print("[green]Cloud mode enabled[/green]")
5656
console.print(f"[dim]All CLI commands now work against {host_url}[/dim]")
5757

5858
except SubscriptionRequiredError as e:
59-
console.print("\n[red]Subscription Required[/red]\n")
59+
console.print("\n[red]Subscription Required[/red]\n")
6060
console.print(f"[yellow]{e.args[0]}[/yellow]\n")
6161
console.print(f"Subscribe at: [blue underline]{e.subscribe_url}[/blue underline]\n")
6262
console.print(
@@ -77,7 +77,7 @@ def logout():
7777
config.cloud_mode = False
7878
config_manager.save_config(config)
7979

80-
console.print("[green]Cloud mode disabled[/green]")
80+
console.print("[green]Cloud mode disabled[/green]")
8181
console.print("[dim]All CLI commands now work locally[/dim]")
8282

8383

@@ -157,12 +157,12 @@ def setup() -> None:
157157
# Step 2: Get tenant info
158158
console.print("\n[blue]Step 2: Getting tenant information...[/blue]")
159159
tenant_info = asyncio.run(get_mount_info())
160-
console.print(f"[green]Found tenant: {tenant_info.tenant_id}[/green]")
160+
console.print(f"[green]Found tenant: {tenant_info.tenant_id}[/green]")
161161

162162
# Step 3: Generate credentials
163163
console.print("\n[blue]Step 3: Generating sync credentials...[/blue]")
164164
creds = asyncio.run(generate_mount_credentials(tenant_info.tenant_id))
165-
console.print("[green]Generated secure credentials[/green]")
165+
console.print("[green]Generated secure credentials[/green]")
166166

167167
# Step 4: Configure rclone remote
168168
console.print("\n[blue]Step 4: Configuring rclone remote...[/blue]")
@@ -171,7 +171,7 @@ def setup() -> None:
171171
secret_key=creds.secret_key,
172172
)
173173

174-
console.print("\n[bold green]Cloud setup completed successfully![/bold green]")
174+
console.print("\n[bold green]Cloud setup completed successfully![/bold green]")
175175
console.print("\n[bold]Next steps:[/bold]")
176176
console.print("1. Add a project with local sync path:")
177177
console.print(" bm project add research --local-path ~/Documents/research")

src/basic_memory/cli/commands/cloud/rclone_config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,5 +106,5 @@ def configure_rclone_remote(
106106
# Save updated config
107107
save_rclone_config(config)
108108

109-
console.print(f"[green]Configured rclone remote: {REMOTE_NAME}[/green]")
109+
console.print(f"[green]Configured rclone remote: {REMOTE_NAME}[/green]")
110110
return REMOTE_NAME

src/basic_memory/cli/commands/cloud/rclone_installer.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def install_rclone_macos() -> None:
5858
try:
5959
console.print("[blue]Installing rclone via Homebrew...[/blue]")
6060
run_command(["brew", "install", "rclone"])
61-
console.print("[green]rclone installed via Homebrew[/green]")
61+
console.print("[green]rclone installed via Homebrew[/green]")
6262
return
6363
except RcloneInstallError:
6464
console.print(
@@ -69,7 +69,7 @@ def install_rclone_macos() -> None:
6969
console.print("[blue]Installing rclone via official script...[/blue]")
7070
try:
7171
run_command(["sh", "-c", "curl https://rclone.org/install.sh | sudo bash"])
72-
console.print("[green]rclone installed via official script[/green]")
72+
console.print("[green]rclone installed via official script[/green]")
7373
except RcloneInstallError:
7474
raise RcloneInstallError(
7575
"Failed to install rclone. Please install manually: brew install rclone"
@@ -83,7 +83,7 @@ def install_rclone_linux() -> None:
8383
try:
8484
console.print("[blue]Installing rclone via snap...[/blue]")
8585
run_command(["sudo", "snap", "install", "rclone"])
86-
console.print("[green]rclone installed via snap[/green]")
86+
console.print("[green]rclone installed via snap[/green]")
8787
return
8888
except RcloneInstallError:
8989
console.print("[yellow]Snap installation failed, trying apt...[/yellow]")
@@ -94,7 +94,7 @@ def install_rclone_linux() -> None:
9494
console.print("[blue]Installing rclone via apt...[/blue]")
9595
run_command(["sudo", "apt", "update"])
9696
run_command(["sudo", "apt", "install", "-y", "rclone"])
97-
console.print("[green]rclone installed via apt[/green]")
97+
console.print("[green]rclone installed via apt[/green]")
9898
return
9999
except RcloneInstallError:
100100
console.print("[yellow]apt installation failed, trying official script...[/yellow]")
@@ -103,7 +103,7 @@ def install_rclone_linux() -> None:
103103
console.print("[blue]Installing rclone via official script...[/blue]")
104104
try:
105105
run_command(["sh", "-c", "curl https://rclone.org/install.sh | sudo bash"])
106-
console.print("[green]rclone installed via official script[/green]")
106+
console.print("[green]rclone installed via official script[/green]")
107107
except RcloneInstallError:
108108
raise RcloneInstallError(
109109
"Failed to install rclone. Please install manually: sudo snap install rclone"
@@ -117,7 +117,7 @@ def install_rclone_windows() -> None:
117117
try:
118118
console.print("[blue]Installing rclone via winget...[/blue]")
119119
run_command(["winget", "install", "Rclone.Rclone"])
120-
console.print("[green]rclone installed via winget[/green]")
120+
console.print("[green]rclone installed via winget[/green]")
121121
return
122122
except RcloneInstallError:
123123
console.print("[yellow]winget installation failed, trying chocolatey...[/yellow]")
@@ -127,7 +127,7 @@ def install_rclone_windows() -> None:
127127
try:
128128
console.print("[blue]Installing rclone via chocolatey...[/blue]")
129129
run_command(["choco", "install", "rclone", "-y"])
130-
console.print("[green]rclone installed via chocolatey[/green]")
130+
console.print("[green]rclone installed via chocolatey[/green]")
131131
return
132132
except RcloneInstallError:
133133
console.print("[yellow]chocolatey installation failed, trying scoop...[/yellow]")
@@ -137,7 +137,7 @@ def install_rclone_windows() -> None:
137137
try:
138138
console.print("[blue]Installing rclone via scoop...[/blue]")
139139
run_command(["scoop", "install", "rclone"])
140-
console.print("[green]rclone installed via scoop[/green]")
140+
console.print("[green]rclone installed via scoop[/green]")
141141
return
142142
except RcloneInstallError:
143143
console.print("[yellow]scoop installation failed[/yellow]")
@@ -172,7 +172,7 @@ def install_rclone(platform_override: Optional[str] = None) -> None:
172172
if not is_rclone_installed():
173173
raise RcloneInstallError("rclone installation completed but command not found in PATH")
174174

175-
console.print("[green]rclone installation completed successfully[/green]")
175+
console.print("[green]rclone installation completed successfully[/green]")
176176

177177
except RcloneInstallError:
178178
raise

src/basic_memory/cli/commands/cloud/upload.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ async def upload_path(
108108
if dry_run:
109109
print(f"\nTotal: {len(files_to_upload)} file(s) ({size_str})")
110110
else:
111-
print(f"Upload complete: {len(files_to_upload)} file(s) ({size_str})")
111+
print(f"Upload complete: {len(files_to_upload)} file(s) ({size_str})")
112112

113113
return True
114114

src/basic_memory/cli/commands/cloud/upload_command.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ async def _upload():
7878
console.print(f"[blue]Creating cloud project '{project}'...[/blue]")
7979
try:
8080
await create_cloud_project(project)
81-
console.print(f"[green]Created project '{project}'[/green]")
81+
console.print(f"[green]Created project '{project}'[/green]")
8282
except Exception as e:
8383
console.print(f"[red]Failed to create project: {e}[/red]")
8484
raise typer.Exit(1)
@@ -109,7 +109,7 @@ async def _upload():
109109
if dry_run:
110110
console.print("[yellow]DRY RUN complete - no files were uploaded[/yellow]")
111111
else:
112-
console.print(f"[green]Successfully uploaded to '{project}'[/green]")
112+
console.print(f"[green]Successfully uploaded to '{project}'[/green]")
113113

114114
# Sync project if requested (skip on dry run)
115115
# Force full scan after bisync to ensure database is up-to-date with synced files

src/basic_memory/cli/commands/command_utils.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ async def run_sync(project: Optional[str] = None, force_full: bool = False):
3232
url += "?force_full=true"
3333
response = await call_post(client, url)
3434
data = response.json()
35-
console.print(f"[green]{data['message']}[/green]")
35+
console.print(f"[green]{data['message']}[/green]")
3636
except (ToolError, ValueError) as e:
37-
console.print(f"[red]Sync failed: {e}[/red]")
37+
console.print(f"[red]Sync failed: {e}[/red]")
3838
raise typer.Exit(1)
3939

4040

@@ -47,5 +47,5 @@ async def get_project_info(project: str):
4747
response = await call_get(client, f"{project_item.project_url}/project/info")
4848
return ProjectInfoResponse.model_validate(response.json())
4949
except (ToolError, ValueError) as e:
50-
console.print(f"[red]Sync failed: {e}[/red]")
50+
console.print(f"[red]Sync failed: {e}[/red]")
5151
raise typer.Exit(1)

0 commit comments

Comments
 (0)