Skip to content

Add pear open <dir> CLI to open or create a project for a directory#72

Merged
willwashburn merged 8 commits into
mainfrom
claude/cool-cray-2Qmzq
Jun 3, 2026
Merged

Add pear open <dir> CLI to open or create a project for a directory#72
willwashburn merged 8 commits into
mainfrom
claude/cool-cray-2Qmzq

Conversation

@willwashburn
Copy link
Copy Markdown
Member

@willwashburn willwashburn commented Jun 3, 2026

User description

Summary

Adds a CLI command so pear open ./my-directory opens Pear with the first project that already contains that directory, or creates a new project with that directory as its only root.

Matching behavior: a project matches if the directory is an exact root or nested under one of its roots (paths are resolved to absolute, so relative inputs like ./my-directory match stored absolute roots). If no project matches, a new one is created, named after the directory's basename, with that single root.

How it works

  • bin/pear.mjs — thin launcher (wired via package.json "bin") that forwards args to the Electron app.
  • src/main/cli.ts — pure, dependency-injected logic:
    • parseOpenCommand(argv) — extracts the path after the open verb (robust to Electron's varying argv shapes and intervening flags).
    • findProjectForPath(projects, path) — finds the first project whose roots contain the directory.
    • openProjectForPath(path, deps) — reuses + activates a matching project, or creates a new one (rejecting non-directories).
  • src/main/index.ts — a single-instance lock routes a second pear open … invocation into the already-running window (restoring/focusing it). The initial-launch path is queued until the renderer finishes loading, then sent as cli:open-project.
  • use-broker-events.ts — the renderer listens for cli:open-project, reloads the project list (to pick up a newly created project), and switches the active project.

Testing

  • 10 new unit tests in src/main/__tests__/cli.test.ts covering argv parsing, exact/nested/sibling matching, reuse, create, and non-directory rejection. Full suite passes (20/20).
  • Type-check: identical pre-existing error count before and after the change; zero errors in the new/changed files.
  • npm run build succeeds with the new code bundled.

Notes

bin/pear.mjs launches the locally-built app (out/main/index.js), so it works in the repo after npm run build. A packaged distributable would point pear at the installed binary instead — happy to wire that up in a follow-up if wanted.

https://claude.ai/code/session_01BGTwZWKEUQ324n1REnhZPW

Generated by Claude Code


CodeAnt-AI Description

Add a terminal command to open projects from a directory, with installer and update support

What Changed

  • pear open <dir> now opens the matching project for that folder, or creates a new project when none exists
  • If the app is already open, the command brings that window forward and switches to the target project instead of starting a second copy
  • The app can now install a pear command into your PATH from the menu, and shows a confirmation or error message after install
  • The app now checks for published updates, shows when an update is ready, and lets you trigger a manual update check from the menu
  • Launching the CLI now reports signal-based exits as failures instead of success, and dash-prefixed directory names can be opened with pear open -- -name

Impact

✅ Faster access to the right project from the terminal
✅ Fewer duplicate app windows when reopening Pear
✅ Clearer install and update feedback for macOS users

🔄 Retrigger CodeAnt AI Review

💡 Usage Guide

Checking Your Pull Request

Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.

Talking to CodeAnt AI

Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:

@codeant-ai ask: Your question here

This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.

Example

@codeant-ai ask: Can you suggest a safer alternative to storing this secret?

Preserve Org Learnings with CodeAnt

You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:

@codeant-ai: Your feedback here

This helps CodeAnt AI learn and adapt to your team's coding style and standards.

Example

@codeant-ai: Do not flag unused imports.

Retrigger review

Ask CodeAnt AI to review the PR again, by typing:

@codeant-ai: review

Check Your Repository Health

To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.

Adds a CLI command so `pear open ./my-directory` opens Pear with the first
project that already contains that directory (as an exact root or nested
under one), or creates a new project with that directory as its only root.

- bin/pear.mjs: thin launcher forwarding args to the Electron app
- src/main/cli.ts: pure, testable argv parsing + find-or-create logic
- src/main/index.ts: single-instance lock routes a second `pear open`
  invocation to the running window; initial-launch path is queued until
  the renderer loads
- renderer listens for cli:open-project to reload and switch projects
- tests cover argv parsing and find/create/reuse behavior
@gemini-code-assist
Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@codeant-ai
Copy link
Copy Markdown

codeant-ai Bot commented Jun 3, 2026

CodeAnt AI is reviewing your PR.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 3, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a pear CLI launcher and package bin, parses and resolves pear open <path> to reuse or create a project, queues opens until the renderer signals readiness, enforces single-instance startup with second-instance forwarding, and adds a macOS CLI installer, auto-update wiring, packaging/notarization config, tests, and release workflow.

Changes

CLI and project open flow

Layer / File(s) Summary
CLI contract and parsing
src/main/cli.ts
parseOpenCommand extracts the target path after open; findProjectForPath matches absolute targets to exact or descendant project roots; result/deps types define injected store/filesystem operations.
Project open/create logic and tests
src/main/cli.ts, src/main/__tests__/cli.test.ts
openProjectForPath reuses an existing project if a root contains the path or validates the path and creates a new single-root project; tests include a harness and coverage for reuse, creation, and non-directory errors.
CLI parsing & project matching tests
src/main/__tests__/cli.test.ts
Unit tests for parseOpenCommand and findProjectForPath (flag skipping, missing arg, exact vs nested matching, prefix-only rejection).
Main process CLI integration and single-instance
src/main/index.ts
Bundles open-path dependencies, handles handleOpenCommand() and flushPendingOpen() with renderer-ready gating, and enforces single-instance startup with second-instance forwarding.
IPC, preload, and renderer handler
src/main/ipc-handlers.ts, src/preload/index.ts, src/renderer/src/hooks/use-broker-events.ts
Refactors project lookup to reuse findProjectForPath, exposes pear.app.notifyCliReady() in preload, and registers cli:open-project listener in renderer to load the project, open the agents tab, and set active project; unsubscribes on cleanup.
Package registration and CLI launcher
package.json, bin/pear.mjs
package.json maps pear to bin/pear.mjs; launcher resolves Electron, checks build presence, spawns Electron with the built entrypoint and forwarded args, and exits on child completion or error.
CLI installer and IPC UI
src/main/cli-install.ts
macOS shim installer stages a shell shim, installs via osascript with auth, returns structured result, shows success/warning dialogs, and registers cli:install IPC handler.
Auto-updater and IPC
src/main/updater.ts
Adds electron-updater integration for packaged builds, broadcasts update lifecycle events to renderers, provides silent and interactive checks, and exposes IPC endpoints for check/install.
Packaging, notarization, and entitlements
electron-builder.yml, build/notarize.cjs, build/entitlements.mac.plist
Electron Builder config for macOS targets, an afterSign notarization hook that supports API-key or Apple-ID modes, and entitlements plist enabling required macOS capabilities.
Release workflow and docs
.github/workflows/release.yml, RELEASING.md, .gitignore
GitHub Actions workflow for tag-based macOS releases, RELEASING.md documenting macOS packaging and release steps, and .gitignore updated to ignore release/.

Sequence Diagram(s)

sequenceDiagram
  participant CLI as CLI Launcher
  participant App as MainProcess
  participant Window as MainWindow
  participant Renderer as Renderer
  CLI->>App: spawn Electron with argv
  App->>App: requestSingleInstanceLock()
  alt lock acquired
    App->>App: handleOpenCommand(argv,cwd)
    App->>Window: createWindow()
    Window->>Renderer: register IPC on did-finish-load
    App->>Renderer: cli:open-project (if pending)
  else lock not acquired
    App->>App: emit second-instance
    App->>Window: focus/restore
    App->>App: handleOpenCommand(argv,cwd)
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

I hop along the command-line trail,
A tiny pear that tells its tale.
One lock, one open, queues that sing,
The renderer wakes — the projects spring.
🐰✨


Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

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

@codeant-ai codeant-ai Bot added the size:L This PR changes 100-499 lines, ignoring generated files label Jun 3, 2026
Comment thread bin/pear.mjs Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f5fdef281f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/main/cli.ts Outdated
Comment thread src/main/cli.ts
Comment thread src/main/cli.ts Outdated
Comment thread src/main/index.ts Outdated
Comment thread src/renderer/src/hooks/use-broker-events.ts
@codeant-ai
Copy link
Copy Markdown

codeant-ai Bot commented Jun 3, 2026

CodeAnt AI finished reviewing your PR.

@agent-relay-code
Copy link
Copy Markdown
Contributor

pr-reviewer applied fixes — committed and pushed 105cce1 to this PR. The notes below describe what changed.

Reviewed PR #72 and made scoped fixes:

  • Fixed project path containment to use path.relative()/isAbsolute() instead of hard-coded /, so nested project matching works cross-platform.
  • Queued CLI open IPC until the renderer is ready, avoiding lost cli:open-project events during startup/loading.
  • Ensured pear open <dir> creates a window when a single app instance is running with no window.
  • Updated the renderer CLI handler to open a project-scoped agents tab before setting the active project, preventing the app’s tab sync from reverting the CLI-selected project.

Checked PR bot comments; there were no actionable bot findings beyond summaries/quota notices.

Verification:

  • npm test passed.
  • npm run build passed after installing dependencies with npm ci.

@agent-relay-code
Copy link
Copy Markdown
Contributor

Reviewed PR #72 and fixed the issues I found.

Changes made:

  • Replaced the did-finish-load timing assumption with an explicit cli:renderer-ready signal from the renderer after the cli:open-project listener is registered.
  • Added the preload/API typing for pear.app.notifyCliReady().
  • Reused the new boundary-safe findProjectForPath helper in the existing main IPC path guard so sibling path prefixes are handled consistently.

Local verification:

  • npm test passes.
  • npm run build passes.

@agent-relay-code
Copy link
Copy Markdown
Contributor

pr-reviewer applied fixes — committed and pushed ea89f5d to this PR. The notes below describe what changed.

Reviewed PR #72 and fixed the issues I found.

Changes made:

  • Replaced the did-finish-load timing assumption with an explicit cli:renderer-ready signal from the renderer after the cli:open-project listener is registered.
  • Added the preload/API typing for pear.app.notifyCliReady().
  • Reused the new boundary-safe findProjectForPath helper in the existing main IPC path guard so sibling path prefixes are handled consistently.

Local verification:

  • npm test passes.
  • npm run build passes.

- Resolve index.ts conflict: keep cli:renderer-ready IPC handler and fold
  in burnManager.warmUp() from main
- Guard second-instance window calls with !mainWindow.isDestroyed()
- bin/pear.mjs: propagate signal termination as non-zero exit (128+signal)
  instead of reporting success
- parseOpenCommand: treat -- as end-of-options so dash-named dirs can open
- Serialize cli:open-project handling (latest-wins) to avoid out-of-order
  active-project switches on rapid opens
@codeant-ai
Copy link
Copy Markdown

codeant-ai Bot commented Jun 3, 2026

CodeAnt AI is running Incremental review

@codeant-ai codeant-ai Bot added size:L This PR changes 100-499 lines, ignoring generated files and removed size:L This PR changes 100-499 lines, ignoring generated files labels Jun 3, 2026
Copy link
Copy Markdown
Member Author

Merged latest main (resolved an index.ts conflict — kept the cli:renderer-ready handler and folded in burnManager.warmUp()) and addressed the open review feedback in c61706e:

  • bin/pear.mjs exit code — a signal-terminated child reported code === null → success. Now exits 128 + signal so callers can detect abnormal termination.
  • parseOpenCommand skipping dash args — added -- end-of-options handling so pear open -- -repo can target a dash-named directory (with a test).
  • Stale window in second-instance — guarded the focus/restore path with !mainWindow.isDestroyed().
  • cli:open-project race — added a monotonic "latest-wins" token so overlapping opens can't leave the UI on an older project.
  • Windows path separator (nested-root matching) — already addressed earlier by switching to path.relative/isAbsolute.

All 22 tests pass and npm run build succeeds. The earlier merge conflict is cleared (PR is no longer dirty).


Generated by Claude Code

@codeant-ai
Copy link
Copy Markdown

codeant-ai Bot commented Jun 3, 2026

CodeAnt AI Incremental review completed.

claude added 3 commits June 3, 2026 02:56
Make Pear a releasable signed/notarized macOS app:

- electron-builder.yml: dmg + zip (arm64/x64), hardened runtime, entitlements,
  native-module unpacking (ssh2/cpu-features), GitHub publish config
- build/entitlements.mac.plist + build/notarize.cjs (afterSign notarization,
  App Store Connect API key or Apple ID, skips cleanly without creds)
- electron-updater wiring (src/main/updater.ts): checks GitHub Releases on
  launch + every 6h, prompts to restart, 'Check for Updates…' menu item
- In-app 'Install pear CLI' action (src/main/cli-install.ts): admin-elevated
  shim into /usr/local/bin/pear pointing at the packaged app binary
- .github/workflows/release.yml: tag-triggered macOS build/sign/notarize/publish
- RELEASING.md: required Apple credentials + GitHub secrets and release steps
- package.json: pack/dist/release scripts, electron-builder/-updater/notarize deps
Ship downloads as Pear-<version>-<arch>.dmg/.zip while keeping the installed
app named 'Pear by Agent Relay'.
Resolve the packaging conflicts by adopting the pipeline from #76/#77 (now on
main), which correctly handles the per-arch prebuilt broker binary, and layer
our additive features on top:

- electron-builder.yml: take main's config (arm64-only, npmRebuild:false,
  resources bundled + app-icon extraResource, build/icon.png, notarize:true,
  draft release); add a zip target so electron-updater can self-update
- release.yml, entitlements.mac.plist, package.json deps/scripts: adopt main's
- Drop our redundant afterSign notarize hook + @electron/notarize dep
  (replaced by built-in notarize:true)
- Keep our additions: pear open CLI, in-app CLI installer, electron-updater
  auto-update wiring, and clean artifact filenames
- Update RELEASING.md to match (manual dispatch, draft, arm64)
@codeant-ai
Copy link
Copy Markdown

codeant-ai Bot commented Jun 3, 2026

CodeAnt AI is running Incremental review

@codeant-ai codeant-ai Bot added size:XL This PR changes 500-999 lines, ignoring generated files and removed size:L This PR changes 100-499 lines, ignoring generated files labels Jun 3, 2026
@codeant-ai
Copy link
Copy Markdown

codeant-ai Bot commented Jun 3, 2026

CodeAnt AI Incremental review completed.

main now owns the signed/notarized release pipeline (#76/#77), so drop the
duplicate packaging config from this PR and keep only the application-level
work:

- Revert electron-builder.yml / release.yml / entitlements.mac.plist to main's
- Remove RELEASING.md and the stale release/ gitignore entry
- Keep: pear open CLI, in-app CLI installer, and electron-updater auto-update
- The sole release-config change retained is a zip target in electron-builder.yml,
  which auto-update requires (generates latest-mac.yml + the update artifact)
@willwashburn willwashburn merged commit 37c370d into main Jun 3, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL This PR changes 500-999 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants