-
Notifications
You must be signed in to change notification settings - Fork 1
fix: replace readFileSync with async readFile in library tool handler #212
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
8e131fe
ba6ec2b
933fa0a
311f1c4
f94ea7b
96cb5e2
692886b
0d24d51
02ee086
fd40ef2
cd70600
e9e4a58
8c7e8a9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -0,0 +1 @@ | ||||
| /Volumes/Development/booked/helixir/build | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove the accidental absolute-path Line 1 introduces a local absolute path as a tracked file/symlink. This is non-portable and may break build pipelines that expect Proposed fix-/Volumes/Development/booked/helixir/build📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -0,0 +1 @@ | ||||
| /Volumes/Development/booked/helixir/node_modules | ||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove the accidental absolute-path Line 1 tracks a machine-specific absolute path. This is non-portable, leaks local path info, and can break installs by conflicting with the expected Proposed fix-/Volumes/Development/booked/helixir/node_modules📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,7 +16,7 @@ | |
| }, | ||
| "license": "MIT", | ||
| "dependencies": { | ||
| "@modelcontextprotocol/sdk": "^1.26.0", | ||
| "@modelcontextprotocol/sdk": "^1.27.1", | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Verify manifest vs lockfile specifiers for `@modelcontextprotocol/sdk` without modifying repo.
set -euo pipefail
echo "== package.json entries =="
rg -n '"@modelcontextprotocol/sdk"\s*:' packages/core/package.json packages/mcp/package.json
echo
echo "== lockfile entries (importers + packages) =="
rg -n '@modelcontextprotocol/sdk|packages/core|packages/mcp' pnpm-lock.yaml -C2
echo
echo "Expected: lockfile importer specifiers match '^1.27.1' where corresponding manifests were updated."Repository: bookedsolidtech/helixir Length of output: 1454 Update The manifests for both 🤖 Prompt for AI Agents |
||
| "zod": "^3.22.0" | ||
| }, | ||
| "peerDependencies": { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -145,7 +145,7 @@ function lightPlaceholder(tokenName: string, category: string): string { | |
| return '200ms'; | ||
|
|
||
| default: | ||
| return '/* TODO: set value */'; | ||
| return `var(${tokenName})`; | ||
| } | ||
|
Comment on lines
147
to
149
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🌐 Web query:
💡 Result: In CSS Custom Properties, a self-referential declaration like --x: var(--x); creates a cyclic dependency. The browser constructs a dependency graph for custom properties on each element. If a custom property's value contains a var reference to itself (directly or indirectly through other properties), it forms a cycle. All custom properties in the cycle are invalid at computed-value time, resulting in the "guaranteed-invalid value" (initial value for custom properties). When var(--x) is used elsewhere, it substitutes nothing (empty token stream), and fallbacks (if provided) are used. This behavior is consistent across browsers and prevents infinite recursion during resolution. Citations:
🏁 Script executed: cat -n packages/core/src/handlers/theme.ts | sed -n '140,160p'Repository: bookedsolidtech/helixir Length of output: 870 🏁 Script executed: # Find the test file mentioned in the scratchpad
fd "theme.test" -t fRepository: bookedsolidtech/helixir Length of output: 95 🏁 Script executed: # Check the full context of the lightPlaceholder function
rg -A 10 -B 10 "lightPlaceholder" packages/core/src/handlers/theme.tsRepository: bookedsolidtech/helixir Length of output: 1596 🏁 Script executed: # Find and examine the test file
fd "theme.test.ts" -t f -x wc -l {}Repository: bookedsolidtech/helixir Length of output: 101 🏁 Script executed: # Look at tests related to default/unknown categories
rg -A 20 "unknown|default" tests/handlers/theme.test.tsRepository: bookedsolidtech/helixir Length of output: 1914 🏁 Script executed: # Show how lightValues are used in the createTheme function
rg -A 10 "lightValues" packages/core/src/handlers/theme.tsRepository: bookedsolidtech/helixir Length of output: 1494 Self-referential fallback creates invalid custom-property values Line 148 generates Proposed fix default:
- return `var(${tokenName})`;
+ return 'initial';Please also adjust the test in 🤖 Prompt for AI Agents |
||
| } | ||
|
|
||
|
|
||
| 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/ |
| 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 | ||
| - **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. | ||
|
|
||
| ## 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 | | ||
|
|
||
| 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) |
| 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); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| { | ||
| "name": "helixir-vscode", | ||
| "displayName": "Helixir", | ||
| "description": "AI-powered web component intelligence for VS Code — powered by helixir MCP", | ||
| "version": "0.1.0", | ||
| "publisher": "bookedsolidtech", | ||
| "private": true, | ||
| "engines": { | ||
| "vscode": "^1.99.0" | ||
| }, | ||
| "categories": [ | ||
| "Other", | ||
| "AI" | ||
| ], | ||
| "keywords": [ | ||
| "mcp", | ||
| "web components", | ||
| "helixir", | ||
| "ai", | ||
| "custom elements" | ||
| ], | ||
| "activationEvents": [ | ||
| "onStartupFinished" | ||
| ], | ||
| "main": "./dist/extension.js", | ||
| "contributes": { | ||
| "mcpServerDefinitionProviders": [ | ||
| { | ||
| "id": "helixir", | ||
| "label": "Helixir" | ||
| } | ||
| ], | ||
| "commands": [ | ||
| { | ||
| "command": "helixir.runHealthCheck", | ||
| "title": "Helixir: Run Health Check", | ||
| "category": "Helixir" | ||
| } | ||
| ], | ||
| "configuration": { | ||
| "title": "Helixir", | ||
| "properties": { | ||
| "helixir.configPath": { | ||
| "type": "string", | ||
| "default": "", | ||
| "description": "Path to mcpwc.config.json (relative to workspace root or absolute). Leave empty to use workspace root defaults." | ||
| } | ||
| } | ||
| } | ||
| }, | ||
| "scripts": { | ||
| "vscode:prepublish": "node esbuild.config.mjs --production", | ||
| "build": "node esbuild.config.mjs", | ||
| "watch": "node esbuild.config.mjs --watch", | ||
| "package": "vsce package --no-dependencies", | ||
| "publish": "vsce publish --no-dependencies" | ||
| }, | ||
| "dependencies": { | ||
| "helixir": "workspace:*" | ||
| }, | ||
| "devDependencies": { | ||
| "@types/vscode": "^1.99.0", | ||
| "@vscode/vsce": "^3.0.0", | ||
| "esbuild": "^0.25.0", | ||
| "ovsx": "^0.9.0" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import * as vscode from 'vscode'; | ||
| import { registerMcpProvider } from './mcpProvider.js'; | ||
|
|
||
| /** | ||
| * Called when the extension is activated. | ||
| * Registers the Helixir MCP server definition provider and the | ||
| * "Helixir: Run Health Check" command. | ||
| */ | ||
| export function activate(context: vscode.ExtensionContext): void { | ||
| registerMcpProvider(context); | ||
|
|
||
| const healthCheckCommand = vscode.commands.registerCommand( | ||
| 'helixir.runHealthCheck', | ||
| async () => { | ||
| const workspaceFolders = vscode.workspace.workspaceFolders; | ||
| if (!workspaceFolders || workspaceFolders.length === 0) { | ||
| await vscode.window.showErrorMessage( | ||
| 'Helixir: No workspace folder is open. ' + | ||
| 'Open a component library folder to run a health check.' | ||
| ); | ||
| return; | ||
| } | ||
|
|
||
| await vscode.window.showInformationMessage( | ||
| 'Helixir: MCP server is active. ' + | ||
| 'Ask your AI assistant to call score_all_components via the Helixir MCP server.' | ||
| ); | ||
| } | ||
| ); | ||
|
|
||
| context.subscriptions.push(healthCheckCommand); | ||
| } | ||
|
|
||
| /** | ||
| * Called when the extension is deactivated. | ||
| */ | ||
| export function deactivate(): void { | ||
| // Subscriptions are disposed automatically via context.subscriptions. | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| /** | ||
| * Helixir MCP Server — entry point for the bundled server. | ||
| * | ||
| * This file is bundled by esbuild into dist/mcp-server.js (ESM format). | ||
| * It is spawned as a child process by the VS Code extension (mcpProvider.ts) | ||
| * using stdio transport. | ||
| * | ||
| * The helixir/mcp module exports a `main()` function that initialises and | ||
| * starts the MCP server, listening on stdin/stdout. | ||
| */ | ||
| import { main } from 'helixir/mcp'; | ||
|
|
||
| main().catch((err: unknown) => { | ||
| process.stderr.write(`[helixir-mcp] Fatal: ${String(err)}\n`); | ||
| process.exit(1); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unify the tool-count messaging.
Line 20 shows
tools-87+, but the README copy still says30+ MCP tools(Line 31). Please make these consistent to avoid confusing users.🤖 Prompt for AI Agents