agnix 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,88 @@
1
+ # agnix
2
+
3
+ Linter for AI agent configurations. Validates SKILL.md, CLAUDE.md, hooks, MCP, and more.
4
+
5
+ **100 rules** | **Real-time validation** | **Auto-fix** | **Multi-tool support**
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install -g agnix
11
+ ```
12
+
13
+ Or run directly with npx:
14
+
15
+ ```bash
16
+ npx agnix .
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ### Command Line
22
+
23
+ ```bash
24
+ # Lint current directory
25
+ agnix .
26
+
27
+ # Lint specific file
28
+ agnix CLAUDE.md
29
+
30
+ # Auto-fix issues
31
+ agnix --fix .
32
+
33
+ # JSON output
34
+ agnix --format json .
35
+
36
+ # Target specific tool
37
+ agnix --target cursor .
38
+ ```
39
+
40
+ ### Node.js API
41
+
42
+ ```javascript
43
+ const agnix = require('agnix');
44
+
45
+ // Async lint
46
+ const result = await agnix.lint('./');
47
+ console.log(result);
48
+
49
+ // Sync run
50
+ const { stdout, exitCode } = agnix.runSync(['--version']);
51
+
52
+ // Get version
53
+ console.log(agnix.version());
54
+ ```
55
+
56
+ ## Supported Files
57
+
58
+ | File | Tool |
59
+ |------|------|
60
+ | `SKILL.md` | Claude Code |
61
+ | `CLAUDE.md`, `AGENTS.md` | Claude Code, Codex |
62
+ | `.claude/settings.json` | Claude Code |
63
+ | `plugin.json` | Claude Code |
64
+ | `*.mcp.json` | All |
65
+ | `.github/copilot-instructions.md` | GitHub Copilot |
66
+ | `.cursor/rules/*.mdc` | Cursor |
67
+
68
+ ## Options
69
+
70
+ ```
71
+ -t, --target <tool> Target tool (ClaudeCode, Cursor, Copilot, CodexCli)
72
+ -f, --format <format> Output format (text, json, sarif)
73
+ --fix Auto-fix issues
74
+ -q, --quiet Only show errors
75
+ -v, --verbose Show detailed output
76
+ --version Show version
77
+ -h, --help Show help
78
+ ```
79
+
80
+ ## Links
81
+
82
+ - [GitHub Repository](https://github.com/avifenesh/agnix)
83
+ - [Validation Rules](https://github.com/avifenesh/agnix/blob/main/knowledge-base/VALIDATION-RULES.md)
84
+ - [VS Code Extension](https://marketplace.visualstudio.com/items?itemName=avifenesh.agnix)
85
+
86
+ ## License
87
+
88
+ MIT OR Apache-2.0
package/bin/agnix ADDED
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawn } = require('child_process');
4
+ const path = require('path');
5
+ const os = require('os');
6
+
7
+ const binDir = __dirname;
8
+ const binaryName = os.platform() === 'win32' ? 'agnix-binary.exe' : 'agnix-binary';
9
+ const binaryPath = path.join(binDir, binaryName);
10
+
11
+ const child = spawn(binaryPath, process.argv.slice(2), {
12
+ stdio: 'inherit',
13
+ shell: false,
14
+ });
15
+
16
+ child.on('error', (err) => {
17
+ if (err.code === 'ENOENT') {
18
+ console.error('agnix binary not found. Try reinstalling:');
19
+ console.error(' npm install -g agnix');
20
+ } else {
21
+ console.error(`Failed to run agnix: ${err.message}`);
22
+ }
23
+ process.exit(1);
24
+ });
25
+
26
+ child.on('exit', (code) => {
27
+ process.exit(code || 0);
28
+ });
package/index.js ADDED
@@ -0,0 +1,123 @@
1
+ /**
2
+ * agnix - Node.js API
3
+ *
4
+ * Programmatic access to the agnix linter.
5
+ */
6
+
7
+ const { spawn, spawnSync } = require('child_process');
8
+ const path = require('path');
9
+ const os = require('os');
10
+
11
+ const binDir = path.join(__dirname, 'bin');
12
+ const binaryName = os.platform() === 'win32' ? 'agnix-binary.exe' : 'agnix-binary';
13
+ const binaryPath = path.join(binDir, binaryName);
14
+
15
+ /**
16
+ * Run agnix synchronously and return the result.
17
+ *
18
+ * @param {string[]} args - Command line arguments
19
+ * @param {object} options - Options passed to spawnSync
20
+ * @returns {{ stdout: string, stderr: string, exitCode: number }}
21
+ */
22
+ function runSync(args = [], options = {}) {
23
+ const result = spawnSync(binaryPath, args, {
24
+ encoding: 'utf-8',
25
+ ...options,
26
+ });
27
+
28
+ if (result.error) {
29
+ throw result.error;
30
+ }
31
+
32
+ return {
33
+ stdout: result.stdout || '',
34
+ stderr: result.stderr || '',
35
+ exitCode: result.status || 0,
36
+ };
37
+ }
38
+
39
+ /**
40
+ * Run agnix asynchronously and return a promise.
41
+ *
42
+ * @param {string[]} args - Command line arguments
43
+ * @param {object} options - Options passed to spawn
44
+ * @returns {Promise<{ stdout: string, stderr: string, exitCode: number }>}
45
+ */
46
+ function run(args = [], options = {}) {
47
+ return new Promise((resolve, reject) => {
48
+ const child = spawn(binaryPath, args, options);
49
+ let stdout = '';
50
+ let stderr = '';
51
+
52
+ if (child.stdout) {
53
+ child.stdout.on('data', (data) => {
54
+ stdout += data.toString();
55
+ });
56
+ }
57
+
58
+ if (child.stderr) {
59
+ child.stderr.on('data', (data) => {
60
+ stderr += data.toString();
61
+ });
62
+ }
63
+
64
+ child.on('error', reject);
65
+
66
+ child.on('close', (code) => {
67
+ resolve({
68
+ stdout,
69
+ stderr,
70
+ exitCode: code || 0,
71
+ });
72
+ });
73
+ });
74
+ }
75
+
76
+ /**
77
+ * Lint files and return diagnostics as JSON.
78
+ *
79
+ * @param {string} target - Path to file or directory to lint
80
+ * @param {object} options - Lint options
81
+ * @param {string} options.target - Target tool (ClaudeCode, Cursor, etc.)
82
+ * @param {string} options.format - Output format (json, sarif)
83
+ * @returns {Promise<object>} - Parsed JSON diagnostics
84
+ */
85
+ async function lint(target, options = {}) {
86
+ const args = ['--format', 'json'];
87
+
88
+ if (options.target) {
89
+ args.push('--target', options.target);
90
+ }
91
+
92
+ args.push(target);
93
+
94
+ const result = await run(args);
95
+
96
+ try {
97
+ return JSON.parse(result.stdout);
98
+ } catch {
99
+ return {
100
+ files: [],
101
+ summary: { errors: 0, warnings: 0, fixable: 0 },
102
+ raw: result.stdout,
103
+ };
104
+ }
105
+ }
106
+
107
+ /**
108
+ * Get agnix version.
109
+ *
110
+ * @returns {string} - Version string
111
+ */
112
+ function version() {
113
+ const result = runSync(['--version']);
114
+ return result.stdout.trim();
115
+ }
116
+
117
+ module.exports = {
118
+ run,
119
+ runSync,
120
+ lint,
121
+ version,
122
+ binaryPath,
123
+ };
package/install.js ADDED
@@ -0,0 +1,179 @@
1
+ #!/usr/bin/env node
2
+
3
+ const https = require('https');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const { execSync } = require('child_process');
7
+ const os = require('os');
8
+
9
+ const GITHUB_REPO = 'avifenesh/agnix';
10
+ const VERSION = require('./package.json').version;
11
+
12
+ /**
13
+ * Get platform-specific asset name and binary name.
14
+ */
15
+ function getPlatformInfo() {
16
+ const platform = os.platform();
17
+ const arch = os.arch();
18
+
19
+ const mapping = {
20
+ 'darwin-arm64': {
21
+ asset: 'agnix-aarch64-apple-darwin.tar.gz',
22
+ extractedName: 'agnix',
23
+ binary: 'agnix-binary',
24
+ },
25
+ 'darwin-x64': {
26
+ // x64 Mac uses ARM binary via Rosetta 2
27
+ asset: 'agnix-aarch64-apple-darwin.tar.gz',
28
+ extractedName: 'agnix',
29
+ binary: 'agnix-binary',
30
+ },
31
+ 'linux-x64': {
32
+ asset: 'agnix-x86_64-unknown-linux-gnu.tar.gz',
33
+ extractedName: 'agnix',
34
+ binary: 'agnix-binary',
35
+ },
36
+ 'linux-arm64': {
37
+ // ARM Linux not yet available, try x64 with emulation
38
+ asset: 'agnix-x86_64-unknown-linux-gnu.tar.gz',
39
+ extractedName: 'agnix',
40
+ binary: 'agnix-binary',
41
+ },
42
+ 'win32-x64': {
43
+ asset: 'agnix-x86_64-pc-windows-msvc.zip',
44
+ extractedName: 'agnix.exe',
45
+ binary: 'agnix-binary.exe',
46
+ },
47
+ };
48
+
49
+ const key = `${platform}-${arch}`;
50
+ const info = mapping[key];
51
+
52
+ if (!info) {
53
+ console.error(`Unsupported platform: ${platform}-${arch}`);
54
+ console.error('Supported platforms: darwin-arm64, darwin-x64, linux-x64, win32-x64');
55
+ process.exit(1);
56
+ }
57
+
58
+ return info;
59
+ }
60
+
61
+ /**
62
+ * Download a file from URL, following redirects.
63
+ */
64
+ function downloadFile(url, destPath) {
65
+ return new Promise((resolve, reject) => {
66
+ const file = fs.createWriteStream(destPath);
67
+
68
+ const request = https.get(url, (response) => {
69
+ if (response.statusCode === 302 || response.statusCode === 301) {
70
+ const redirectUrl = response.headers.location;
71
+ if (redirectUrl) {
72
+ file.close();
73
+ fs.unlinkSync(destPath);
74
+ downloadFile(redirectUrl, destPath).then(resolve).catch(reject);
75
+ return;
76
+ }
77
+ }
78
+
79
+ if (response.statusCode !== 200) {
80
+ file.close();
81
+ reject(new Error(`Download failed with status ${response.statusCode}`));
82
+ return;
83
+ }
84
+
85
+ response.pipe(file);
86
+
87
+ file.on('finish', () => {
88
+ file.close();
89
+ resolve();
90
+ });
91
+ });
92
+
93
+ request.on('error', (err) => {
94
+ file.close();
95
+ fs.unlinkSync(destPath);
96
+ reject(err);
97
+ });
98
+
99
+ file.on('error', (err) => {
100
+ fs.unlinkSync(destPath);
101
+ reject(err);
102
+ });
103
+ });
104
+ }
105
+
106
+ /**
107
+ * Extract archive based on platform.
108
+ */
109
+ function extractArchive(archivePath, destDir) {
110
+ const platform = os.platform();
111
+
112
+ if (platform === 'win32') {
113
+ // Use PowerShell to extract zip
114
+ execSync(
115
+ `powershell -Command "Expand-Archive -Path '${archivePath}' -DestinationPath '${destDir}' -Force"`,
116
+ { stdio: 'inherit' }
117
+ );
118
+ } else {
119
+ // Use tar for .tar.gz
120
+ execSync(`tar -xzf "${archivePath}" -C "${destDir}"`, { stdio: 'inherit' });
121
+ }
122
+ }
123
+
124
+ async function main() {
125
+ const platformInfo = getPlatformInfo();
126
+ const binDir = path.join(__dirname, 'bin');
127
+ const binaryPath = path.join(binDir, platformInfo.binary);
128
+ const extractedPath = path.join(binDir, platformInfo.extractedName);
129
+
130
+ // Skip if binary already exists
131
+ if (fs.existsSync(binaryPath)) {
132
+ console.log('agnix binary already installed');
133
+ return;
134
+ }
135
+
136
+ // Ensure bin directory exists
137
+ if (!fs.existsSync(binDir)) {
138
+ fs.mkdirSync(binDir, { recursive: true });
139
+ }
140
+
141
+ const downloadUrl = `https://github.com/${GITHUB_REPO}/releases/download/v${VERSION}/${platformInfo.asset}`;
142
+ const archivePath = path.join(binDir, platformInfo.asset);
143
+
144
+ console.log(`Downloading agnix v${VERSION} for ${os.platform()}-${os.arch()}...`);
145
+
146
+ try {
147
+ await downloadFile(downloadUrl, archivePath);
148
+ console.log('Extracting...');
149
+ extractArchive(archivePath, binDir);
150
+
151
+ // Clean up archive
152
+ fs.unlinkSync(archivePath);
153
+
154
+ // Rename extracted binary to avoid conflict with wrapper script
155
+ if (fs.existsSync(extractedPath) && extractedPath !== binaryPath) {
156
+ fs.renameSync(extractedPath, binaryPath);
157
+ }
158
+
159
+ // Make binary executable on Unix
160
+ if (os.platform() !== 'win32') {
161
+ fs.chmodSync(binaryPath, 0o755);
162
+ }
163
+
164
+ // Verify binary exists
165
+ if (!fs.existsSync(binaryPath)) {
166
+ throw new Error('Binary not found after extraction');
167
+ }
168
+
169
+ console.log('agnix installed successfully');
170
+ } catch (error) {
171
+ console.error(`Failed to install agnix: ${error.message}`);
172
+ console.error('');
173
+ console.error('You can install manually:');
174
+ console.error(' cargo install agnix-cli');
175
+ process.exit(1);
176
+ }
177
+ }
178
+
179
+ main();
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "agnix",
3
+ "version": "0.7.0",
4
+ "description": "Linter for AI agent configurations. Validates SKILL.md, CLAUDE.md, hooks, MCP, and more.",
5
+ "keywords": [
6
+ "agent",
7
+ "linter",
8
+ "claude",
9
+ "claude-code",
10
+ "mcp",
11
+ "model-context-protocol",
12
+ "skills",
13
+ "validation",
14
+ "cursor",
15
+ "copilot",
16
+ "codex",
17
+ "ai"
18
+ ],
19
+ "homepage": "https://github.com/avifenesh/agnix",
20
+ "bugs": {
21
+ "url": "https://github.com/avifenesh/agnix/issues"
22
+ },
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/avifenesh/agnix.git"
26
+ },
27
+ "license": "MIT OR Apache-2.0",
28
+ "author": "Avi Fenesh <avifenesh@gmail.com>",
29
+ "bin": {
30
+ "agnix": "bin/agnix"
31
+ },
32
+ "main": "index.js",
33
+ "files": [
34
+ "bin/",
35
+ "install.js",
36
+ "index.js",
37
+ "README.md"
38
+ ],
39
+ "scripts": {
40
+ "postinstall": "node install.js",
41
+ "test": "node test/test.js"
42
+ },
43
+ "engines": {
44
+ "node": ">=16.0.0"
45
+ },
46
+ "os": [
47
+ "darwin",
48
+ "linux",
49
+ "win32"
50
+ ],
51
+ "cpu": [
52
+ "x64",
53
+ "arm64"
54
+ ]
55
+ }