Repository: TobikoData/sqlmesh
Pull request #4831 (2025-06-26 17:17:50)

Chore!: bump sqlglot to v26.31.0
Relevant commits:
- https://github.com/TobikoData/sqlmesh/commit/186f0edceb01f68a37a2b03266d6ab0be76bc8a8
- https://github.com/tobymao/sqlglot/commit/db4e0ece950a6a1f543d8ecad48a7d4b1d6872be


Patch:
diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml
index 765aea04..1d7f6ec8 100644
--- a/.github/workflows/pr.yaml
+++ b/.github/workflows/pr.yaml
@@ -17,7 +17,7 @@ jobs:
       - uses: actions/checkout@v4
       - uses: actions/setup-node@v4
         with:
-          node-version: '20'
+          node-version: '22'
       - uses: pnpm/action-setup@v4
         with:
           version: latest
@@ -25,3 +25,38 @@ jobs:
         run: pnpm install
       - name: Run CI
         run: pnpm run ci
+  test-vscode-e2e:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - uses: actions/setup-node@v4
+        with:
+          node-version: '22'
+      - uses: pnpm/action-setup@v4
+        with:
+          version: latest
+      - name: Install dependencies
+        run: pnpm install
+      - name: Set up Python
+        uses: actions/setup-python@v5
+        with:
+          python-version: '3.12'
+      - name: Install python dependencies
+        run: |
+          python -m venv .venv
+          source .venv/bin/activate
+          make install-dev
+      - name: Fetch VS Code
+        working-directory: ./vscode/extension
+        run: pnpm run fetch-vscode
+
+      - name: Install code-server
+        run: curl -fsSL https://code-server.dev/install.sh | sh
+      - name: Install Playwright browsers
+        working-directory: ./vscode/extension
+        run: pnpm exec playwright install
+      - name: Run e2e tests
+        working-directory: ./vscode/extension
+        run: |
+          source ../../.venv/bin/activate
+          pnpm run test:e2e tests/stop.spec.ts
diff --git a/.github/workflows/release_extension.yaml b/.github/workflows/release_extension.yaml
index 1807fee3..3807bc34 100644
--- a/.github/workflows/release_extension.yaml
+++ b/.github/workflows/release_extension.yaml
@@ -1,14 +1,32 @@
 name: Release VSCode Extension
 on:
-  push:
-    tags:
-      - 'vscode@v*'
+  workflow_dispatch:
+    inputs:
+      version:
+        description: 'Version to release (e.g., 1.0.0)'
+        required: true
+        type: string
 jobs:
   release:
     runs-on: ubuntu-latest
     steps:
       - name: Checkout repository
         uses: actions/checkout@v4
+      - name: Check branch is main
+        run: |
+          if [[ "${{ github.ref }}" != "refs/heads/main" ]]; then
+            echo "Error: This workflow can only be run from the main branch"
+            exit 1
+          fi
+          echo "Branch check passed: running from main branch"
+      - name: Validate version format
+        run: |
+          version="${{ github.event.inputs.version }}"
+          if ! [[ $version =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?(\+[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?$ ]]; then
+            echo "Error: Version must be a valid semantic version (e.g., 1.0.0, 1.0.0-beta.1, 1.0.0+build.1)"
+            exit 1
+          fi
+          echo "Version format is valid: $version"
       - name: Setup Node.js
         uses: actions/setup-node@v4
         with:
@@ -19,26 +37,20 @@ jobs:
           version: 10
       - name: Install dependencies
         run: pnpm install --frozen-lockfile
-      - name: Extract version from tag
-        id: extract_version
-        run: |
-          VERSION=${GITHUB_REF#refs/tags/vscode@v}
-          echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
       - name: Update package.json version
         working-directory: vscode/extension
         run: |
-          npm version ${{ steps.extract_version.outputs.VERSION }} --no-git-tag-version
-      - name: Install dependencies
-        working-directory: vscode/extension
-        run: pnpm install
-      - name: Run CI
-        run: pnpm run ci
+          npm version ${{ github.event.inputs.version }} --no-git-tag-version
       - name: Build extension
         working-directory: vscode/extension
         run: pnpm run vscode:package
       - name: Upload extension to Marketplace
         working-directory: vscode/extension
         run: |
-          pnpx vsce publish --packagePath sqlmesh-${{ steps.extract_version.outputs.VERSION }}.vsix
+          pnpx vsce publish --packagePath sqlmesh-${{ github.event.inputs.version }}.vsix
         env:
           VSCE_PAT: ${{ secrets.VSCE_PAT }}
+      - name: Upload extension to OpenVSX
+        working-directory: vscode/extension
+        run: |
+          pnpx ovsx publish -p ${{ secrets.OPEN_VSX_TOKEN }} sqlmesh-${{ github.event.inputs.version }}.vsix
diff --git a/.nvmrc b/.nvmrc
index 2edeafb0..209e3ef4 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1,1 +1,1 @@
-20
\ No newline at end of file
+20
diff --git a/pyproject.toml b/pyproject.toml
index 235bbb81..99312887 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -22,7 +22,7 @@ dependencies = [
     "requests",
     "rich[jupyter]",
     "ruamel.yaml",
-    "sqlglot[rs]~=26.30.0",
+    "sqlglot[rs]~=26.31.0",
     "tenacity",
     "time-machine",
     "json-stream"
diff --git a/sqlmesh/core/snapshot/definition.py b/sqlmesh/core/snapshot/definition.py
index 573d3bc7..af6641b5 100644
--- a/sqlmesh/core/snapshot/definition.py
+++ b/sqlmesh/core/snapshot/definition.py
@@ -15,6 +15,7 @@ from sqlglot.optimizer.normalize_identifiers import normalize_identifiers
 
 from sqlmesh.core import constants as c
 from sqlmesh.core.audit import StandaloneAudit
+from sqlmesh.core.environment import EnvironmentSuffixTarget
 from sqlmesh.core.macros import call_macro
 from sqlmesh.core.model import Model, ModelKindMixin, ModelKindName, ViewKind, CustomKind
 from sqlmesh.core.model.definition import _Model
@@ -783,7 +784,9 @@ class Snapshot(PydanticModel, SnapshotInfoMixin):
 
             # only warn if the requested removal interval was a subset of the actual model intervals and was automatically expanded
             # if the requested interval was the same or wider than the actual model intervals, no need to warn
-            if requested_start > expanded_start or requested_end < expanded_end:
+            if (
+                requested_start > expanded_start or requested_end < expanded_end
+            ) and self.is_incremental:
                 from sqlmesh.core.console import get_console
 
                 get_console().log_warning(
@@ -1589,12 +1592,18 @@ def display_name(
     if snapshot_info_like.is_audit:
         return snapshot_info_like.name
     view_name = exp.to_table(snapshot_info_like.name)
+
+    catalog = (
+        None
+        if (
+            environment_naming_info.suffix_target != EnvironmentSuffixTarget.CATALOG
+            and view_name.catalog == default_catalog
+        )
+        else view_name.catalog
+    )
+
     qvn = QualifiedViewName(
-        catalog=(
-            view_name.catalog
-            if view_name.catalog and view_name.catalog != default_catalog
-            else None
-        ),
+        catalog=catalog,
         schema_name=view_name.db or None,
         table=view_name.name,
     )
diff --git a/sqlmesh/integrations/github/cicd/command.py b/sqlmesh/integrations/github/cicd/command.py
index cd5104df..021c49cf 100644
--- a/sqlmesh/integrations/github/cicd/command.py
+++ b/sqlmesh/integrations/github/cicd/command.py
@@ -44,7 +44,7 @@ def _check_required_approvers(controller: GithubController) -> bool:
         )
         return True
     controller.update_required_approval_check(
-        status=GithubCheckStatus.COMPLETED, conclusion=GithubCheckConclusion.NEUTRAL
+        status=GithubCheckStatus.COMPLETED, conclusion=GithubCheckConclusion.FAILURE
     )
     return False
 
diff --git a/vscode/extension/package.json b/vscode/extension/package.json
index cc5722c6..e8b7d5f0 100644
--- a/vscode/extension/package.json
+++ b/vscode/extension/package.json
@@ -120,9 +120,10 @@
     "lint": "eslint src",
     "lint:fix": "eslint src --fix",
     "test:unit": "vitest run",
-    "test:e2e": "playwright test",
-    "test:e2e:ui": "playwright test --ui",
-    "test:e2e:headed": "playwright test --headed",
+    "code-server": "code-server",
+    "test:e2e": "pnpm run vscode:package && playwright test",
+    "test:e2e:ui": "pnpm run vscode:package && playwright test --ui",
+    "test:e2e:headed": "pnpm run vscode:package && playwright test --headed",
     "fetch-vscode": "tsx scripts/fetch-vscode.ts",
     "compile": "pnpm run check-types && node esbuild.js",
     "check-types": "tsc --noEmit -p ./tsconfig.build.json",
diff --git a/vscode/extension/playwright.config.ts b/vscode/extension/playwright.config.ts
index 6820f2c8..599e5e37 100644
--- a/vscode/extension/playwright.config.ts
+++ b/vscode/extension/playwright.config.ts
@@ -11,7 +11,7 @@ export default defineConfig({
       use: {
         // ⭢ we'll launch Electron ourselves – no browser needed
         browserName: 'chromium',
-        headless: false, // headed makes screenshots deterministic
+        headless: true, // headless mode for tests
         launchOptions: {
           slowMo: process.env.CI ? 0 : 100,
         },


Test patch:
diff --git a/tests/core/engine_adapter/test_mssql.py b/tests/core/engine_adapter/test_mssql.py
index a420a2d8..d32343d5 100644
--- a/tests/core/engine_adapter/test_mssql.py
+++ b/tests/core/engine_adapter/test_mssql.py
@@ -296,7 +296,7 @@ def test_insert_overwrite_by_time_partition_supports_insert_overwrite_pandas_not
         f"__temp_test_table_{temp_table_id}", [(1, "2022-01-01"), (2, "2022-01-02")]
     )
     assert to_sql_calls(adapter) == [
-        f"""IF NOT EXISTS (SELECT * FROM information_schema.tables WHERE table_name = '__temp_test_table_{temp_table_id}') EXEC('CREATE TABLE [__temp_test_table_{temp_table_id}] ([a] INTEGER, [ds] VARCHAR(MAX))');""",
+        f"""IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '__temp_test_table_{temp_table_id}') EXEC('CREATE TABLE [__temp_test_table_{temp_table_id}] ([a] INTEGER, [ds] VARCHAR(MAX))');""",
         f"""MERGE INTO [test_table] AS [__MERGE_TARGET__] USING (SELECT [a] AS [a], [ds] AS [ds] FROM (SELECT CAST([a] AS INTEGER) AS [a], CAST([ds] AS VARCHAR(MAX)) AS [ds] FROM [__temp_test_table_{temp_table_id}]) AS [_subquery] WHERE [ds] BETWEEN '2022-01-01' AND '2022-01-02') AS [__MERGE_SOURCE__] ON (1 = 0) WHEN NOT MATCHED BY SOURCE AND [ds] BETWEEN '2022-01-01' AND '2022-01-02' THEN DELETE WHEN NOT MATCHED THEN INSERT ([a], [ds]) VALUES ([a], [ds]);""",
         f"DROP TABLE IF EXISTS [__temp_test_table_{temp_table_id}];",
     ]
@@ -366,7 +366,7 @@ def test_insert_overwrite_by_time_partition_replace_where_pandas(
     )
 
     assert to_sql_calls(adapter) == [
-        f"""IF NOT EXISTS (SELECT * FROM information_schema.tables WHERE table_name = '__temp_test_table_{temp_table_id}') EXEC('CREATE TABLE [__temp_test_table_{temp_table_id}] ([a] INTEGER, [ds] VARCHAR(MAX))');""",
+        f"""IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '__temp_test_table_{temp_table_id}') EXEC('CREATE TABLE [__temp_test_table_{temp_table_id}] ([a] INTEGER, [ds] VARCHAR(MAX))');""",
         f"""MERGE INTO [test_table] AS [__MERGE_TARGET__] USING (SELECT [a] AS [a], [ds] AS [ds] FROM (SELECT CAST([a] AS INTEGER) AS [a], CAST([ds] AS VARCHAR(MAX)) AS [ds] FROM [__temp_test_table_{temp_table_id}]) AS [_subquery] WHERE [ds] BETWEEN '2022-01-01' AND '2022-01-02') AS [__MERGE_SOURCE__] ON (1 = 0) WHEN NOT MATCHED BY SOURCE AND [ds] BETWEEN '2022-01-01' AND '2022-01-02' THEN DELETE WHEN NOT MATCHED THEN INSERT ([a], [ds]) VALUES ([a], [ds]);""",
         f"DROP TABLE IF EXISTS [__temp_test_table_{temp_table_id}];",
     ]
@@ -401,7 +401,7 @@ def test_insert_append_pandas(
     )
 
     assert to_sql_calls(adapter) == [
-        f"""IF NOT EXISTS (SELECT * FROM information_schema.tables WHERE table_name = '__temp_test_table_{temp_table_id}') EXEC('CREATE TABLE [__temp_test_table_{temp_table_id}] ([a] INTEGER, [b] INTEGER)');""",
+        f"""IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '__temp_test_table_{temp_table_id}') EXEC('CREATE TABLE [__temp_test_table_{temp_table_id}] ([a] INTEGER, [b] INTEGER)');""",
         f"INSERT INTO [test_table] ([a], [b]) SELECT CAST([a] AS INTEGER) AS [a], CAST([b] AS INTEGER) AS [b] FROM [__temp_test_table_{temp_table_id}];",
         f"DROP TABLE IF EXISTS [__temp_test_table_{temp_table_id}];",
     ]
@@ -417,7 +417,7 @@ def test_create_table(make_mocked_engine_adapter: t.Callable):
     adapter.create_table("test_table", columns_to_types)
 
     adapter.cursor.execute.assert_called_once_with(
-        """IF NOT EXISTS (SELECT * FROM information_schema.tables WHERE table_name = 'test_table') EXEC('CREATE TABLE [test_table] ([cola] INTEGER, [colb] VARCHAR(MAX))');"""
+        """IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'test_table') EXEC('CREATE TABLE [test_table] ([cola] INTEGER, [colb] VARCHAR(MAX))');"""
     )
 
 
@@ -436,7 +436,7 @@ def test_create_physical_properties(make_mocked_engine_adapter: t.Callable):
     )
 
     adapter.cursor.execute.assert_called_once_with(
-        """IF NOT EXISTS (SELECT * FROM information_schema.tables WHERE table_name = 'test_table') EXEC('CREATE TABLE [test_table] ([cola] INTEGER, [colb] VARCHAR(MAX))');"""
+        """IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'test_table') EXEC('CREATE TABLE [test_table] ([cola] INTEGER, [colb] VARCHAR(MAX))');"""
     )
 
 
@@ -471,7 +471,7 @@ def test_merge_pandas(
     )
 
     assert to_sql_calls(adapter) == [
-        f"""IF NOT EXISTS (SELECT * FROM information_schema.tables WHERE table_name = '__temp_target_{temp_table_id}') EXEC('CREATE TABLE [__temp_target_{temp_table_id}] ([id] INTEGER, [ts] DATETIME2, [val] INTEGER)');""",
+        f"""IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '__temp_target_{temp_table_id}') EXEC('CREATE TABLE [__temp_target_{temp_table_id}] ([id] INTEGER, [ts] DATETIME2, [val] INTEGER)');""",
         f"MERGE INTO [target] AS [__MERGE_TARGET__] USING (SELECT CAST([id] AS INTEGER) AS [id], CAST([ts] AS DATETIME2) AS [ts], CAST([val] AS INTEGER) AS [val] FROM [__temp_target_{temp_table_id}]) AS [__MERGE_SOURCE__] ON [__MERGE_TARGET__].[id] = [__MERGE_SOURCE__].[id] WHEN MATCHED AND EXISTS(SELECT [__MERGE_TARGET__].[ts], [__MERGE_TARGET__].[val] EXCEPT SELECT [__MERGE_SOURCE__].[ts], [__MERGE_SOURCE__].[val]) THEN UPDATE SET [__MERGE_TARGET__].[ts] = [__MERGE_SOURCE__].[ts], [__MERGE_TARGET__].[val] = [__MERGE_SOURCE__].[val] WHEN NOT MATCHED THEN INSERT ([id], [ts], [val]) VALUES ([__MERGE_SOURCE__].[id], [__MERGE_SOURCE__].[ts], [__MERGE_SOURCE__].[val]);",
         f"DROP TABLE IF EXISTS [__temp_target_{temp_table_id}];",
     ]
@@ -494,7 +494,7 @@ def test_merge_pandas(
     )
 
     assert to_sql_calls(adapter) == [
-        f"""IF NOT EXISTS (SELECT * FROM information_schema.tables WHERE table_name = '__temp_target_{temp_table_id}') EXEC('CREATE TABLE [__temp_target_{temp_table_id}] ([id] INTEGER, [ts] DATETIME2, [val] INTEGER)');""",
+        f"""IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '__temp_target_{temp_table_id}') EXEC('CREATE TABLE [__temp_target_{temp_table_id}] ([id] INTEGER, [ts] DATETIME2, [val] INTEGER)');""",
         f"MERGE INTO [target] AS [__MERGE_TARGET__] USING (SELECT CAST([id] AS INTEGER) AS [id], CAST([ts] AS DATETIME2) AS [ts], CAST([val] AS INTEGER) AS [val] FROM [__temp_target_{temp_table_id}]) AS [__MERGE_SOURCE__] ON [__MERGE_TARGET__].[id] = [__MERGE_SOURCE__].[id] AND [__MERGE_TARGET__].[ts] = [__MERGE_SOURCE__].[ts] WHEN MATCHED AND EXISTS(SELECT [__MERGE_TARGET__].[val] EXCEPT SELECT [__MERGE_SOURCE__].[val]) THEN UPDATE SET [__MERGE_TARGET__].[val] = [__MERGE_SOURCE__].[val] WHEN NOT MATCHED THEN INSERT ([id], [ts], [val]) VALUES ([__MERGE_SOURCE__].[id], [__MERGE_SOURCE__].[ts], [__MERGE_SOURCE__].[val]);",
         f"DROP TABLE IF EXISTS [__temp_target_{temp_table_id}];",
     ]
@@ -554,7 +554,7 @@ def test_replace_query_pandas(
     )
 
     assert to_sql_calls(adapter) == [
-        f"""IF NOT EXISTS (SELECT * FROM information_schema.tables WHERE table_name = '{temp_table_name}') EXEC('CREATE TABLE [{temp_table_name}] ([a] INTEGER, [b] INTEGER)');""",
+        f"""IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = '{temp_table_name}') EXEC('CREATE TABLE [{temp_table_name}] ([a] INTEGER, [b] INTEGER)');""",
         "TRUNCATE TABLE [test_table];",
         f"INSERT INTO [test_table] ([a], [b]) SELECT CAST([a] AS INTEGER) AS [a], CAST([b] AS INTEGER) AS [b] FROM [{temp_table_name}];",
         f"DROP TABLE IF EXISTS [{temp_table_name}];",
@@ -571,7 +571,7 @@ def test_create_table_primary_key(make_mocked_engine_adapter: t.Callable):
     adapter.create_table("test_table", columns_to_types, primary_key=("cola", "colb"))
 
     adapter.cursor.execute.assert_called_once_with(
-        """IF NOT EXISTS (SELECT * FROM information_schema.tables WHERE table_name = 'test_table') EXEC('CREATE TABLE [test_table] ([cola] INTEGER, [colb] VARCHAR(MAX), PRIMARY KEY ([cola], [colb]))');"""
+        """IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'test_table') EXEC('CREATE TABLE [test_table] ([cola] INTEGER, [colb] VARCHAR(MAX), PRIMARY KEY ([cola], [colb]))');"""
     )
 
 
@@ -846,7 +846,7 @@ def test_replace_query_strategy(adapter: MSSQLEngineAdapter, mocker: MockerFixtu
 
     assert to_sql_calls(adapter) == [
         # initial - create table if not exists
-        "IF NOT EXISTS (SELECT * FROM information_schema.tables WHERE table_name = 'test_table') EXEC('SELECT * INTO [test_table] FROM (SELECT [a] AS [a], [b] AS [b] FROM [db].[upstream_table] AS [upstream_table]) AS temp');",
+        "IF NOT EXISTS (SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'test_table') EXEC('SELECT * INTO [test_table] FROM (SELECT [a] AS [a], [b] AS [b] FROM [db].[upstream_table] AS [upstream_table]) AS temp');",
         # subsequent - truncate + insert
         "TRUNCATE TABLE [test_table];",
         "INSERT INTO [test_table] ([a], [b]) SELECT [a] AS [a], [b] AS [b] FROM [db].[upstream_table] AS [upstream_table];",
diff --git a/tests/core/test_snapshot.py b/tests/core/test_snapshot.py
index e4eb12c5..f09083f5 100644
--- a/tests/core/test_snapshot.py
+++ b/tests/core/test_snapshot.py
@@ -2178,6 +2178,21 @@ def test_deployability_index_missing_parent(make_snapshot):
             "snowflake",
             "CATALOG_OVERRIDE.test_db.test_model__DEV",
         ),
+        # EnvironmentSuffixTarget.CATALOG
+        (
+            "test_db.test_model",
+            EnvironmentNamingInfo(name="dev", suffix_target=EnvironmentSuffixTarget.CATALOG),
+            "default_catalog",
+            "duckdb",
+            "default_catalog__dev.test_db.test_model",
+        ),
+        (
+            "test_db.test_model",
+            EnvironmentNamingInfo(name="dev", suffix_target=EnvironmentSuffixTarget.CATALOG),
+            "default_catalog",
+            "snowflake",
+            "DEFAULT_CATALOG__DEV.test_db.test_model",
+        ),
     ),
 )
 def test_display_name(
diff --git a/tests/integrations/github/cicd/test_github_commands.py b/tests/integrations/github/cicd/test_github_commands.py
index 5f1dfd0a..6be6a455 100644
--- a/tests/integrations/github/cicd/test_github_commands.py
+++ b/tests/integrations/github/cicd/test_github_commands.py
@@ -382,7 +382,7 @@ def test_run_all_missing_approval(
     assert GithubCheckStatus(approval_checks_runs[0]["status"]).is_queued
     assert GithubCheckStatus(approval_checks_runs[1]["status"]).is_in_progress
     assert GithubCheckStatus(approval_checks_runs[2]["status"]).is_completed
-    assert GithubCheckConclusion(approval_checks_runs[2]["conclusion"]).is_neutral
+    assert GithubCheckConclusion(approval_checks_runs[2]["conclusion"]).is_failure
 
     assert len(controller._context.apply.call_args_list) == 1
     pr_plan = controller._context.apply.call_args_list[0][0]
@@ -402,7 +402,7 @@ def test_run_all_missing_approval(
         output = f.read()
         assert (
             output
-            == "run_unit_tests=success\nhas_required_approval=neutral\ncreated_pr_environment=true\npr_environment_name=hello_world_2\npr_environment_synced=success\nprod_plan_preview=success\nprod_environment_synced=skipped\n"
+            == "run_unit_tests=success\nhas_required_approval=failure\ncreated_pr_environment=true\npr_environment_name=hello_world_2\npr_environment_synced=success\nprod_plan_preview=success\nprod_environment_synced=skipped\n"
         )
 
 
diff --git a/tests/integrations/github/cicd/test_integration.py b/tests/integrations/github/cicd/test_integration.py
index cd70ad72..beda7a5c 100644
--- a/tests/integrations/github/cicd/test_integration.py
+++ b/tests/integrations/github/cicd/test_integration.py
@@ -1040,7 +1040,7 @@ def test_no_merge_since_no_deploy_signal(
     assert GithubCheckStatus(approval_checks_runs[0]["status"]).is_queued
     assert GithubCheckStatus(approval_checks_runs[1]["status"]).is_in_progress
     assert GithubCheckStatus(approval_checks_runs[2]["status"]).is_completed
-    assert GithubCheckConclusion(approval_checks_runs[2]["conclusion"]).is_neutral
+    assert GithubCheckConclusion(approval_checks_runs[2]["conclusion"]).is_failure
     assert approval_checks_runs[2]["output"]["title"] == "Need a Required Approval"
     assert (
         approval_checks_runs[2]["output"]["summary"]
@@ -1068,7 +1068,7 @@ def test_no_merge_since_no_deploy_signal(
         output = f.read()
         assert (
             output
-            == "run_unit_tests=success\nhas_required_approval=neutral\ncreated_pr_environment=true\npr_environment_name=hello_world_2\npr_environment_synced=success\nprod_plan_preview=success\nprod_environment_synced=skipped\n"
+            == "run_unit_tests=success\nhas_required_approval=failure\ncreated_pr_environment=true\npr_environment_name=hello_world_2\npr_environment_synced=success\nprod_plan_preview=success\nprod_environment_synced=skipped\n"
         )
 
 
diff --git a/vscode/extension/tests/find_references.spec.ts b/vscode/extension/tests/find_references.spec.ts
index 7b703257..605eae84 100644
--- a/vscode/extension/tests/find_references.spec.ts
+++ b/vscode/extension/tests/find_references.spec.ts
@@ -9,612 +9,652 @@ const GO_TO_REFERENCES_KEY = 'Shift+F12'
 const FIND_ALL_REFERENCES_KEY =
   process.platform === 'darwin' ? 'Alt+Shift+F12' : 'Ctrl+Shift+F12'
 
-test.describe('Model References', () => {
-  let tempDir: string
-  let window: any
-  let close: () => Promise<void>
-
-  test.beforeEach(async () => {
-    tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'vscode-test-sushi-'))
-    await fs.copy(SUSHI_SOURCE_PATH, tempDir)
-    const vscode = await startVSCode(tempDir)
-    window = vscode.window
-    close = vscode.close
-  })
-
-  test.afterEach(async () => {
-    await close()
-    fs.removeSync(tempDir)
-  })
+// Helper function to set up a test environment for model references
+async function setupModelTestEnvironment() {
+  const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'vscode-test-sushi-'))
+  await fs.copy(SUSHI_SOURCE_PATH, tempDir)
+  const { window, close } = await startVSCode(tempDir)
+  return { window, close, tempDir }
+}
+
+// Helper function to navigate to models folder
+async function navigateToModels(window: any) {
+  await window.waitForSelector('text=models')
+  await window
+    .getByRole('treeitem', { name: 'models', exact: true })
+    .locator('a')
+    .click()
+}
+
+// Helper function to navigate to audits folder
+async function navigateToAudits(window: any) {
+  await window.waitForSelector('text=audits')
+  await window
+    .getByRole('treeitem', { name: 'audits', exact: true })
+    .locator('a')
+    .click()
+}
+
+// Helper function to open customers.sql and wait for SQLMesh context
+async function openCustomersFile(window: any) {
+  await navigateToModels(window)
+  await window
+    .getByRole('treeitem', { name: 'customers.sql', exact: true })
+    .locator('a')
+    .click()
+  await window.waitForSelector('text=grain')
+  await window.waitForSelector('text=Loaded SQLMesh Context')
+}
+
+// Helper function to open top_waiters.sql and wait for SQLMesh context
+async function openTopWaitersFile(window: any) {
+  await navigateToModels(window)
+  await window
+    .getByRole('treeitem', { name: 'top_waiters.sql', exact: true })
+    .locator('a')
+    .click()
+  await window.waitForSelector('text=grain')
+  await window.waitForSelector('text=Loaded SQLMesh Context')
+}
 
+test.describe('Model References', () => {
   test('Go to References (Shift+F12) for Model usage', async () => {
-    // Step 1: Expand the models folder in the file explorer to access model files
-    await window.waitForSelector('text=models')
-    await window
-      .getByRole('treeitem', { name: 'models', exact: true })
-      .locator('a')
-      .click()
-
-    // Step 2: Open customers.sql which contains references to other models
-    await window
-      .getByRole('treeitem', { name: 'customers.sql', exact: true })
-      .locator('a')
-      .click()
-
-    // Step 3: Ensure SQLMesh extension has fully loaded by checking for model metadata
-    await window.waitForSelector('text=grain')
-    await window.waitForSelector('text=Loaded SQLMesh Context')
-
-    // Step 4: Position cursor on the sushi.orders model reference in the SQL query
-    await window.locator('text=sushi.orders').first().click()
-
-    // Step 5: Trigger "Go to References" command using Shift+F12 keyboard shortcut
-    await window.keyboard.press(GO_TO_REFERENCES_KEY)
-
-    // Step 6: Wait for VSCode references panel to appear at the bottom
-    await window.waitForSelector('text=References')
-
-    // Step 7: Ensure references panel has populated with all usages of sushi.orders model
-    await window.waitForFunction(
-      () => {
-        const referenceElements = document.querySelectorAll(
-          '.reference-item, .monaco-list-row, .references-view .tree-row',
-        )
-        return referenceElements.length >= 6
-      },
-      { timeout: 10000 },
-    )
-
-    // Step 8: Verify the references panel shows both SQL and Python files containing references
-    const hasReferences = await window.evaluate(() => {
-      const body = document.body.textContent || ''
-      return (
-        body.includes('References') &&
-        (body.includes('.sql') || body.includes('.py'))
+    const { window, close, tempDir } = await setupModelTestEnvironment()
+
+    try {
+      // Open customers.sql which contains references to other models
+      await openCustomersFile(window)
+
+      // Step 4: Position cursor on the sushi.orders model reference in the SQL query
+      await window.locator('text=sushi.orders').first().click()
+
+      // Step 5: Trigger "Go to References" command using Shift+F12 keyboard shortcut
+      await window.keyboard.press(GO_TO_REFERENCES_KEY)
+
+      // Step 6: Wait for VSCode references panel to appear at the bottom
+      await window.waitForSelector('text=References')
+
+      // Step 7: Ensure references panel has populated with all usages of sushi.orders model
+      await window.waitForFunction(
+        () => {
+          const referenceElements = document.querySelectorAll(
+            '.reference-item, .monaco-list-row, .references-view .tree-row',
+          )
+          return referenceElements.length >= 6
+        },
+        { timeout: 10000 },
       )
-    })
-
-    expect(hasReferences).toBe(true)
 
-    // Step 9: Find and click on the orders.py reference to navigate to the model definition
-    let clickedReference = false
+      // Step 8: Verify the references panel shows both SQL and Python files containing references
+      const hasReferences = await window.evaluate(() => {
+        const body = document.body.textContent || ''
+        return (
+          body.includes('References') &&
+          (body.includes('.sql') || body.includes('.py'))
+        )
+      })
 
-    const referenceItems = await window.locator(
-      '.monaco-list-row, .reference-item, .monaco-tl-row',
-    )
-    const count = await referenceItems.count()
+      expect(hasReferences).toBe(true)
 
-    for (let i = 0; i < count; i++) {
-      const item = referenceItems.nth(i)
-      const text = await item.textContent()
+      // Step 9: Find and click on the orders.py reference to navigate to the model definition
+      let clickedReference = false
 
-      // Search for the orders.py reference which contains the Python model definition
-      if (text && text.includes('orders.py')) {
-        await item.click()
-        clickedReference = true
-        break
+      const referenceItems = window.locator(
+        '.monaco-list-row, .reference-item, .monaco-tl-row',
+      )
+      const count = await referenceItems.count()
+
+      for (let i = 0; i < count; i++) {
+        const item = referenceItems.nth(i)
+        const text = await item.textContent()
+
+        // Search for the orders.py reference which contains the Python model definition
+        if (text && text.includes('orders.py')) {
+          await item.click()
+          clickedReference = true
+          break
+        }
       }
-    }
 
-    expect(clickedReference).toBe(true)
+      expect(clickedReference).toBe(true)
 
-    // Step 10: Verify successful navigation to orders.py by checking for unique Python code
-    await expect(window.locator('text=list(range(0, 100))')).toBeVisible()
+      // Step 10: Verify successful navigation to orders.py by checking for unique Python code
+      await expect(window.locator('text=list(range(0, 100))')).toBeVisible()
+    } finally {
+      await close()
+      fs.removeSync(tempDir)
+    }
   })
 
   test('Find All References (Alt+Shift+F12) for Model', async () => {
-    // Step 1: Expand the models folder to access SQLMesh model files
-    await window.waitForSelector('text=models')
-    await window
-      .getByRole('treeitem', { name: 'models', exact: true })
-      .locator('a')
-      .click()
-
-    // Step 2: Open customers.sql which contains multiple model references
-    await window
-      .getByRole('treeitem', { name: 'customers.sql', exact: true })
-      .locator('a')
-      .click()
-
-    // Step 3: Wait for SQLMesh context to fully initialize
-    await window.waitForSelector('text=grain')
-    await window.waitForSelector('text=Loaded SQLMesh Context')
-
-    // Step 4: Click on sushi.orders model reference to position cursor
-    await window.locator('text=sushi.orders').first().click()
-
-    // Step 5: Trigger "Find All References" command using Alt+Shift+F12 (or Ctrl+Shift+F12 on Windows/Linux)
-    await window.keyboard.press(FIND_ALL_REFERENCES_KEY)
-
-    let clickedReference = false
-    const referenceItems = await window.locator(
-      '.monaco-list-row, .reference-item, .monaco-tl-row',
-    )
-    const count = await referenceItems.count()
-
-    // Step 6: Iterate through references to find and click on orders.py
-    for (let i = 0; i < count; i++) {
-      const item = referenceItems.nth(i)
-      const text = await item.textContent()
-
-      // Find the orders.py reference which contains the model implementation
-      if (text && text.includes('orders.py')) {
-        await item.click()
-
-        clickedReference = true
-        break
-      }
-    }
+    const { window, close, tempDir } = await setupModelTestEnvironment()
 
-    expect(clickedReference).toBe(true)
+    try {
+      // Open customers.sql which contains multiple model references
+      await openCustomersFile(window)
 
-    // Step 7: Verify navigation to orders.py by checking for Python import statement
-    await expect(window.locator('text=import random')).toBeVisible()
+      // Step 4: Click on sushi.orders model reference to position cursor
+      await window.locator('text=sushi.orders').first().click()
 
-    // Step 8: Click on the import statement to ensure file is fully loaded and interactive
-    await window.locator('text=import random').first().click()
+      // Step 5: Trigger "Find All References" command using Alt+Shift+F12 (or Ctrl+Shift+F12 on Windows/Linux)
+      await window.keyboard.press(FIND_ALL_REFERENCES_KEY)
 
-    // Step 9: Final verification that we're viewing the correct Python model file
-    await expect(window.locator('text=list(range(0, 100))')).toBeVisible()
-  })
+      let clickedReference = false
+      const referenceItems = window.locator(
+        '.monaco-list-row, .reference-item, .monaco-tl-row',
+      )
+      const count = await referenceItems.count()
 
-  test('Go to References for Model from Audit', async () => {
-    // Step 1: Expand audits folder to access SQLMesh audit files
-    await window.waitForSelector('text=audits')
-    await window
-      .getByRole('treeitem', { name: 'audits', exact: true })
-      .locator('a')
-      .click()
-
-    // Step 2: Open assert_item_price_above_zero.sql audit file which references sushi.items model
-    await window
-      .getByRole('treeitem', {
-        name: 'assert_item_price_above_zero.sql',
-        exact: true,
-      })
-      .locator('a')
-      .click()
+      // Step 6: Iterate through references to find and click on orders.py
+      for (let i = 0; i < count; i++) {
+        const item = referenceItems.nth(i)
+        const text = await item.textContent()
 
-    // Step 3: Wait for audit file to load and SQLMesh context to initialize
-    await window.waitForSelector('text=standalone')
-    await window.waitForSelector('text=Loaded SQLMesh Context')
+        // Find the orders.py reference which contains the model implementation
+        if (text && text.includes('orders.py')) {
+          await item.click()
 
-    // Step 4: Click on sushi.items model reference in the audit query
-    await window.locator('text=sushi.items').first().click()
+          clickedReference = true
+          break
+        }
+      }
 
-    // Step 5: Trigger "Go to References" to find all places where sushi.items is used
-    await window.keyboard.press(GO_TO_REFERENCES_KEY)
+      expect(clickedReference).toBe(true)
 
-    // Step 6: Wait for VSCode references panel to appear
-    await window.waitForSelector('text=References')
+      // Step 7: Verify navigation to orders.py by checking for Python import statement
+      await expect(window.locator('text=import random')).toBeVisible()
 
-    // Step 7: Ensure references panel shows multiple files that reference sushi.items
-    await window.waitForFunction(
-      () => {
-        const referenceElements = document.querySelectorAll(
-          '.reference-item, .monaco-list-row, .references-view .tree-row',
-        )
-        return referenceElements.length >= 4
-      },
-      { timeout: 10000 },
-    )
-
-    // Step 8: Verify references panel contains both audit and model files
-    const hasReferences = await window.evaluate(() => {
-      const body = document.body.textContent || ''
-      return (
-        body.includes('References') &&
-        (body.includes('.sql') || body.includes('.py'))
-      )
-    })
+      // Step 8: Click on the import statement to ensure file is fully loaded and interactive
+      await window.locator('text=import random').first().click()
 
-    expect(hasReferences).toBe(true)
+      // Step 9: Final verification that we're viewing the correct Python model file
+      await expect(window.locator('text=list(range(0, 100))')).toBeVisible()
+    } finally {
+      await close()
+      fs.removeSync(tempDir)
+    }
+  })
 
-    // 9. Click on one of the references to navigate to it
-    let clickedReference = false
+  test('Go to References for Model from Audit', async () => {
+    const { window, close, tempDir } = await setupModelTestEnvironment()
+
+    try {
+      // Open assert_item_price_above_zero.sql audit file which references sushi.items model
+      await navigateToAudits(window)
+      await window
+        .getByRole('treeitem', {
+          name: 'assert_item_price_above_zero.sql',
+          exact: true,
+        })
+        .locator('a')
+        .click()
+
+      // Wait for audit file to load and SQLMesh context to initialize
+      await window.waitForSelector('text=standalone')
+      await window.waitForSelector('text=Loaded SQLMesh Context')
+
+      // Step 4: Click on sushi.items model reference in the audit query
+      await window.locator('text=sushi.items').first().click()
+
+      // Step 5: Trigger "Go to References" to find all places where sushi.items is used
+      await window.keyboard.press(GO_TO_REFERENCES_KEY)
+
+      // Step 6: Wait for VSCode references panel to appear
+      await window.waitForSelector('text=References')
+
+      // Step 7: Ensure references panel shows multiple files that reference sushi.items
+      await window.waitForFunction(
+        () => {
+          const referenceElements = document.querySelectorAll(
+            '.reference-item, .monaco-list-row, .references-view .tree-row',
+          )
+          return referenceElements.length >= 4
+        },
+        { timeout: 10000 },
+      )
 
-    const referenceItems = await window.locator(
-      '.monaco-list-row, .reference-item, .monaco-tl-row',
-    )
-    const count = await referenceItems.count()
+      // Step 8: Verify references panel contains both audit and model files
+      const hasReferences = await window.evaluate(() => {
+        const body = document.body.textContent || ''
+        return (
+          body.includes('References') &&
+          (body.includes('.sql') || body.includes('.py'))
+        )
+      })
+
+      expect(hasReferences).toBe(true)
 
-    for (let i = 0; i < count; i++) {
-      const item = referenceItems.nth(i)
-      const text = await item.textContent()
+      // 9. Click on one of the references to navigate to it
+      let clickedReference = false
 
-      // Search for the customer_revenue_by_day.sql file which joins with sushi.items
-      if (text && text.includes('customer_revenue_by_day.sql')) {
-        await item.click()
-        clickedReference = true
-        break
+      const referenceItems = window.locator(
+        '.monaco-list-row, .reference-item, .monaco-tl-row',
+      )
+      const count = await referenceItems.count()
+
+      for (let i = 0; i < count; i++) {
+        const item = referenceItems.nth(i)
+        const text = await item.textContent()
+
+        // Search for the customer_revenue_by_day.sql file which joins with sushi.items
+        if (text && text.includes('customer_revenue_by_day.sql')) {
+          await item.click()
+          clickedReference = true
+          break
+        }
       }
-    }
 
-    expect(clickedReference).toBe(true)
+      expect(clickedReference).toBe(true)
 
-    // Step 10: Verify navigation to customer_revenue_by_day.sql by checking for SQL JOIN syntax
-    await expect(window.locator('text=LEFT JOIN')).toBeVisible()
+      // Step 10: Verify navigation to customer_revenue_by_day.sql by checking for SQL JOIN syntax
+      await expect(window.locator('text=LEFT JOIN')).toBeVisible()
 
-    // Step 11: Click on LEFT JOIN to ensure file is interactive and verify content
-    await window.locator('text=LEFT JOIN').first().click()
-    await expect(
-      window.locator('text=FROM sushi.order_items AS oi'),
-    ).toBeVisible()
+      // Step 11: Click on LEFT JOIN to ensure file is interactive and verify content
+      await window.locator('text=LEFT JOIN').first().click()
+      await expect(
+        window.locator('text=FROM sushi.order_items AS oi'),
+      ).toBeVisible()
+    } finally {
+      await close()
+      fs.removeSync(tempDir)
+    }
   })
 
   test('Find All Model References from Audit', async () => {
-    // Step 1: Expand audits folder in the file explorer
-    await window.waitForSelector('text=audits')
-    await window
-      .getByRole('treeitem', { name: 'audits', exact: true })
-      .locator('a')
-      .click()
-
-    // Step 2: Open the audit file that validates item prices
-    await window
-      .getByRole('treeitem', {
-        name: 'assert_item_price_above_zero.sql',
-        exact: true,
-      })
-      .locator('a')
-      .click()
+    const { window, close, tempDir } = await setupModelTestEnvironment()
+
+    try {
+      // Open the audit file that validates item prices
+      await navigateToAudits(window)
+      await window
+        .getByRole('treeitem', {
+          name: 'assert_item_price_above_zero.sql',
+          exact: true,
+        })
+        .locator('a')
+        .click()
+
+      // Ensure audit file and SQLMesh context are fully loaded
+      await window.waitForSelector('text=standalone')
+      await window.waitForSelector('text=Loaded SQLMesh Context')
+
+      // Step 4: Position cursor on sushi.items model reference
+      await window.locator('text=sushi.items').first().click()
+
+      // Step 5: Use Find All References to see all occurrences across the project
+      await window.keyboard.press(FIND_ALL_REFERENCES_KEY)
+
+      // Step 6: Click on a reference to navigate to customer_revenue_by_day.sql
+      let clickedReference = false
+
+      const referenceItems = window.locator(
+        '.monaco-list-row, .reference-item, .monaco-tl-row',
+      )
+      const count = await referenceItems.count()
+
+      for (let i = 0; i < count; i++) {
+        const item = referenceItems.nth(i)
+        const text = await item.textContent()
+
+        // Look for a reference that contains customer_revenue_by_day
+        if (text && text.includes('customer_revenue_by_day.sql')) {
+          await item.click()
+          clickedReference = true
+          break
+        }
+      }
 
-    // Step 3: Ensure audit file and SQLMesh context are fully loaded
-    await window.waitForSelector('text=standalone')
-    await window.waitForSelector('text=Loaded SQLMesh Context')
+      expect(clickedReference).toBe(true)
 
-    // Step 4: Position cursor on sushi.items model reference
-    await window.locator('text=sushi.items').first().click()
+      // Step 7: Verify successful navigation by checking for SQL JOIN statement
+      await expect(window.locator('text=LEFT JOIN')).toBeVisible()
 
-    // Step 5: Use Find All References to see all occurrences across the project
-    await window.keyboard.press(FIND_ALL_REFERENCES_KEY)
+      // Step 8: Interact with the file to verify it's fully loaded and check its content
+      await window.locator('text=LEFT JOIN').first().click()
+      await expect(
+        window.locator('text=FROM sushi.order_items AS oi'),
+      ).toBeVisible()
+    } finally {
+      await close()
+      fs.removeSync(tempDir)
+    }
+  })
+})
 
-    // Step 6: Click on a reference to navigate to customer_revenue_by_day.sql
-    let clickedReference = false
+test.describe('CTE References', () => {
+  test('Go to references from definition of CTE', async () => {
+    const { window, close, tempDir } = await setupModelTestEnvironment()
 
-    const referenceItems = await window.locator(
-      '.monaco-list-row, .reference-item, .monaco-tl-row',
-    )
-    const count = await referenceItems.count()
+    try {
+      await openCustomersFile(window)
 
-    for (let i = 0; i < count; i++) {
-      const item = referenceItems.nth(i)
-      const text = await item.textContent()
+      // Click on the CTE definition "current_marketing_outer" at line 20 to position cursor
+      await window.locator('text=current_marketing_outer').first().click()
 
-      // Look for a reference that contains customer_revenue_by_day
-      if (text && text.includes('customer_revenue_by_day.sql')) {
-        await item.click()
-        clickedReference = true
-        break
-      }
-    }
+      // Use keyboard shortcut to find all references
+      await window.keyboard.press(GO_TO_REFERENCES_KEY)
 
-    expect(clickedReference).toBe(true)
+      // Wait for the references to appear
+      await window.waitForSelector('text=References')
 
-    // Step 7: Verify successful navigation by checking for SQL JOIN statement
-    await expect(window.locator('text=LEFT JOIN')).toBeVisible()
+      // Wait for reference panel to populate
+      await window.waitForFunction(
+        () => {
+          const referenceElements = document.querySelectorAll(
+            '.reference-item, .monaco-list-row, .references-view .tree-row',
+          )
+          return referenceElements.length >= 2
+        },
+        { timeout: 5000 },
+      )
 
-    // Step 8: Interact with the file to verify it's fully loaded and check its content
-    await window.locator('text=LEFT JOIN').first().click()
-    await expect(
-      window.locator('text=FROM sushi.order_items AS oi'),
-    ).toBeVisible()
-  })
-})
+      // Verify that the customers.sql file is shown in results
+      await expect(window.locator('text=customers.sql').first()).toBeVisible()
 
-test.describe('CTE References', () => {
-  let tempDir: string
-  let window: any
-  let close: () => Promise<void>
-
-  test.beforeEach(async () => {
-    tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'vscode-test-sushi-'))
-    await fs.copy(SUSHI_SOURCE_PATH, tempDir)
-    const vscode = await startVSCode(tempDir)
-    window = vscode.window
-    close = vscode.close
-
-    // Common setup: navigate to customers.sql
-    await window.waitForSelector('text=models')
-    await window
-      .getByRole('treeitem', { name: 'models', exact: true })
-      .locator('a')
-      .click()
-    await window
-      .getByRole('treeitem', { name: 'customers.sql', exact: true })
-      .locator('a')
-      .click()
-    await window.waitForSelector('text=grain')
-    await window.waitForSelector('text=Loaded SQLMesh Context')
+      // Check that both CTE definition and usage are listed in references
+      await window.waitForSelector('text=References')
+      await window.waitForSelector('text=WITH current_marketing_outer AS')
+      await window.waitForSelector('text=FROM current_marketing_outer')
+    } finally {
+      await close()
+      fs.removeSync(tempDir)
+    }
   })
 
-  test.afterEach(async () => {
-    await close()
-    fs.removeSync(tempDir)
-  })
+  test('Go to references from usage of CTE', async () => {
+    const { window, close, tempDir } = await setupModelTestEnvironment()
 
-  test('Go to references from definition of CTE', async () => {
-    // Click on the CTE definition "current_marketing_outer" at line 20 to position cursor
-    await window.locator('text=current_marketing_outer').first().click()
+    try {
+      await openCustomersFile(window)
+
+      // Click on the CTE usage this time for "current_marketing_outer"
+      await window.locator('text=FROM current_marketing_outer').click({
+        position: { x: 80, y: 5 }, // Clicks on the usage rather than first which was definition
+      })
 
-    // Use keyboard shortcut to find all references
-    await window.keyboard.press(GO_TO_REFERENCES_KEY)
+      // Use keyboard shortcut to go to references
+      await window.keyboard.press(GO_TO_REFERENCES_KEY)
+
+      // Wait for the references to appear
+      await window.waitForSelector('text=References')
+
+      // Better assertions: wait for reference panel to populate
+      await window.waitForFunction(
+        () => {
+          const referenceElements = document.querySelectorAll(
+            '.reference-item, .monaco-list-row, .references-view .tree-row',
+          )
+          return referenceElements.length >= 2
+        },
+        { timeout: 5000 },
+      )
 
-    // Wait for the references to appear
-    await window.waitForSelector('text=References')
+      await window.waitForSelector('text=References')
+      await window.waitForSelector('text=WITH current_marketing_outer AS')
+      await window.waitForSelector('text=FROM current_marketing_outer')
 
-    // Wait for reference panel to populate
-    await window.waitForFunction(
-      () => {
-        const referenceElements = document.querySelectorAll(
-          '.reference-item, .monaco-list-row, .references-view .tree-row',
-        )
-        return referenceElements.length >= 2
-      },
-      { timeout: 5000 },
-    )
-
-    // Verify that the customers.sql file is shown in results
-    await expect(window.locator('text=customers.sql').first()).toBeVisible()
-
-    // Check that both CTE definition and usage are listed in references
-    await window.waitForSelector('text=References')
-    await window.waitForSelector('text=WITH current_marketing_outer AS')
-    await window.waitForSelector('text=FROM current_marketing_outer')
+      // Verify that the customers.sql file is shown in results
+      await expect(window.locator('text=customers.sql').first()).toBeVisible()
+    } finally {
+      await close()
+      fs.removeSync(tempDir)
+    }
   })
 
-  test('Go to references from usage of CTE', async () => {
-    // Click on the CTE usage this time for "current_marketing_outer"
-    await window.locator('text=FROM current_marketing_outer').click({
-      position: { x: 80, y: 5 }, // Clicks on the usage rather than first which was definition
-    })
-
-    // Use keyboard shortcut to go to references
-    await window.keyboard.press(GO_TO_REFERENCES_KEY)
-
-    // Wait for the references to appear
-    await window.waitForSelector('text=References')
-
-    // Better assertions: wait for reference panel to populate
-    await window.waitForFunction(
-      () => {
-        const referenceElements = document.querySelectorAll(
-          '.reference-item, .monaco-list-row, .references-view .tree-row',
-        )
-        return referenceElements.length >= 2
-      },
-      { timeout: 5000 },
-    )
+  test('Go to references for nested CTE', async () => {
+    const { window, close, tempDir } = await setupModelTestEnvironment()
 
-    await window.waitForSelector('text=References')
-    await window.waitForSelector('text=WITH current_marketing_outer AS')
-    await window.waitForSelector('text=FROM current_marketing_outer')
+    try {
+      await openCustomersFile(window)
 
-    // Verify that the customers.sql file is shown in results
-    await expect(window.locator('text=customers.sql').first()).toBeVisible()
-  })
+      // Click on the nested CTE "current_marketing"
+      await window.locator('text=WITH current_marketing AS').click({
+        position: { x: 100, y: 5 }, // Click on the CTE name part
+      })
 
-  test('Go to references for nested CTE', async () => {
-    // Click on the nested CTE "current_marketing"
-    await window.locator('text=WITH current_marketing AS').click({
-      position: { x: 100, y: 5 }, // Click on the CTE name part
-    })
-
-    // Use keyboard shortcut to find all references
-    await window.keyboard.press(GO_TO_REFERENCES_KEY)
-
-    // Wait for the references to appear
-    await window.waitForSelector('text=References')
-
-    // Wait for reference panel to populate
-    await window.waitForFunction(
-      () => {
-        const referenceElements = document.querySelectorAll(
-          '.reference-item, .monaco-list-row, .references-view .tree-row',
-        )
-        return referenceElements.length >= 2
-      },
-      { timeout: 5000 },
-    )
-
-    // Verify that the customers.sql file is shown in results
-    await expect(window.locator('text=customers.sql').first()).toBeVisible()
-
-    // Check that both CTE definition and usage are listed in references
-    await window.waitForSelector('text=References')
-    await window.waitForSelector('text=WITH current_marketing AS')
-    await window.waitForSelector('text=FROM current_marketing')
+      // Use keyboard shortcut to find all references
+      await window.keyboard.press(GO_TO_REFERENCES_KEY)
+
+      // Wait for the references to appear
+      await window.waitForSelector('text=References')
+
+      // Wait for reference panel to populate
+      await window.waitForFunction(
+        () => {
+          const referenceElements = document.querySelectorAll(
+            '.reference-item, .monaco-list-row, .references-view .tree-row',
+          )
+          return referenceElements.length >= 2
+        },
+        { timeout: 5000 },
+      )
+
+      // Verify that the customers.sql file is shown in results
+      await expect(window.locator('text=customers.sql').first()).toBeVisible()
+
+      // Check that both CTE definition and usage are listed in references
+      await window.waitForSelector('text=References')
+      await window.waitForSelector('text=WITH current_marketing AS')
+      await window.waitForSelector('text=FROM current_marketing')
+    } finally {
+      await close()
+      fs.removeSync(tempDir)
+    }
   })
 
   test('Find all references for CTE', async () => {
-    // Click on the CTE definition "current_marketing_outer"
-    await window.locator('text=current_marketing_outer').first().click()
+    const { window, close, tempDir } = await setupModelTestEnvironment()
+
+    try {
+      await openCustomersFile(window)
 
-    // Use keyboard shortcut to find all references
-    await window.keyboard.press(FIND_ALL_REFERENCES_KEY)
+      // Click on the CTE definition "current_marketing_outer"
+      await window.locator('text=current_marketing_outer').first().click()
 
-    // Verify references contains expected content
-    await window.waitForSelector('text=References')
-    await window.waitForSelector('text=WITH current_marketing_outer AS')
-    await window.waitForSelector('text=FROM current_marketing_outer')
+      // Use keyboard shortcut to find all references
+      await window.keyboard.press(FIND_ALL_REFERENCES_KEY)
 
-    // Verify that the customers.sql file is shown in results
-    await expect(window.locator('text=customers.sql').first()).toBeVisible()
+      // Verify references contains expected content
+      await window.waitForSelector('text=References')
+      await window.waitForSelector('text=WITH current_marketing_outer AS')
+      await window.waitForSelector('text=FROM current_marketing_outer')
+
+      // Verify that the customers.sql file is shown in results
+      await expect(window.locator('text=customers.sql').first()).toBeVisible()
+    } finally {
+      await close()
+      fs.removeSync(tempDir)
+    }
   })
 
   test('Find all references from usage for CTE', async () => {
-    // Click on the CTE usage of "current_marketing_outer" using last
-    await window.locator('text=current_marketing_outer').last().click()
+    const { window, close, tempDir } = await setupModelTestEnvironment()
 
-    // Use keyboard shortcut to find all references
-    await window.keyboard.press(FIND_ALL_REFERENCES_KEY)
+    try {
+      await openCustomersFile(window)
 
-    // Verify references contains expected content
-    await window.waitForSelector('text=References')
-    await window.waitForSelector('text=WITH current_marketing_outer AS')
-    await window.waitForSelector('text=FROM current_marketing_outer')
+      // Click on the CTE usage of "current_marketing_outer" using last
+      await window.locator('text=current_marketing_outer').last().click()
 
-    // Verify that the customers.sql file is shown in results
-    await expect(window.locator('text=customers.sql').first()).toBeVisible()
+      // Use keyboard shortcut to find all references
+      await window.keyboard.press(FIND_ALL_REFERENCES_KEY)
+
+      // Verify references contains expected content
+      await window.waitForSelector('text=References')
+      await window.waitForSelector('text=WITH current_marketing_outer AS')
+      await window.waitForSelector('text=FROM current_marketing_outer')
+
+      // Verify that the customers.sql file is shown in results
+      await expect(window.locator('text=customers.sql').first()).toBeVisible()
+    } finally {
+      await close()
+      fs.removeSync(tempDir)
+    }
   })
 
   test('Find all references for nested CTE', async () => {
-    // Click on the nested CTE "current_marketing" at line 33
-    // We need to be more specific to get the inner one
-    await window.locator('text=WITH current_marketing AS').click({
-      position: { x: 100, y: 5 }, // Click on the CTE name part
-    })
-
-    // Use keyboard shortcut to find all references
-    await window.keyboard.press(FIND_ALL_REFERENCES_KEY)
-
-    // Verify references contains expected content
-    await window.waitForSelector('text=References')
-    await window.waitForSelector('text=WITH current_marketing AS')
-    await window.waitForSelector('text=FROM current_marketing')
-
-    // Verify that the customers.sql file is shown in results
-    await expect(window.locator('text=customers.sql').first()).toBeVisible()
+    const { window, close, tempDir } = await setupModelTestEnvironment()
+
+    try {
+      await openCustomersFile(window)
+
+      // Click on the nested CTE "current_marketing" at line 33
+      // We need to be more specific to get the inner one
+      await window.locator('text=WITH current_marketing AS').click({
+        position: { x: 100, y: 5 }, // Click on the CTE name part
+      })
+
+      // Use keyboard shortcut to find all references
+      await window.keyboard.press(FIND_ALL_REFERENCES_KEY)
+
+      // Verify references contains expected content
+      await window.waitForSelector('text=References')
+      await window.waitForSelector('text=WITH current_marketing AS')
+      await window.waitForSelector('text=FROM current_marketing')
+
+      // Verify that the customers.sql file is shown in results
+      await expect(window.locator('text=customers.sql').first()).toBeVisible()
+    } finally {
+      await close()
+      fs.removeSync(tempDir)
+    }
   })
 })
 
 test.describe('Macro References', () => {
-  let tempDir: string
-  let window: any
-  let close: () => Promise<void>
-
-  test.beforeEach(async () => {
-    tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'vscode-test-sushi-'))
-    await fs.copy(SUSHI_SOURCE_PATH, tempDir)
-    const vscode = await startVSCode(tempDir)
-    window = vscode.window
-    close = vscode.close
-
-    // Common setup: navigate to top_waiters.sql which uses macros
-    await window.waitForSelector('text=models')
-    await window
-      .getByRole('treeitem', { name: 'models', exact: true })
-      .locator('a')
-      .click()
-    await window
-      .getByRole('treeitem', { name: 'top_waiters.sql', exact: true })
-      .locator('a')
-      .click()
-    await window.waitForSelector('text=grain')
-    await window.waitForSelector('text=Loaded SQLMesh Context')
-  })
+  test('Go to References for @ADD_ONE macro', async () => {
+    const { window, close, tempDir } = await setupModelTestEnvironment()
 
-  test.afterEach(async () => {
-    await close()
-    fs.removeSync(tempDir)
-  })
+    try {
+      await openTopWaitersFile(window)
 
-  test('Go to References for @ADD_ONE macro', async () => {
-    // Click on the @ADD_ONE macro usage
-    await window.locator('text=@ADD_ONE').first().click()
+      // Click on the @ADD_ONE macro usage
+      await window.locator('text=@ADD_ONE').first().click()
 
-    // Use keyboard shortcut to find all references
-    await window.keyboard.press(GO_TO_REFERENCES_KEY)
+      // Use keyboard shortcut to find all references
+      await window.keyboard.press(GO_TO_REFERENCES_KEY)
 
-    // Wait for the references to appear
-    await window.waitForSelector('text=References')
+      // Wait for the references to appear
+      await window.waitForSelector('text=References')
 
-    // Wait for reference panel to populate
-    await window.waitForFunction(
-      () => {
-        const referenceElements = document.querySelectorAll(
-          '.reference-item, .monaco-list-row, .references-view .tree-row',
-        )
-        return referenceElements.length >= 2
-      },
-      { timeout: 5000 },
-    )
-
-    // Verify that both the definition and two usages are shown
-    await expect(window.locator('text=utils.py').first()).toBeVisible()
-    await expect(window.locator('text=top_waiters.sql').first()).toBeVisible()
-    await expect(window.locator('text=customers.sql').first()).toBeVisible()
+      // Wait for reference panel to populate
+      await window.waitForFunction(
+        () => {
+          const referenceElements = document.querySelectorAll(
+            '.reference-item, .monaco-list-row, .references-view .tree-row',
+          )
+          return referenceElements.length >= 2
+        },
+        { timeout: 5000 },
+      )
+
+      // Verify that both the definition and two usages are shown
+      await expect(window.locator('text=utils.py').first()).toBeVisible()
+      await expect(window.locator('text=top_waiters.sql').first()).toBeVisible()
+      await expect(window.locator('text=customers.sql').first()).toBeVisible()
+    } finally {
+      await close()
+      fs.removeSync(tempDir)
+    }
   })
 
   test('Find All References for @MULTIPLY macro', async () => {
-    // Click on the @MULTIPLY macro usage and then navigate to it
-    await window.locator('text=@MULTIPLY').first().click()
-
-    // Use keyboard shortcut to find all references
-    await window.keyboard.press(FIND_ALL_REFERENCES_KEY)
-
-    // Verify references contains expected content
-    await window.waitForSelector('text=References')
-
-    // Verify that both utils.py (definition) and top_waiters.sql (usage) are shown
-    await expect(window.locator('text=utils.py').first()).toBeVisible()
-    await expect(window.locator('text=top_waiters.sql').first()).toBeVisible()
-
-    // Click on the utils.py reference to navigate to the macro definition
-    let clickedReference = false
-    const referenceItems = await window.locator(
-      '.monaco-list-row, .reference-item, .monaco-tl-row',
-    )
-    const count = await referenceItems.count()
-
-    for (let i = 0; i < count; i++) {
-      const item = referenceItems.nth(i)
-      const text = await item.textContent()
-
-      // Find the utils.py reference which contains the macro definition
-      if (text && text.includes('utils.py')) {
-        await item.click()
-        clickedReference = true
-        break
+    const { window, close, tempDir } = await setupModelTestEnvironment()
+
+    try {
+      await openTopWaitersFile(window)
+
+      // Click on the @MULTIPLY macro usage and then navigate to it
+      await window.locator('text=@MULTIPLY').first().click()
+
+      // Use keyboard shortcut to find all references
+      await window.keyboard.press(FIND_ALL_REFERENCES_KEY)
+
+      // Verify references contains expected content
+      await window.waitForSelector('text=References')
+
+      // Verify that both utils.py (definition) and top_waiters.sql (usage) are shown
+      await expect(window.locator('text=utils.py').first()).toBeVisible()
+      await expect(window.locator('text=top_waiters.sql').first()).toBeVisible()
+
+      // Click on the utils.py reference to navigate to the macro definition
+      let clickedReference = false
+      const referenceItems = window.locator(
+        '.monaco-list-row, .reference-item, .monaco-tl-row',
+      )
+      const count = await referenceItems.count()
+
+      for (let i = 0; i < count; i++) {
+        const item = referenceItems.nth(i)
+        const text = await item.textContent()
+
+        // Find the utils.py reference which contains the macro definition
+        if (text && text.includes('utils.py')) {
+          await item.click()
+          clickedReference = true
+          break
+        }
       }
-    }
 
-    expect(clickedReference).toBe(true)
+      expect(clickedReference).toBe(true)
 
-    // Verify it appeared and click on it
-    await expect(window.locator('text=def multiply')).toBeVisible()
-    await window.locator('text=def multiply').first().click()
+      // Verify it appeared and click on it
+      await expect(window.locator('text=def multiply')).toBeVisible()
+      await window.locator('text=def multiply').first().click()
 
-    // Verify navigation to utils.py by checking the import that appears there
-    await expect(
-      window.locator('text=from sqlmesh import SQL, macro'),
-    ).toBeVisible()
+      // Verify navigation to utils.py by checking the import that appears there
+      await expect(
+        window.locator('text=from sqlmesh import SQL, macro'),
+      ).toBeVisible()
+    } finally {
+      await close()
+      fs.removeSync(tempDir)
+    }
   })
 
   test('Go to References for @SQL_LITERAL macro', async () => {
-    // Click on the @SQL_LITERAL macro usage
-    await window.locator('text=@SQL_LITERAL').first().click()
+    const { window, close, tempDir } = await setupModelTestEnvironment()
 
-    // Use keyboard shortcut to find references
-    await window.keyboard.press(GO_TO_REFERENCES_KEY)
+    try {
+      await openTopWaitersFile(window)
 
-    // Wait for the references to appear
-    await window.waitForSelector('text=References')
+      // Click on the @SQL_LITERAL macro usage
+      await window.locator('text=@SQL_LITERAL').first().click()
 
-    // Wait for reference panel to populate
-    await window.waitForFunction(
-      () => {
-        const referenceElements = document.querySelectorAll(
-          '.reference-item, .monaco-list-row, .references-view .tree-row',
-        )
-        return referenceElements.length >= 2
-      },
-      { timeout: 5000 },
-    )
-
-    // Verify that references include both definition and usage
-    const hasReferences = await window.evaluate(() => {
-      const body = document.body.textContent || ''
-      return (
-        body.includes('References') &&
-        body.includes('.py') &&
-        body.includes('.sql')
+      // Use keyboard shortcut to find references
+      await window.keyboard.press(GO_TO_REFERENCES_KEY)
+
+      // Wait for the references to appear
+      await window.waitForSelector('text=References')
+
+      // Wait for reference panel to populate
+      await window.waitForFunction(
+        () => {
+          const referenceElements = document.querySelectorAll(
+            '.reference-item, .monaco-list-row, .references-view .tree-row',
+          )
+          return referenceElements.length >= 2
+        },
+        { timeout: 5000 },
       )
-    })
 
-    expect(hasReferences).toBe(true)
+      // Verify that references include both definition and usage
+      const hasReferences = await window.evaluate(() => {
+        const body = document.body.textContent || ''
+        return (
+          body.includes('References') &&
+          body.includes('.py') &&
+          body.includes('.sql')
+        )
+      })
+
+      expect(hasReferences).toBe(true)
 
-    await expect(window.locator('text=utils.py').first()).toBeVisible()
-    await expect(window.locator('text=top_waiters.sql').first()).toBeVisible()
+      await expect(window.locator('text=utils.py').first()).toBeVisible()
+      await expect(window.locator('text=top_waiters.sql').first()).toBeVisible()
+    } finally {
+      await close()
+      fs.removeSync(tempDir)
+    }
   })
 })
diff --git a/vscode/extension/tests/stop.spec.ts b/vscode/extension/tests/stop.spec.ts
index 61422991..d7b2d08c 100644
--- a/vscode/extension/tests/stop.spec.ts
+++ b/vscode/extension/tests/stop.spec.ts
@@ -1,57 +1,67 @@
 import path from 'path'
-import { startVSCode, SUSHI_SOURCE_PATH } from './utils'
+import { SUSHI_SOURCE_PATH } from './utils'
 import os from 'os'
 import { test } from '@playwright/test'
 import fs from 'fs-extra'
+import { startCodeServer, stopCodeServer } from './utils_code_server'
 
-test('Stop server works', async () => {
+test('Stop server works', async ({ page }) => {
+  test.setTimeout(120000) // Increase timeout to 2 minutes
+
+  console.log('Starting test: Stop server works')
   const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'vscode-test-sushi-'))
   await fs.copy(SUSHI_SOURCE_PATH, tempDir)
 
+  const context = await startCodeServer(tempDir, true)
+
   try {
-    const { window, close } = await startVSCode(tempDir)
+    // Navigate to code-server instance
+    await page.goto(`http://127.0.0.1:${context.codeServerPort}`)
+
+    // Wait for code-server to load
+    await page.waitForLoadState('networkidle')
+    await page.waitForSelector('[role="application"]', { timeout: 10000 })
 
-    //   Wait for the models folder to be visible
-    await window.waitForSelector('text=models')
+    // Wait for the models folder to be visible in the file explorer
+    await page.waitForSelector('text=models')
 
     // Click on the models folder, excluding external_models
-    await window
+    await page
       .getByRole('treeitem', { name: 'models', exact: true })
       .locator('a')
       .click()
 
-    // Open the customer_revenue_lifetime model
-    await window
+    // Open the customers.sql model
+    await page
       .getByRole('treeitem', { name: 'customers.sql', exact: true })
       .locator('a')
       .click()
 
-    await window.waitForSelector('text=grain')
-    await window.waitForSelector('text=Loaded SQLMesh Context')
+    await page.waitForSelector('text=grain')
+    await page.waitForSelector('text=Loaded SQLMesh Context')
 
     // Stop the server
-    await window.keyboard.press(
+    await page.keyboard.press(
       process.platform === 'darwin' ? 'Meta+Shift+P' : 'Control+Shift+P',
     )
-    await window.keyboard.type('SQLMesh: Stop Server')
-    await window.keyboard.press('Enter')
+    await page.keyboard.type('SQLMesh: Stop Server')
+    await page.keyboard.press('Enter')
 
     // Await LSP server stopped message
-    await window.waitForSelector('text=LSP server stopped')
+    await page.waitForSelector('text=LSP server stopped')
 
     // Render the model
-    await window.keyboard.press(
+    await page.keyboard.press(
       process.platform === 'darwin' ? 'Meta+Shift+P' : 'Control+Shift+P',
     )
-    await window.keyboard.type('Render Model')
-    await window.keyboard.press('Enter')
+    await page.keyboard.type('Render Model')
+    await page.keyboard.press('Enter')
 
     // Await error message
-    await window.waitForSelector(
+    await page.waitForSelector(
       'text="Failed to render model: LSP client not ready."',
     )
-    await close()
   } finally {
-    await fs.remove(tempDir)
+    await stopCodeServer(context)
   }
 })
diff --git a/vscode/extension/tests/utils_code_server.ts b/vscode/extension/tests/utils_code_server.ts
new file mode 100644
index 00000000..c38fee61
--- /dev/null
+++ b/vscode/extension/tests/utils_code_server.ts
@@ -0,0 +1,165 @@
+import { spawn, ChildProcess, execSync } from 'child_process'
+import path from 'path'
+import fs from 'fs-extra'
+
+export interface CodeServerContext {
+  codeServerProcess: ChildProcess
+  codeServerPort: number
+  tempDir: string
+}
+
+/**
+ * @param tempDir - The temporary directory to use for the code-server instance
+ * @param placeFileWithPythonInterpreter - Whether to place a vscode/settings.json file in the temp directory that points to the python interpreter of the environmen the test is running in.
+ * @returns The code-server context
+ */
+export async function startCodeServer(
+  tempDir: string,
+  placeFileWithPythonInterpreter: boolean = false,
+): Promise<CodeServerContext> {
+  // Find an available port
+  const codeServerPort = Math.floor(Math.random() * 10000) + 50000
+
+  // Create .vscode/settings.json with Python interpreter if requested
+  if (placeFileWithPythonInterpreter) {
+    const vscodeDir = path.join(tempDir, '.vscode')
+    await fs.ensureDir(vscodeDir)
+
+    // Get the current Python interpreter path
+    const pythonPath = execSync('which python', {
+      encoding: 'utf-8',
+    }).trim()
+
+    const settings = {
+      'python.defaultInterpreterPath': path.join(
+        __dirname,
+        '..',
+        '..',
+        '..',
+        '.venv',
+        'bin',
+        'python',
+      ),
+    }
+
+    await fs.writeJson(path.join(vscodeDir, 'settings.json'), settings, {
+      spaces: 2,
+    })
+    console.log(
+      `Created .vscode/settings.json with Python interpreter: ${pythonPath}`,
+    )
+  }
+
+  // Get the extension version from package.json
+  const extensionDir = path.join(__dirname, '..')
+  const packageJson = JSON.parse(
+    fs.readFileSync(path.join(extensionDir, 'package.json'), 'utf-8'),
+  )
+  const version = packageJson.version
+  const extensionName = packageJson.name || 'sqlmesh'
+
+  // Look for the specific version .vsix file
+  const vsixFileName = `${extensionName}-${version}.vsix`
+  const vsixPath = path.join(extensionDir, vsixFileName)
+
+  if (!fs.existsSync(vsixPath)) {
+    throw new Error(
+      `Extension file ${vsixFileName} not found. Run "pnpm run vscode:package" first.`,
+    )
+  }
+
+  console.log(`Using extension: ${vsixFileName}`)
+
+  // Install the extension first
+  const extensionsDir = path.join(tempDir, 'extensions')
+  console.log('Installing extension...')
+  execSync(
+    `pnpm run code-server --user-data-dir "${tempDir}" --extensions-dir "${extensionsDir}" --install-extension "${vsixPath}"`,
+    { stdio: 'inherit' },
+  )
+
+  // Start code-server instance
+  const codeServerProcess = spawn(
+    'pnpm',
+    [
+      'run',
+      'code-server',
+      '--bind-addr',
+      `127.0.0.1:${codeServerPort}`,
+      '--auth',
+      'none',
+      '--disable-telemetry',
+      '--disable-update-check',
+      '--disable-workspace-trust',
+      '--user-data-dir',
+      tempDir,
+      '--extensions-dir',
+      extensionsDir,
+      tempDir,
+    ],
+    {
+      stdio: 'pipe',
+      cwd: path.join(__dirname, '..'),
+    },
+  )
+
+  // Wait for code-server to be ready
+  await new Promise<void>((resolve, reject) => {
+    let output = ''
+    const timeout = setTimeout(() => {
+      reject(new Error('Code-server failed to start within timeout'))
+    }, 30000)
+
+    codeServerProcess.stdout?.on('data', data => {
+      output += data.toString()
+      if (output.includes('HTTP server listening on')) {
+        clearTimeout(timeout)
+        resolve()
+      }
+    })
+
+    codeServerProcess.stderr?.on('data', data => {
+      console.error('Code-server stderr:', data.toString())
+    })
+
+    codeServerProcess.on('error', error => {
+      clearTimeout(timeout)
+      reject(error)
+    })
+
+    codeServerProcess.on('exit', code => {
+      if (code !== 0) {
+        clearTimeout(timeout)
+        reject(new Error(`Code-server exited with code ${code}`))
+      }
+    })
+  })
+
+  return { codeServerProcess, codeServerPort, tempDir }
+}
+
+export async function stopCodeServer(
+  context: CodeServerContext,
+): Promise<void> {
+  const { codeServerProcess, tempDir } = context
+
+  // Clean up code-server process
+  codeServerProcess.kill('SIGTERM')
+
+  // Wait for process to exit
+  await new Promise<void>(resolve => {
+    codeServerProcess.on('exit', () => {
+      resolve()
+    })
+    // Force kill after 5 seconds
+    setTimeout(() => {
+      if (!codeServerProcess.killed) {
+        codeServerProcess.kill('SIGKILL')
+      }
+      resolve()
+    }, 5000)
+  })
+
+  // Clean up temporary directory
+  await fs.remove(tempDir)
+}