naider 1.18.0 → 1.20.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/bin/naide.js +218 -6
- package/mcp/server.js +249 -0
- package/package.json +4 -2
- package/src/gen.js +731 -0
- package/src/index.js +8 -1
- package/src/parser.js +1 -1
package/bin/naide.js
CHANGED
|
@@ -8,6 +8,42 @@ import { spawn } from 'child_process';
|
|
|
8
8
|
import { createRequire } from 'module';
|
|
9
9
|
const _require = createRequire(import.meta.url);
|
|
10
10
|
|
|
11
|
+
const NAIDE_VERSION = '1.20.0';
|
|
12
|
+
|
|
13
|
+
function crashReport(err, context = {}) {
|
|
14
|
+
const info = [
|
|
15
|
+
`NAIDE v${NAIDE_VERSION}`,
|
|
16
|
+
`Node ${process.version}`,
|
|
17
|
+
`${process.platform} ${process.arch}`,
|
|
18
|
+
];
|
|
19
|
+
if (context.file) info.push(`File: ${context.file}`);
|
|
20
|
+
if (context.target) info.push(`Target: ${context.target}`);
|
|
21
|
+
|
|
22
|
+
console.error(`\n ┌─ NAIDE Internal Error ───────────────────────────`);
|
|
23
|
+
console.error(` │ ${err.message}`);
|
|
24
|
+
console.error(` │`);
|
|
25
|
+
console.error(` │ ${info.join(' | ')}`);
|
|
26
|
+
if (err.stack) {
|
|
27
|
+
const frames = err.stack.split('\n').slice(1, 4).map(l => l.trim());
|
|
28
|
+
for (const f of frames) console.error(` │ ${f}`);
|
|
29
|
+
}
|
|
30
|
+
console.error(` │`);
|
|
31
|
+
console.error(` │ This is a compiler bug, not a syntax error.`);
|
|
32
|
+
console.error(` │ Report: https://github.com/irxk/naide/issues/new`);
|
|
33
|
+
console.error(` │ Include the .naide file and the info above.`);
|
|
34
|
+
console.error(` └──────────────────────────────────────────────────\n`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
process.on('uncaughtException', (err) => {
|
|
38
|
+
crashReport(err);
|
|
39
|
+
process.exit(99);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
process.on('unhandledRejection', (reason) => {
|
|
43
|
+
crashReport(reason instanceof Error ? reason : new Error(String(reason)));
|
|
44
|
+
process.exit(99);
|
|
45
|
+
});
|
|
46
|
+
|
|
11
47
|
function checkDependencies(jsCode) {
|
|
12
48
|
const depMap = {
|
|
13
49
|
"from 'express'": { pkg: 'express', reason: 'server' },
|
|
@@ -77,6 +113,7 @@ const flags = {
|
|
|
77
113
|
debug: false,
|
|
78
114
|
check: false,
|
|
79
115
|
target: 'node',
|
|
116
|
+
expand: false,
|
|
80
117
|
};
|
|
81
118
|
|
|
82
119
|
const files = [];
|
|
@@ -95,10 +132,108 @@ for (let i = 0; i < args.length; i++) {
|
|
|
95
132
|
case '--debug': case '-d': flags.debug = true; break;
|
|
96
133
|
case '--check': flags.check = true; flags.run = false; break;
|
|
97
134
|
case '--target': case '-t': flags.target = args[++i]; break;
|
|
135
|
+
case '--expand': flags.expand = true; flags.run = false; break;
|
|
98
136
|
default: files.push(arg);
|
|
99
137
|
}
|
|
100
138
|
}
|
|
101
139
|
|
|
140
|
+
// ── Code Generator (~~) ──
|
|
141
|
+
if (files[0] === 'gen' || files[0] === '~~') {
|
|
142
|
+
const instruction = files.slice(1).join(' ');
|
|
143
|
+
if (!instruction) {
|
|
144
|
+
console.log(`
|
|
145
|
+
NAIDE Code Generator (~~)
|
|
146
|
+
|
|
147
|
+
Usage:
|
|
148
|
+
naide ~~ "REST API for users with auth"
|
|
149
|
+
naide gen "todo app with database"
|
|
150
|
+
naide gen "Discord bot with hello command"
|
|
151
|
+
|
|
152
|
+
Generates valid NAIDE code from natural language instructions.
|
|
153
|
+
No AI, no network — pure pattern matching with self-healing validation.
|
|
154
|
+
|
|
155
|
+
Examples:
|
|
156
|
+
naide ~~ "REST API for products with name price stock"
|
|
157
|
+
naide ~~ "blog app with auth and database"
|
|
158
|
+
naide ~~ "Discord bot with hello and help commands"
|
|
159
|
+
naide ~~ "CLI tool"
|
|
160
|
+
naide ~~ "chat app with websocket"
|
|
161
|
+
naide ~~ "user management fullstack app"
|
|
162
|
+
naide ~~ "ユーザー管理APIを認証付きで"
|
|
163
|
+
naide ~~ "掲示板アプリ"
|
|
164
|
+
|
|
165
|
+
In .naide files:
|
|
166
|
+
~~ "REST API for users with auth"
|
|
167
|
+
# Expands at compile time to full NAIDE code
|
|
168
|
+
|
|
169
|
+
Debug:
|
|
170
|
+
naide --expand app.naide Show ~~ expansion results
|
|
171
|
+
|
|
172
|
+
API:
|
|
173
|
+
import { generate } from 'naider';
|
|
174
|
+
const result = generate("REST API for users");
|
|
175
|
+
console.log(result.code);
|
|
176
|
+
|
|
177
|
+
── Keyword Cheat Sheet ──────────────────────────────────────
|
|
178
|
+
|
|
179
|
+
Intent server, api, rest, bot, cli, page, test, database,
|
|
180
|
+
ai, crud, auth, websocket, mail, graphql
|
|
181
|
+
Composite todo, blog, chat, shop, fullstack, board
|
|
182
|
+
Platform discord, slack, telegram, line
|
|
183
|
+
DB Type sqlite, postgres
|
|
184
|
+
JP Intent サーバー, 認証, ログイン, 会員, CRUD, 管理, データベース,
|
|
185
|
+
ボット, テスト, ページ, メール, リアルタイム
|
|
186
|
+
JP Entity ユーザー, 商品, 記事, タスク, 注文, コメント, イベント,
|
|
187
|
+
問い合わせ, 通知, カテゴリ, プロジェクト, 掲示板, 決済
|
|
188
|
+
Fields "with name email age" — auto-inferred types & validators
|
|
189
|
+
Field Alias e-mail→email, pwd→password, tel→phone, desc→description
|
|
190
|
+
|
|
191
|
+
────────────────────────────────────────────────────────────
|
|
192
|
+
`);
|
|
193
|
+
process.exit(0);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const { generate } = await import('../src/gen.js');
|
|
197
|
+
const result = generate(instruction);
|
|
198
|
+
|
|
199
|
+
if (flags.output) {
|
|
200
|
+
writeFileSync(flags.output, result.code, 'utf-8');
|
|
201
|
+
console.log(` Generated: ${flags.output} (${result.intents.join(' + ')})`);
|
|
202
|
+
} else {
|
|
203
|
+
console.log(result.code);
|
|
204
|
+
const meta = [`[${result.intents.join(' + ')}]`];
|
|
205
|
+
if (result.schema) meta.push(`→ ${result.schema}`);
|
|
206
|
+
meta.push(`valid: ${result.valid}`);
|
|
207
|
+
if (result.fixed) meta.push('(auto-fixed)');
|
|
208
|
+
process.stderr.write(`\n ── gen ~~ ${meta.join(' ')} ──\n`);
|
|
209
|
+
if (result.repairs.length > 0) {
|
|
210
|
+
process.stderr.write(' Repairs:\n');
|
|
211
|
+
for (const r of result.repairs) process.stderr.write(` - ${r}\n`);
|
|
212
|
+
}
|
|
213
|
+
if (result.suggestion) {
|
|
214
|
+
process.stderr.write(`\n${result.suggestion}\n`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
process.exit(0);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// ── Expand Debug ──
|
|
221
|
+
if (flags.expand && files.length > 0) {
|
|
222
|
+
const { expandDirectives } = await import('../src/gen.js');
|
|
223
|
+
for (const file of files) {
|
|
224
|
+
const filePath = resolve(file);
|
|
225
|
+
const source = readFileSync(filePath, 'utf-8');
|
|
226
|
+
const { source: expanded, expanded: didExpand } = expandDirectives(source);
|
|
227
|
+
if (didExpand) {
|
|
228
|
+
console.log(` ── ${file} (expanded) ──\n`);
|
|
229
|
+
console.log(expanded);
|
|
230
|
+
} else {
|
|
231
|
+
console.log(` ${file}: no ~~ directives found`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
process.exit(0);
|
|
235
|
+
}
|
|
236
|
+
|
|
102
237
|
// ── VS Code Extension Install ──
|
|
103
238
|
if (files[0] === 'vscode') {
|
|
104
239
|
const os = await import('os');
|
|
@@ -357,24 +492,67 @@ if (files[0] === 'build') {
|
|
|
357
492
|
|
|
358
493
|
console.log(`\n NAIDE build — ${sourceFiles.length} file(s)\n`);
|
|
359
494
|
let errors = 0;
|
|
495
|
+
const schemaMap = {};
|
|
496
|
+
const routeMap = {};
|
|
497
|
+
|
|
360
498
|
for (const srcFile of sourceFiles) {
|
|
361
499
|
const rel = relative(dir, srcFile);
|
|
362
500
|
const mode = srcFile.endsWith('.nx') ? 'x' : 'naide';
|
|
363
501
|
try {
|
|
364
502
|
const source = readFileSync(srcFile, 'utf-8');
|
|
365
|
-
const { js } = compile(source, { mode });
|
|
503
|
+
const { js, ast } = compile(source, { mode });
|
|
366
504
|
const outName = rel.replace(/\.(naide|nx)$/, '.mjs');
|
|
367
505
|
const outPath = outDir ? join(outDir, outName) : join(dir, outName);
|
|
368
506
|
const outDirPath = resolve(outPath, '..');
|
|
369
507
|
if (!existsSync(outDirPath)) mkdirSync(outDirPath, { recursive: true });
|
|
370
508
|
writeFileSync(outPath, js);
|
|
371
509
|
console.log(` ${rel} → ${outDir ? join(relative('.', outDir), outName) : outName}`);
|
|
510
|
+
|
|
511
|
+
if (ast && ast.body) {
|
|
512
|
+
for (const node of ast.body) {
|
|
513
|
+
if (node.type === 'SchemaDecl' && node.name) {
|
|
514
|
+
(schemaMap[node.name] = schemaMap[node.name] || []).push(rel);
|
|
515
|
+
}
|
|
516
|
+
if (node.type === 'Server' && node.routes) {
|
|
517
|
+
for (const s of node.routes) {
|
|
518
|
+
if (s.type === 'CrudDecl' && s.path) {
|
|
519
|
+
const key = `CRUD ${s.path.raw || s.path}`;
|
|
520
|
+
(routeMap[key] = routeMap[key] || []).push(rel);
|
|
521
|
+
}
|
|
522
|
+
if (s.type === 'Route' && s.path) {
|
|
523
|
+
const key = `${(s.method || 'get').toUpperCase()} ${s.path.raw || s.path}`;
|
|
524
|
+
(routeMap[key] = routeMap[key] || []).push(rel);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
372
530
|
} catch (e) {
|
|
373
|
-
|
|
531
|
+
const isSyntaxErr = e.message.includes('line ') || e.message.includes('Unexpected') || e.message.includes('Expected');
|
|
532
|
+
if (isSyntaxErr) {
|
|
533
|
+
console.error(` FAIL ${rel}: ${e.message.split('\n')[0]}`);
|
|
534
|
+
} else {
|
|
535
|
+
crashReport(e, { file: rel });
|
|
536
|
+
}
|
|
374
537
|
errors++;
|
|
375
538
|
}
|
|
376
539
|
}
|
|
377
|
-
|
|
540
|
+
|
|
541
|
+
let warnings = 0;
|
|
542
|
+
for (const [name, files] of Object.entries(schemaMap)) {
|
|
543
|
+
if (files.length > 1) {
|
|
544
|
+
console.error(` WARN: schema "${name}" defined in ${files.length} files: ${files.join(', ')}`);
|
|
545
|
+
warnings++;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
for (const [route, files] of Object.entries(routeMap)) {
|
|
549
|
+
if (files.length > 1) {
|
|
550
|
+
console.error(` WARN: route ${route} defined in ${files.length} files: ${files.join(', ')}`);
|
|
551
|
+
warnings++;
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
console.log(`\n Done. ${sourceFiles.length - errors} compiled, ${errors} failed${warnings > 0 ? `, ${warnings} warning(s)` : ''}.`);
|
|
378
556
|
process.exit(errors > 0 ? 1 : 0);
|
|
379
557
|
}
|
|
380
558
|
|
|
@@ -664,6 +842,8 @@ if (flags.help) {
|
|
|
664
842
|
naide Start interactive REPL
|
|
665
843
|
naide <file.naide> Run a NAIDE file
|
|
666
844
|
naide <file.nx> Run a NAIDE-X file (auto-detected)
|
|
845
|
+
naide ~~ "instruction" Generate NAIDE code from instruction (no AI)
|
|
846
|
+
naide gen "instruction" Same as ~~ (alias)
|
|
667
847
|
naide init [dir] Create a new NAIDE project
|
|
668
848
|
naide build [dir] [outdir] Transpile all files to JavaScript
|
|
669
849
|
naide check <files...> Type-check without running
|
|
@@ -683,10 +863,28 @@ if (flags.help) {
|
|
|
683
863
|
naide -w <file.naide> Watch mode (auto-restart on changes)
|
|
684
864
|
naide -d <file> Debug mode (Node.js inspector)
|
|
685
865
|
|
|
686
|
-
|
|
866
|
+
Code Generation (~~):
|
|
867
|
+
naide ~~ "instruction" Generate code from instruction (no AI)
|
|
868
|
+
naide gen "instruction" Alias for ~~
|
|
869
|
+
naide --expand <file> Show ~~ directive expansion results
|
|
870
|
+
In .naide files: ~~ "instruction" expands at compile time
|
|
871
|
+
|
|
872
|
+
Targets (15):
|
|
687
873
|
node Node.js / JavaScript (default)
|
|
688
874
|
bun Bun-optimized JavaScript
|
|
689
|
-
|
|
875
|
+
ts TypeScript
|
|
876
|
+
python Python (Flask)
|
|
877
|
+
go Go (net/http)
|
|
878
|
+
java Java (HttpServer)
|
|
879
|
+
rust Rust (actix-web)
|
|
880
|
+
cpp C++ (cpp-httplib)
|
|
881
|
+
c C (libmicrohttpd)
|
|
882
|
+
csharp C# (ASP.NET)
|
|
883
|
+
kotlin Kotlin (Ktor)
|
|
884
|
+
swift Swift (Vapor)
|
|
885
|
+
dart Dart (shelf)
|
|
886
|
+
php PHP
|
|
887
|
+
ruby Ruby (Sinatra)
|
|
690
888
|
|
|
691
889
|
Modes:
|
|
692
890
|
.naide Standard NAIDE (~40% fewer tokens than JS)
|
|
@@ -701,9 +899,18 @@ if (flags.help) {
|
|
|
701
899
|
-t, --target Compile target: node (default), bun, python/py
|
|
702
900
|
--check Type-check files without running
|
|
703
901
|
--mid Show intermediate NAIDE v1 (X mode only)
|
|
902
|
+
--expand Show ~~ directive expansion (debug)
|
|
704
903
|
--ast Print AST
|
|
705
904
|
--tokens Print tokens
|
|
706
905
|
-h, --help Show this help
|
|
906
|
+
|
|
907
|
+
~~ Keyword Cheat Sheet:
|
|
908
|
+
Intent server api rest bot cli page test database ai crud auth ws mail graphql
|
|
909
|
+
Composite todo blog chat shop fullstack board
|
|
910
|
+
Platform discord slack telegram line
|
|
911
|
+
JP Intent サーバー 認証 ログイン 会員 CRUD 管理 データベース ボット テスト ページ
|
|
912
|
+
JP Entity ユーザー 商品 記事 タスク 注文 コメント イベント 問い合わせ 掲示板 決済
|
|
913
|
+
Fields "with name email age done" → auto-inferred types
|
|
707
914
|
`);
|
|
708
915
|
process.exit(0);
|
|
709
916
|
}
|
|
@@ -872,7 +1079,12 @@ for (const file of files) {
|
|
|
872
1079
|
} catch {}
|
|
873
1080
|
}
|
|
874
1081
|
} catch (err) {
|
|
875
|
-
|
|
1082
|
+
const isSyntaxErr = err.message.includes('line ') || err.message.includes('Unexpected') || err.message.includes('Expected');
|
|
1083
|
+
if (isSyntaxErr) {
|
|
1084
|
+
console.error(`\n${err.message}`);
|
|
1085
|
+
} else {
|
|
1086
|
+
crashReport(err, { file, target: flags.target });
|
|
1087
|
+
}
|
|
876
1088
|
if (process.env.NAIDE_DEBUG) console.error(err.stack);
|
|
877
1089
|
process.exit(1);
|
|
878
1090
|
}
|
package/mcp/server.js
ADDED
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { createInterface } from 'readline';
|
|
4
|
+
import { resolve, dirname } from 'path';
|
|
5
|
+
import { readFileSync } from 'fs';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
|
|
10
|
+
let compileModule = null;
|
|
11
|
+
async function getCompiler() {
|
|
12
|
+
if (!compileModule) {
|
|
13
|
+
compileModule = await import(resolve(__dirname, '..', 'src', 'index.js'));
|
|
14
|
+
}
|
|
15
|
+
return compileModule;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function send(msg) {
|
|
19
|
+
const json = JSON.stringify(msg);
|
|
20
|
+
const buf = Buffer.from(json, 'utf-8');
|
|
21
|
+
process.stdout.write(`Content-Length: ${buf.length}\r\n\r\n`);
|
|
22
|
+
process.stdout.write(buf);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function respond(id, result) {
|
|
26
|
+
send({ jsonrpc: '2.0', id, result });
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function respondError(id, code, message) {
|
|
30
|
+
send({ jsonrpc: '2.0', id, error: { code, message } });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const TOOLS = [
|
|
34
|
+
{
|
|
35
|
+
name: 'naide_compile',
|
|
36
|
+
description: 'Compile NAIDE code to a target language. NAIDE is an AI-optimized language that transpiles to 15 targets.',
|
|
37
|
+
inputSchema: {
|
|
38
|
+
type: 'object',
|
|
39
|
+
properties: {
|
|
40
|
+
code: { type: 'string', description: 'NAIDE source code to compile' },
|
|
41
|
+
target: {
|
|
42
|
+
type: 'string',
|
|
43
|
+
description: 'Target language (default: node)',
|
|
44
|
+
enum: ['node', 'python', 'bun', 'typescript', 'go', 'java', 'rust', 'cpp', 'c', 'csharp', 'kotlin', 'swift', 'dart', 'php', 'ruby']
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
required: ['code']
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: 'naide_run',
|
|
52
|
+
description: 'Compile NAIDE code to JavaScript and execute it. Returns stdout output.',
|
|
53
|
+
inputSchema: {
|
|
54
|
+
type: 'object',
|
|
55
|
+
properties: {
|
|
56
|
+
code: { type: 'string', description: 'NAIDE source code to run' }
|
|
57
|
+
},
|
|
58
|
+
required: ['code']
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: 'naide_targets',
|
|
63
|
+
description: 'List all available NAIDE compilation targets with details.',
|
|
64
|
+
inputSchema: { type: 'object', properties: {} }
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: 'naide_generate',
|
|
68
|
+
description: 'Generate NAIDE code from a natural language instruction. No AI — uses pattern matching and template composition with self-healing parser validation. Extremely lightweight, runs in microseconds.',
|
|
69
|
+
inputSchema: {
|
|
70
|
+
type: 'object',
|
|
71
|
+
properties: {
|
|
72
|
+
instruction: { type: 'string', description: 'Natural language instruction (e.g. "REST API for users with auth", "Discord bot", "todo app")' },
|
|
73
|
+
port: { type: 'number', description: 'Server port (default: 3000)' },
|
|
74
|
+
schemaName: { type: 'string', description: 'Override schema/entity name' }
|
|
75
|
+
},
|
|
76
|
+
required: ['instruction']
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: 'naide_spec',
|
|
81
|
+
description: 'Get the NAIDE language specification. Use this to understand NAIDE syntax before writing code.',
|
|
82
|
+
inputSchema: {
|
|
83
|
+
type: 'object',
|
|
84
|
+
properties: {
|
|
85
|
+
section: {
|
|
86
|
+
type: 'string',
|
|
87
|
+
description: 'Optional section to retrieve (e.g. "variables", "functions", "server"). Omit for full spec.'
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
];
|
|
93
|
+
|
|
94
|
+
const TARGETS_INFO = [
|
|
95
|
+
{ name: 'node', language: 'JavaScript (ES Modules)', server: 'Express', flag: 'default' },
|
|
96
|
+
{ name: 'python', language: 'Python', server: 'Flask', flag: '--target python' },
|
|
97
|
+
{ name: 'bun', language: 'JavaScript (Bun)', server: 'Bun.serve', flag: '--target bun' },
|
|
98
|
+
{ name: 'typescript', language: 'TypeScript', server: 'Express', flag: '--target ts' },
|
|
99
|
+
{ name: 'go', language: 'Go', server: 'net/http', flag: '--target go' },
|
|
100
|
+
{ name: 'java', language: 'Java', server: 'HttpServer', flag: '--target java' },
|
|
101
|
+
{ name: 'rust', language: 'Rust', server: 'actix-web', flag: '--target rust' },
|
|
102
|
+
{ name: 'cpp', language: 'C++', server: 'cpp-httplib', flag: '--target cpp' },
|
|
103
|
+
{ name: 'c', language: 'C', server: 'libmicrohttpd', flag: '--target c' },
|
|
104
|
+
{ name: 'csharp', language: 'C#', server: 'ASP.NET', flag: '--target csharp' },
|
|
105
|
+
{ name: 'kotlin', language: 'Kotlin', server: 'Ktor', flag: '--target kotlin' },
|
|
106
|
+
{ name: 'swift', language: 'Swift', server: 'Vapor', flag: '--target swift' },
|
|
107
|
+
{ name: 'dart', language: 'Dart', server: 'shelf', flag: '--target dart' },
|
|
108
|
+
{ name: 'php', language: 'PHP', server: 'Built-in / Laravel', flag: '--target php' },
|
|
109
|
+
{ name: 'ruby', language: 'Ruby', server: 'Sinatra', flag: '--target ruby' },
|
|
110
|
+
];
|
|
111
|
+
|
|
112
|
+
async function handleToolCall(name, args) {
|
|
113
|
+
const { compile, compileAsync } = await getCompiler();
|
|
114
|
+
|
|
115
|
+
switch (name) {
|
|
116
|
+
case 'naide_compile': {
|
|
117
|
+
const target = args.target || 'node';
|
|
118
|
+
try {
|
|
119
|
+
if (target === 'node') {
|
|
120
|
+
const result = compile(args.code);
|
|
121
|
+
return { content: [{ type: 'text', text: result.js }] };
|
|
122
|
+
}
|
|
123
|
+
const result = await compileAsync(args.code, { target });
|
|
124
|
+
return { content: [{ type: 'text', text: result.code }] };
|
|
125
|
+
} catch (e) {
|
|
126
|
+
return { content: [{ type: 'text', text: `Compilation error: ${e.message}` }], isError: true };
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
case 'naide_run': {
|
|
131
|
+
try {
|
|
132
|
+
const result = compile(args.code);
|
|
133
|
+
const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
|
|
134
|
+
let output = '';
|
|
135
|
+
const fakeConsole = { log: (...a) => { output += a.map(String).join(' ') + '\n'; }, error: (...a) => { output += a.map(String).join(' ') + '\n'; } };
|
|
136
|
+
const fn = new AsyncFunction('console', result.js);
|
|
137
|
+
await fn(fakeConsole);
|
|
138
|
+
return { content: [{ type: 'text', text: output || '(no output)' }] };
|
|
139
|
+
} catch (e) {
|
|
140
|
+
return { content: [{ type: 'text', text: `Error: ${e.message}` }], isError: true };
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
case 'naide_targets': {
|
|
145
|
+
const text = TARGETS_INFO.map(t => `${t.name.padEnd(12)} ${t.language.padEnd(25)} ${t.server.padEnd(20)} ${t.flag}`).join('\n');
|
|
146
|
+
return { content: [{ type: 'text', text: `NAIDE Compilation Targets (15):\n\n${'Target'.padEnd(12)} ${'Language'.padEnd(25)} ${'Server'.padEnd(20)} Flag\n${'─'.repeat(75)}\n${text}` }] };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
case 'naide_generate': {
|
|
150
|
+
try {
|
|
151
|
+
const { generate } = await import(resolve(__dirname, '..', 'src', 'gen.js'));
|
|
152
|
+
const opts = {};
|
|
153
|
+
if (args.port) opts.port = args.port;
|
|
154
|
+
if (args.schemaName) opts.schemaName = args.schemaName;
|
|
155
|
+
const result = generate(args.instruction, opts);
|
|
156
|
+
const meta = `[${result.intents.join(' + ')}]${result.schema ? ` → ${result.schema}` : ''} | valid: ${result.valid}${result.fixed ? ' (auto-fixed)' : ''}`;
|
|
157
|
+
return { content: [{ type: 'text', text: `${result.code}\n# ${meta}` }] };
|
|
158
|
+
} catch (e) {
|
|
159
|
+
return { content: [{ type: 'text', text: `Generation error: ${e.message}` }], isError: true };
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
case 'naide_spec': {
|
|
164
|
+
try {
|
|
165
|
+
let spec = readFileSync(resolve(__dirname, '..', 'SPEC.naide'), 'utf-8');
|
|
166
|
+
if (args.section) {
|
|
167
|
+
const s = args.section.toLowerCase();
|
|
168
|
+
const lines = spec.split('\n');
|
|
169
|
+
const chunks = [];
|
|
170
|
+
let capturing = false;
|
|
171
|
+
for (const line of lines) {
|
|
172
|
+
if (line.startsWith('# ---- ') && line.toLowerCase().includes(s)) capturing = true;
|
|
173
|
+
else if (line.startsWith('# ---- ') && capturing) break;
|
|
174
|
+
if (capturing) chunks.push(line);
|
|
175
|
+
}
|
|
176
|
+
if (chunks.length > 0) spec = chunks.join('\n');
|
|
177
|
+
}
|
|
178
|
+
return { content: [{ type: 'text', text: spec }] };
|
|
179
|
+
} catch (e) {
|
|
180
|
+
return { content: [{ type: 'text', text: `Error reading spec: ${e.message}` }], isError: true };
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
default:
|
|
185
|
+
return { content: [{ type: 'text', text: `Unknown tool: ${name}` }], isError: true };
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async function handleMessage(msg) {
|
|
190
|
+
switch (msg.method) {
|
|
191
|
+
case 'initialize':
|
|
192
|
+
respond(msg.id, {
|
|
193
|
+
protocolVersion: '2024-11-05',
|
|
194
|
+
capabilities: { tools: {} },
|
|
195
|
+
serverInfo: { name: 'naide-mcp', version: '1.20.0' }
|
|
196
|
+
});
|
|
197
|
+
break;
|
|
198
|
+
|
|
199
|
+
case 'notifications/initialized':
|
|
200
|
+
break;
|
|
201
|
+
|
|
202
|
+
case 'tools/list':
|
|
203
|
+
respond(msg.id, { tools: TOOLS });
|
|
204
|
+
break;
|
|
205
|
+
|
|
206
|
+
case 'tools/call':
|
|
207
|
+
try {
|
|
208
|
+
const result = await handleToolCall(msg.params.name, msg.params.arguments || {});
|
|
209
|
+
respond(msg.id, result);
|
|
210
|
+
} catch (e) {
|
|
211
|
+
respondError(msg.id, -32000, e.message);
|
|
212
|
+
}
|
|
213
|
+
break;
|
|
214
|
+
|
|
215
|
+
case 'ping':
|
|
216
|
+
respond(msg.id, {});
|
|
217
|
+
break;
|
|
218
|
+
|
|
219
|
+
default:
|
|
220
|
+
if (msg.id !== undefined) {
|
|
221
|
+
respondError(msg.id, -32601, `Method not found: ${msg.method}`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
let buffer = '';
|
|
227
|
+
process.stdin.setEncoding('utf-8');
|
|
228
|
+
process.stdin.on('data', (chunk) => {
|
|
229
|
+
buffer += chunk;
|
|
230
|
+
while (true) {
|
|
231
|
+
const headerEnd = buffer.indexOf('\r\n\r\n');
|
|
232
|
+
if (headerEnd === -1) break;
|
|
233
|
+
const header = buffer.slice(0, headerEnd);
|
|
234
|
+
const match = header.match(/Content-Length:\s*(\d+)/i);
|
|
235
|
+
if (!match) { buffer = buffer.slice(headerEnd + 4); continue; }
|
|
236
|
+
const len = parseInt(match[1], 10);
|
|
237
|
+
const bodyStart = headerEnd + 4;
|
|
238
|
+
if (buffer.length < bodyStart + len) break;
|
|
239
|
+
const body = buffer.slice(bodyStart, bodyStart + len);
|
|
240
|
+
buffer = buffer.slice(bodyStart + len);
|
|
241
|
+
try {
|
|
242
|
+
handleMessage(JSON.parse(body));
|
|
243
|
+
} catch (e) {
|
|
244
|
+
process.stderr.write(`Parse error: ${e.message}\n`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
process.stderr.write('NAIDE MCP Server running on stdio\n');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "naider",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.20.0",
|
|
4
4
|
"description": "NAIDE - Simpler than Python, compiles to 15 targets. AI-specialized language with 35+ built-in functions, syntax sugar (unless/until/repeat/swap/is/isnt), and 47 features. Targets: Node.js, Python, TypeScript, C, C++, Java, Go, Rust, PHP, Ruby, Kotlin, Swift, Dart, C#, Bun.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -8,13 +8,15 @@
|
|
|
8
8
|
"./runtime": "./src/runtime.js"
|
|
9
9
|
},
|
|
10
10
|
"bin": {
|
|
11
|
-
"naide": "bin/naide.js"
|
|
11
|
+
"naide": "bin/naide.js",
|
|
12
|
+
"naide-mcp": "mcp/server.js"
|
|
12
13
|
},
|
|
13
14
|
"type": "module",
|
|
14
15
|
"files": [
|
|
15
16
|
"bin/",
|
|
16
17
|
"src/",
|
|
17
18
|
"assets/",
|
|
19
|
+
"mcp/",
|
|
18
20
|
"lsp/",
|
|
19
21
|
"examples/",
|
|
20
22
|
"vscode-naide/",
|