Repository: stateful/vscode-runme
Pull request #1256 (2024-04-04 20:49:58)

Use extension env var collection API for "globals vars"
Two things:

1. This will simplify setting Runme-related of ENV vars.
2. Moves runner v1 types into a namespace to prep v2 migration.

sonarcloud[bot]: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=stateful_vscode-runme&pullRequest=1256) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=stateful_vscode-runme&pullRequest=1256&resolved=false&inNewCodePeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/component_measures?id=stateful_vscode-runme&pullRequest=1256&metric=new_accepted_issues&view=list)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=stateful_vscode-runme&pullRequest=1256&resolved=false&inNewCodePeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [66.2% Coverage on New Code](https://sonarcloud.io/component_measures?id=stateful_vscode-runme&pullRequest=1256&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=stateful_vscode-runme&pullRequest=1256&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarCloud](https://sonarcloud.io/dashboard?id=stateful_vscode-runme&pullRequest=1256)



Patch:
diff --git a/src/client/components/env/store.ts b/src/client/components/env/store.ts
index 511f217e..606be2b3 100644
--- a/src/client/components/env/store.ts
+++ b/src/client/components/env/store.ts
@@ -10,7 +10,7 @@ import '../tooltip'
 import { formatDate, formatDateWithTimeAgo } from '../../utils'
 import { SnapshotEnv } from '../../../types'
 import { CustomErrorIcon } from '../icons/error'
-import { MonitorEnvStoreResponseSnapshot_Status } from '../../../extension/grpc/runnerTypes'
+import { MonitorEnvStoreResponseSnapshot_Status } from '../../../extension/grpc/runner/v1'
 
 const RUNME_ENV_VARS_NAME = '__'
 
diff --git a/src/client/components/envViewer.ts b/src/client/components/envViewer.ts
index ce552712..94cb18e3 100644
--- a/src/client/components/envViewer.ts
+++ b/src/client/components/envViewer.ts
@@ -3,7 +3,7 @@ import { LitElement, css, html } from 'lit'
 import { customElement, property, state } from 'lit/decorators.js'
 import { when } from 'lit/directives/when.js'
 
-import { MonitorEnvStoreResponseSnapshot_Status } from '../../extension/grpc/runnerTypes'
+import { MonitorEnvStoreResponseSnapshot_Status } from '../../extension/grpc/runner/v1'
 
 import { CopyIcon } from './icons/copy'
 import { EyeClosedIcon } from './icons/eyeClosed'
diff --git a/src/extension/commands/index.ts b/src/extension/commands/index.ts
index f07a75f4..cd1d9f71 100644
--- a/src/extension/commands/index.ts
+++ b/src/extension/commands/index.ts
@@ -31,12 +31,10 @@ import { Kernel } from '../kernel'
 import {
   getAnnotations,
   getNotebookCategories,
-  getRunnerSessionEnvs,
   getTerminalByCell,
   openFileAsRunmeNotebook,
   promptUserSession,
 } from '../utils'
-import IServer from '../server/runmeServer'
 import { NotebookToolbarCommand } from '../../types'
 import getLogger from '../logger'
 import { RecommendExtensionMessage } from '../messaging'
@@ -148,12 +146,7 @@ export function stopBackgroundTask(cell: NotebookCell) {
   terminal.dispose()
 }
 
-export function runCLICommand(
-  extensionBaseUri: Uri,
-  grpcRunner: boolean,
-  server: IServer,
-  kernel: Kernel,
-) {
+export function runCLICommand(extensionBaseUri: Uri, grpcRunner: boolean) {
   return async function (cell: NotebookCell) {
     if (cell.notebook.isDirty) {
       const option = await window.showInformationMessage(
@@ -189,21 +182,16 @@ export function runCLICommand(
       `--index=${index}`,
     ]
 
-    let envs: Record<string, string> = {}
-
     if (grpcRunner) {
       if (!getTLSEnabled()) {
         args.push('--insecure')
       }
-
-      envs = getRunnerSessionEnvs(extensionBaseUri, kernel, server)
     }
 
     const annotations = getAnnotations(cell.metadata)
     const term = window.createTerminal({
       name: `CLI: ${annotations.name}`,
       cwd,
-      env: envs,
     })
 
     const runmeExec = getCLIUseIntegratedRunme() ? getBinaryPath(extensionBaseUri).fsPath : 'runme'
@@ -253,7 +241,7 @@ export async function askNewRunnerSession(kernel: Kernel) {
   )
   if (action) {
     await commands.executeCommand('workbench.action.files.save')
-    await kernel.newRunnerEnvironment()
+    await kernel.newRunnerEnvironment({})
     await commands.executeCommand('workbench.action.files.save')
   }
 }
diff --git a/src/extension/executors/runner/index.ts b/src/extension/executors/runner/index.ts
index 5f18457e..83063da7 100644
--- a/src/extension/executors/runner/index.ts
+++ b/src/extension/executors/runner/index.ts
@@ -34,7 +34,7 @@ import {
   ResolveProgramRequest_Mode,
   ResolveProgramResponse_Status,
   ResolveProgramResponse_VarResult,
-} from '../../grpc/runnerTypes'
+} from '../../grpc/runner/v1'
 import { closeTerminalByEnvID } from '../task'
 import {
   getCellProgram,
diff --git a/src/extension/executors/task.ts b/src/extension/executors/task.ts
index 9340dcc9..0a855e2e 100644
--- a/src/extension/executors/task.ts
+++ b/src/extension/executors/task.ts
@@ -16,7 +16,7 @@ import getLogger from '../logger'
 import { getAnnotations, getTerminalRunmeId } from '../utils'
 import { PLATFORM_OS, ENV_STORE } from '../constants'
 import { DEFAULT_PROMPT_ENV } from '../../constants'
-import { ResolveProgramRequest_Mode } from '../grpc/runnerTypes'
+import { ResolveProgramRequest_Mode } from '../grpc/runner/v1'
 
 import {
   getCmdShellSeq,
diff --git a/src/extension/executors/utils.ts b/src/extension/executors/utils.ts
index 52ce8fd0..4c3bc3cd 100644
--- a/src/extension/executors/utils.ts
+++ b/src/extension/executors/utils.ts
@@ -16,7 +16,7 @@ import { DEFAULT_PROMPT_ENV, OutputType } from '../../constants'
 import type { CellOutputPayload, Serializer, ShellType } from '../../types'
 import { NotebookCellOutputManager } from '../cell'
 import { getAnnotations, getWorkspaceFolder } from '../utils'
-import { CommandMode } from '../grpc/runnerTypes'
+import { CommandMode } from '../grpc/runner/v1'
 
 const HASH_PREFIX_REGEXP = /^\s*\#\s*/g
 const ENV_VAR_REGEXP = /(\$\w+)/g
diff --git a/src/extension/extension.ts b/src/extension/extension.ts
index 2ea88a3b..a0604131 100644
--- a/src/extension/extension.ts
+++ b/src/extension/extension.ts
@@ -16,7 +16,6 @@ import {
   getForceNewWindowConfig,
   getSessionOutputs,
   isPlatformAuthEnabled,
-  registerExtensionEnvironmentVariables,
 } from '../utils/configuration'
 import { WebViews } from '../constants'
 
@@ -158,7 +157,7 @@ export class RunmeExtension {
     ]
     const stopBackgroundTaskProvider = new StopBackgroundTaskProvider()
 
-    const runCLI = runCLICommand(context.extensionUri, !!grpcRunner, server, kernel)
+    const runCLI = runCLICommand(context.extensionUri, !!grpcRunner)
 
     const codeLensProvider = new RunmeCodeLensProvider(
       context.extensionUri,
@@ -170,7 +169,6 @@ export class RunmeExtension {
       server,
     )
 
-    registerExtensionEnvironmentVariables(context)
     await resetNotebookAutosaveSettings()
 
     const transientOutputs = !getSessionOutputs()
diff --git a/src/extension/grpc/runnerTypes.ts b/src/extension/grpc/runner/v1.ts
similarity index 100%
rename from src/extension/grpc/runnerTypes.ts
rename to src/extension/grpc/runner/v1.ts
diff --git a/src/extension/grpc/runner/v2alpha1.ts b/src/extension/grpc/runner/v2alpha1.ts
new file mode 100644
index 00000000..3269d836
--- /dev/null
+++ b/src/extension/grpc/runner/v2alpha1.ts
@@ -0,0 +1,1 @@
+export * from '@buf/stateful_runme.community_timostamm-protobuf-ts/runme/runner/v2alpha1/runner_pb'
diff --git a/src/extension/kernel.ts b/src/extension/kernel.ts
index e3e74b43..72202917 100644
--- a/src/extension/kernel.ts
+++ b/src/extension/kernel.ts
@@ -36,7 +36,11 @@ import {
 } from '../constants'
 import { API } from '../utils/deno/api'
 import { postClientMessage } from '../utils/messaging'
-import { getNotebookExecutionOrder, isPlatformAuthEnabled } from '../utils/configuration'
+import {
+  getNotebookExecutionOrder,
+  isPlatformAuthEnabled,
+  registerExtensionEnvVarsMutation,
+} from '../utils/configuration'
 
 import getLogger from './logger'
 import executor, { type IEnvironmentManager, ENV_STORE_MANAGER, IKernelExecutor } from './executors'
@@ -52,11 +56,12 @@ import {
   suggestCategories,
   handleNotebookAutosaveSettings,
   getWorkspaceFolder,
+  getRunnerSessionEnvs,
 } from './utils'
 import { isShellLanguage } from './executors/utils'
 import './wasm/wasm_exec.js'
 import { RpcError } from './grpc/client'
-import { IRunner } from './runner'
+import { IRunner, IRunnerReady } from './runner'
 import { IRunnerEnvironment } from './runner/environment'
 import { executeRunner } from './executors/runner'
 import { ITerminalState, NotebookTerminalType } from './terminal/terminalState'
@@ -78,7 +83,7 @@ import { handleGCPMessage } from './messages/gcp'
 import { IPanel } from './panels/base'
 import { handleAWSMessage } from './messages/aws'
 import EnvVarsChangedEvent from './events/envVarsChanged'
-import { SessionEnvStoreType } from './grpc/runnerTypes'
+import { SessionEnvStoreType } from './grpc/runner/v1'
 
 enum ConfirmationItems {
   Yes = 'Yes',
@@ -700,7 +705,7 @@ export class Kernel implements Disposable {
     return this.runnerEnv
   }
 
-  async newRunnerEnvironment(): Promise<void> {
+  async newRunnerEnvironment({ address }: IRunnerReady): Promise<void> {
     if (!this.runner) {
       log.error('Skipping new runner environment request since runner is not initialized.')
       return
@@ -728,6 +733,11 @@ export class Kernel implements Disposable {
 
       this.cellManager.setRunnerEnv(runnerEnv)
 
+      registerExtensionEnvVarsMutation(
+        this.context,
+        getRunnerSessionEnvs(this.context.extensionUri, runnerEnv, address),
+      )
+
       const monitor = await this.runner.createMonitorEnvStore()
       const streaming = monitor.monitorEnvStore(runnerEnv?.getSessionId())
       streaming.responses.onMessage(({ data }) => {
@@ -766,7 +776,7 @@ export class Kernel implements Disposable {
           await this.runner?.setEnvironmentVariables(this.runnerEnv, { [key]: val })
         },
         reset: async () => {
-          await this.newRunnerEnvironment()
+          await this.newRunnerEnvironment({})
         },
       }
     } else {
diff --git a/src/extension/provider/codelens.ts b/src/extension/provider/codelens.ts
index 65ac4f7f..ad4961cb 100644
--- a/src/extension/provider/codelens.ts
+++ b/src/extension/provider/codelens.ts
@@ -24,7 +24,7 @@ import { SerializerBase } from '../serializer'
 import type { runCLICommand } from '../commands'
 import { IRunner } from '../runner'
 import { Kernel } from '../kernel'
-import { getAnnotations, getRunnerSessionEnvs } from '../utils'
+import { getAnnotations } from '../utils'
 import { Serializer } from '../../types'
 import { getCodeLensEnabled } from '../../utils/configuration'
 import { RunmeExtension } from '../extension'
@@ -228,11 +228,7 @@ export class RunmeCodeLensProvider implements CodeLensProvider, Disposable {
           let activeTerminal = window.activeTerminal
 
           if (!activeTerminal) {
-            let envs: Record<string, string> = {}
-            if (this.runner && this.kernel && this.server) {
-              envs = getRunnerSessionEnvs(this.extensionBaseUri, this.kernel, this.server)
-            }
-            activeTerminal = window.createTerminal({ env: envs })
+            activeTerminal = window.createTerminal()
           }
 
           activeTerminal.show(false)
diff --git a/src/extension/provider/runmeTask.ts b/src/extension/provider/runmeTask.ts
index 80eac1bb..0f895114 100644
--- a/src/extension/provider/runmeTask.ts
+++ b/src/extension/provider/runmeTask.ts
@@ -41,7 +41,7 @@ import { ProjectServiceClient, initProjectClient, type ReadyPromise } from '../g
 import { LoadEventFoundTask, LoadRequest, LoadResponse } from '../grpc/projectTypes'
 import { RunmeIdentity } from '../grpc/serializerTypes'
 import { resolveRunProgramExecution } from '../executors/runner'
-import { CommandMode, ResolveProgramRequest_Mode } from '../grpc/runnerTypes'
+import { CommandMode, ResolveProgramRequest_Mode } from '../grpc/runner/v1'
 
 import { RunmeLauncherProvider } from './launcher'
 
diff --git a/src/extension/runner/client.ts b/src/extension/runner/client.ts
index 6181c4bf..e730c2a2 100644
--- a/src/extension/runner/client.ts
+++ b/src/extension/runner/client.ts
@@ -18,25 +18,31 @@ import {
   MonitorEnvStoreResponse,
   ResolveProgramRequest,
   ResolveProgramResponse,
-} from '../grpc/runnerTypes'
+} from '../grpc/runner/v1'
 import { IRunnerServiceClient, RunnerServiceClient } from '../grpc/client'
 import { IServer } from '../server/runmeServer'
 
+import { IRunnerReady } from '.'
+
 export type IRunnerClient = IRunnerServiceClient & Disposable
 
 export class GrpcRunnerClient implements IRunnerClient {
   private disposables: Disposable[] = []
 
+  protected address?: string
   protected client?: RunnerServiceClient
-  protected _onReady?: EventEmitter<void>
+  protected _onReady?: EventEmitter<IRunnerReady>
 
   constructor(
     protected server: IServer,
-    ready?: EventEmitter<void>,
+    ready?: EventEmitter<IRunnerReady>,
   ) {
     this._onReady = ready
     this.disposables.push(
-      server.onTransportReady(({ transport }) => this.initRunnerClient(transport)),
+      server.onTransportReady(({ transport, address }) => {
+        this.address = address
+        this.initRunnerClient(transport)
+      }),
     )
 
     this.disposables.push(
@@ -53,7 +59,7 @@ export class GrpcRunnerClient implements IRunnerClient {
   private async initRunnerClient(transport?: GrpcTransport) {
     this.deinitRunnerClient()
     this.client = new RunnerServiceClient(transport ?? (await this.server.transport()))
-    this._onReady?.fire()
+    this._onReady?.fire({ address: this.address })
   }
 
   static assertClient(client: RunnerServiceClient | undefined): asserts client {
diff --git a/src/extension/runner/environment.ts b/src/extension/runner/environment.ts
index c89b68e9..8e0c03b4 100644
--- a/src/extension/runner/environment.ts
+++ b/src/extension/runner/environment.ts
@@ -1,5 +1,5 @@
 import { IRunnerServiceClient } from '../grpc/client'
-import { Session } from '../grpc/runnerTypes'
+import { Session } from '../grpc/runner/v1'
 import getLogger from '../logger'
 import { convertEnvList } from '../utils'
 
diff --git a/src/extension/runner/index.ts b/src/extension/runner/index.ts
index 21a8c84e..2146cb9e 100644
--- a/src/extension/runner/index.ts
+++ b/src/extension/runner/index.ts
@@ -18,7 +18,7 @@ import {
   ResolveProgramRequest_Mode,
   SessionEnvStoreType,
   Winsize,
-} from '../grpc/runnerTypes'
+} from '../grpc/runner/v1'
 import { IRunnerServiceClient, RpcError } from '../grpc/client'
 import { getSystemShellPath } from '../executors/utils'
 import { IServer } from '../server/runmeServer'
@@ -63,13 +63,15 @@ export interface RunProgramOptions {
   commandMode?: CommandMode
 }
 
+export type IRunnerReady = { address?: string }
+
 export interface IRunner extends Disposable {
   /**
    * Called when underlying transport is ready
    *
    * May be called multiple times if server restarts
    */
-  readonly onReady: Event<void>
+  readonly onReady: Event<IRunnerReady>
 
   close(): void
 
@@ -186,7 +188,7 @@ export default class GrpcRunner implements IRunner {
   private children: WeakRef<IRunnerChild>[] = []
   private disposables: Disposable[] = []
 
-  protected _onReady = this.register(new EventEmitter<void>())
+  protected _onReady = this.register(new EventEmitter<IRunnerReady>())
   onReady = this._onReady.event
 
   constructor(protected server: IServer) {
diff --git a/src/extension/runner/monitorEnv.ts b/src/extension/runner/monitorEnv.ts
index ec70761c..0562a862 100644
--- a/src/extension/runner/monitorEnv.ts
+++ b/src/extension/runner/monitorEnv.ts
@@ -1,7 +1,7 @@
 import { Disposable } from 'vscode'
 
 import { IRunnerServiceClient } from '../grpc/client'
-import { MonitorEnvStoreRequest } from '../grpc/runnerTypes'
+import { MonitorEnvStoreRequest } from '../grpc/runner/v1'
 
 import { IRunnerChild } from './types'
 
diff --git a/src/extension/runner/program.ts b/src/extension/runner/program.ts
index 6b74563f..535abe20 100644
--- a/src/extension/runner/program.ts
+++ b/src/extension/runner/program.ts
@@ -1,7 +1,7 @@
 import { Disposable } from 'vscode'
 
 import { IRunnerServiceClient } from '../grpc/client'
-import { ResolveProgramRequest_Mode, ResolveProgramRequest } from '../grpc/runnerTypes'
+import { ResolveProgramRequest_Mode, ResolveProgramRequest } from '../grpc/runner/v1'
 
 import { IRunnerChild } from './types'
 
diff --git a/src/extension/server/runmeServer.ts b/src/extension/server/runmeServer.ts
index 6319cc65..6e9fa870 100644
--- a/src/extension/server/runmeServer.ts
+++ b/src/extension/server/runmeServer.ts
@@ -40,7 +40,7 @@ const log = getLogger('RunmeServer')
 export interface IServer extends Disposable {
   transportType: ServerTransportType
 
-  onTransportReady: Event<{ transport: GrpcTransport }>
+  onTransportReady: Event<{ transport: GrpcTransport; address?: string }>
   onClose: Event<{
     code: number | null
   }>
@@ -66,7 +66,9 @@ class RunmeServer implements IServer {
   #forceExternalServer: boolean
 
   readonly #onClose = this.register(new EventEmitter<{ code: number | null }>())
-  readonly #onTransportReady = this.register(new EventEmitter<{ transport: GrpcTransport }>())
+  readonly #onTransportReady = this.register(
+    new EventEmitter<{ transport: GrpcTransport; address?: string }>(),
+  )
 
   readonly transportType: ServerTransportType
   readonly onClose = this.#onClose.event
@@ -366,7 +368,7 @@ class RunmeServer implements IServer {
     this.closeTransport()
     await this.acceptsConnection()
 
-    this.#onTransportReady.fire({ transport: await this.transport() })
+    this.#onTransportReady.fire({ transport: await this.transport(), address: this.address() })
   }
 
   private _port() {
diff --git a/src/extension/utils.ts b/src/extension/utils.ts
index 8cb3155c..b1f2a6ff 100644
--- a/src/extension/utils.ts
+++ b/src/extension/utils.ts
@@ -58,8 +58,7 @@ import CategoryQuickPickItem from './quickPickItems/category'
 import getLogger from './logger'
 import { Kernel } from './kernel'
 import { BOOTFILE, BOOTFILE_DEMO } from './constants'
-import { GrpcRunnerEnvironment } from './runner/environment'
-import { IServer } from './server/runmeServer'
+import { GrpcRunnerEnvironment, IRunnerEnvironment } from './runner/environment'
 import { setCurrentCellExecutionDemo } from './handler/utils'
 import ContextState from './contextState'
 import { RunmeService } from './services/runme'
@@ -577,15 +576,20 @@ export function fetchStaticHtml(appUrl: string) {
   return fetch(appUrl)
 }
 
-export function getRunnerSessionEnvs(extensionBaseUri: Uri, kernel: Kernel, server: IServer) {
+export function getRunnerSessionEnvs(
+  extensionBaseUri: Uri,
+  runnerEnv: IRunnerEnvironment | undefined,
+  address?: string,
+) {
   const envs: Record<string, string> = {}
-  envs['RUNME_SERVER_ADDR'] = server.address()
+  if (address) {
+    envs['RUNME_SERVER_ADDR'] = address
+  }
 
   if (getTLSEnabled()) {
     envs['RUNME_TLS_DIR'] = getTLSDir(extensionBaseUri)
   }
 
-  const runnerEnv = kernel.getRunnerEnvironment()
   if (runnerEnv && runnerEnv instanceof GrpcRunnerEnvironment) {
     envs['RUNME_SESSION'] = runnerEnv.getSessionId()
   }
diff --git a/src/schema.ts b/src/schema.ts
index 23c44846..dc6a0b0c 100644
--- a/src/schema.ts
+++ b/src/schema.ts
@@ -1,6 +1,6 @@
 import { z } from 'zod'
 
-import { ResolveProgramRequest_Mode } from './extension/grpc/runnerTypes'
+import { ResolveProgramRequest_Mode } from './extension/grpc/runner/v1'
 
 const cleanAnnotation = (value: string, character: string): string => {
   return value
diff --git a/src/types.ts b/src/types.ts
index c95b8e2a..d73bf269 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -22,7 +22,7 @@ import { IAppToken } from './extension/services/runme'
 import type { TerminalConfiguration } from './utils/configuration'
 import { GCPSupportedView } from './extension/resolvers/gcpResolver'
 import { AWSSupportedView } from './extension/resolvers/awsResolver'
-import { MonitorEnvStoreResponseSnapshot_SnapshotEnv } from './extension/grpc/runnerTypes'
+import { MonitorEnvStoreResponseSnapshot_SnapshotEnv } from './extension/grpc/runner/v1'
 
 export interface SyncSchema {
   onCommand?: {
diff --git a/src/utils/configuration.ts b/src/utils/configuration.ts
index 88400410..dd216ab4 100644
--- a/src/utils/configuration.ts
+++ b/src/utils/configuration.ts
@@ -281,11 +281,17 @@ const getNotebookExecutionOrder = (): boolean => {
   return getNotebookConfigurationValue<boolean>('executionOrder', true)
 }
 
-const registerExtensionEnvironmentVariables = (context: ExtensionContext): void => {
-  context.environmentVariableCollection.prepend(
-    'PATH',
-    path.dirname(getBinaryPath(context.extensionUri).fsPath) + (isWindows() ? ';' : ':'),
-  )
+const registerExtensionEnvVarsMutation = (
+  context: ExtensionContext,
+  envs: Record<string, string>,
+): void => {
+  const binaryBasePath =
+    path.dirname(getBinaryPath(context.extensionUri).fsPath) + (isWindows() ? ';' : ':')
+  context.environmentVariableCollection.prepend('PATH', binaryBasePath)
+
+  Object.entries(envs).forEach(([k, v]) => {
+    context.environmentVariableCollection.replace(k, v)
+  })
 }
 
 const getActionsOpenViewInEditor = () => {
@@ -415,7 +421,7 @@ export {
   isNotebookTerminalFeatureEnabled,
   isRunmeAppButtonsEnabled,
   isPlatformAuthEnabled,
-  registerExtensionEnvironmentVariables,
+  registerExtensionEnvVarsMutation,
   getSessionOutputs,
   getLoginPrompt,
 }


Test patch:
diff --git a/tests/extension/cell.test.ts b/tests/extension/cell.test.ts
index 40727f7e..e0a871f6 100644
--- a/tests/extension/cell.test.ts
+++ b/tests/extension/cell.test.ts
@@ -26,7 +26,7 @@ vi.mock('vscode', async () => {
 vi.mock('vscode-telemetry')
 
 vi.mock('../../src/extension/grpc/client', () => ({}))
-vi.mock('../../../src/extension/grpc/runnerTypes', () => ({
+vi.mock('../../../src/extension/grpc/runner/v1', () => ({
   ResolveProgramRequest_Mode: vi.fn(),
 }))
 
diff --git a/tests/extension/commands/index.test.ts b/tests/extension/commands/index.test.ts
index 400cfd9c..c16b44d4 100644
--- a/tests/extension/commands/index.test.ts
+++ b/tests/extension/commands/index.test.ts
@@ -74,7 +74,7 @@ vi.mock('../../../src/extension/runner', () => ({
   GrpcRunnerEnvironment: class {},
 }))
 
-vi.mock('../../../src/extension/grpc/runnerTypes', () => ({}))
+vi.mock('../../../src/extension/grpc/runner/v1', () => ({}))
 
 beforeEach(() => {
   vi.mocked(window.showWarningMessage).mockClear()
diff --git a/tests/extension/configuration.test.ts b/tests/extension/configuration.test.ts
index b32b4de3..a5152037 100644
--- a/tests/extension/configuration.test.ts
+++ b/tests/extension/configuration.test.ts
@@ -20,7 +20,7 @@ import { SERVER_PORT } from '../../src/constants'
 import { RunmeIdentity } from '../../src/extension/grpc/serializerTypes'
 
 vi.mock('../../src/extension/grpc/client', () => ({}))
-vi.mock('../../../src/extension/grpc/runnerTypes', () => ({
+vi.mock('../../../src/extension/grpc/runner/v1', () => ({
   ResolveProgramRequest_Mode: vi.fn(),
 }))
 
diff --git a/tests/extension/executors/runner.test.ts b/tests/extension/executors/runner.test.ts
index 43b8a10b..be1f6f2a 100644
--- a/tests/extension/executors/runner.test.ts
+++ b/tests/extension/executors/runner.test.ts
@@ -11,7 +11,7 @@ import { createRunProgramOptions } from '../../../src/extension/executors/runner
 import {
   ResolveProgramResponse_Status,
   ResolveProgramResponse_VarResult,
-} from '../../../src/extension/grpc/runnerTypes'
+} from '../../../src/extension/grpc/runner/v1'
 
 vi.mock('vscode-telemetry', () => ({}))
 vi.mock('vscode')
diff --git a/tests/extension/executors/task.test.ts b/tests/extension/executors/task.test.ts
index 52a2b626..ff08d921 100644
--- a/tests/extension/executors/task.test.ts
+++ b/tests/extension/executors/task.test.ts
@@ -24,7 +24,7 @@ vi.mock('node:fs/promises', () => ({
   },
 }))
 
-vi.mock('../../../src/extension/grpc/runnerTypes', () => ({
+vi.mock('../../../src/extension/grpc/runner/v1', () => ({
   CommandMode: {
     INLINE_SHELL: 1,
     TEMP_FILE: 2,
diff --git a/tests/extension/executors/utils.test.ts b/tests/extension/executors/utils.test.ts
index 0a8fc94e..0724e3ec 100644
--- a/tests/extension/executors/utils.test.ts
+++ b/tests/extension/executors/utils.test.ts
@@ -34,7 +34,7 @@ vi.mock('node:fs/promises', () => ({
 const COMMAND_MODE_INLINE_SHELL = 1
 const COMMAND_MODE_TEMP_FILE = 2
 
-vi.mock('../../../src/extension/grpc/runnerTypes', () => ({
+vi.mock('../../../src/extension/grpc/runner/v1', () => ({
   CommandMode: {
     INLINE_SHELL: 1,
     TEMP_FILE: 2,
diff --git a/tests/extension/extension.test.ts b/tests/extension/extension.test.ts
index fa18ce98..9a9281fd 100644
--- a/tests/extension/extension.test.ts
+++ b/tests/extension/extension.test.ts
@@ -69,7 +69,7 @@ vi.mock('../../src/extension/utils', async () => ({
   resetNotebookAutosaveSettings: vi.fn(),
 }))
 
-vi.mock('../../src/extension/grpc/runnerTypes', () => ({}))
+vi.mock('../../src/extension/grpc/runner/v1', () => ({}))
 
 test('initializes all providers', async () => {
   const configValues = {
diff --git a/tests/extension/github.test.ts b/tests/extension/github.test.ts
index b86cd35e..835fdfef 100644
--- a/tests/extension/github.test.ts
+++ b/tests/extension/github.test.ts
@@ -23,7 +23,7 @@ vi.mock('vscode', async () => {
 vi.mock('vscode-telemetry')
 
 vi.mock('../../src/extension/grpc/client', () => ({}))
-vi.mock('../../../src/extension/grpc/runnerTypes', () => ({
+vi.mock('../../../src/extension/grpc/runner/v1', () => ({
   ResolveProgramRequest_Mode: vi.fn(),
 }))
 
diff --git a/tests/extension/kernel.test.ts b/tests/extension/kernel.test.ts
index faa07087..457952cc 100644
--- a/tests/extension/kernel.test.ts
+++ b/tests/extension/kernel.test.ts
@@ -37,7 +37,7 @@ vi.mock('../../src/extension/executors/index.js', () => ({
   ENV_STORE_MANAGER: {},
 }))
 vi.mock('../../src/extension/runner', () => ({}))
-vi.mock('../../src/extension/grpc/runnerTypes', () => ({}))
+vi.mock('../../src/extension/grpc/runner/v1', () => ({}))
 vi.mock('../../src/extension/commands', () => ({ askAlternativeOutputsAction: vi.fn() }))
 vi.mock('../../src/extension/messages/platformRequest/saveCellExecution')
 vi.mock('../../src/extension/messages/cloudApiRequest/saveCellExecution')
diff --git a/tests/extension/messages/cellOutput.test.ts b/tests/extension/messages/cellOutput.test.ts
index b215dd27..080d18c8 100644
--- a/tests/extension/messages/cellOutput.test.ts
+++ b/tests/extension/messages/cellOutput.test.ts
@@ -9,7 +9,7 @@ vi.mock('vscode')
 vi.mock('vscode-telemetry')
 vi.mock('../../../src/extension/runner', () => ({}))
 
-vi.mock('../../../src/extension/grpc/runnerTypes', () => ({
+vi.mock('../../../src/extension/grpc/runner/v1', () => ({
   ResolveProgramRequest_Mode: vi.fn(),
 }))
 
diff --git a/tests/extension/messages/cloudApiRequest/saveCellExecution.test.ts b/tests/extension/messages/cloudApiRequest/saveCellExecution.test.ts
index 5ca50347..be6142d3 100644
--- a/tests/extension/messages/cloudApiRequest/saveCellExecution.test.ts
+++ b/tests/extension/messages/cloudApiRequest/saveCellExecution.test.ts
@@ -13,7 +13,7 @@ import { getCellById } from '../../../../src/extension/cell'
 
 vi.mock('vscode-telemetry')
 vi.mock('../../../src/extension/runner', () => ({}))
-vi.mock('../../../src/extension/grpc/runnerTypes', () => ({}))
+vi.mock('../../../src/extension/grpc/runner/v1', () => ({}))
 vi.mock('../../../../src/extension/services/runme', () => ({
   RunmeService: class {
     async getUserToken() {}
diff --git a/tests/extension/messages/platformApiRequest/saveCellExecution.test.ts b/tests/extension/messages/platformApiRequest/saveCellExecution.test.ts
index fe0e39c6..afdea5cb 100644
--- a/tests/extension/messages/platformApiRequest/saveCellExecution.test.ts
+++ b/tests/extension/messages/platformApiRequest/saveCellExecution.test.ts
@@ -13,7 +13,7 @@ import { getCellById } from '../../../../src/extension/cell'
 
 vi.mock('vscode-telemetry')
 vi.mock('../../../src/extension/runner', () => ({}))
-vi.mock('../../../src/extension/grpc/runnerTypes', () => ({}))
+vi.mock('../../../src/extension/grpc/runner/v1', () => ({}))
 
 vi.mock('vscode', async () => {
   const mocked = (await vi.importActual('../../../../__mocks__/vscode')) as any
diff --git a/tests/extension/messaging.test.ts b/tests/extension/messaging.test.ts
index 864bf41f..f13d5313 100644
--- a/tests/extension/messaging.test.ts
+++ b/tests/extension/messaging.test.ts
@@ -31,7 +31,7 @@ vi.mock('vscode')
 vi.mock('vscode-telemetry')
 
 vi.mock('../../src/extension/grpc/client', () => ({}))
-vi.mock('../../../src/extension/grpc/runnerTypes', () => ({
+vi.mock('../../../src/extension/grpc/runner/v1', () => ({
   ResolveProgramRequest_Mode: vi.fn(),
 }))
 
diff --git a/tests/extension/provider/annotations.test.ts b/tests/extension/provider/annotations.test.ts
index 4bcfcc14..3abe6c47 100644
--- a/tests/extension/provider/annotations.test.ts
+++ b/tests/extension/provider/annotations.test.ts
@@ -31,7 +31,7 @@ vi.mock('../../../src/extension/utils', () => ({
 }))
 
 vi.mock('../../../src/extension/runner', () => ({}))
-vi.mock('../../../src/extension/grpc/runnerTypes', () => ({}))
+vi.mock('../../../src/extension/grpc/runner/v1', () => ({}))
 
 describe('Runme Annotations', () => {
   const kernel = new Kernel({} as any)
diff --git a/tests/extension/provider/launcher.test.ts b/tests/extension/provider/launcher.test.ts
index 396bf620..f0d8f0fb 100644
--- a/tests/extension/provider/launcher.test.ts
+++ b/tests/extension/provider/launcher.test.ts
@@ -5,7 +5,7 @@ import { RunmeFile, RunmeLauncherProvider } from '../../../src/extension/provide
 import { getDefaultWorkspace } from '../../../src/extension/utils'
 
 vi.mock('../../../src/extension/grpc/client', () => ({}))
-vi.mock('../../../src/extension/grpc/runnerTypes', () => ({}))
+vi.mock('../../../src/extension/grpc/runner/v1', () => ({}))
 
 vi.mock('vscode')
 vi.mock('vscode-telemetry')
diff --git a/tests/extension/runner/runner.test.ts b/tests/extension/runner/runner.test.ts
index 6760dc95..d91c0265 100644
--- a/tests/extension/runner/runner.test.ts
+++ b/tests/extension/runner/runner.test.ts
@@ -20,7 +20,7 @@ import GrpcRunner, {
   RunProgramOptions,
 } from '../../../src/extension/runner'
 import { GrpcRunnerEnvironment } from '../../../src/extension/runner/environment'
-import { type ExecuteResponse } from '../../../src/extension/grpc/runnerTypes'
+import { type ExecuteResponse } from '../../../src/extension/grpc/runner/v1'
 import { ActionCommand, RunmeCodeLensProvider } from '../../../src/extension/provider/codelens'
 import { RunmeTaskProvider } from '../../../src/extension/provider/runmeTask'
 import { isWindows } from '../../../src/extension/utils'
diff --git a/tests/extension/utils.test.ts b/tests/extension/utils.test.ts
index 97175806..e70a5d35 100644
--- a/tests/extension/utils.test.ts
+++ b/tests/extension/utils.test.ts
@@ -32,7 +32,7 @@ import { ENV_STORE, DEFAULT_ENV } from '../../src/extension/constants'
 import { CellAnnotations } from '../../src/types'
 
 vi.mock('../../src/extension/grpc/client', () => ({}))
-vi.mock('../../../src/extension/grpc/runnerTypes', () => ({
+vi.mock('../../../src/extension/grpc/runner/v1', () => ({
   ResolveProgramRequest_Mode: vi.fn(),
 }))