Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
8e131fe
docs: add social card image + update README badges
himerus Mar 26, 2026
ba6ec2b
docs: update social card with color-branded export
himerus Mar 26, 2026
933fa0a
refactor: fix: align @modelcontextprotocol/sdk versions across monore…
himerus Mar 26, 2026
311f1c4
Merge pull request #206 from bookedsolidtech/feature/fix-align-modelc…
himerus Mar 26, 2026
f94ea7b
refactor: fix: wire scaffold_component and extend_component into MCP …
himerus Mar 26, 2026
96cb5e2
Merge pull request #207 from bookedsolidtech/feature/fix-wire-scaffol…
himerus Mar 26, 2026
692886b
feat: scaffold packages/vscode VS Code extension MVP
himerus Mar 26, 2026
0d24d51
Merge pull request #208 from bookedsolidtech/feature/feat-scaffold-pa…
himerus Mar 26, 2026
a7e99c0
docs: update README social card to PNG and fix tool count to 87+
himerus Mar 26, 2026
02ee086
fix: replace TODO placeholder with var() fallback in theme handler de…
himerus Mar 26, 2026
fd40ef2
test: add test suite for styling tools (29 tools, 75 tests)
himerus Mar 26, 2026
cd70600
Merge pull request #210 from bookedsolidtech/feature/fix-theme-handle…
himerus Mar 26, 2026
41f5237
Merge remote-tracking branch 'origin/dev' into feature/docs-update-re…
himerus Mar 26, 2026
e9e4a58
Merge pull request #211 from bookedsolidtech/feature/test-add-test-su…
himerus Mar 26, 2026
42524fc
fix: replace plain new Error() throws with MCPError
himerus Mar 26, 2026
d5d6552
Merge pull request #214 from bookedsolidtech/feature/fix-replace-plai…
himerus Mar 26, 2026
7c05077
fix: update README tool count badge and add missing tools to reference
himerus Mar 26, 2026
97a3edb
Merge pull request #215 from bookedsolidtech/feature/fix-update-readm…
himerus Mar 26, 2026
d695d62
fix: add typecheck script alias to resolve post-merge verification fa…
himerus Mar 26, 2026
8b8d40b
Merge pull request #216 from bookedsolidtech/feature/fix-post-merge-v…
himerus Mar 26, 2026
51905e0
test: add test suites for scaffold, extend, theme, and bundle tools
himerus Mar 26, 2026
1909566
Merge pull request #217 from bookedsolidtech/feature/test-add-test-su…
himerus Mar 26, 2026
60ad017
Merge branch 'origin/dev' into feature/docs-update-readme-social-card-to
himerus Mar 26, 2026
fa8b4c6
Merge pull request #209 from bookedsolidtech/feature/docs-update-read…
himerus Mar 26, 2026
0508d52
test: add test suites for cdn, composition, framework, story, tokens,…
himerus Mar 26, 2026
37eca94
Merge pull request #218 from bookedsolidtech/feature/test-add-test-su…
himerus Mar 26, 2026
2bbbfb7
refactor: replace env var if-blocks with lookup tables in config.ts
himerus Mar 26, 2026
496dede
Merge pull request #219 from bookedsolidtech/feature/fix-refactor-con…
himerus Mar 26, 2026
1436936
feat(vscode): add Configure for Cursor/Windsurf command
himerus Mar 26, 2026
8208b22
Merge pull request #220 from bookedsolidtech/feature/feat-add-cursorw…
himerus Mar 26, 2026
201ebaa
fix: add bounds checking for CLI array args before access
himerus Mar 26, 2026
600373c
Merge pull request #221 from bookedsolidtech/feature/fix-add-bounds-c…
himerus Mar 26, 2026
e62ea1f
test: add test suites for 8 untested analyzer modules
himerus Mar 26, 2026
19c25c4
fix: correct test assertions to match actual analyzer APIs
himerus Mar 26, 2026
db217f2
Merge pull request #222 from bookedsolidtech/feature/test-add-test-su…
himerus Mar 26, 2026
b476e1c
Merge pull request #223 from bookedsolidtech/dev
himerus Mar 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 76 additions & 9 deletions README.md

Large diffs are not rendered by default.

Binary file added assets/social-card.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/social-card.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions build
1 change: 1 addition & 0 deletions node_modules
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"test:coverage": "vitest run --coverage",
"test:watch": "vitest",
"type-check": "tsc --noEmit",
"typecheck": "pnpm run type-check",
"lint": "eslint src packages/core/src",
"lint:fix": "eslint src packages/core/src --fix",
"format": "prettier --write .",
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
},
"license": "MIT",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.26.0",
"@modelcontextprotocol/sdk": "^1.27.1",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Checking `@modelcontextprotocol/sdk` specifiers in manifests and lockfile..."
rg -n '"@modelcontextprotocol/sdk"\s*:' package.json packages/core/package.json packages/mcp/package.json pnpm-lock.yaml

Repository: bookedsolidtech/helixir

Length of output: 348


🏁 Script executed:

#!/bin/bash
# Search for `@modelcontextprotocol/sdk` in pnpm-lock.yaml with more flexible pattern
rg -n "modelcontextprotocol" pnpm-lock.yaml | head -20

Repository: bookedsolidtech/helixir

Length of output: 279


🏁 Script executed:

#!/bin/bash
# Check context around lines 18, 73, 104 to see what versions are referenced
rg -B2 -A2 "^\s*'@modelcontextprotocol/sdk':" pnpm-lock.yaml | head -40

Repository: bookedsolidtech/helixir

Length of output: 461


Regenerate pnpm-lock.yaml to sync with the updated SDK version.

The manifest files specify @modelcontextprotocol/sdk@^1.27.1, but pnpm-lock.yaml still has stale specifiers:

  • packages/core: specifier ^1.26.0 (should be ^1.27.1)
  • packages/mcp: specifier ^1.26.0 (should be ^1.27.1)

CI with frozen-lockfile will fail until these specifiers are regenerated and committed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/package.json` at line 19, The pnpm lockfile is out of sync with
the updated dependency `@modelcontextprotocol/sdk` in package manifests
(packages/core and packages/mcp); regenerate and commit an updated
pnpm-lock.yaml by running a workspace install so the specifiers change from
^1.26.0 to ^1.27.1. From the repository root run the pnpm workspace install
(e.g., pnpm install or pnpm -w install) to update pnpm-lock.yaml, verify the
lock now contains `@modelcontextprotocol/sdk`@^1.27.1 for packages/core and
packages/mcp, then commit the updated pnpm-lock.yaml.

"zod": "^3.22.0"
},
"peerDependencies": {
Expand Down
70 changes: 25 additions & 45 deletions packages/core/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ const defaults: McpWcConfig = {
};

function readConfigFile(projectRoot: string): Partial<McpWcConfig> {
// Primary config file name
const primaryPath = resolve(projectRoot, 'helixir.mcp.json');
if (existsSync(primaryPath)) {
try {
Expand All @@ -44,21 +43,6 @@ function readConfigFile(projectRoot: string): Partial<McpWcConfig> {
}
}

// Backward-compatible fallback to legacy config file name
const legacyPath = resolve(projectRoot, 'mcpwc.config.json');
if (existsSync(legacyPath)) {
process.stderr.write(
`[helixir] Warning: mcpwc.config.json is deprecated. Rename to helixir.mcp.json.\n`,
);
try {
const raw = readFileSync(legacyPath, 'utf-8');
return JSON.parse(raw) as Partial<McpWcConfig>;
} catch {
process.stderr.write(`[helixir] Warning: mcpwc.config.json is malformed. Using defaults.\n`);
return {};
}
}

return {};
}

Expand Down Expand Up @@ -92,36 +76,32 @@ export function loadConfig(): Readonly<McpWcConfig> {
}

// Apply env vars (highest priority)
if (process.env['MCP_WC_CEM_PATH'] !== undefined) {
config.cemPath = process.env['MCP_WC_CEM_PATH'];
}
if (process.env['MCP_WC_PROJECT_ROOT'] !== undefined) {
config.projectRoot = process.env['MCP_WC_PROJECT_ROOT'];
}
if (process.env['MCP_WC_COMPONENT_PREFIX'] !== undefined) {
config.componentPrefix = process.env['MCP_WC_COMPONENT_PREFIX'];
}
if (process.env['MCP_WC_HEALTH_HISTORY_DIR'] !== undefined) {
config.healthHistoryDir = process.env['MCP_WC_HEALTH_HISTORY_DIR'];
}
if (process.env['MCP_WC_TSCONFIG_PATH'] !== undefined) {
config.tsconfigPath = process.env['MCP_WC_TSCONFIG_PATH'];
}
if (process.env['MCP_WC_TOKENS_PATH'] !== undefined) {
const val = process.env['MCP_WC_TOKENS_PATH'];
config.tokensPath = val === 'null' ? null : val;
}
if (process.env['MCP_WC_CDN_BASE'] !== undefined) {
const val = process.env['MCP_WC_CDN_BASE'];
config.cdnBase = val === 'null' ? null : val;
}
if (process.env['MCP_WC_CDN_AUTOLOADER'] !== undefined) {
const val = process.env['MCP_WC_CDN_AUTOLOADER'];
config.cdnAutoloader = val === 'null' ? null : val;
// String keys map directly; nullable keys treat the literal string 'null' as null.
const ENV_MAP_STRING: Readonly<Record<string, keyof McpWcConfigMutable>> = {
MCP_WC_CEM_PATH: 'cemPath',
MCP_WC_PROJECT_ROOT: 'projectRoot',
MCP_WC_COMPONENT_PREFIX: 'componentPrefix',
MCP_WC_HEALTH_HISTORY_DIR: 'healthHistoryDir',
MCP_WC_TSCONFIG_PATH: 'tsconfigPath',
};
const ENV_MAP_NULLABLE: Readonly<Record<string, keyof McpWcConfigMutable>> = {
MCP_WC_TOKENS_PATH: 'tokensPath',
MCP_WC_CDN_BASE: 'cdnBase',
MCP_WC_CDN_AUTOLOADER: 'cdnAutoloader',
MCP_WC_CDN_STYLESHEET: 'cdnStylesheet',
};

for (const [envKey, configKey] of Object.entries(ENV_MAP_STRING)) {
const val = process.env[envKey];
if (val !== undefined) {
(config as Record<string, unknown>)[configKey] = val;
}
}
if (process.env['MCP_WC_CDN_STYLESHEET'] !== undefined) {
const val = process.env['MCP_WC_CDN_STYLESHEET'];
config.cdnStylesheet = val === 'null' ? null : val;
for (const [envKey, configKey] of Object.entries(ENV_MAP_NULLABLE)) {
const val = process.env[envKey];
if (val !== undefined) {
(config as Record<string, unknown>)[configKey] = val === 'null' ? null : val;
}
}

// --watch CLI flag overrides config file value
Expand Down
5 changes: 4 additions & 1 deletion packages/core/src/handlers/cem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -725,7 +725,10 @@ export function findComponentsByToken(
cem: Cem,
): FindComponentsByTokenResult {
if (!token.startsWith('--')) {
throw new Error(`CSS custom property name must start with "--": "${token}"`);
throw new MCPError(
`CSS custom property name must start with "--": "${token}"`,
ErrorCategory.VALIDATION,
);
}

const components: TokenComponentMatch[] = [];
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/handlers/dependencies.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Cem } from './cem.js';
import { MCPError, ErrorCategory } from '../shared/error-handling.js';

export interface ComponentDependencyResult {
tagName: string;
Expand Down Expand Up @@ -105,7 +106,7 @@ export function getComponentDependencies(
}

if (!found) {
throw new Error(`Component "${tagName}" not found in CEM.`);
throw new MCPError(`Component "${tagName}" not found in CEM.`, ErrorCategory.NOT_FOUND);
}

const depMap = buildDependencyMap(cem);
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/handlers/extend.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Cem, CemDeclaration } from './cem.js';
import { MCPError, ErrorCategory } from '../shared/error-handling.js';

// --- Helpers ---

Expand Down Expand Up @@ -66,7 +67,7 @@ export function extendComponent(
): ExtendComponentResult {
const parentDecl = findDeclaration(cem, parentTagName);
if (!parentDecl) {
throw new Error(`Component "${parentTagName}" not found in CEM.`);
throw new MCPError(`Component "${parentTagName}" not found in CEM.`, ErrorCategory.NOT_FOUND);
}

const parentClassName = tagNameToClassName(parentTagName);
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/handlers/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ function lightPlaceholder(tokenName: string, category: string): string {
return '200ms';

default:
return '/* TODO: set value */';
return `var(${tokenName})`;
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/mcp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"homepage": "https://github.com/bookedsolidtech/helixir/tree/main/packages/mcp#readme",
"peerDependencies": {
"helixir": ">=0.5.0",
"@modelcontextprotocol/sdk": "^1.26.0",
"@modelcontextprotocol/sdk": "^1.27.1",
"zod": "^3.22.0"
},
"devDependencies": {
Expand Down
30 changes: 30 additions & 0 deletions packages/vscode/.vscodeignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Source files — not needed in the packaged extension
src/
tsconfig.json
esbuild.config.mjs

# Development dependencies and lock files
node_modules/
.pnpm-store/
pnpm-lock.yaml
package-lock.json

# Test artefacts
coverage/
*.test.ts
*.spec.ts

# Build intermediates (keep dist/)
*.map

# Editor and OS artefacts
.vscode/
.DS_Store
*.log

# Root-level workspace files that should not be bundled
../../node_modules/
../../src/
../../build/
../../packages/
../../.github/
84 changes: 84 additions & 0 deletions packages/vscode/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Helixir — VS Code Extension

**AI-powered web component intelligence for VS Code.**

Helixir gives AI assistants full situational awareness of any web component library by wiring the [helixir MCP server](https://github.com/bookedsolidtech/helixir) directly into VS Code's MCP layer.

## Features

- **MCP server auto-registration** — the helixir MCP server starts automatically with VS Code, no manual configuration required
- **30+ MCP tools** — component discovery, health scoring, breaking-change detection, TypeScript diagnostics, design token lookup, and more
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Inconsistent tool count with main README.

This README says "30+ MCP tools" but the main README states "87+ MCP tools". Update for consistency.

📝 Suggested fix
-- **30+ MCP tools** — component discovery, health scoring, breaking-change detection, TypeScript diagnostics, design token lookup, and more
+- **87+ MCP tools** — component discovery, health scoring, breaking-change detection, TypeScript diagnostics, design token lookup, and more
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- **30+ MCP tools** — component discovery, health scoring, breaking-change detection, TypeScript diagnostics, design token lookup, and more
- **87+ MCP tools** — component discovery, health scoring, breaking-change detection, TypeScript diagnostics, design token lookup, and more
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vscode/README.md` at line 10, The README line currently reads "**30+
MCP tools** — component discovery, health scoring, breaking-change detection,
TypeScript diagnostics, design token lookup, and more"; update that phrase to
match the main README by replacing "30+ MCP tools" with "87+ MCP tools" (i.e.,
change the string "**30+ MCP tools**" to "**87+ MCP tools**" so the two READMEs
are consistent).

- **Zero hallucinations** — every AI component suggestion is grounded in your actual `custom-elements.json`
- **Framework-agnostic** — works with Lit, Stencil, FAST, Spectrum, Shoelace, or any library that produces a Custom Elements Manifest

## Requirements

- VS Code **≥ 1.99.0**
- A component library with a `custom-elements.json` (Custom Elements Manifest)
- Node.js **≥ 20** on `PATH`

## Getting Started

1. Install the extension from the VS Code Marketplace
2. Open your component library folder in VS Code
3. The Helixir MCP server will register automatically with AI assistants that support MCP (e.g., GitHub Copilot, Claude)

### Optional: Configure the Config Path

If your `mcpwc.config.json` is not at the workspace root, set the path via VS Code settings:

```json
// .vscode/settings.json
{
"helixir.configPath": "packages/web-components/mcpwc.config.json"
}
```

The path can be relative to the workspace root or absolute.

## Commands

| Command | Description |
|---------|-------------|
| `Helixir: Run Health Check` | Guides you to run a health check via your AI assistant |

## Extension Settings

| Setting | Type | Default | Description |
|---------|------|---------|-------------|
| `helixir.configPath` | `string` | `""` | Path to `mcpwc.config.json`. Empty = workspace root. |

## How It Works

When the extension activates, it registers a **MCP server definition provider** (`helixir`) with VS Code's language model API (`vscode.lm`). VS Code spawns the bundled helixir MCP server (`dist/mcp-server.js`) as a child process over stdio.

The server reads your `custom-elements.json` and exposes 30+ tools that AI models can call to look up component APIs, run health scans, generate type declarations, and more.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Another reference to outdated tool count.

Line 55 also mentions "30+ tools" — update to match the current count.

📝 Suggested fix
-The server reads your `custom-elements.json` and exposes 30+ tools that AI models can call to look up component APIs, run health scans, generate type declarations, and more.
+The server reads your `custom-elements.json` and exposes 87+ tools that AI models can call to look up component APIs, run health scans, generate type declarations, and more.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
The server reads your `custom-elements.json` and exposes 30+ tools that AI models can call to look up component APIs, run health scans, generate type declarations, and more.
The server reads your `custom-elements.json` and exposes 87+ tools that AI models can call to look up component APIs, run health scans, generate type declarations, and more.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vscode/README.md` at line 55, Update the outdated "30+ tools"
reference in the README sentence starting with "The server reads your
`custom-elements.json`..." to the current tools count (replace "30+ tools" with
the accurate number or a dynamic phrase like "40+ tools" or "dozens of tools"),
and ensure the new count matches other mentions in the repository so the README
remains consistent.


## Configuration Reference

The helixir server is configured via environment variables passed by the extension:

| Variable | Description |
|----------|-------------|
| `MCP_WC_PROJECT_ROOT` | Set to your workspace folder automatically |
| `MCP_WC_CONFIG_PATH` | Set when `helixir.configPath` is configured |
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Search for MCP_WC_CONFIG_PATH usage in the codebase

# Check if this env var is used anywhere
rg -n 'MCP_WC_CONFIG_PATH' --type ts --type js

# Also check mcpProvider.ts which sets env vars for the spawned server
rg -n 'CONFIG_PATH' --type ts --type js

Repository: bookedsolidtech/helixir

Length of output: 609


🏁 Script executed:

# Examine config.ts to see the env-var mappings structure
head -100 packages/core/src/config.ts

Repository: bookedsolidtech/helixir

Length of output: 3787


🏁 Script executed:

# Look at mcpProvider.ts to understand how MCP_WC_CONFIG_PATH is being used
sed -n '30,50p' packages/vscode/src/mcpProvider.ts

Repository: bookedsolidtech/helixir

Length of output: 638


🏁 Script executed:

# Search for configPath usage and mapping in config.ts to understand the pattern
rg -n 'configPath' packages/core/src/config.ts -A 2 -B 2

Repository: bookedsolidtech/helixir

Length of output: 652


Remove MCP_WC_CONFIG_PATH from documentation or implement it in the config system.

The environment variable MCP_WC_CONFIG_PATH is set in packages/vscode/src/mcpProvider.ts (line 38) but is not handled in the env-var mappings in packages/core/src/config.ts. It should either be added to the ENV_MAP_STRING mapping with a corresponding property in McpWcConfig, or the reference should be removed from the documentation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/vscode/README.md` at line 64, Documentation references the
environment variable MCP_WC_CONFIG_PATH but the config system doesn't map or
expose it; either remove the doc line or add mapping and schema support. To fix,
add MCP_WC_CONFIG_PATH to the ENV_MAP_STRING mapping in the config loader
(ENV_MAP_STRING) and add a corresponding property on the McpWcConfig
interface/schema, then read it into the config initialization so code in
mcpProvider.ts (which sets MCP_WC_CONFIG_PATH) is supported; alternatively,
remove the MCP_WC_CONFIG_PATH entry from packages/vscode/README.md if you prefer
not to support it.


Additional configuration (token path, component prefix, health history dir) belongs in `mcpwc.config.json`. See the [helixir documentation](https://github.com/bookedsolidtech/helixir) for the full config reference.

## Troubleshooting

**MCP server not appearing in AI assistant tools**
- Verify VS Code ≥ 1.99.0 is installed
- Confirm your workspace contains a `custom-elements.json`
- Check the Output panel → Helixir for error messages

**"No workspace folder" error from Run Health Check**
- Open a folder (not just a file) in VS Code — the extension uses the workspace folder as the project root

**Server starts but returns no components**
- Ensure `custom-elements.json` exists at the workspace root or configure `helixir.configPath`
- Regenerate the manifest: `npm run analyze:cem` (or your CEM generation script)

## License

MIT — see [LICENSE](../../LICENSE)
69 changes: 69 additions & 0 deletions packages/vscode/esbuild.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* esbuild configuration for the Helixir VS Code extension.
*
* Produces two bundles:
* dist/extension.js — VS Code extension host entry (CJS, externalizes 'vscode')
* dist/mcp-server.js — Helixir MCP server entry (ESM, bundles helixir)
*/

import * as esbuild from 'esbuild';

const isProduction = process.argv.includes('--production');
const isWatch = process.argv.includes('--watch');

const sharedOptions = {
bundle: true,
sourcemap: !isProduction,
minify: isProduction,
logLevel: 'info',
platform: 'node',
target: 'node20',
};

/**
* Bundle 1: VS Code extension host entry
* - CommonJS (VS Code extension host requires CJS)
* - 'vscode' is externalized — provided by the VS Code runtime
*/
const extensionConfig = {
...sharedOptions,
entryPoints: ['src/extension.ts'],
outfile: 'dist/extension.js',
format: 'cjs',
external: ['vscode'],
};

/**
* Bundle 2: Helixir MCP server
* - ESM format (helixir is an ES module)
* - Bundles helixir and its dependencies so the extension is self-contained
* - Spawned as a child process via stdio by the VS Code extension
*/
const mcpServerConfig = {
...sharedOptions,
entryPoints: ['src/mcp-server-entry.ts'],
outfile: 'dist/mcp-server.js',
format: 'esm',
banner: {
js: '#!/usr/bin/env node\n// Helixir MCP Server — bundled by esbuild',
},
};

async function build() {
const extensionCtx = await esbuild.context(extensionConfig);
const mcpServerCtx = await esbuild.context(mcpServerConfig);

if (isWatch) {
await Promise.all([extensionCtx.watch(), mcpServerCtx.watch()]);
console.log('[helixir-vscode] Watching for changes...');
} else {
await Promise.all([extensionCtx.rebuild(), mcpServerCtx.rebuild()]);
await Promise.all([extensionCtx.dispose(), mcpServerCtx.dispose()]);
console.log('[helixir-vscode] Build complete.');
}
}

build().catch((err) => {
console.error('[helixir-vscode] Build failed:', err);
process.exit(1);
});
Loading
Loading