diff --git a/.github/workflows/build-extension.yml b/.github/workflows/build-extension.yml index 3de4248..a2f9e76 100644 --- a/.github/workflows/build-extension.yml +++ b/.github/workflows/build-extension.yml @@ -4,11 +4,11 @@ on: workflow_call: inputs: os_target: - description: "target architecture" # linux-x64, darwin-arm64 + description: "target architecture" # linux-x64, darwin-arm64, win32-x64 required: true type: string os_name: - description: "operating system" # ubuntu-latest, macos-latest + description: "operating system" # ubuntu-latest, macos-latest, windows-latest required: true type: string secrets: @@ -29,10 +29,10 @@ jobs: node-version: 20.x cache: "npm" - - name: Download fastedge-cli Artifact + - name: Download fastedge-run Artifact uses: actions/download-artifact@v4 with: - name: fastedge-cli-${{ inputs.os_name }}-artifact + name: fastedge-run-${{ inputs.os_name }}-artifact path: fastedge-cli - name: Install dependencies @@ -60,8 +60,9 @@ jobs: npx vsce ls - name: Ensure extension is exectuable + if: ${{ inputs.os_target != 'win32-x64' }} run: | - chmod +x ./fastedge-cli/cli-${{ inputs.os_target }} + chmod +x ./fastedge-cli/fastedge-run-${{ inputs.os_target }} - name: Package extension run: | diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml index a3084f2..1464c33 100644 --- a/.github/workflows/create-release.yml +++ b/.github/workflows/create-release.yml @@ -38,7 +38,7 @@ jobs: echo "Creating new release tag: $TAG_VERSION"" git tag -a $TAG_VERSION" -m "Release $TAG_VERSION"" git push origin $TAG_VERSION" - echo "has_tag=false" >> $GITHUB_OUTPUT + echo "has_tag=true" >> $GITHUB_OUTPUT else TAG_VERSION=${GITHUB_REF#refs/tags/} if [[ ! "$TAG_VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9]+)?$ ]]; then @@ -74,3 +74,13 @@ jobs: os_name: macos-latest secrets: VAULT_TOKEN: ${{ secrets.VAULT_TOKEN }} + + build_windows_extension: + uses: ./.github/workflows/build-extension.yml + needs: ["check_tags", "build_darwin_extension"] + if: ${{ needs.check_tags.outputs.has_release_tag == 'true' }} + with: + os_target: win32-x64 + os_name: windows-latest + secrets: + VAULT_TOKEN: ${{ secrets.VAULT_TOKEN }} diff --git a/.github/workflows/download-cli.yml b/.github/workflows/download-cli.yml index 2e3c0ae..904c82f 100644 --- a/.github/workflows/download-cli.yml +++ b/.github/workflows/download-cli.yml @@ -35,11 +35,18 @@ jobs: include: - target: linux-x64 os: ubuntu-latest - file_suffix: x86_64-unknown-linux-gnu + file_name: x86_64-unknown-linux-gnu + file_ext: tar.gz - target: darwin-arm64 os: macos-latest - file_suffix: aarch64-apple-darwin + file_name: aarch64-apple-darwin + file_ext: tar.gz + + - target: win32 + os: windows-latest + file_name: x86_64-pc-windows-msvc + file_ext: zip steps: - name: Checkout this repository @@ -53,29 +60,43 @@ jobs: - name: Download FastEdge-lib assets run: | echo "Downloading version $VERSION for ${{ matrix.os }}" - curl -L -o cli-$VERSION-${{ matrix.file_suffix }}.tar.gz https://github.com/G-Core/FastEdge-lib/releases/download/$VERSION/cli-$VERSION-${{ matrix.file_suffix }}.tar.gz - curl -L -o cli-$VERSION-${{ matrix.file_suffix }}.tar.gz.sha256 https://github.com/G-Core/FastEdge-lib/releases/download/$VERSION/cli-$VERSION-${{ matrix.file_suffix }}.tar.gz.sha256 + curl -L -o fastedge-run-$VERSION-${{ matrix.file_name }}.${{ matrix.file_ext }} https://github.com/G-Core/FastEdge-lib/releases/download/$VERSION/fastedge-run-$VERSION-${{ matrix.file_name }}.${{ matrix.file_ext }} + curl -L -o fastedge-run-$VERSION-${{ matrix.file_name }}.${{ matrix.file_ext }}.sha256 https://github.com/G-Core/FastEdge-lib/releases/download/$VERSION/fastedge-run-$VERSION-${{ matrix.file_name }}.${{ matrix.file_ext }}.sha256 + + - name: Convert Windows SHA256 to Linux format + if: ${{ matrix.os == 'windows-latest' }} + run: | + HASH=$(grep -oP '^[0-9a-f]{64}' fastedge-run-$VERSION-${{ matrix.file_name }}.${{ matrix.file_ext }}.sha256) + echo "$HASH fastedge-run-$VERSION-${{ matrix.file_name }}.${{ matrix.file_ext }}" > fastedge-run-$VERSION-${{ matrix.file_name }}.${{ matrix.file_ext }}.sha256 - name: Verify checksum run: | - sha256sum -c cli-$VERSION-${{ matrix.file_suffix }}.tar.gz.sha256 + sha256sum -c fastedge-run-$VERSION-${{ matrix.file_name }}.${{ matrix.file_ext }}.sha256 - - name: Extract fastedge-cli + - name: Extract fastedge-run run: | - tar -xzf cli-$VERSION-${{ matrix.file_suffix }}.tar.gz + if [[ ${{ matrix.os }} == 'windows-latest' ]]; then + unzip fastedge-run-$VERSION-${{ matrix.file_name }}.${{ matrix.file_ext }} + else + tar -xzf fastedge-run-$VERSION-${{ matrix.file_name }}.${{ matrix.file_ext }} + fi - - name: Rename and copy fastedge-cli + - name: Rename and copy fastedge-run run: | - cp cli-$VERSION-${{ matrix.file_suffix }}/cli ./fastedge-cli/cli-${{ matrix.target }} + if [[ ${{ matrix.os }} == 'windows-latest' ]]; then + cp fastedge-run-$VERSION-${{ matrix.file_name }}/fastedge-run.exe ./fastedge-cli/fastedge-run.exe + else + cp fastedge-run-$VERSION-${{ matrix.file_name }}/fastedge-run ./fastedge-cli/fastedge-run-${{ matrix.target }} + fi - name: Create a RELEASE.json file run: | - echo "{\"fastedge_cli_version\": \"$VERSION\"}" > fastedge-cli/METADATA.json + echo "{\"fastedge_run_version\": \"$VERSION\"}" > fastedge-cli/METADATA.json - - name: Upload fastedge-cli Artifact + - name: Upload fastedge-run Artifact uses: actions/upload-artifact@v4 with: - name: fastedge-cli-${{ matrix.os }}-artifact + name: fastedge-run-${{ matrix.os }}-artifact retention-days: 1 path: | fastedge-cli/ diff --git a/README.md b/README.md index c689179..9250a53 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ In order for this extension to compile and run any code, you will need to have t Examples: -- Rust: `rustup target add wasm32-wasi` +- Rust: `rustup target add wasm32-wasip1` - Javascript: `npm install --save-dev @gcoredev/fastedge-sdk-js` More detail can be found in the SDK documentation above. 👆 diff --git a/exampleFolder/package-lock.json b/exampleFolder/package-lock.json index 8a8bc3b..69059dd 100644 --- a/exampleFolder/package-lock.json +++ b/exampleFolder/package-lock.json @@ -8,7 +8,7 @@ "name": "extension-playground", "version": "1.0.0", "devDependencies": { - "@gcoredev/fastedge-sdk-js": "^1.1.1", + "@gcoredev/fastedge-sdk-js": "^1.1.2", "typescript": "^5.4.5" } }, @@ -735,9 +735,9 @@ } }, "node_modules/@gcoredev/fastedge-sdk-js": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@gcoredev/fastedge-sdk-js/-/fastedge-sdk-js-1.1.1.tgz", - "integrity": "sha512-oU+8y1zIFSqDOvUoSeTweU25b+ssk5EmNe6hzsowRqOgbcR4XpDJlj7BBQQCYV+INGJz3C89flsT5GlRZcghEw==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@gcoredev/fastedge-sdk-js/-/fastedge-sdk-js-1.1.2.tgz", + "integrity": "sha512-nqrsyqTTa9stEyGcidylSzdlqihOmfXxZ7uPaXALY53jaJVh4PTXFscuLI99HxeSn1K47dZlsjH0ruNnTdpvXg==", "dev": true, "license": "Apache-2.0", "dependencies": { diff --git a/exampleFolder/package.json b/exampleFolder/package.json index 5ab7d5a..9ab5238 100644 --- a/exampleFolder/package.json +++ b/exampleFolder/package.json @@ -10,7 +10,8 @@ "type": "module", "author": "Gordon Farquharson", "devDependencies": { - "@gcoredev/fastedge-sdk-js": "^1.1.1", + "@gcoredev/fastedge-sdk-js": "^1.1.2", "typescript": "^5.4.5" - } + }, + "dependencies": {} } diff --git a/package-lock.json b/package-lock.json index 43a8acc..13ef87c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,8 @@ "name": "fastedge", "version": "0.2.0", "dependencies": { + "toml": "^3.0.0", + "tree-kill": "^1.2.2", "vscode-debugadapter": "^1.51.0", "vscode-debugprotocol": "^1.51.0" }, @@ -4112,6 +4114,21 @@ "node": ">=8.0" } }, + "node_modules/toml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==", + "license": "MIT" + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, "node_modules/ts-api-utils": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", diff --git a/package.json b/package.json index 2871c2b..2e0f5e9 100644 --- a/package.json +++ b/package.json @@ -150,6 +150,8 @@ "typescript": "^5.4.5" }, "dependencies": { + "toml": "^3.0.0", + "tree-kill": "^1.2.2", "vscode-debugadapter": "^1.51.0", "vscode-debugprotocol": "^1.51.0" } diff --git a/src/BinaryDebugConfigurationProvider.ts b/src/BinaryDebugConfigurationProvider.ts index 54676ff..d60d9fc 100644 --- a/src/BinaryDebugConfigurationProvider.ts +++ b/src/BinaryDebugConfigurationProvider.ts @@ -14,24 +14,23 @@ export class BinaryDebugConfigurationProvider private getLauncherPath(extensionPath: string): string { switch (os.platform()) { - // todo: add support for windows - // case "win32": - // return vscode.Uri.joinPath( - // vscode.Uri.file(extensionPath), - // "fastedge-cli", - // "cli.exe" - // ).fsPath; + case "win32": + return vscode.Uri.joinPath( + vscode.Uri.file(extensionPath), + "fastedge-cli", + "fastedge-run.exe" + ).fsPath; case "darwin": return vscode.Uri.joinPath( vscode.Uri.file(extensionPath), "fastedge-cli", - "cli-darwin-arm64" + "fastedge-run-darwin-arm64" ).fsPath; case "linux": return vscode.Uri.joinPath( vscode.Uri.file(extensionPath), "fastedge-cli", - "cli-linux-x64" + "fastedge-run-linux-x64" ).fsPath; default: throw new Error("Unsupported platform"); diff --git a/src/FastEdgeDebugSession.ts b/src/FastEdgeDebugSession.ts index 1eef9f1..341ffcb 100644 --- a/src/FastEdgeDebugSession.ts +++ b/src/FastEdgeDebugSession.ts @@ -1,17 +1,20 @@ +import * as os from "os"; import * as vscode from "vscode"; -import * as cp from "child_process"; +import treeKill from "tree-kill"; +import { DebugProtocol } from "vscode-debugprotocol"; import { DebugSession, OutputEvent, TerminatedEvent, } from "vscode-debugadapter"; -import { DebugProtocol } from "vscode-debugprotocol"; +import { spawn, ChildProcess } from "child_process"; + import { DebugConfig } from "./BinaryDebugConfigurationProvider"; import { compileActiveEditorsBinary } from "./compiler"; export class FastEdgeDebugSession extends DebugSession { - private childProcess: cp.ChildProcess | undefined; + private childProcess: ChildProcess | undefined; private breakpoints: vscode.Breakpoint[] = []; private disabledBreakpoints: vscode.Breakpoint[] = []; @@ -84,7 +87,6 @@ export class FastEdgeDebugSession extends DebugSession { _args: unknown ): Promise { const args: DebugConfig = _args as DebugConfig; - // Clear the debug console before starting a new session this.clearDebugConsole(); @@ -168,22 +170,27 @@ export class FastEdgeDebugSession extends DebugSession { execArgs.push(...this.injectVariables("env", args.env)); } - this.childProcess = cp.spawn(cli, execArgs, { + const isWindows = os.platform() === "win32"; + const shell = isWindows ? "cmd.exe" : "sh"; + + this.childProcess = spawn(cli, execArgs, { + shell, + stdio: ["ignore", "pipe", "pipe"], env: { RUST_LOG: loggingLevel, ...process.env, // Preserve existing environment variables }, }); - this.childProcess?.stdout?.on("data", (data) => { + this.childProcess?.stdout?.on("data", (data: Buffer) => { this.logDebugConsole(data.toString(), "stdout"); }); - this.childProcess?.stderr?.on("data", (data) => { + this.childProcess?.stderr?.on("data", (data: Buffer) => { this.logDebugConsole(data.toString(), "stderr"); }); - this.childProcess?.on("close", (code) => { + this.childProcess?.on("close", (code: number) => { this.sendEvent(new TerminatedEvent()); }); @@ -209,7 +216,7 @@ export class FastEdgeDebugSession extends DebugSession { for (const key in vars) { result.push( type === "env" ? "--env" : "--headers", - `${key}=${vars[key]}` + `"${key}=${vars[key]}"` ); } return result; @@ -220,7 +227,11 @@ export class FastEdgeDebugSession extends DebugSession { args: DebugProtocol.DisconnectArguments ): void { if (this.childProcess) { - this.childProcess.kill(); + if (this.childProcess?.pid) { + treeKill(this.childProcess.pid); + } else { + this.childProcess.kill(); + } this.childProcess = undefined; } // Remove all disabled breakpoints @@ -228,7 +239,7 @@ export class FastEdgeDebugSession extends DebugSession { // Add original breakpoints vscode.debug.addBreakpoints(this.breakpoints); - this.logDebugConsole("FastEdge App stopping..."); + this.logDebugConsole("FastEdge App stopping...\n"); this.sendResponse(response); } } diff --git a/src/compiler/index.ts b/src/compiler/index.ts index 6aef22b..d74e3bf 100644 --- a/src/compiler/index.ts +++ b/src/compiler/index.ts @@ -1,4 +1,5 @@ import * as vscode from "vscode"; +import path from "node:path"; import { compileJavascriptBinary } from "./jsBuild"; import { compileRustAndFindBinary } from "./rustBuild"; @@ -45,11 +46,18 @@ async function compileActiveEditorsBinary( if (activeFileLanguage === "javascript") { return { - path: await compileJavascriptBinary(activeFile, debugContext), + path: await compileJavascriptBinary( + activeFile, + debugContext, + logDebugConsole + ), lang: activeFileLanguage, }; } else if (activeFileLanguage === "rust") { - const activeFilePath = activeFile?.slice(0, activeFile?.lastIndexOf("/")); + const activeFilePath = activeFile?.slice( + 0, + activeFile?.lastIndexOf(path.sep) + ); return { path: await compileRustAndFindBinary(activeFilePath, logDebugConsole), lang: activeFileLanguage, diff --git a/src/compiler/jsBuild.ts b/src/compiler/jsBuild.ts index eb2ac00..3369007 100644 --- a/src/compiler/jsBuild.ts +++ b/src/compiler/jsBuild.ts @@ -1,9 +1,9 @@ import * as vscode from "vscode"; -import { exec } from "child_process"; +import { spawn } from "child_process"; import fs from "fs"; import path from "path"; -import { DebugContext } from "./types"; +import { DebugContext, LogToDebugConsole } from "./types"; const BINARY_NAME = "debugger.wasm"; @@ -41,8 +41,10 @@ const getPackageJsonEntryPoint = (workspaceFolder: vscode.WorkspaceFolder) => export function compileJavascriptBinary( activeFilePath: string, - debugContext: DebugContext + debugContext: DebugContext, + logDebugConsole: LogToDebugConsole ) { + logDebugConsole("Compiling javascript binary..."); return new Promise(async (resolve, reject) => { try { const workspaceFolder = vscode.workspace.workspaceFolders?.[0]; @@ -63,13 +65,35 @@ export function compileJavascriptBinary( await getPackageJsonEntryPoint(workspaceFolder) ); - exec( - `npx fastedge-build ${jsEntryPoint} ${binPath}/${BINARY_NAME}`, - { cwd: workspaceFolder?.uri.fsPath }, - (err) => { - return err ? reject(err) : resolve(`${binPath}/${BINARY_NAME}`); + const jsBuild = spawn( + "npx", + ["fastedge-build", jsEntryPoint, `${binPath}/${BINARY_NAME}`], + { + shell: true, + stdio: ["ignore", "pipe", "pipe"], + cwd: workspaceFolder?.uri.fsPath, } ); + + let stdout = ""; + let stderr = ""; + + jsBuild.stdout?.on("data", (data: Buffer) => { + stdout += data; + }); + + jsBuild.stderr?.on("data", (data: Buffer) => { + logDebugConsole(data.toString()); + stderr += data; + }); + + jsBuild.on("close", (code: number) => { + if (code !== 0) { + reject(new Error(`build exited with code ${code}: ${stderr}`)); + return; + } + resolve(`${binPath}/${BINARY_NAME}`); + }); } catch (err) { reject(err); } diff --git a/src/compiler/rustBuild.ts b/src/compiler/rustBuild.ts index a8cee73..9b7605b 100644 --- a/src/compiler/rustBuild.ts +++ b/src/compiler/rustBuild.ts @@ -1,23 +1,38 @@ import { spawn } from "child_process"; +import * as os from "os"; + import { LogToDebugConsole } from "./types"; +import { rustConfigWasiTarget } from "./rustConfig"; export function compileRustAndFindBinary( activeFilePath: string, logDebugConsole: LogToDebugConsole ) { return new Promise(async (resolve, reject) => { - const cargoBuild = spawn("cargo", ["build", "--message-format=json"], { - cwd: activeFilePath, - }); + logDebugConsole("Compiling Rust binary...\n"); + const isWindows = os.platform() === "win32"; + const shell = isWindows ? "cmd.exe" : "sh"; + + const target = rustConfigWasiTarget(logDebugConsole, activeFilePath); + logDebugConsole("wasm build target: " + target + "\n", "stderr"); + const cargoBuild = spawn( + "cargo", + ["build", "--message-format=json", `--target=${target}`], + { + shell, + stdio: ["ignore", "pipe", "pipe"], + cwd: activeFilePath, + } + ); let stdout = ""; let stderr = ""; - cargoBuild.stdout.on("data", (data: Buffer) => { + cargoBuild.stdout?.on("data", (data: Buffer) => { stdout += data; }); - cargoBuild.stderr.on("data", (data: Buffer) => { + cargoBuild.stderr?.on("data", (data: Buffer) => { logDebugConsole(data.toString()); stderr += data; }); diff --git a/src/compiler/rustConfig.ts b/src/compiler/rustConfig.ts new file mode 100644 index 0000000..f7e63fa --- /dev/null +++ b/src/compiler/rustConfig.ts @@ -0,0 +1,43 @@ +import * as fs from "node:fs"; +import * as path from "node:path"; +import * as toml from "toml"; +import { LogToDebugConsole } from "./types"; + +function findCargoConfig(startDir: string): string | null { + let dir = startDir; + while (dir !== path.parse(dir).root) { + const configPath = path.join(dir, ".cargo", "config.toml"); + if (fs.existsSync(configPath)) { + return configPath; + } + dir = path.dirname(dir); + } + return null; +} + +function rustConfigWasiTarget( + logDebugConsole: LogToDebugConsole, + startDir: string +): string { + let wasiTarget = "wasm32-wasip1"; + try { + const configPath = findCargoConfig(startDir); + if (configPath === null) { + throw new Error("No .cargo/config.toml found"); + } + const configContent = fs.readFileSync(configPath, "utf-8"); + const config = toml.parse(configContent); + if (config?.build?.target) { + wasiTarget = config.build.target; + } + } catch (error) { + logDebugConsole( + `Failed to read or parse config.toml (fallback target: ${wasiTarget})\n`, + "stderr" + ); + } finally { + return wasiTarget; + } +} + +export { rustConfigWasiTarget }; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 3725564..811e78f 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -8,4 +8,22 @@ type BinaryInfo = { type LogToDebugConsole = (message: string, type?: "stdout" | "stderr") => void; -export { BinaryInfo, DebugContext, ExtLanguage, LogToDebugConsole }; +interface LaunchConfiguration { + cliPath?: string; + entrypoint?: string; + binary?: string; + port?: number; + geoIpHeaders?: boolean; + headers?: Record; + env?: Record; + memoryLimit?: number; + traceLogging?: boolean; +} + +export { + BinaryInfo, + DebugContext, + ExtLanguage, + LaunchConfiguration, + LogToDebugConsole, +}; diff --git a/src/extension.ts b/src/extension.ts index 5095c00..9a01be4 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -4,6 +4,18 @@ import { readFileSync } from "fs"; import { FastEdgeDebugAdapterDescriptorFactory } from "./FastEdgeDebugAdapterDescriptorFactory"; import { BinaryDebugConfigurationProvider } from "./BinaryDebugConfigurationProvider"; +import { LaunchConfiguration } from "./compiler/types"; + +function getLaunchConfigurations( + scope?: vscode.ConfigurationScope | null +): LaunchConfiguration { + const config = vscode.workspace.getConfiguration("launch", scope); + const configurations = config.get("configurations"); + const fastedgeConfig = configurations?.find( + (c) => c.type === "fastedge" && c.request === "launch" + ); + return fastedgeConfig ?? {}; +} export function activate(context: vscode.ExtensionContext) { // Read the cliVersion from METADATA.json @@ -12,7 +24,7 @@ export function activate(context: vscode.ExtensionContext) { "fastedge-cli/METADATA.json" ); const metadataJson = JSON.parse(readFileSync(metadataJsonPath, "utf8")); - const cliVersion = metadataJson.fastedge_cli_version || "unknown"; + const cliVersion = metadataJson.fastedge_run_version || "unknown"; // Set the cliVersion setting vscode.workspace @@ -31,23 +43,15 @@ export function activate(context: vscode.ExtensionContext) { vscode.window.showInformationMessage( `activeEditor: ${activeEditor?.document.uri.fsPath}` ); - const workspaceFolder = vscode.workspace.workspaceFolders?.[0]; - vscode.window.showInformationMessage( - `workspaceFolder ${workspaceFolder?.uri.fsPath}` - ); - vscode.window.showInformationMessage("FastEdge: Running File"); - vscode.debug.startDebugging( - undefined, - { - type: "fastedge", - name: "Debug File", - request: "launch", - program: "${file}", - debugContext: "file", - }, - { noDebug: true } - ); + vscode.debug.startDebugging(undefined, { + ...getLaunchConfigurations(activeEditor?.document.uri), + type: "fastedge", + name: "Debug File", + request: "launch", + program: "${file}", + debugContext: "file", + }); } else { vscode.window.showErrorMessage("No active file to debug."); } @@ -59,6 +63,7 @@ export function activate(context: vscode.ExtensionContext) { vscode.debug.startDebugging( undefined, { + ...getLaunchConfigurations(workspaceFolder.uri), type: "fastedge", name: "Debug Workspace", request: "launch",