Skip to content

fix(desktop): handle characters around paths in terminal#724

Merged
Kitenite merged 5 commits intomainfrom
failed-to-open-file
Jan 13, 2026
Merged

fix(desktop): handle characters around paths in terminal#724
Kitenite merged 5 commits intomainfrom
failed-to-open-file

Conversation

@Kitenite
Copy link
Copy Markdown
Collaborator

@Kitenite Kitenite commented Jan 12, 2026

Summary

  • Capture stderr from spawn process to surface actual error messages from the open command
  • Instead of generic "exited with code 1", users now see the real error (e.g., "Unable to find application named 'Cursor'")
  • Strip wrapper characters and trailing punctuation from file paths before opening
    • Handles quotes (", ', `), parentheses, brackets
    • Handles trailing punctuation (. , : ; ? !) while preserving extensions and line:col suffixes
    • Examples: "./file.ts"../file.ts, (./path/file.ts),./path/file.ts

Test plan

  • Click a file path in terminal with CMD+click when target app is not installed
  • Verify toast shows actual error message from macOS instead of generic message
  • Click paths wrapped in quotes like "./src/file.ts" - should open correctly
  • Click paths in parentheses like (./src/file.ts) - should open correctly
  • Click paths with trailing punctuation like ./src/file.ts. - should open correctly
  • Verify normal paths like ./src/file.ts:42 still work (line number preserved)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added path wrapper stripping functionality to handle quoted, parenthesized, and bracketed file paths, including support for nested wrappers and trailing punctuation removal.
  • Improvements

    • Enhanced error reporting to capture and display stderr output for better diagnostic messages.
  • Tests

    • Extended test coverage for path wrapper stripping with edge cases and various file extension types.
  • Chores

    • Removed unnecessary comments for cleaner, more maintainable code.

✏️ Tip: You can customize this high-level summary in your review settings.

Capture stderr from spawn process to surface actual error messages
from the `open` command instead of generic "exited with code 1".

Before: "'open' exited with code 1. The application may not be installed."
After: "Unable to find application named 'Cursor'" (actual error from macOS)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 12, 2026

📝 Walkthrough

Walkthrough

A new helper function stripPathWrappers was introduced to normalize file paths by removing surrounding wrapper characters and trailing punctuation, with support for nested wrappers. The resolvePath function was updated to use this new preprocessor. Additionally, spawnAsync was enhanced to capture stderr output and use it in error messages on process failures with improved error reporting.

Changes

Cohort / File(s) Summary
Path wrapper stripping utility
apps/desktop/src/lib/trpc/routers/external/helpers.ts
Added new exported function stripPathWrappers(filePath: string): string that removes surrounding wrapper characters (quotes, parentheses, brackets, etc.) and trailing punctuation with nested wrapper support. Introduced PATH_WRAPPERS set, TRAILING_PUNCTUATION regex, and internal stripTrailingPunctuation helper. Modified resolvePath to preprocess input via stripPathWrappers.
Path wrapper stripping tests
apps/desktop/src/lib/trpc/routers/external/helpers.test.ts
Added comprehensive test suite for stripPathWrappers covering single wrappers, nested wrappers, edge cases, trailing punctuation, line-number suffixes, and various extension types. Extended resolvePath tests to validate wrapper stripping behavior.
Enhanced spawn error handling
apps/desktop/src/lib/trpc/routers/external/helpers.ts
Modified spawnAsync to capture stderr output (stdio changed from "ignore" to ["ignore", "ignore", "pipe"]), propagate stderr in error messages on non-zero exits, and provide improved spawn failure messages with application installation guidance.
Comment cleanup
apps/desktop/src/lib/trpc/routers/workspaces/procedures/{create,init}.ts
Removed comment lines across workspace creation and initialization procedures with no functional changes to control flow or behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 A rabbit's path through twisted vines,
We strip the wrappers, clean the signs!
With nested quotes and brackets bare,
stripPathWrappers strips with care.
Stderr now flows, no more's unknown—
Better errors, keener shown! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Description check ❓ Inconclusive The PR description provides a clear summary of changes, test plan with checkboxes, and additional context. However, it does not follow the template structure with formal sections like 'Related Issues' and 'Type of Change' that are defined in the repository template. Consider restructuring the description to match the template with explicit sections: Related Issues, Type of Change (mark Bug fix or Refactor), Testing, and Additional Notes.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: adding functionality to handle and strip wrapper characters and trailing punctuation from file paths in terminal contexts.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 95afbc8 and a2261da.

📒 Files selected for processing (4)
  • apps/desktop/src/lib/trpc/routers/external/helpers.test.ts
  • apps/desktop/src/lib/trpc/routers/external/helpers.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts
  • apps/desktop/src/lib/trpc/routers/workspaces/procedures/init.ts
💤 Files with no reviewable changes (1)
  • apps/desktop/src/lib/trpc/routers/workspaces/procedures/init.ts
✅ Files skipped from review due to trivial changes (1)
  • apps/desktop/src/lib/trpc/routers/workspaces/procedures/create.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/desktop/src/lib/trpc/routers/external/helpers.test.ts
  • apps/desktop/src/lib/trpc/routers/external/helpers.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

…file paths

Add path cleaning to handle common terminal output patterns when opening files:
- Strip wrapper characters: quotes ("'`), parentheses, brackets
- Strip trailing punctuation: . , : ; ? ! (but preserve extensions and line:col)
- Handle nested wrappers and wrappers with trailing punctuation

Examples: "(./file.ts)." → "./file.ts", '"./file.ts",' → "./file.ts"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @apps/desktop/src/lib/trpc/routers/external/index.ts:
- Line 11: Import/usage mismatch: the code imports resolvePathWithFallback but
the router calls resolvePath (and the helpers module only exports resolvePath),
so fix by making the import and usage match; either change the named import
resolvePathWithFallback to resolvePath in the import list or change the call
site to resolvePathWithFallback if you add that export to the helpers module.
Locate the import statement referencing resolvePathWithFallback and replace it
with resolvePath, or alternatively export resolvePathWithFallback from the
helpers module to match the call to resolvePathWithFallback, ensuring the
function name is consistent with the call site (resolvePath).
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cb84ff8 and 95afbc8.

📒 Files selected for processing (3)
  • apps/desktop/src/lib/trpc/routers/external/helpers.test.ts
  • apps/desktop/src/lib/trpc/routers/external/helpers.ts
  • apps/desktop/src/lib/trpc/routers/external/index.ts
🧰 Additional context used
📓 Path-based instructions (5)
apps/desktop/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)

apps/desktop/**/*.{ts,tsx}: For Electron interprocess communication, ALWAYS use tRPC as defined in src/lib/trpc
Use alias as defined in tsconfig.json when possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary.
For tRPC subscriptions with trpc-electron, ALWAYS use the observable pattern from @trpc/server/observable instead of async generators, as the library explicitly checks isObservable(result) and throws an error otherwise

Files:

  • apps/desktop/src/lib/trpc/routers/external/helpers.ts
  • apps/desktop/src/lib/trpc/routers/external/helpers.test.ts
  • apps/desktop/src/lib/trpc/routers/external/index.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use object parameters for functions with 2+ parameters instead of positional arguments
Functions with 2+ parameters should accept a single params object with named properties for self-documentation and extensibility
Use prefixed console logging with context pattern: [domain/operation] message
Extract magic numbers and hardcoded values to named constants at module top
Use lookup objects/maps instead of repeated if (type === ...) conditionals
Avoid using any type - maintain type safety in TypeScript code
Never swallow errors silently - at minimum log them with context
Import from concrete files directly when possible - avoid barrel file abuse that creates circular dependencies
Avoid deep nesting (4+ levels) - use early returns, extract functions, and invert conditions
Use named properties in options objects instead of boolean parameters to avoid boolean blindness

Files:

  • apps/desktop/src/lib/trpc/routers/external/helpers.ts
  • apps/desktop/src/lib/trpc/routers/external/helpers.test.ts
  • apps/desktop/src/lib/trpc/routers/external/index.ts
apps/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Drizzle ORM for all database operations - never use raw SQL

Files:

  • apps/desktop/src/lib/trpc/routers/external/helpers.ts
  • apps/desktop/src/lib/trpc/routers/external/helpers.test.ts
  • apps/desktop/src/lib/trpc/routers/external/index.ts
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use Biome for formatting and linting - run at root level with bun run lint:fix or biome check --write

Files:

  • apps/desktop/src/lib/trpc/routers/external/helpers.ts
  • apps/desktop/src/lib/trpc/routers/external/helpers.test.ts
  • apps/desktop/src/lib/trpc/routers/external/index.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Co-locate tests with implementation files using .test.ts or .test.tsx suffix

Files:

  • apps/desktop/src/lib/trpc/routers/external/helpers.test.ts
🧠 Learnings (7)
📚 Learning: 2026-01-02T06:50:28.671Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.671Z
Learning: Applies to apps/desktop/src/lib/electron-router-dom.ts : Do not import Node.js modules like node:path or dotenv in electron-router-dom.ts and similar shared files - they run in both main and renderer processes

Applied to files:

  • apps/desktop/src/lib/trpc/routers/external/helpers.ts
  • apps/desktop/src/lib/trpc/routers/external/helpers.test.ts
  • apps/desktop/src/lib/trpc/routers/external/index.ts
📚 Learning: 2026-01-02T06:50:28.671Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.671Z
Learning: Applies to apps/api/**/*.{ts,tsx} : Extract business logic from tRPC procedures into utility functions when logic exceeds ~50 lines, is used by multiple procedures, or needs independent testing

Applied to files:

  • apps/desktop/src/lib/trpc/routers/external/helpers.ts
  • apps/desktop/src/lib/trpc/routers/external/helpers.test.ts
📚 Learning: 2026-01-02T06:50:28.671Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.671Z
Learning: Applies to apps/desktop/src/renderer/**/*.{ts,tsx} : Never import Node.js modules (fs, path, os, net) in renderer process or shared code - they are externalized for browser compatibility

Applied to files:

  • apps/desktop/src/lib/trpc/routers/external/index.ts
📚 Learning: 2026-01-02T06:50:28.671Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.671Z
Learning: Applies to apps/desktop/src/lib/*.ts : Never import Node.js modules in shared code like electron-router-dom.ts - it runs in both main and renderer processes

Applied to files:

  • apps/desktop/src/lib/trpc/routers/external/index.ts
📚 Learning: 2026-01-02T06:50:28.671Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-02T06:50:28.671Z
Learning: Applies to **/*.{ts,tsx} : Import from concrete files directly when possible - avoid barrel file abuse that creates circular dependencies

Applied to files:

  • apps/desktop/src/lib/trpc/routers/external/index.ts
📚 Learning: 2025-12-21T04:39:28.543Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-12-21T04:39:28.543Z
Learning: Applies to apps/desktop/**/*.{ts,tsx} : Use alias as defined in `tsconfig.json` when possible

Applied to files:

  • apps/desktop/src/lib/trpc/routers/external/index.ts
📚 Learning: 2025-12-21T04:39:28.543Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-12-21T04:39:28.543Z
Learning: Applies to apps/desktop/**/*.{ts,tsx} : For Electron interprocess communication, ALWAYS use tRPC as defined in `src/lib/trpc`

Applied to files:

  • apps/desktop/src/lib/trpc/routers/external/index.ts
🧬 Code graph analysis (1)
apps/desktop/src/lib/trpc/routers/external/helpers.test.ts (1)
apps/desktop/src/lib/trpc/routers/external/helpers.ts (2)
  • resolvePath (149-177)
  • stripPathWrappers (115-142)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build
🔇 Additional comments (8)
apps/desktop/src/lib/trpc/routers/external/helpers.ts (5)

43-54: LGTM!

The wrapper pairs constant is well-structured and covers common path wrapper characters. Good use of typed tuples for the open/close pairs.


68-102: LGTM! Well-designed helper with good edge case handling.

The logic correctly preserves file extensions and line number suffixes while stripping sentence-ending punctuation.


115-142: LGTM!

The iterative stripping algorithm correctly handles nested wrappers and trailing punctuation. The loop termination is well-guarded with both the changed flag and length check.


149-151: LGTM!

Good integration point - stripping wrappers first ensures subsequent path operations work on clean input.


183-214: LGTM! This change directly addresses the PR objective.

Capturing stderr and surfacing the actual OS error message (e.g., "Unable to find application named 'Cursor'") is a significant UX improvement over the generic "exited with code 1" message. The optional chaining on child.stderr?.on correctly handles the edge case where stderr might be null.

apps/desktop/src/lib/trpc/routers/external/helpers.test.ts (3)

4-4: LGTM!

Good practice to import and test the exported stripPathWrappers directly alongside resolvePath.


215-265: LGTM! Thorough integration tests.

Good coverage of wrapper stripping combined with other resolvePath features like ~ expansion and relative path resolution.


268-428: LGTM! Excellent test coverage.

The test suite thoroughly covers:

  • All wrapper types individually
  • Nested and mixed wrappers
  • Critical edge cases (mismatched wrappers, internal wrappers, empty input)
  • Trailing punctuation with proper preservation of extensions and line numbers
  • Combined scenarios (wrappers + trailing punctuation)

Comment thread apps/desktop/src/lib/trpc/routers/external/index.ts Outdated
@Kitenite Kitenite changed the title fix(desktop): improve error messages when opening files in external apps fix(desktop): handle characters around paths in terminal Jan 13, 2026
Kitenite and others added 2 commits January 12, 2026 16:20
Add tests for:
- Line numbers with trailing punctuation (file.ts:42. → file.ts:42)
- Line:col with trailing punctuation
- Various extension types (.mp3, .c, .TSX)
- Dotfiles (.gitignore, .eslintrc.json)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@Kitenite Kitenite merged commit 5467c53 into main Jan 13, 2026
5 checks passed
@Kitenite Kitenite deleted the failed-to-open-file branch January 13, 2026 00:27
@github-actions
Copy link
Copy Markdown
Contributor

🧹 Preview Cleanup Complete

The following preview resources have been cleaned up:

  • ⚠️ Neon database branch
  • ⚠️ Electric Fly.io app

Thank you for your contribution! 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant