Skip to content

Conversation

@zerob13
Copy link
Collaborator

@zerob13 zerob13 commented Nov 22, 2025

Summary by CodeRabbit

  • New Features

    • Added external dependency checks and a dependency dialog guiding users to install missing tools.
    • Added terminal paste via clipboard with a new readClipboardText API.
  • UI/UX Improvements

    • Streamlined terminal dialog with a single paste action and clearer status badge.
    • When required dependencies are missing, initialization halts and users are shown actionable guidance.
  • Localization

    • Added dependency-related strings and paste/pasteError translations across locales.

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 22, 2025

Walkthrough

Adds pre-initialization external dependency checks for ACP agents (e.g., Git Bash), exposes clipboard read API and paste action in the ACP terminal, adjusts system-install npm environment handling, introduces a dependency dialog UI, and updates i18n strings across locales.

Changes

Cohort / File(s) Summary
Build Configuration
build/nsis-installer.nsh
Whitespace-only formatting change; no functional impact.
Runtime Utilities
src/main/lib/runtimeHelper.ts
Added isInstalledInSystemDirectory() and getUserNpmPrefix() public methods to detect system installs and retrieve user npm prefix on Windows.
ACP Initialization Logic
src/main/presenter/configPresenter/acpInitHelper.ts, src/main/presenter/configPresenter/index.ts
Introduced ExternalDependency model, checkExternalDependency() and checkRequiredDependencies() checks; integrated dependency gating into initializeBuiltinAgent; adjusted Windows PowerShell execution policy and environment/npm prefix/PATH handling for system installs; initializeAcpAgent now short-circuits when init returns null.
Preload / Clipboard API
src/preload/index.d.ts, src/preload/index.ts
Added readClipboardText(): string to the preload API and implementation exposing clipboard.readText().
Terminal Dialog UI & IPC
src/renderer/settings/components/AcpTerminalDialog.vue
Reworked dialog layout and controls, replaced close/kill with paste button that uses window.api.readClipboardText(), emits dependencies-required when missing deps detected, added IPC listener for external-deps-required, switched icon import to @iconify/vue, removed sr-only CSS.
Dependency Dialog Component
src/renderer/settings/components/AcpDependencyDialog.vue
New component to list missing external dependencies with descriptions, platform-specific install commands, download URL, and copy-to-clipboard (with fallback and toasts).
ACP Settings Integration
src/renderer/settings/components/AcpSettings.vue
Integrated AcpDependencyDialog, added reactive dependencyDialogOpen and missingDependencies, and handler to open dependency dialog when terminal emits missing-deps event.
Internationalization
src/renderer/src/i18n/{en-US,fa-IR,fr-FR,ja-JP,ko-KR,pt-BR,ru-RU,zh-CN,zh-HK,zh-TW}/settings.json
Removed terminal.description, added terminal.paste and terminal.pasteError, and introduced dependency object (title, description, installCommands, downloadUrl, copy, copied, copyFailed) across locales.

Sequence Diagram(s)

sequenceDiagram
    participant Renderer as Renderer (AcpTerminalDialog)
    participant Preload as Preload API
    participant Main as Main Process (acpInitHelper)
    participant UI as Renderer (AcpDependencyDialog)

    Renderer->>Main: Request initialize ACP agent
    Main->>Main: checkRequiredDependencies()
    alt Missing dependencies
        Main->>Renderer: external-deps-required (IPC)
        Renderer->>Renderer: handleExternalDepsRequired()
        Renderer->>UI: emit dependencies-required (open dialog)
        UI->>UI: show dependency list / copy commands
    else All dependencies OK
        Main->>Renderer: initialization proceeds
        Renderer->>Renderer: terminal session active
    end

    rect rgba(200,220,240,0.6)
    Note over Renderer,Preload: Paste flow
    Renderer->>Preload: readClipboardText()
    Preload->>Renderer: clipboard text
    Renderer->>Main: send pasted text to terminal input (IPC)
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Files/areas to focus review on:
    • src/main/presenter/configPresenter/acpInitHelper.ts — dependency detection logic, platform/path checks, environment variable adjustments for system installs, and PowerShell invocation flags.
    • src/renderer/settings/components/AcpTerminalDialog.vue — IPC wiring, paste handling via preload API, lifecycle and cleanup of listeners, and modified UI/UX interactions.
    • src/renderer/settings/components/AcpDependencyDialog.vue — clipboard fallback behavior and copy-to-clipboard/toast error handling.
    • Cross-module behavior — confirm the event/IPC flow between main, preload, terminal dialog, settings, and dependency dialog.

Possibly related PRs

Suggested labels

codex

Poem

🐰 I checked the paths and nibbled code,
Clipboard ready, with a joyful hop and ode.
Paste a line, dependencies shown,
Dialogs open, errors blown—
Locales sing, our pipeline grows.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding Windows-specific helper functionality for ACP agent installation, including dependency checking, clipboard paste support, and environment setup.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/windows-auto-install-acp

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d8bc51c and 53f784d.

📒 Files selected for processing (2)
  • src/renderer/src/i18n/ko-KR/settings.json (1 hunks)
  • src/renderer/src/i18n/pt-BR/settings.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/renderer/src/i18n/ko-KR/settings.json
  • src/renderer/src/i18n/pt-BR/settings.json
⏰ 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-check (x64)

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.

@zerob13 zerob13 marked this pull request as ready for review November 23, 2025 06:43
Copy link
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: 3

🧹 Nitpick comments (6)
src/main/presenter/configPresenter/index.ts (1)

1047-1072: Graceful handling of missing dependencies in builtin init

The new const result = await initializeBuiltinAgent(...); if (result === null) return correctly turns the “missing dependencies” case into a no-op from the caller’s perspective, relying on the helper to notify the renderer. This avoids throwing while keeping the happy path unchanged.

If you like, you could inline the check to avoid the temporary variable, but that’s purely stylistic.

src/renderer/settings/components/AcpSettings.vue (1)

260-270: Dependency dialog wiring and event flow look solid; consider reusing shared type

The new flow is coherent:

  • AcpTerminalDialog emits dependencies-required when the main process reports missing deps.
  • handleDependenciesRequired stores the payload, closes the terminal dialog, and opens AcpDependencyDialog.
  • AcpDependencyDialog receives missingDependencies plus open as props and is controlled via update:open.

This should give a clean UX transition from the terminal to the dependency explanation.

The only concern is type duplication: missingDependencies inlines the dependency shape locally. Since the PR already introduces a shared ExternalDependency type, it would be safer to reuse that to avoid drift if fields change later, e.g.:

import type { ExternalDependency } from '@/shared/…' // adjust path

const missingDependencies = ref<ExternalDependency[]>([])

const handleDependenciesRequired = (dependencies: ExternalDependency[]) => {
  console.log('[AcpSettings] Dependencies required:', dependencies)
  missingDependencies.value = dependencies
  dependencyDialogOpen.value = true
  terminalDialogOpen.value = false
}

Also applies to: 306-343, 707-712

src/renderer/settings/components/AcpDependencyDialog.vue (3)

13-15: Prefer stable keys for dependency list rendering

Using :key="index" works but is fragile if the list ever reorders or items are inserted/removed. You already have a natural key (dep.name, or \${dep.name}-${dep.platform?.join(',')}``) that would be more stable and reduce unnecessary re-renders.

-  v-for="(dep, index) in dependencies"
-  :key="index"
+  v-for="dep in dependencies"
+  :key="dep.name"

104-117: Deduplicate ExternalDependency type across main and renderer

The ExternalDependency interface is duplicated (here, in AcpTerminalDialog.vue, and in acpInitHelper.ts). That increases the chance of fields drifting over time (e.g., new properties added in one place only). Consider moving this type to a shared module (e.g., in @shared or a small TS file imported by both main and renderer) and reusing it everywhere.

- interface ExternalDependency {
-   name: string
-   description: string
-   ...
- }
+// import type { ExternalDependency } from '@shared/acpDependencies'

131-160: Provide user feedback when clipboard APIs are unavailable

copyToClipboard logs a warning when neither window.api.copyText nor navigator.clipboard exist, but the user gets no visual feedback. It would be more user-friendly to show the same destructive toast used in the error path so they know copy didn’t work.

   } else {
-    console.warn('[AcpDependencyDialog] Clipboard API not available')
+    console.warn('[AcpDependencyDialog] Clipboard API not available')
+    toast({
+      title: t('settings.acp.dependency.copyFailed'),
+      variant: 'destructive'
+    })
   }
src/main/presenter/configPresenter/acpInitHelper.ts (1)

18-51: Centralize ExternalDependency type and constant for cross-process consistency

This backend ExternalDependency interface and EXTERNAL_DEPENDENCIES shape are mirrored in at least two renderer components. To avoid drift between what main sends and what the renderer expects, it would be better to define the type (and possibly the base metadata) in a shared module (e.g., @shared/acpDependencies) and import it here and in the renderer, instead of redefining the interface multiple times.

- interface ExternalDependency { ... }
- const EXTERNAL_DEPENDENCIES: ExternalDependency[] = [...]
+ // import type { ExternalDependency } from '@shared/acpDependencies'
+ // import { EXTERNAL_DEPENDENCIES } from '@shared/acpDependencies'
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1215814 and d8bc51c.

📒 Files selected for processing (19)
  • build/nsis-installer.nsh (1 hunks)
  • src/main/lib/runtimeHelper.ts (1 hunks)
  • src/main/presenter/configPresenter/acpInitHelper.ts (6 hunks)
  • src/main/presenter/configPresenter/index.ts (1 hunks)
  • src/preload/index.d.ts (1 hunks)
  • src/preload/index.ts (1 hunks)
  • src/renderer/settings/components/AcpDependencyDialog.vue (1 hunks)
  • src/renderer/settings/components/AcpSettings.vue (4 hunks)
  • src/renderer/settings/components/AcpTerminalDialog.vue (7 hunks)
  • src/renderer/src/i18n/en-US/settings.json (1 hunks)
  • src/renderer/src/i18n/fa-IR/settings.json (1 hunks)
  • src/renderer/src/i18n/fr-FR/settings.json (2 hunks)
  • src/renderer/src/i18n/ja-JP/settings.json (1 hunks)
  • src/renderer/src/i18n/ko-KR/settings.json (1 hunks)
  • src/renderer/src/i18n/pt-BR/settings.json (1 hunks)
  • src/renderer/src/i18n/ru-RU/settings.json (1 hunks)
  • src/renderer/src/i18n/zh-CN/settings.json (1 hunks)
  • src/renderer/src/i18n/zh-HK/settings.json (2 hunks)
  • src/renderer/src/i18n/zh-TW/settings.json (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/main/lib/runtimeHelper.ts (1)
test/mocks/electron.ts (1)
  • app (2-10)
src/main/presenter/configPresenter/index.ts (2)
src/main/presenter/configPresenter/acpInitHelper.ts (2)
  • initializeBuiltinAgent (177-232)
  • initializeBuiltinAgent (625-641)
src/shared/types/presenters/legacy.presenters.d.ts (1)
  • AcpBuiltinAgentId (678-678)
⏰ 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-windows (x64)
🔇 Additional comments (21)
src/preload/index.ts (1)

25-27: LGTM! Clean clipboard read implementation.

The readClipboardText method follows the established pattern and correctly exposes Electron's clipboard API to the renderer process.

src/renderer/src/i18n/zh-CN/settings.json (1)

875-892: LGTM! Localization additions support new features.

The new translation keys for clipboard paste functionality and dependency notifications are properly structured and align with the PR's feature set.

build/nsis-installer.nsh (1)

133-133: LGTM! Formatting-only change.

This whitespace removal has no functional impact on the installer behavior.

src/renderer/src/i18n/zh-TW/settings.json (1)

892-909: LGTM! Consistent localization for Traditional Chinese.

The translation additions for dependency handling and paste functionality are properly structured and align with other locale files.

src/main/lib/runtimeHelper.ts (2)

323-345: LGTM! Appropriate Windows system directory detection.

The method correctly identifies when the app is installed in a system directory on Windows by checking for "program files" in the normalized path. The logging is helpful for troubleshooting.


347-359: LGTM! Correct npm user prefix path for Windows.

The method returns the standard Windows user npm prefix location (%APPDATA%\npm), which is used when the app needs to install npm packages without system-level permissions.

src/renderer/src/i18n/fr-FR/settings.json (2)

895-895: Minor punctuation improvement.

The colon formatting in the exit error message is now more consistent.


907-918: LGTM! French localization for new features.

The translation additions for clipboard paste and dependency notifications are properly structured.

src/renderer/src/i18n/fa-IR/settings.json (1)

906-918: LGTM! Persian localization additions.

The translation keys for clipboard paste and dependency handling are properly added with appropriate RTL Persian text.

src/renderer/src/i18n/ja-JP/settings.json (1)

906-918: LGTM! Japanese localization complete.

The translation additions for clipboard paste and dependency notifications are properly structured and align with other locale files.

src/preload/index.d.ts (1)

7-14: Clipboard API typing looks consistent

readClipboardText(): string matches the synchronous Electron clipboard API and is consistent with other Window.api methods here.

src/renderer/src/i18n/en-US/settings.json (1)

875-892: New terminal/dependency strings are clear and aligned with behavior

The terminal.paste / terminal.pasteError labels and the acp.dependency block read naturally and match the intended UX for missing dependencies and clipboard paste.

src/renderer/src/i18n/ru-RU/settings.json (1)

893-918: RU terminal/dependency translations look correct

The new terminal.waiting/paste/pasteError strings and the dependency block are idiomatic Russian and accurately mirror the English meanings, so the new UI should render fine for this locale.

src/renderer/src/i18n/zh-HK/settings.json (1)

899-917: ZH-HK terminal/dependency strings align with new ACP UI

terminal.paste / pasteError and the dependency labels (“已復製到剪貼板”, “缺少外部依賴”, etc.) are clear and consistent with the English source, so the new dialogs should display correctly in zh-HK.

src/main/presenter/configPresenter/acpInitHelper.ts (3)

83-143: Dependency check flow for builtin agents looks solid

The multi-step checkExternalDependency (direct command, known paths, then where/which) and platform gating in checkRequiredDependencies give a good balance of robustness and safety. Returning true when platform doesn’t match is a nice way to avoid spurious failures on unsupported OSes, and the 5-second timeouts should keep startup responsive with the small, fixed dependency list.


194-209: Short-circuiting builtin initialization on missing deps is a good pattern

Blocking initializeBuiltinAgent when missingDeps.length > 0 and emitting an external-deps-required payload to the renderer gives a clean contract: either you get a live PTY or you get a structured dependency list. The Promise<IPty | null> return type reflects this nicely, and avoiding a thrown error here should make the UI flow much smoother.


549-577: Code is correct; getUserNpmPrefix() returns the proper npm bin directory

Verification confirms that getUserNpmPrefix() correctly returns C:\Users\...\AppData\Roaming\npm, which is both the npm global prefix and the directory containing globally installed binaries on Windows. The code properly uses this value for both npm_config_prefix/NPM_CONFIG_PREFIX and PATH prepending. No changes needed.

src/renderer/settings/components/AcpTerminalDialog.vue (4)

12-29: Status badge + paste button integration looks good

The new header layout with a compact status pill and a dedicated paste button is straightforward, and :disabled="!isRunning" on the paste action avoids sending input when no process is alive. The static statusBadgeClass computed is fine for now and leaves room for future styling based on status.


283-299: External dependency notification wiring is clean and decoupled

handleExternalDepsRequired simply forwards missingDeps to the parent via dependencies-required and then closes the dialog, which keeps the terminal component focused on I/O while letting settings/UI decide how to present the dependency dialog. The defensive early return when missingDeps is empty is also a nice touch.


301-326: IPC listener setup/teardown covers new external-deps-required channel

Adding and removing the external-deps-required listener alongside the existing acp-init:* listeners keeps the lifecycle consistent and avoids dangling handlers after the dialog closes or unmounts. This should prevent duplicate events across multiple openings.


261-281: I found the implementation. Now let me verify Electron's clipboard.readText() API to confirm whether it's synchronous or asynchronous.

Remove suggestion to add awaitreadClipboardText is synchronous

Electron's clipboard.readText() returns a string directly, not a Promise. The documentation shows usage as const text = clipboard.readText() without await. The preload wrapper in src/preload/index.ts (lines 25–27) returns clipboard.readText() synchronously, and the type definition (src/preload/index.d.ts, line 9) declares readClipboardText(): string, confirming synchronous behavior. The current code in AcpTerminalDialog.vue line 268 is correct and requires no changes.

Likely an incorrect or invalid review comment.

Comment on lines 113 to 125
const handleOpenUpdate = (val: boolean) => {
if (!val) {
handleManualClose()
}
}
const handleManualClose = () => {
// Kill process if running
if (isRunning.value) {
if (window.electron) {
window.electron.ipcRenderer.send('acp-terminal:kill')
// Kill process if running
if (isRunning.value) {
if (window.electron) {
window.electron.ipcRenderer.send('acp-terminal:kill')
}
}
emit('update:open', false)
emit('close')
} else {
emit('update:open', val)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Ensure backend process is also killed on programmatic close, not just user-triggered

handleOpenUpdate sends acp-terminal:kill only when the dialog is closed via the Dialog component’s own update:open event. If the parent sets open to false programmatically while isRunning is still true, the watcher will clean up the terminal and listeners but the backend process may continue running. Consider mirroring the kill behavior in the watcher when open transitions to false so all close paths terminate the PTY.

 watch(
   () => props.open,
   async (open) => {
     if (open) {
       ...
     } else {
       console.log('[AcpTerminal] Dialog closing, cleaning up')
+      if (isRunning.value && window.electron) {
+        window.electron.ipcRenderer.send('acp-terminal:kill')
+      }
       removeIpcListeners()
       cleanupTerminal()
     }
   }
 )

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/renderer/settings/components/AcpTerminalDialog.vue around lines 113–125,
the current logic sends 'acp-terminal:kill' only when the Dialog emits
update:open (user close) but not when the parent programmatically sets open to
false; update the watcher that reacts to the open prop so that when open
transitions to false it also checks if isRunning.value is true and, if
window.electron is available, sends
window.electron.ipcRenderer.send('acp-terminal:kill') before performing the
existing listener/terminal cleanup to ensure the backend PTY is terminated on
all close paths.

@zerob13 zerob13 merged commit 7f22d00 into dev Nov 23, 2025
2 checks passed
@zerob13 zerob13 deleted the feat/windows-auto-install-acp branch November 23, 2025 13:51
@zerob13 zerob13 restored the feat/windows-auto-install-acp branch November 23, 2025 13:51
@zerob13 zerob13 deleted the feat/windows-auto-install-acp branch November 23, 2025 13:52
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.

2 participants