Skip to content

Commit f903e8c

Browse files
authored
feat(vscode): Add VS Code extension (#22) (#169)
* feat(vscode): create extension directory structure Add .gitignore and .vscodeignore for the VS Code extension. * feat(vscode): add package.json and build configuration - package.json with LSP client dependencies and VS Code configuration - tsconfig.json for TypeScript compilation - esbuild.js for bundling the extension * feat(vscode): implement LSP client and status bar - LanguageClient setup connecting to agnix-lsp - ServerOptions with configurable path from settings - ClientOptions with documentSelector for markdown/json - File pattern filtering for SKILL.md, CLAUDE.md, etc. - Status bar showing validation status - Error handling when agnix-lsp not found - Commands for restart and showing output * feat(vscode): add SKILL.md syntax highlighting - TextMate grammar for YAML frontmatter in SKILL.md files - Language configuration for bracket matching and auto-closing - Highlights skill-specific keys (name, model, allowed_tools, etc.) * docs(vscode): add extension documentation - editors/vscode/README.md with installation and usage instructions - editors/vscode/CHANGELOG.md with initial release notes - Update main README.md with VS Code section and roadmap - Update crates/agnix-lsp/README.md with VS Code instructions * chore(vscode): add package-lock.json Ensures reproducible dependency installation. * refactor(vscode): remove redundant comments * fix(vscode): prevent command injection in LSP binary check Replace shell command execution (where/which) with safe filesystem checks to prevent command injection through user-controlled lspPath. The previous implementation passed lspPath directly to shell commands, allowing malicious input like "; rm -rf /" to execute arbitrary code. Security improvements: - Use fs.accessSync instead of shell commands - Check PATH directories manually for command names - Resolve absolute/relative paths safely with path.resolve - Handle Windows extensions (.exe, .cmd, .bat) explicitly - Convert from async to sync since no async operations needed - Move dynamic require() to static imports * docs: update documentation for VS Code extension * fix(vscode): address reviewer feedback - Add missing activationEvents for .local files, plugin.json, instructions, and cursor rules - Add scope: machine to agnix.lspPath for security hardening - Fix SKILL.md syntax highlighting for model values (sonnet, opus, haiku, inherit) - Add async/await to config change handler to prevent overlapping operations
1 parent 905788b commit f903e8c

14 files changed

Lines changed: 3700 additions & 3 deletions

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2424
- Editor support for VS Code, Neovim, Helix, and other LSP-compatible editors
2525
- Comprehensive test coverage with 36 unit and integration tests
2626
- Installation: `cargo install --path crates/agnix-lsp`
27+
- VS Code extension with full LSP integration (#22)
28+
- Real-time diagnostics for all 99 validation rules
29+
- Status bar indicator showing agnix validation status
30+
- Syntax highlighting for SKILL.md YAML frontmatter
31+
- Commands: 'Restart Language Server' and 'Show Output Channel'
32+
- Configuration: agnix.lspPath, agnix.enable, agnix.trace.server
33+
- Safe LSP binary detection (prevents command injection)
34+
- Documentation in editors/vscode/README.md
2735
- Spec Drift Sentinel workflow for automated upstream specification monitoring (#107)
2836
- Weekly checks for S-tier sources (Agent Skills, MCP, Claude Code, Codex CLI, OpenCode)
2937
- Monthly checks for A-tier sources (Cursor, GitHub Copilot, Cline)

README.md

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,33 @@ command = "agnix-lsp"
333333

334334
See `crates/agnix-lsp/README.md` for more editor configurations.
335335

336+
**VS Code:**
337+
338+
Install the agnix extension from the VS Code Marketplace, or build from source:
339+
340+
```bash
341+
cd editors/vscode
342+
npm install
343+
npm run compile
344+
```
345+
346+
Then use "Install from VSIX" in VS Code or run `code --install-extension agnix-0.1.0.vsix`.
347+
348+
The extension provides:
349+
- Real-time diagnostics as you type
350+
- Status bar indicator
351+
- Syntax highlighting for SKILL.md frontmatter
352+
353+
Configure the LSP path in settings if needed:
354+
355+
```json
356+
{
357+
"agnix.lspPath": "/path/to/agnix-lsp"
358+
}
359+
```
360+
361+
See `editors/vscode/README.md` for full documentation.
362+
336363
## Performance
337364

338365
agnix validates files in parallel using [rayon](https://github.com/rayon-rs/rayon) for optimal performance on large projects. Results are sorted deterministically (errors first, then by file path) to ensure consistent output across runs.
@@ -482,7 +509,7 @@ agnix/
482509
├── tests/
483510
│ └── fixtures/ # Test configs
484511
└── editors/
485-
└── vscode/ # VS Code extension (coming)
512+
└── vscode/ # VS Code extension
486513
```
487514
488515
## Roadmap
@@ -502,7 +529,7 @@ agnix/
502529
- [x] MCP tool validation (MCP-001 to MCP-006)
503530
- [x] GitHub Action for CI/CD integration
504531
- [x] LSP server
505-
- [ ] VS Code extension
532+
- [x] VS Code extension
506533
507534
## License
508535

crates/agnix-lsp/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ agnix-lsp
3030

3131
### VS Code
3232

33-
A dedicated VS Code extension is planned. For now, you can use a generic LSP client extension.
33+
A dedicated VS Code extension is available at `editors/vscode`. See `editors/vscode/README.md` for installation and usage.
3434

3535
### Neovim (with nvim-lspconfig)
3636

editors/vscode/.gitignore

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Dependencies
2+
node_modules/
3+
4+
# Build output
5+
out/
6+
dist/
7+
8+
# VS Code extension package
9+
*.vsix
10+
11+
# VS Code test directory
12+
.vscode-test/
13+
14+
# TypeScript cache
15+
*.tsbuildinfo
16+
17+
# npm debug
18+
npm-debug.log*
19+
20+
# OS files
21+
.DS_Store
22+
Thumbs.db

editors/vscode/.vscodeignore

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Source files (not needed in package)
2+
src/**
3+
**/*.ts
4+
!out/**/*.js
5+
6+
# Build configuration
7+
tsconfig.json
8+
esbuild.js
9+
10+
# Development files
11+
.gitignore
12+
.vscode-test/
13+
node_modules/
14+
15+
# Other
16+
*.vsix
17+
.DS_Store

editors/vscode/CHANGELOG.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Change Log
2+
3+
All notable changes to the "agnix" extension will be documented in this file.
4+
5+
## [0.1.0] - 2025-02-04
6+
7+
### Added
8+
9+
- Initial release
10+
- LSP client connecting to agnix-lsp for real-time validation
11+
- Support for all agnix-validated file types:
12+
- SKILL.md (Agent Skills)
13+
- CLAUDE.md, AGENTS.md (Claude Code memory)
14+
- .claude/settings.json (Hooks)
15+
- plugin.json (Plugins)
16+
- *.mcp.json (MCP tools)
17+
- .github/copilot-instructions.md (GitHub Copilot)
18+
- .cursor/rules/*.mdc (Cursor)
19+
- Status bar indicator showing validation status
20+
- Syntax highlighting for SKILL.md YAML frontmatter
21+
- Commands:
22+
- `agnix: Restart Language Server`
23+
- `agnix: Show Output Channel`
24+
- Configuration options:
25+
- `agnix.lspPath` - Custom path to agnix-lsp binary
26+
- `agnix.enable` - Enable/disable validation
27+
- `agnix.trace.server` - Server communication tracing

editors/vscode/README.md

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# agnix - Agent Config Linter
2+
3+
Real-time validation for agent configuration files in VS Code.
4+
5+
## Features
6+
7+
- Real-time diagnostics for agent configuration files
8+
- Validates 99 rules across multiple configuration types
9+
- Status bar indicator showing validation status
10+
- Syntax highlighting for SKILL.md frontmatter
11+
12+
## Supported File Types
13+
14+
- `SKILL.md` - Agent skill definitions (agentskills.io spec)
15+
- `CLAUDE.md`, `AGENTS.md` - Claude Code memory files
16+
- `.claude/settings.json` - Hook configurations
17+
- `plugin.json` - Plugin manifests
18+
- `*.mcp.json` - MCP tool configurations
19+
- `.github/copilot-instructions.md` - GitHub Copilot instructions
20+
- `.cursor/rules/*.mdc` - Cursor project rules
21+
22+
## Requirements
23+
24+
This extension requires the `agnix-lsp` binary to be installed:
25+
26+
```bash
27+
# From the agnix repository
28+
cargo install --path crates/agnix-lsp
29+
30+
# Or from crates.io (when published)
31+
cargo install agnix-lsp
32+
```
33+
34+
## Extension Settings
35+
36+
This extension contributes the following settings:
37+
38+
- `agnix.lspPath`: Path to the agnix-lsp executable (default: `agnix-lsp`)
39+
- `agnix.enable`: Enable/disable agnix validation (default: `true`)
40+
- `agnix.trace.server`: Traces communication between VS Code and the language server
41+
42+
## Commands
43+
44+
- `agnix: Restart Language Server` - Restart the agnix language server
45+
- `agnix: Show Output Channel` - Show the agnix output channel for debugging
46+
47+
## Configuration
48+
49+
The extension respects `.agnix.toml` configuration files in your workspace:
50+
51+
```toml
52+
severity = "Warning"
53+
target = "ClaudeCode"
54+
55+
[rules]
56+
skills = true
57+
hooks = true
58+
agents = true
59+
mcp = true
60+
61+
exclude = [
62+
"node_modules/**",
63+
".git/**"
64+
]
65+
```
66+
67+
See the [agnix documentation](https://github.com/avifenesh/agnix) for full configuration options.
68+
69+
## Troubleshooting
70+
71+
### agnix-lsp not found
72+
73+
If you see "agnix-lsp not found", ensure the binary is installed and in your PATH:
74+
75+
```bash
76+
# Check if installed
77+
which agnix-lsp # Unix
78+
where agnix-lsp # Windows
79+
80+
# Or specify the full path in settings
81+
"agnix.lspPath": "/path/to/agnix-lsp"
82+
```
83+
84+
### No diagnostics appearing
85+
86+
1. Check that the file is a supported type (see above)
87+
2. Verify the language server is running (check status bar)
88+
3. Open the output channel (`agnix: Show Output Channel`) for errors
89+
90+
## Links
91+
92+
- [agnix on GitHub](https://github.com/avifenesh/agnix)
93+
- [Agent Skills Specification](https://agentskills.io)
94+
- [Model Context Protocol](https://modelcontextprotocol.io)
95+
96+
## License
97+
98+
MIT OR Apache-2.0

editors/vscode/esbuild.js

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// @ts-check
2+
const esbuild = require('esbuild');
3+
4+
const production = process.argv.includes('--production');
5+
const watch = process.argv.includes('--watch');
6+
7+
async function main() {
8+
const ctx = await esbuild.context({
9+
entryPoints: ['src/extension.ts'],
10+
bundle: true,
11+
format: 'cjs',
12+
minify: production,
13+
sourcemap: !production,
14+
sourcesContent: false,
15+
platform: 'node',
16+
outfile: 'out/extension.js',
17+
external: ['vscode'],
18+
logLevel: 'info',
19+
plugins: [
20+
{
21+
name: 'watch-plugin',
22+
setup(build) {
23+
build.onEnd((result) => {
24+
if (result.errors.length === 0) {
25+
console.log('[watch] build finished');
26+
}
27+
});
28+
},
29+
},
30+
],
31+
});
32+
33+
if (watch) {
34+
await ctx.watch();
35+
console.log('[watch] watching for changes...');
36+
} else {
37+
await ctx.rebuild();
38+
await ctx.dispose();
39+
}
40+
}
41+
42+
main().catch((e) => {
43+
console.error(e);
44+
process.exit(1);
45+
});
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"comments": {
3+
"lineComment": "#"
4+
},
5+
"brackets": [
6+
["{", "}"],
7+
["[", "]"],
8+
["(", ")"]
9+
],
10+
"autoClosingPairs": [
11+
{ "open": "{", "close": "}" },
12+
{ "open": "[", "close": "]" },
13+
{ "open": "(", "close": ")" },
14+
{ "open": "\"", "close": "\"", "notIn": ["string"] },
15+
{ "open": "'", "close": "'", "notIn": ["string"] },
16+
{ "open": "`", "close": "`", "notIn": ["string"] }
17+
],
18+
"surroundingPairs": [
19+
["{", "}"],
20+
["[", "]"],
21+
["(", ")"],
22+
["\"", "\""],
23+
["'", "'"],
24+
["`", "`"]
25+
],
26+
"folding": {
27+
"markers": {
28+
"start": "^---\\s*$",
29+
"end": "^---\\s*$"
30+
}
31+
},
32+
"wordPattern": "(-?\\d*\\.\\d\\w*)|([^\\`\\~\\!\\@\\#\\%\\^\\&\\*\\(\\)\\-\\=\\+\\[\\{\\]\\}\\\\\\|\\;\\:\\'\\\"\\,\\.\\<\\>\\/\\?\\s]+)"
33+
}

0 commit comments

Comments
 (0)