# Project export: Twist & Code

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: OpenAI Build Week
- Tagline: Built with GPT-5.6 & Codex for Logitech's Global Product Manager: a plugin that brings MX Creative Console support to VS Code, easing the daily workflow of developers everywhere.
- Devpost: https://devpost.com/software/twist-code
- GitHub: https://github.com/Harish03r/Logitech-MX-Creative-Console-Plugins.git
- Video: https://www.youtube.com/embed/cxgyYcK6Wzc?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 1 GitHub contributor(s) — Harish03r (2 commits)

## Devpost submission (written by the team)

### Inspiration

The developer community is one of the most underserved audiences when it comes to purpose-built hardware. Creative professionals have consoles, dials, and shortcut decks tuned to their workflows — but developers are largely left with just a keyboard and mouse, even though a huge amount of daily work is repetitive: opening a terminal, scrolling through logs, reaching for an AI assistant, switching context dozens of times an hour. We saw the Logitech MX Creative Console and asked a simple question: why should this only serve designers and video editors? A developer's "day in the life" — jumping between the editor, the terminal, and now AI coding assistants like GitHub Copilot — is exactly the kind of repetitive, physical friction a console like this could remove. We pitched this idea, and it resonated further than we expected: Logitech's Global Hardware & Software Product Manager reached out directly after seeing our pitch, and asked us to help build out exactly this category of plugin — starting with in-editor AI agent access and navigation simplification for developers.

### What it does

Twist & Code turns the Logitech MX Creative Console into a physical control surface for Visual Studio Code. The plugin detects when VS Code is the active, focused application and automatically switches the console into a VS Code-specific action profile. When you switch away, it steps back out of the way. Once active, it gives developers: Open/Focus GitHub Copilot Chat — one button press opens Copilot Chat if it's closed, or brings it to focus if it's already open. Open/Focus Integrated Terminal — reveals and focuses the terminal, reusing the existing terminal instance instead of spawning duplicates. Rotary scroll for the Terminal — turn a dial clockwise or counter-clockwise to scroll terminal output down or up. Rotary scroll for the Editor — the same gesture scrolls your active file, without touching the cursor position. Send Prompt to Copilot — the most ambitious action: opens Copilot Chat, focuses the prompt box, inserts a prompt, and submits it — all from the console. The result: a developer can open an AI agent, scroll code, and manage their terminal without ever reaching for keyboard shortcuts or breaking flow.

### How we built it

We built the entire plugin using Codex with GPT-5.6, treating it as our primary engineering partner rather than an autocomplete tool. Our approach: Architecture first. We had Codex study the Logitech Actions SDK's documented capabilities before writing any code, explicitly ruling out invented or undocumented APIs. Separation of concerns. We identified early that some features — like injecting text directly into Copilot Chat's input box — couldn't be done by the Logitech plugin alone. So we had Codex design a minimal companion VS Code extension that exposes just the necessary hooks through documented VS Code extension APIs, with a defined communication channel between the plugin and the extension. Production-grade code, not a demo. We pushed for a complete TypeScript project: manifest, icons, build scripts, structured logging (INFO/WARN/ERROR/DEBUG), and full error handling for edge cases like VS Code restarts, Logitech Options+ restarts, multiple VS Code windows, and no active workspace. Documentation as a deliverable. Setup, build, packaging, and troubleshooting instructions were generated alongside the code so the plugin is installable and testable by anyone, not just us.

### Challenges we ran into

SDK boundaries. The Logitech Actions SDK can't reach into VS Code's internal UI elements (like the Copilot Chat input box). We had to design a companion extension and a communication bridge rather than force a hacky workaround. Avoiding fragile automation. Our early instinct was to lean on keyboard shortcut simulation for reliability, but we deliberately constrained ourselves to official VS Code commands wherever possible, only falling back to simulated input where no documented API existed. Reliability across restarts. Making sure the plugin correctly re-detects VS Code focus and reconnects to the companion extension after VS Code or Logitech Options+ restarts required careful state handling, not just a happy-path implementation. Staying within documented capability. It was tempting to assume SDK features that would have made things easier — we held the line on only using confirmed, documented functionality.

### Accomplishments we're proud of

Going from a hackathon pitch to a real collaboration request from Logitech's Global Hardware & Software Product Manager within the event window. Shipping a genuinely production-ready plugin — not a proof of concept — with no placeholder code, no TODOs, and full error handling. Solving the "text injection into Copilot Chat" problem cleanly, with a proper companion extension architecture instead of a keyboard-simulation hack. Building something that addresses a real, everyday friction point for developers, using hardware that wasn't originally designed with developers in mind.

### What we learned

How much of a developer's daily friction is physical and repetitive, not just cognitive — and how removing that friction with dedicated hardware controls can meaningfully improve flow. How to responsibly extend a hardware SDK with a companion software layer when the SDK's documented capability has a hard boundary, rather than reaching for undocumented or fragile workarounds. How effective Codex with GPT-5.6 is as a build partner for a project that spans a hardware SDK, a VS Code extension, and cross-process communication — accelerating architecture decisions as much as the code itself.

### What's next

Expand the action library based on direct feedback from Logitech's product team, including more navigation-simplification actions for developers. Support for additional editors and IDEs beyond VS Code. Package and submit through Logitech's official plugin distribution channel so any MX Creative Console owner in the developer community can install it directly.

## README (from the GitHub repository)

# VS Code MX Creative Console

Cross-platform MX Creative Console controls for Visual Studio Code, Codex, Claude Code, and Microsoft Excel.

## Architecture

```mermaid
flowchart LR
  MX[MX Creative Console / Actions Ring] --> LP[Logi Plugin Service]
  LP --> NP[Native C# application plugin]
  NP --> VS[VS Code localhost bridge]
  VS --> CE[Codex + Claude Code extensions]
  NP --> HUB[Excel control hub]
  HUB --> OA[Office.js Excel add-in]
```

The production Logitech plugin is in `native-plugin/`. It is a C# `ClientApplication` plugin that activates for `Code.exe` and uses documented Logitech command and adjustment classes. The VS Code bridge uses public commands exposed by the installed Codex and Claude Code extensions. The Excel path uses Office.js rather than COM, AppleScript, or UI automation.

## Available MX actions

| Area | Actions |
| --- | --- |
| VS Code | Open VS Code, Copilot Chat, Terminal, editor scroll, terminal scroll |
| Codex | Open sidebar, new agent, open command menu, add active file to thread |
| Claude Code | Open, new conversation, focus input, Plan/Manual mode for the next conversation, accept/reject proposed changes |
| Excel | Open Excel, Home, End, create PivotTable, create chart, Copilot guidance |

Codex and Claude model pickers, private chat controls, and arbitrary model questions intentionally remain inside their extensions. No supported public VS Code commands exist to control those private UI elements, so this project does not simulate clicks or keystrokes.

## Requirements

- Windows 10/11 or macOS with Logi Options+ and an MX Creative Console
- .NET SDK 10 for the native plugin build
- Node.js 22 for the VS Code bridge and Excel control hub
- Visual Studio Code with `openai.chatgpt` and/or `anthropic.claude-code`
- Excel desktop with Office.js support for Excel actions

## Build

For a complete Windows release build (native package, VSIX, control-hub integration test, and Excel compilation):

```powershell
.\scripts\build-release.ps1
```

Install the resulting native development link into Logi Options+ and the VSIX into VS Code:

```powershell
.\scripts\install-windows.ps1
```

### Native Logitech plugin

```powershell
cd native-plugin
& 'C:\Program Files\dotnet\dotnet.exe' build -c Release
```

The post-build target links the plugin into Logi Plugin Service. Confirm the native plugin loaded by checking:

```text
%LOCALAPPDATA%\Logi\LogiPluginService\Logs\plugin_logs\VsCodeMxConsoleNative.log
```

### VS Code bridge

```powershell
cd vscode-extension
npm install
npm run package
code --install-extension .\logitech-vscode-bridge-1.0.0.vsix --force
```

Reload VS Code, then run **Logitech VS Code: Show Bridge Status**. Use the **Logitech VS Code Bridge** Output channel to inspect requests.

### Excel control hub and add-in

```powershell
cd control-hub
npm install
npm run build
npm start
```

Host `excel-addin/public/` over HTTPS and update `excel-addin/manifest.xml` to the trusted host before sideloading it into Excel. Keep the task pane open while using Excel controls. The control hub uses localhost ports `48732` (native TCP) and `48733` (Office.js polling).

Copy `excel-addin/public/config.example.js` to `config.js` and place the shared token in it before hosting the task pane.

## Configuration

1. In Logi Options+, enable **Adapt to App** for the Creative Console.
2. Focus VS Code and assign actions from **VS Code MX Console** to buttons, dials, or Actions Ring controls.
3. The first VS Code profile is blank until actions are assigned. Disable Adapt to App temporarily to return to the general profile.
4. For Copilot prompts, run **Logitech VS Code: Set Copilot Prompt**.

### Bridge security

The components bind only to loopback. Before deployment, generate a unique random token of at least 32 characters and configure the same value in all components:

- `MX_CONSOLE_BRIDGE_TOKEN` for Logi Plugin Service and the control hub.
- `logitechVsCode.bridgeToken` in VS Code user settings.
- `excel-addin/public/config.js` for the locally hosted task pane.

The included default token exists only to make first-run local development possible and emits warnings. Restart Logi Options+ after changing its environment. Set `MX_CONSOLE_ADDIN_ORIGIN` on the control hub when the task pane is hosted somewhere other than `https://localhost:3000`.

## Testing

- Native build succeeds with zero errors.
- `VsCodeMxConsoleNative.log` reports registered dynamic actions.
- VS Code Output shows `Bridge request received` after an MX action.
- Codex/Claude actions open the appropriate VS Code extension command surface.
- Claude proposed-diff actions only run when a proposed diff is active.
- Excel task pane displays `MX Console Excel bridge ready`; test Home, End, PivotTable, and chart operations against a sample workbook.

Run `npm test` in `control-hub/` for authenticated queue integration coverage. Complete [HARDWARE-ACCEPTANCE.md](HARDWARE-ACCEPTANCE.md) on both Windows and macOS before publishing a release.

## Platform notes

- Windows defaults: `Code.exe`, `code`, `excel`, and `%LOCALAPPDATA%\Logi\LogiPluginService\Plugins`.
- macOS defaults: VS Code bundle `com.microsoft.VSCode`, `open -a "Visual Studio Code"`, `open -a "Microsoft Excel"`, and the user Logi Plugin Service plugin directory.
- Override non-standard Windows launch/process detection with `MX_CONSOLE_VSCODE_COMMAND`, `MX_CONSOLE_EXCEL_COMMAND`, `MX_CONSOLE_VSCODE_PROCESS`, and `MX_CONSOLE_VSCODE_BUNDLE`.

## Project structure

```text
native-plugin/     Native C# Logitech application plugin
vscode-extension/  VS Code bridge extension
control-hub/        Local Excel command queue
excel-addin/        Office.js Excel task pane
src/ + index.ts     Legacy Node SDK experiment retained as reference
```

## Official references

- [Logi C# plugin structure](https://logitech.github.io/actions-sdk-docs/csharp/Plugin-structure/)
- [Logi application activation](https://logitech.github.io/actions-sdk-docs/csharp/Link-the-plugin-to-an-application/)
- [VS Code command API](https://code.visualstudio.com/api/references/commands)
- [Codex IDE commands](https://learn.chatgpt.com/docs/developer-commands.md?surface=ide)


## Detected evidence (automated analysis)

Indexed codebase: 32 recognized source files, 53 KB.
- C# (language) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- TypeScript (language) — detected in the code
- Python (language) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (49 of 49)

```
.gitignore
assets/.gitkeep
control-hub/package.json
control-hub/src/server.ts
control-hub/test/integration.test.mjs
control-hub/tsconfig.json
excel-addin/manifest.xml
excel-addin/package.json
excel-addin/public/config.example.js
excel-addin/public/taskpane.html
excel-addin/README.md
excel-addin/src/taskpane.ts
excel-addin/tsconfig.json
HARDWARE-ACCEPTANCE.md
icons/README.md
index.ts
LICENSE
native-plugin/BridgeClient.cs
native-plugin/package/metadata/LoupedeckPackage.yaml
native-plugin/PluginConfiguration.cs
native-plugin/PluginLog.cs
native-plugin/README.md
native-plugin/VsCodeAdjustments.cs
native-plugin/VsCodeApplication.cs
native-plugin/VsCodeCommands.cs
native-plugin/VsCodeMxConsoleNativePlugin.cs
native-plugin/VsCodeMxConsoleNativePlugin.csproj
package.json
package/metadata/LoupedeckPackage.yaml
README.md
scripts/build-release.ps1
scripts/install-windows.ps1
scripts/README.md
src/actions/adjustment-actions.ts
src/actions/command-actions.ts
src/services/bridge-client.ts
src/types/bridge.ts
src/utils/logger.ts
tsconfig.json
tsup.config.ts
vscode-extension/.vscodeignore
vscode-extension/LICENSE
vscode-extension/package.json
vscode-extension/README.md
vscode-extension/src/bridge-server.ts
vscode-extension/src/extension.ts
vscode-extension/src/logger.ts
vscode-extension/src/protocol.ts
vscode-extension/tsconfig.json
```

### Dependencies

- control-hub/package.json: @types/node@^22.18.8, typescript@^5.9.3
- excel-addin/package.json: @types/office-js@^1.0.544, typescript@^5.9.3
- package.json: @logitech/plugin-sdk@0.1.1, @logitech/plugin-toolkit@0.1.1, @types/node@^22.18.8, cross-env@^7.0.3, tsup@^8.5.0, typescript@^5.9.3, yaml@^2.8.1
- vscode-extension/package.json: @types/node@^22.18.8, @types/vscode@^1.103.0, @vscode/vsce@^3.6.0, typescript@^5.9.3

### Recent commits (newest first)

- Complete production-ready MX Console integration
- Expand MX controls for Codex Claude and Excel
- Document end-to-end Codex development workflow
- Add VS Code MX Creative Console plugin

## Key source files (fetched from GitHub, selected and truncated for size)

### HARDWARE-ACCEPTANCE.md

```markdown
# Hardware acceptance checklist

Run this checklist on both Windows 10/11 and a supported macOS release with current Logi Options+, VS Code, Excel, and MX Creative Console firmware.

## Installation and profile switching

- Plugin appears as **VS Code MX Console** in Logi Options+ without load errors.
- **Adapt to App** switches to the VS Code profile when VS Code gains focus and returns to the general profile afterward.
- Every action can be assigned to buttons, dials, and Actions Ring positions allowed by Logi Options+.
- Disconnect/reconnect, sleep/wake, Logi Options+ restart, VS Code restart, and OS restart preserve assignments.

## VS Code, Codex, and Claude

- Open/focus VS Code, Copilot Chat, terminal, editor scroll, and terminal scroll behave correctly at slow and rapid input rates.
- Missing Codex or Claude extensions produce a clear bridge error and do not crash the plugin.
- Codex sidebar, new agent, command menu, and add-file actions work with the installed Codex extension version.
- Claude sidebar, new conversation, focus, Plan/Manual mode, and accept/reject actions work in their valid contexts.

## Excel

- With the hub and task pane open, Home and End select the expected used-range corners.
- Pivot creation rejects empty or header-only selections and succeeds on a rectangular table with headers.
- Chart creation rejects an invalid selection and succeeds on selected PivotTable output.
- A stale command older than 30 seconds is discarded; unauthorized polling and TCP requests are rejected.

## Reliability and security

- Use a unique 32+ character token consistently in Logi Plugin Service, VS Code settings, control hub, and add-in config.
- Verify listeners bind only to `127.0.0.1` on ports 48731-48733.
- Exercise at least 200 mixed button/dial operations; confirm no lost service, unbounded memory growth, or persistent queue backlog.
- Confirm logs contain operation names and actionable errors but no token or prompt contents.

```

### package.json

```
{
  "name": "vs-code-mx-console",
  "version": "1.0.0",
  "description": "Logi Actions SDK controls for Visual Studio Code",
  "type": "module",
  "main": "./dist/index.mjs",
  "scripts": {
    "build": "npm run typecheck && tsup",
    "build:pack": "npm run build:prod && npm run pack",
    "build:prod": "npm run typecheck && cross-env NODE_ENV=production tsup",
    "pack": "logitoolkit pack",
    "link": "logitoolkit link",
    "typecheck": "tsc --noEmit",
    "unlink": "logitoolkit unlink",
    "watch": "npm run typecheck && tsup --watch"
  },
  "author": "VS Code MX Console contributors",
  "license": "MIT",
  "engines": {
    "node": ">=22.0.0"
  },
  "dependencies": {
    "@logitech/plugin-sdk": "0.1.1"
  },
  "devDependencies": {
    "@logitech/plugin-toolkit": "0.1.1",
    "@types/node": "^22.18.8",
    "cross-env": "^7.0.3",
    "tsup": "^8.5.0",
    "typescript": "^5.9.3",
    "yaml": "^2.8.1"
  }
}

```

### excel-addin/package.json

```
{
  "name": "mx-console-excel-addin",
  "private": true,
  "version": "1.0.0",
  "scripts": { "build": "tsc -p ." },
  "devDependencies": { "@types/office-js": "^1.0.544", "typescript": "^5.9.3" }
}

```

### control-hub/package.json

```
{
  "name": "mx-console-control-hub",
  "private": true,
  "version": "1.0.0",
  "type": "module",
  "scripts": { "build": "tsc -p .", "start": "node dist/server.js", "test": "npm run build && node --test test/*.test.mjs" },
  "devDependencies": { "@types/node": "^22.18.8", "typescript": "^5.9.3" }
}

```

### vscode-extension/package.json

```
{
  "name": "logitech-vscode-bridge",
  "displayName": "Logitech VS Code Bridge",
  "description": "Local companion bridge for the VS Code MX Console Logi Actions plugin.",
  "version": "1.0.0",
  "publisher": "vscode-mx-console",
  "repository": { "type": "git", "url": "https://github.com/Harish03r/Logitech-MX-Creative-Console-Plugins.git" },
  "license": "MIT",
  "engines": { "vscode": "^1.103.0" },
  "categories": ["Other"],
  "activationEvents": ["onStartupFinished"],
  "main": "./dist/extension.js",
  "contributes": {
    "commands": [
      { "command": "logitechVsCodeBridge.setCopilotPrompt", "title": "Logitech VS Code: Set Copilot Prompt" },
      { "command": "logitechVsCodeBridge.status", "title": "Logitech VS Code: Show Bridge Status" }
    ],
    "configuration": {
      "title": "Logitech VS Code Bridge",
      "properties": {
        "logitechVsCode.bridgeToken": {
          "type": "string",
          "default": "logitech-vscode-local-bridge-v1",
          "markdownDescription": "Shared loopback token. For deployment, set a unique 32+ character token here and as `MX_CONSOLE_BRIDGE_TOKEN` in the Logi Plugin Service environment, then restart Logi Options+. The default is only for first-run development."
        },
        "logitechVsCode.copilotPrompt": {
          "type": "string",
          "default": "",
          "markdownDescription": "Prompt sent when the console's Send Prompt to Copilot action is pressed."
        }
      }
    }
  },
  "scripts": {
    "compile": "tsc -p .",
    "package": "npm run compile && npx @vscode/vsce package",
    "watch": "tsc -watch -p ."
  },
  "devDependencies": { "@types/node": "^22.18.8", "@types/vscode": "^1.103.0", "@vscode/vsce": "^3.6.0", "typescript": "^5.9.3" }
}

```

### index.ts

```typescript
import { LoggerLevel, PluginSDK } from '@logitech/plugin-sdk';
import { OpenCopilotChatAction, OpenTerminalAction, SendPromptToCopilotAction } from './src/actions/command-actions.js';
import { ScrollEditorAction, ScrollTerminalAction } from './src/actions/adjustment-actions.js';
import { BridgeClient } from './src/services/bridge-client.js';
import { Logger } from './src/utils/logger.js';

const logger = new Logger('plugin');
const bridge = new BridgeClient(logger);
const sdk = new PluginSDK({ logLevel: LoggerLevel.INFO });

sdk.registerAction(new OpenCopilotChatAction(bridge, logger));
sdk.registerAction(new OpenTerminalAction(bridge, logger));
sdk.registerAction(new SendPromptToCopilotAction(bridge, logger));
sdk.registerAction(new ScrollTerminalAction(bridge, logger));
sdk.registerAction(new ScrollEditorAction(bridge, logger));

try {
  await sdk.connect();
  logger.info('Connected to Logi Plugin Service', { actionCount: 5 });
} catch (error) {
  logger.error('Unable to connect to Logi Plugin Service', error);
}

```

### control-hub/src/server.ts

```typescript
import crypto from 'node:crypto';
import http from 'node:http';
import net from 'node:net';

type ExcelOperation = 'excel.openCopilot' | 'excel.home' | 'excel.end' | 'excel.createPivot' | 'excel.createPivotChart';
type HubRequest = { id?: string; token?: string; operation?: ExcelOperation };
type QueuedOperation = { id: string; operation: ExcelOperation; createdAt: number };

const HOST = '127.0.0.1';
const TCP_PORT = 48732;
const HTTP_PORT = 48733;
const MAX_REQUEST_BYTES = 8 * 1024;
const MAX_QUEUE_DEPTH = 32;
const COMMAND_TTL_MS = 30_000;
const DEVELOPMENT_TOKEN = 'logitech-vscode-local-bridge-v1';
const allowedOperations = new Set<ExcelOperation>(['excel.openCopilot', 'excel.home', 'excel.end', 'excel.createPivot', 'excel.createPivotChart']);
const token = process.env.MX_CONSOLE_BRIDGE_TOKEN ?? DEVELOPMENT_TOKEN;
const addinOrigin = process.env.MX_CONSOLE_ADDIN_ORIGIN ?? 'https://localhost:3000';
const queue: QueuedOperation[] = [];

if (token === DEVELOPMENT_TOKEN) console.warn('MX_CONSOLE_BRIDGE_TOKEN is not configured; the development token is active. Set a unique 32+ character token before deployment.');
if (token.length < 32 && token !== DEVELOPMENT_TOKEN) console.warn('MX_CONSOLE_BRIDGE_TOKEN should contain at least 32 characters.');

function authorized(candidate: unknown): boolean {
  if (typeof candidate !== 'string') return false;
  const expected = Buffer.from(token);
  const actual = Buffer.from(candidate);
  return expected.length === actual.length && crypto.timingSafeEqual(expected, actual);
}

function pruneQueue(): void {
  const earliest = Date.now() - COMMAND_TTL_MS;
  while (queue[0]?.createdAt < earliest) queue.shift();
}

function writeJson(response: http.ServerResponse, status: number, body: unknown): void {
  response.statusCode = status;
  response.setHeader('Content-Type', 'application/json; charset=utf-8');
  response.setHeader('Cache-Control', 'no-store');
  response.end(JSON.stringify(body));
}

const tcp = net.createServer((socket) => {
  socket.setEncoding('utf8');
  let buffer = '';
  socket.on('data', (chunk: string) => {
    buffer += chunk;
    if (Buffer.byteLength(buffer, 'utf8') > MAX_REQUEST_BYTES) { socket.destroy(); return; }
    const newline = buffer.indexOf('\n');
    if (newline < 0) return;
    try {
      const request = JSON.parse(buffer.slice(0, newline)) as HubRequest;
      if (!authorized(request.token) || !request.operation || !allowedOperations.has(request.operation)) throw new Error('Unauthorized request');
      pruneQueue();
      if (queue.length >= MAX_QUEUE_DEPTH) throw new Error('Queue is full');
      const id = typeof request.id === 'string' && request.id.length <= 64 ? request.id : crypto.randomUUID();
      queue.push({ id, operation: request.operation, createdAt: Date.now() });
      socket.end(`${JSON.stringify({ id, ok: true })}\n`);
    } catch {
      socket.end('{"ok":false,"error":"Request rejected."}\n');
    }
  });
  socket.on('error', () => undefined);
});

const httpServer = http.createServer((request, response) => {
  const origin = request.headers.origin;
  if (origin === addinOrigin) response.setHeader('Access-Control-Allow-Origin', addinOrigin);
  response.setHeader('Vary', 'Origin');
  response.setHeader('Access-Control-Allow-Headers', 'X-MX-Console-Token');
  response.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
  if (request.method === 'OPTIONS') { response.statusCode = 204; response.end(); return; }
  if (request.method !== 'GET') { writeJson(response, 405, { ok: false }); return; }
  if (request.url === '/health') { pruneQueue(); writeJson(response, 200, { ok: true, queued: queue.length }); return; }
  if (request.url === '/excel/next') {
    if (origin !== addinOrigin || !authorized(request.headers['x-mx-console-token'])) { writeJson(response, 401, { ok: false }); return; }
    pruneQueue();
    writeJson(response, 200, { operation: queue.shift()?.operation ?? null });
    return;
  }
  writeJson(response, 404, { ok: false });
});

tcp.listen(TCP_PORT, HOST, () => console.log(`MX Console control hub TCP listening on ${HOST}:${TCP_PORT}`));
httpServer.listen(HTTP_PORT, HOST, () => console.log(`MX Console Excel endpoint listening on http://${HOST}:${HTTP_PORT}`));

```

### tsup.config.ts

```typescript
import { unlinkPlugin, postBuildProcessing } from '@logitech/plugin-toolkit';
import { esmShimPlugin } from '@logitech/plugin-toolkit/esbuild';
import { dirname } from 'path';
import { fileURLToPath } from 'url';

import { defineConfig } from 'tsup';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const isProduction = process.env.NODE_ENV === 'production';
const isWatchEnabled = process.argv.includes('--watch') || process.argv.includes('-w');

export default defineConfig({
  entry: ['index.ts'],
  format: ['esm'],
  outDir: 'dist',
  outExtension: () => ({ js: '.mjs' }),
  clean: true,
  bundle: true,
  platform: 'node',
  target: 'es2022',
  noExternal: [/.*/],
  minify: isProduction,
  sourcemap: !isProduction,
  onSuccess: async () => {
    console.log('✅ TS build completed.');
    await postBuildProcessing(__dirname, isWatchEnabled);

    if (isWatchEnabled) {
      console.log('👀 Watching for file changes... Press Ctrl+C to stop.');
    }
  },
  watch: isWatchEnabled,
  shims: true,
  esbuildPlugins: [
    esmShimPlugin({ require: true })
  ]
});

if (isWatchEnabled) {
  // Handle graceful shutdown
  const cleanup = async () => {
    try {
      console.log('🛑 Stopping watch mode...');
      console.log('🔓 Unlinking plugin...');
      await unlinkPlugin(true);
    } catch (error) {
      console.warn('⚠️ Failed to unlink plugin:', (error as Error).message);
    }
    process.exit(0);
  };

  process.on('SIGINT', cleanup);
  process.on('SIGTERM', cleanup);
}

```

### native-plugin/PluginLog.cs

```c#
namespace Loupedeck.VsCodeMxConsole;

using System;

internal static class PluginLog
{
    private static PluginLogFile? logger;
    internal static void Init(PluginLogFile pluginLogger) => logger = pluginLogger;
    internal static void Info(String message) => logger?.Info(message);
    internal static void Warning(String message) => logger?.Warning(message);
}

```

### native-plugin/VsCodeApplication.cs

```c#
namespace Loupedeck.VsCodeMxConsole;

using System;

/** Selects this application profile whenever a Visual Studio Code window is foregrounded. */
public sealed class VsCodeApplication : ClientApplication
{
    protected override String GetProcessName() => PluginConfiguration.VsCodeProcessName;
    protected override String GetBundleName() => OperatingSystem.IsMacOS() ? PluginConfiguration.VsCodeBundleName : String.Empty;
    public override ClientApplicationStatus GetApplicationStatus() => ClientApplicationStatus.Unknown;
}

```

[20 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]