Skip to content

feat(settings): add global dbt Core v1/v2 version management#339

Open
Nuri1977 wants to merge 4 commits into
devfrom
feature/dbt-core-v2-support
Open

feat(settings): add global dbt Core v1/v2 version management#339
Nuri1977 wants to merge 4 commits into
devfrom
feature/dbt-core-v2-support

Conversation

@Nuri1977

@Nuri1977 Nuri1977 commented Jul 13, 2026

Copy link
Copy Markdown
Contributor
  • support global dbt-core upgrades, downgrades, and rollback
  • add side-by-side Python v1 and Rust v2 runtime cards
  • show five stable v1 releases and available v2 previews
  • verify Apache dbt-core provenance after installation
  • add adapter compatibility and project safety checks
  • enable experimental Postgres support for scoped v2 commands
  • preserve settings when installation or verification fails
  • add confirmation, warning, progress, and result states
  • add unit tests for version management and runtime switching

Summary by CodeRabbit

  • New Features

    • Added dbt Core version management, including previews, upgrades, downgrades, rollback information, and package management.
    • Added project and adapter compatibility checks before running dbt commands.
    • Added support for configurable CLI environments and richer command results with exit codes and output.
    • Improved tool execution reporting with clearer success and error states.
  • Bug Fixes

    • Improved dbt command error detection and messaging.
    • Fixed tool calls and dbt runs being displayed with incorrect statuses.
    • Improved toast layout for long, multi-line messages.
  • Tests

    • Added coverage for version changes, compatibility checks, CLI failures, and error reporting.

- support global dbt-core upgrades, downgrades, and rollback
- add side-by-side Python v1 and Rust v2 runtime cards
- show five stable v1 releases and available v2 previews
- verify Apache dbt-core provenance after installation
- add adapter compatibility and project safety checks
- enable experimental Postgres support for scoped v2 commands
- preserve settings when installation or verification fails
- add confirmation, warning, progress, and result states
- add unit tests for version management and runtime switching
@Nuri1977 Nuri1977 self-assigned this Jul 13, 2026
@Nuri1977 Nuri1977 added the enhancement New feature or request label Jul 13, 2026
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds managed dbt-core version and package management, adapter compatibility checks, environment-aware CLI execution with exit codes, failure-aware agent/tool reporting, expanded settings workflows, and toast layout refinements.

Changes

DBT runtime management

Layer / File(s) Summary
Runtime contracts and service operations
src/types/backend.ts, src/services/dbtCoreVersion.service.ts, tests/unit/services/dbtCoreVersion.service.test.ts
Adds typed runtime models and implements version discovery, package installation, verification, planning, adapter diagnostics, and project compatibility checks.
Runtime IPC and renderer API wiring
src/main/ipcHandlers/settings.ipcHandlers.ts, src/types/ipc.ts, src/renderer/services/dbtVersions.service.ts, src/renderer/controllers/dbtVersions.controller.ts
Exposes dbt version, package, adapter, and compatibility operations through IPC, renderer services, and controller hooks.
Runtime settings workflows and UI
src/renderer/components/settings/DbtSettings.tsx, tests/unit/components/DbtSettings.versionChange.test.tsx
Adds version planning, confirmation, installation, rollback, package management, runtime filtering, and compatibility displays.
CLI process environment and lifecycle
src/main/adapters/cli.adapter.ts, src/main/ipcHandlers/cli.ipcHandlers.ts, src/renderer/hooks/useCli.tsx, src/renderer/services/projects.service.ts, tests/unit/main/adapters/cli.adapter.test.ts
Propagates approved environment variables to CLI processes and reports exit codes through completion and error events.

Tool outcome handling

Layer / File(s) Summary
Tool result and command error contracts
src/shared/toolResult.ts, src/renderer/utils/dbtCommandResult.ts, src/renderer/utils/dbtProcessEnvironment.ts, src/main/services/ai/tools/dbt.tools.ts, src/main/services/ai/tools/studio/cli.tools.ts, tests/unit/main/services/ai/dbt.tools.test.ts, tests/unit/shared/toolResult.test.ts, tests/unit/utils/dbtCommandResult.test.ts
Adds standardized failure extraction, exit-code output shapes, adapter execution gates, and dbt command result tests.
Agent failure classification
src/main/services/agent.service.ts, src/main/services/ai/agents/projectAgent.ts, src/renderer/hooks/useAgentStream.ts, tests/unit/hooks/useDbt.experimentalAdapters.test.ts
Records failed tool results as errors in streaming, non-streaming, and persisted agent execution paths, while tightening dbt outcome instructions.
Tool result rendering and command gating
src/renderer/components/chat/*, src/renderer/hooks/useDbt.ts
Renders failures from stored tool envelopes and prevents incompatible dbt commands from executing.
Toast sizing and overflow
src/renderer/toastStyles.css
Adds constrained toast dimensions, scrolling, wrapping, and updated control alignment.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Suggested labels: enhancement

Suggested reviewers: jasir99

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: global dbt Core v1/v2 version management in settings.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/dbt-core-v2-support

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install timed out. The project may have too many dependencies for the sandbox.


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.

@Nuri1977 Nuri1977 marked this pull request as ready for review July 13, 2026 14:10
Nuri1977 added 3 commits July 13, 2026 16:15
- add side-by-side dbt Core v1 Python and v2 Rust runtime cards
- support verified global upgrades, downgrades, preview installs, and rollback
- block unsupported v2 adapters and preserve experimental adapter warnings
- propagate dbt exit codes and complete command output to the AI agent
- render failed AI tool calls correctly instead of showing green success states
- prevent partial dbt runs from being reported as fully successful
- require a second run when validating incremental models
- remove repetitive adapter warning toasts from dbt commands
- fix long toast messages overflowing their containers
- add regression tests for failed dbt commands and tool-result envelopes
- detect project adapters from connections and profiles.yml
- separate v1 Python adapters from v2 built-in adapters
- block unsupported v2 adapters before command execution
- show v2 adapter compatibility in Settings
- apply adapter checks to UI and AI dbt commands
- consolidate adapter logic into dbtCoreVersion service

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (4)
tests/unit/main/adapters/cli.adapter.test.ts (1)

49-81: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Add coverage for the signal-killed (code === null) case and the success path.

Current tests cover env sanitization and a plain non-zero exit, but not: the streaming runCommand's success (code === 0) path, or a signal-killed process (child.emit('close', null, 'SIGTERM')) — the latter directly exercises the null-code regression flagged in cli.adapter.ts.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/main/adapters/cli.adapter.test.ts` around lines 49 - 81, Add tests
alongside the existing nonzero-exit test for CliAdapter.runCommand covering both
successful completion with close code 0 and signal termination via close(null,
'SIGTERM'). Assert the success path resolves and emits the expected cli:done
behavior, and the signal-killed path exercises the null-code handling with the
expected rejection/error and event ordering.
src/renderer/components/settings/DbtSettings.tsx (1)

384-397: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Verify confirmDbtVersionChange handles an empty settings.pythonPath gracefully.

handleInstallDbt explicitly guards if (!settings.pythonPath) throw ... before installing, but confirmDbtVersionChange/the "Available dbt runtimes" version buttons (reachable before any dbt-core setup finishes, since that panel isn't gated on settings.dbtPath/pythonPath) send pythonPath: settings.pythonPath unguarded. If the backend's getPythonExecutable fallback doesn't gracefully resolve a default when pythonPath is empty, a first-time user could trigger a confusing backend error via this path instead of the clear "Install Python first" message used elsewhere.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/renderer/components/settings/DbtSettings.tsx` around lines 384 - 397,
Update confirmDbtVersionChange to validate settings.pythonPath before calling
installDbtVersionChange, matching handleInstallDbt’s existing “Install Python
first” behavior. Return or throw the same clear user-facing error when the path
is empty, and only pass pythonPath after validation.
tests/unit/components/DbtSettings.versionChange.test.tsx (1)

156-163: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Checkbox click leaves "check current project after install" untested.

Clicking this checkbox actually unchecks it (defaults to checked since the mocked plan has isMajorVersionChange: true), so confirmDbtVersionChange's checkCurrentProjectCompatibility() branch is skipped rather than exercised — and useCheckCurrentProjectCompatibility has no mockResolvedValue to assert against. As written, this test never verifies the post-install project-check flow. Consider either asserting on compatibilityResult rendering with the checkbox left checked, or removing the click if it's not meant to test anything.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/components/DbtSettings.versionChange.test.tsx` around lines 156 -
163, The test currently unchecks the default-enabled “Check current project
after install” option, so it skips the compatibility-check branch. Update the
test around confirmDbtVersionChange to leave the checkbox checked or explicitly
configure it accordingly, mock useCheckCurrentProjectCompatibility with a
resolved result, and assert the resulting compatibilityResult rendering to
verify the post-install project-check flow.
src/main/ipcHandlers/settings.ipcHandlers.ts (1)

148-198: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

New dbt IPC handlers leave request payloads untyped.

Unlike the pre-existing handlers in this file (e.g. settings:save types body: SettingsType), all 12 new dbt:* handlers accept an implicitly-any request/req. The corresponding request types (DbtVersionListOptions, DbtVersionChangePlanRequest, DbtVersionChangeRequest, PythonPackageActionRequest, PythonPackageInstallVersionRequest, PythonPackageVersionListRequest) already exist in src/types/backend.ts and are imported by the renderer controller — applying them here would restore compile-time safety at this IPC boundary.

♻️ Example for one handler
-  ipcMain.handle('dbt:versions:list', async (_event, request) => {
+  ipcMain.handle('dbt:versions:list', async (_event, request: DbtVersionListOptions) => {
     return DbtCoreVersionService.listDbtCoreVersions(request);
   });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/ipcHandlers/settings.ipcHandlers.ts` around lines 148 - 198, Type
every request parameter in the new dbt IPC handlers in the registration block,
importing and reusing the existing request types from backend.ts. Apply the
appropriate types to version listing, version-change, package action,
package-version listing, and package-version installation handlers, and type
adapter requests consistently with their expected projectPath payload. Leave
handlers without request payloads unchanged and ensure no request/req remains
implicitly any.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/services/dbtCoreVersion.service.ts`:
- Around line 775-789: The adapter compatibility check must use the live
dbt-core version detected by checkCurrentProjectCompatibility instead of
settings.dbtVersion. Thread that detected version through
checkProjectAdapterCompatibility and its callers, including the anchor flow at
src/main/services/dbtCoreVersion.service.ts:775-789 and sibling flow at
src/main/services/dbtCoreVersion.service.ts:1009-1037; update the corresponding
test setup and expectations at
tests/unit/services/dbtCoreVersion.service.test.ts:376-399 to verify stale
settings cannot misclassify v1/v2 or bypass the Postgres safety block.
- Around line 237-267: Update runProcess to enforce a finite execution timeout
for spawned commands, terminating the child process when the timeout elapses and
rejecting or otherwise returning a timeout failure so awaiting IPC calls cannot
remain blocked indefinitely. Preserve the existing stdout, stderr, exit-code,
and process-error handling for commands that complete normally.

In `@src/renderer/components/settings/DbtSettings.tsx`:
- Around line 261-296: Update the adapter-package branch in the install loop
around installLatestPackage so failures accumulate instead of replacing the
existing version-change result. Preserve the first or combined adapter failure
in setVersionChangeResult, and stop or otherwise prevent later failures from
clobbering it while retaining the existing dbt-core failure handling.

In `@src/renderer/utils/dbtCommandResult.ts`:
- Line 1: Update ANSI_ESCAPE_REGEX to require the ANSI escape character before
the bracketed formatting sequence, supporting the ESC representation used by
terminal output and preventing literal text such as “[1m” from matching.

---

Nitpick comments:
In `@src/main/ipcHandlers/settings.ipcHandlers.ts`:
- Around line 148-198: Type every request parameter in the new dbt IPC handlers
in the registration block, importing and reusing the existing request types from
backend.ts. Apply the appropriate types to version listing, version-change,
package action, package-version listing, and package-version installation
handlers, and type adapter requests consistently with their expected projectPath
payload. Leave handlers without request payloads unchanged and ensure no
request/req remains implicitly any.

In `@src/renderer/components/settings/DbtSettings.tsx`:
- Around line 384-397: Update confirmDbtVersionChange to validate
settings.pythonPath before calling installDbtVersionChange, matching
handleInstallDbt’s existing “Install Python first” behavior. Return or throw the
same clear user-facing error when the path is empty, and only pass pythonPath
after validation.

In `@tests/unit/components/DbtSettings.versionChange.test.tsx`:
- Around line 156-163: The test currently unchecks the default-enabled “Check
current project after install” option, so it skips the compatibility-check
branch. Update the test around confirmDbtVersionChange to leave the checkbox
checked or explicitly configure it accordingly, mock
useCheckCurrentProjectCompatibility with a resolved result, and assert the
resulting compatibilityResult rendering to verify the post-install project-check
flow.

In `@tests/unit/main/adapters/cli.adapter.test.ts`:
- Around line 49-81: Add tests alongside the existing nonzero-exit test for
CliAdapter.runCommand covering both successful completion with close code 0 and
signal termination via close(null, 'SIGTERM'). Assert the success path resolves
and emits the expected cli:done behavior, and the signal-killed path exercises
the null-code handling with the expected rejection/error and event ordering.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 466566e3-f983-4e0a-8278-032ceba605c9

📥 Commits

Reviewing files that changed from the base of the PR and between 2dfc086 and 0175160.

📒 Files selected for processing (33)
  • src/main/adapters/cli.adapter.ts
  • src/main/ipcHandlers/cli.ipcHandlers.ts
  • src/main/ipcHandlers/settings.ipcHandlers.ts
  • src/main/services/agent.service.ts
  • src/main/services/ai/agents/projectAgent.ts
  • src/main/services/ai/tools/dbt.tools.ts
  • src/main/services/ai/tools/studio/cli.tools.ts
  • src/main/services/dbtCoreVersion.service.ts
  • src/main/services/dbtVersionManager.service.ts
  • src/renderer/components/chat/AgentStepBlock.tsx
  • src/renderer/components/chat/MessageRenderer.tsx
  • src/renderer/components/chat/ToolCallRow.tsx
  • src/renderer/components/settings/DbtSettings.tsx
  • src/renderer/controllers/dbtVersions.controller.ts
  • src/renderer/controllers/index.ts
  • src/renderer/hooks/useAgentStream.ts
  • src/renderer/hooks/useCli.tsx
  • src/renderer/hooks/useDbt.ts
  • src/renderer/services/dbtVersions.service.ts
  • src/renderer/services/projects.service.ts
  • src/renderer/toastStyles.css
  • src/renderer/utils/dbtCommandResult.ts
  • src/renderer/utils/dbtProcessEnvironment.ts
  • src/shared/toolResult.ts
  • src/types/backend.ts
  • src/types/ipc.ts
  • tests/unit/components/DbtSettings.versionChange.test.tsx
  • tests/unit/hooks/useDbt.experimentalAdapters.test.ts
  • tests/unit/main/adapters/cli.adapter.test.ts
  • tests/unit/main/services/ai/dbt.tools.test.ts
  • tests/unit/services/dbtCoreVersion.service.test.ts
  • tests/unit/shared/toolResult.test.ts
  • tests/unit/utils/dbtCommandResult.test.ts
💤 Files with no reviewable changes (1)
  • src/main/services/dbtVersionManager.service.ts

Comment on lines +237 to +267
const runProcess = (
command: string,
args: string[],
options?: ProcessOptions,
): Promise<ProcessResult> => {
return new Promise((resolve, reject) => {
const child = spawn(command, args, {
shell: false,
...(options?.cwd ? { cwd: options.cwd } : {}),
...(options?.env ? { env: options.env } : {}),
});
let stdout = '';
let stderr = '';

child.stdout.on('data', (data) => {
stdout += String(data);
});

child.stderr.on('data', (data) => {
stderr += String(data);
});

child.on('error', (error) => {
reject(error);
});

child.on('close', (exitCode) => {
resolve({ exitCode, stdout, stderr });
});
});
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

runProcess spawns without any timeout.

Every pip install/uninstall and every dbt parse/dbt compile invocation goes through runProcess, which has no timeout or kill mechanism (unlike fetchPypiProjectJson's axios.get(url, { timeout: 15000 }) in this same file). A hung network install or a stuck dbt process leaves the awaiting IPC call — and the renderer UI state waiting on it — blocked indefinitely.

⏱️ Suggested direction
 const runProcess = (
   command: string,
   args: string[],
   options?: ProcessOptions,
 ): Promise<ProcessResult> => {
   return new Promise((resolve, reject) => {
     const child = spawn(command, args, {
       shell: false,
       ...(options?.cwd ? { cwd: options.cwd } : {}),
       ...(options?.env ? { env: options.env } : {}),
     });
     let stdout = '';
     let stderr = '';
+    const timeoutMs = options?.timeoutMs ?? 5 * 60 * 1000;
+    const timer = setTimeout(() => {
+      child.kill();
+      reject(new Error(`Command timed out after ${timeoutMs}ms: ${command}`));
+    }, timeoutMs);
     ...
     child.on('close', (exitCode) => {
+      clearTimeout(timer);
       resolve({ exitCode, stdout, stderr });
     });
   });
 };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/services/dbtCoreVersion.service.ts` around lines 237 - 267, Update
runProcess to enforce a finite execution timeout for spawned commands,
terminating the child process when the timeout elapses and rejecting or
otherwise returning a timeout failure so awaiting IPC calls cannot remain
blocked indefinitely. Preserve the existing stdout, stderr, exit-code, and
process-error handling for commands that complete normally.

Comment on lines +775 to +789
const adapterCheck = await this.checkProjectAdapterCompatibility(
project.path,
);
if (!adapterCheck.adapter.canExecute) {
return {
ok: false,
projectName: project.name,
projectPath: project.path,
diagnostics: [],
recommendations: [
'Switch the global dbt runtime to a stable v1 release in Settings before running this project.',
],
error: `${adapterCheck.adapter.displayName}: ${adapterCheck.adapter.notes}`,
};
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Use the live dbt-core version for adapter gating checkProjectAdapterCompatibility still derives runtime from settings.dbtVersion; thread the already-detected version from checkCurrentProjectCompatibility through this path so a stale setting can’t misclassify v1/v2 and skip the Postgres safety block.

📍 Affects 2 files
  • src/main/services/dbtCoreVersion.service.ts#L775-L789 (this comment)
  • src/main/services/dbtCoreVersion.service.ts#L1009-L1037
  • tests/unit/services/dbtCoreVersion.service.test.ts#L376-L399
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/services/dbtCoreVersion.service.ts` around lines 775 - 789, The
adapter compatibility check must use the live dbt-core version detected by
checkCurrentProjectCompatibility instead of settings.dbtVersion. Thread that
detected version through checkProjectAdapterCompatibility and its callers,
including the anchor flow at src/main/services/dbtCoreVersion.service.ts:775-789
and sibling flow at src/main/services/dbtCoreVersion.service.ts:1009-1037;
update the corresponding test setup and expectations at
tests/unit/services/dbtCoreVersion.service.test.ts:376-399 to verify stale
settings cannot misclassify v1/v2 or bypass the Postgres safety block.

Comment on lines +261 to 296
for (let i = 0; i < packages.length; i++) {
const pkg = packages[i];
setCurrentPackage(pkg);
setLoadingMessage(`Installing ${pkg}...`);
setInstallProgress((i / packages.length) * 100);

if (pkg === 'dbt-core') {
const result = await installPackageVersion({
pythonPath: settings.pythonPath,
packageName: pkg,
version: targetDbtVersion,
});
if (!result.ok) {
setVersionChangeResult(result);
break;
}
}
} else {
try {
for (let i = 0; i < packages.length; i++) {
const pkg = packages[i];
setCurrentPackage(pkg);
setInstallProgress((i / packages.length) * 100);

try {
await runCommand(`pip install ${pkg}`);
} catch {
/* Continue with next package */
}
if (result.dbtPath) {
onInstallDbtSave('dbtPath', result.dbtPath);
}
if (result.installedVersion) {
onInstallDbtSave('dbtVersion', result.installedVersion);
}
} else {
const result = await installLatestPackage({
pythonPath: settings.pythonPath,
packageName: pkg,
});
if (!result.ok) {
setVersionChangeResult({
ok: false,
error: result.error || `Unable to install ${pkg}.`,
});
}
} catch {
/* empty */
}
}

// Get and save the dbt path
setCurrentPackage('Locating dbt path...');
setInstallProgress(100);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Adapter-package install failures overwrite each other in the loop.

When pkg !== 'dbt-core' fails, setVersionChangeResult clobbers whatever failure was recorded for a previously-failed adapter package in the same loop, and the loop keeps going. If e.g. dbt-postgres and dbt-bigquery both fail, only the dbt-bigquery error ends up visible; the dbt-postgres failure is silently dropped even though checkInstalledPackages() afterward won't show it as installed either.

🐛 Proposed fix: accumulate failures instead of overwriting
+      const failedPackages: string[] = [];
       for (let i = 0; i < packages.length; i++) {
         const pkg = packages[i];
         setCurrentPackage(pkg);
         setLoadingMessage(`Installing ${pkg}...`);
         setInstallProgress((i / packages.length) * 100);

         if (pkg === 'dbt-core') {
           const result = await installPackageVersion({
             pythonPath: settings.pythonPath,
             packageName: pkg,
             version: targetDbtVersion,
           });
           if (!result.ok) {
             setVersionChangeResult(result);
             break;
           }
           if (result.dbtPath) {
             onInstallDbtSave('dbtPath', result.dbtPath);
           }
           if (result.installedVersion) {
             onInstallDbtSave('dbtVersion', result.installedVersion);
           }
         } else {
           const result = await installLatestPackage({
             pythonPath: settings.pythonPath,
             packageName: pkg,
           });
           if (!result.ok) {
-            setVersionChangeResult({
-              ok: false,
-              error: result.error || `Unable to install ${pkg}.`,
-            });
+            failedPackages.push(pkg);
           }
         }
       }
+      if (failedPackages.length > 0) {
+        setVersionChangeResult({
+          ok: false,
+          error: `Unable to install: ${failedPackages.join(', ')}.`,
+        });
+      }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for (let i = 0; i < packages.length; i++) {
const pkg = packages[i];
setCurrentPackage(pkg);
setLoadingMessage(`Installing ${pkg}...`);
setInstallProgress((i / packages.length) * 100);
if (pkg === 'dbt-core') {
const result = await installPackageVersion({
pythonPath: settings.pythonPath,
packageName: pkg,
version: targetDbtVersion,
});
if (!result.ok) {
setVersionChangeResult(result);
break;
}
}
} else {
try {
for (let i = 0; i < packages.length; i++) {
const pkg = packages[i];
setCurrentPackage(pkg);
setInstallProgress((i / packages.length) * 100);
try {
await runCommand(`pip install ${pkg}`);
} catch {
/* Continue with next package */
}
if (result.dbtPath) {
onInstallDbtSave('dbtPath', result.dbtPath);
}
if (result.installedVersion) {
onInstallDbtSave('dbtVersion', result.installedVersion);
}
} else {
const result = await installLatestPackage({
pythonPath: settings.pythonPath,
packageName: pkg,
});
if (!result.ok) {
setVersionChangeResult({
ok: false,
error: result.error || `Unable to install ${pkg}.`,
});
}
} catch {
/* empty */
}
}
// Get and save the dbt path
setCurrentPackage('Locating dbt path...');
setInstallProgress(100);
const failedPackages: string[] = [];
for (let i = 0; i < packages.length; i++) {
const pkg = packages[i];
setCurrentPackage(pkg);
setLoadingMessage(`Installing ${pkg}...`);
setInstallProgress((i / packages.length) * 100);
if (pkg === 'dbt-core') {
const result = await installPackageVersion({
pythonPath: settings.pythonPath,
packageName: pkg,
version: targetDbtVersion,
});
if (!result.ok) {
setVersionChangeResult(result);
break;
}
if (result.dbtPath) {
onInstallDbtSave('dbtPath', result.dbtPath);
}
if (result.installedVersion) {
onInstallDbtSave('dbtVersion', result.installedVersion);
}
} else {
const result = await installLatestPackage({
pythonPath: settings.pythonPath,
packageName: pkg,
});
if (!result.ok) {
failedPackages.push(pkg);
}
}
}
if (failedPackages.length > 0) {
setVersionChangeResult({
ok: false,
error: `Unable to install: ${failedPackages.join(', ')}.`,
});
}
setInstallProgress(100);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/renderer/components/settings/DbtSettings.tsx` around lines 261 - 296,
Update the adapter-package branch in the install loop around
installLatestPackage so failures accumulate instead of replacing the existing
version-change result. Preserve the first or combined adapter failure in
setVersionChangeResult, and stop or otherwise prevent later failures from
clobbering it while retaining the existing dbt-core failure handling.

@@ -0,0 +1,46 @@
const ANSI_ESCAPE_REGEX = /\[[0-9;]*m/g;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Include the ESC character in ANSI_ESCAPE_REGEX.

The current regex /\[[0-9;]*m/g misses the escape character (\x1b or \u001b) and will incorrectly match and strip literal text like [1m from strings (e.g., Array[1m]).

🐛 Proposed fix for the ANSI escape regex
-const ANSI_ESCAPE_REGEX = /\[[0-9;]*m/g;
+const ANSI_ESCAPE_REGEX = /\x1b\[[0-9;]*m/g;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const ANSI_ESCAPE_REGEX = /\[[0-9;]*m/g;
const ANSI_ESCAPE_REGEX = /\x1b\[[0-9;]*m/g;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/renderer/utils/dbtCommandResult.ts` at line 1, Update ANSI_ESCAPE_REGEX
to require the ANSI escape character before the bracketed formatting sequence,
supporting the ESC representation used by terminal output and preventing literal
text such as “[1m” from matching.

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant