# TinyCLR OS — VS Code extension

Visual Studio Code (or Cursor) extension for TinyCLR OS: create projects, build, deploy, and debug **without Visual Studio**. Device tooling runs on **Windows** (USB / MFDeploy stack).

---

## One-step build (recommended)

From a **Developer Command Prompt** or any shell where `node` and `dotnet` are on `PATH`:

```bat
cd path\to\TinyCLR-VSCode
build-all.bat
```

**Signed VSIX (same as `GHIElectronics.TinyCLR.VisualStudio.ProjectSystem.csproj`):**

`build-all.bat -sign` runs **Visual Studio Desktop `MSBuild.exe`** on **`tools\SignVsixHelper\SignVsixHelper.csproj`**, which references the same NuGet package **`GHIElectronics.Tools.VsixSigner`** (version **1.0.3**) as the Visual Studio extension. That package’s targets invoke **`vsixsigntool`** exactly like the VSIX build in the SDK.

```bat
build-all.bat -sign
```

**Why not `dotnet build`?** The VsixSigner targets use **`CodeTaskFactory`**, which is **not supported** on the .NET Core–hosted MSBuild used by `dotnet`. You need **Desktop MSBuild** (Visual Studio 2022 or **Build Tools for Visual Studio 2022** with the **MSBuild** workload). `build-all.bat` locates `MSBuild.exe` via **`VSINSTALLDIR`**, **`vswhere`**, or common install paths.

Requires these **environment variables** (same names as `TinyCLR-SDK\ci_build.bat` documents):

- **`VsixSignerCertificatePath`** — path to the signing `.pfx`  
- **`VsixSignerCertificatePassword`** — PFX password  
- **`VsixSignerCertificateSha1`** — certificate thumbprint for `/sha1`  
- **`VsixSignerTimestampServer`** — optional; defaults to **`http://timestamp.digicert.com`**

`TinyCLR-SDK\ci_build.bat` calls **`build-all.bat -sign`** so official drops are signed when the variables above are set on the agent (CI already runs under **VsMSBuildCmd**, so Desktop MSBuild is available).

`build-all.bat` does the following:

1. Runs **`npm install`** if `node_modules` is missing  
2. Runs **`npm run compile`** (TypeScript → `out/`)  
3. Builds **`DebugServer\TinyCLR.DebugServer.csproj`** in **Release**  
4. Copies **everything** from `DebugServer\bin\Release\net48\` into **`ext_tool\`** (exe, managed dependencies, config)
5. Syncs **`images\logo.png`**, **`LICENSE`**, and **`packages\*.nupkg`** from the Visual Studio extension (**`..\TinyCLR-SDK\GHIElectronics.TinyCLR.VisualStudio.ProjectSystem\`**) when that folder exists (same assets as the TinyCLR OS Project VSIX). The bundled `.nupkg` files ship inside the VSIX so **TinyCLR: New Project** can restore the `GHIElectronics.TinyCLR.*` packages **without nuget.org** — required when pre-release versions are not yet published.
6. Runs **`npm run vsce package`** and writes **`tinyclr-os-vscode-<version>.vsix`** in this folder (version comes from **`package.json`**, currently **0.0.1**)  
7. If **`build-all.bat -sign`**: signs the newest **`tinyclr-os-vscode-*.vsix`** via **`GHIElectronics.Tools.VsixSigner`** (Desktop MSBuild + **`tools\SignVsixHelper`**)

**Install the VSIX:** in VS Code / Cursor, **Extensions** → **⋯** menu → **Install from VSIX…** → pick the `tinyclr-os-vscode-<version>.vsix` that `build-all.bat` just produced (the `<version>` comes from `package.json`).

After a successful run, reload the Extension Development Host (**Ctrl+Shift+F5**) or restart the editor so it picks up **`ext_tool\TinyCLR.DebugServer.exe`** when developing the extension from source.

If **`ext_tool\GHIElectronics.TinyCLR.MetadataProcessor.exe`** is missing, the script prints a warning. Copy that file once (see [First-time: MetadataProcessor](#first-time-metadataprocessor)) — it is not produced by this repo’s `dotnet build`.

---

## Prerequisites

| Tool | Notes |
|------|--------|
| **Windows** | Deploy, debug, and `TinyCLR.DebugServer.exe` target Windows. |
| **Node.js** | v18+ — [https://nodejs.org](https://nodejs.org) |
| **.NET SDK** | For `dotnet build` (C# projects + DebugServer). [Build Tools](https://aka.ms/vs/17/release/vs_BuildTools.exe) also work. |
| **VS Code or Cursor** | [https://code.visualstudio.com](https://code.visualstudio.com) |
| **C# extension** | e.g. `ms-dotnettools.csharp` — IntelliSense for `.cs` / `.csproj` |

### Repository layout

`DebugServer` references the debugger library by relative path:

`TinyCLR-VSCode\DebugServer\` → `TinyCLR-SDK\GHIElectronics.TinyCLR.Debugger\`

Keep **`TinyCLR-VSCode`** and **`TinyCLR-SDK`** under the same parent folder (as in this repo: `TinyCLROS\`).

### First-time: MetadataProcessor

The extension expects **`GHIElectronics.TinyCLR.MetadataProcessor.exe`** next to the DebugServer in **`ext_tool\`**. Build or copy it from your TinyCLR SDK / release pipeline once, for example:

```bat
copy path\to\GHIElectronics.TinyCLR.MetadataProcessor.exe TinyCLR-VSCode\ext_tool\
```

**Important:** The default path is **`TinyCLR-VSCode\ext_tool\GHIElectronics.TinyCLR.MetadataProcessor.exe`** (same folder as `TinyCLR.DebugServer.exe`). Copying the tool only under `TinyCLR-Devices\Tools\MetadataProcessor\Release\` does **not** update the extension unless you set **`tinyclr.metadataProcessorPath`** in VS Code settings to that full path. On each build, the TinyCLR output shows **`[PeBuilder] MetadataProcessor:`** with the exact `.exe` in use—verify it matches the file you rebuilt.

If it is missing, **TinyCLR: Build** will fail when PeBuilder runs.

---

## First-time setup (manual steps)

1. Clone the repo (preserve `TinyCLR-VSCode` + `TinyCLR-SDK` layout above).  
2. **`build-all.bat`** from the `TinyCLR-VSCode` folder.  
3. Ensure **`ext_tool\GHIElectronics.TinyCLR.MetadataProcessor.exe`** exists (see above).
4. Open the **`TinyCLR-VSCode`** folder in VS Code and press **F5** to launch the **Extension Development Host**.  
5. In the host window, open a TinyCLR app folder and use **TinyCLR: Build** or **F5** with a `tinyclr` launch configuration.

---

## Project structure

```
TinyCLR-VSCode/
├── build-all.bat               One-shot: npm compile + DebugServer Release + copy to ext_tool/
├── src/                        TypeScript extension
│   ├── extension.ts            Commands, activation, debug registration
│   ├── buildProvider.ts        dotnet build + DebugServer --build-pe
│   ├── deviceManager.ts        Device selection; path to DebugServer.exe
│   ├── deployProvider.ts       --deploy + progress notification
│   ├── debugConfigProvider.ts  Launch config resolution (F5)
│   ├── debugAdapterFactory.ts  Spawns DebugServer --dap
│   ├── debugLaunchProgressTracker.ts  Status progress during DAP launch
│   ├── newClassCommand.ts      TinyCLR: New Class (item template)
│   └── ...
├── DebugServer/                .NET Framework 4.8 — PeBuilder, deploy, DAP
│   ├── DapServer.cs            Debug Adapter Protocol (--dap)
│   └── ...
├── templates/
│   ├── tinyclr-app/            New TinyCLR application wizard
│   └── tinyclr-class/          Class file template for New Class command
├── ext_tool/                   Runtime payloads (shipped inside the VSIX)
│   ├── TinyCLR.DebugServer.exe
│   ├── GHIElectronics.TinyCLR.Debugger.dll
│   ├── Newtonsoft.Json.dll, System.*.dll, …
│   └── GHIElectronics.TinyCLR.MetadataProcessor.exe  ← supply separately
├── packages/                   Bundled .nupkg files for TinyCLR: New Project
├── package.json
└── tsconfig.json
```

---

## Development workflow

| Goal | Command |
|------|---------|
| Full rebuild (TS + DebugServer + `ext_tool\`) | `build-all.bat` |
| TypeScript only | `npm run compile` |
| TypeScript watch | `npm run watch` |
| DebugServer only | `dotnet build DebugServer\TinyCLR.DebugServer.csproj -c Release` then copy `DebugServer\bin\Release\net48\*` → `ext_tool\` |

Reload the extension host after changes: **Ctrl+Shift+F5** (first window).

Set breakpoints in **`src/*.ts`** when debugging the extension itself from the outer VS Code window.

---

## How it works (short)

1. **Build** — `dotnet build` on your `.csproj`, then **`TinyCLR.DebugServer --build-pe`** produces `.pe` files (MetadataProcessor + resource pipeline).  
2. **Deploy** — **`--deploy`** or the DAP **`launch`** path connects over USB (or serial), runs **`Deployment_Execute`**, then debug attach.  
3. **Debug** — **`--dap`** speaks DAP over stdio; VS Code’s **Watch** uses **`evaluate`** for simple identifiers (same limits as hover).

---

## Feature overview

| Feature | Status |
|---------|--------|
| **TinyCLR: New Project** | Application template + `packages` layout |
| **TinyCLR: New Class** | Adds `.cs` + `<Compile>` (aligned with VS class item) |
| **TinyCLR: Build** | MSBuild + `.pe` generation |
| **TinyCLR: Deploy to Device** | Deploy with progress in the UI |
| **TinyCLR: Select Device** | USB / serial enumeration via DebugServer |
| **F5** Deploy + Debug | `tinyclr` launch; progress in status bar during launch |
| **Watch** | Built-in VS Code Watch; simple names in the current frame |
| **Generate Native Skeleton** | Command still registered; hidden from Command Palette |

---

## Logs

- Extension: **View → Output → TinyCLR**  
- DebugServer: `%TEMP%\TinyCLR.DebugServer.log` (and DAP traffic on stderr when attached to a terminal)

---

## Packaging

**`build-all.bat`** already produces **`tinyclr-os-vscode-<version>.vsix`** (version comes from `package.json`; see above). The VSIX includes **`ext_tool\`**, **`out/`**, **`templates/`**, **`packages/`**, **`images/logo.png`**, and the GHI **`LICENSE`** text; it does **not** ship **`DebugServer\`** sources (only the compiled payloads in **`ext_tool\`**).

To package manually:

```bat
npm run vsix
```

Ensure **`ext_tool\`** contains **`TinyCLR.DebugServer.exe`** and dependencies plus **`GHIElectronics.TinyCLR.MetadataProcessor.exe`** before packaging or installing the VSIX.
