naider 1.20.0 → 1.21.1

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 CHANGED
@@ -77,6 +77,9 @@ naide pkg install <name> # Install a NAIDE package
77
77
  naide pkg publish # Publish package to npm
78
78
  naide -w <file> # Watch mode (auto-restart on changes)
79
79
  naide -d <file> # Debug mode (Node.js inspector)
80
+ naide ~~ "instruction" # Generate NAIDE code from natural language
81
+ naide gen "instruction" # Same as ~~ (alias)
82
+ naide --expand <file> # Show ~~ directive expansion results
80
83
  naide --emit <file> # Print generated JavaScript
81
84
  naide -o <out.js> <file> # Write JavaScript to file
82
85
  naide --mid <file.nx> # Show intermediate NAIDE v1 (debug X mode)
@@ -84,11 +87,80 @@ naide --ast <file> # Print AST
84
87
  naide --tokens <file> # Print token stream
85
88
  ```
86
89
 
90
+ ### Code Generation (`~~`)
91
+
92
+ Generate valid NAIDE code from natural language instructions — no AI, no network, no dependencies. Pure pattern matching + template composition with self-healing parser validation. Multi-entity support with automatic relationship detection, paginated CRUD, soft delete, batch operations, nested routes, seed data, tests, and full project scaffolding.
93
+
94
+ ```bash
95
+ # Single entity
96
+ naide ~~ "REST API for users with auth"
97
+ naide ~~ "todo app with database"
98
+
99
+ # Multi-entity (auto-detects relationships, injects foreign keys)
100
+ naide ~~ "users and products and orders with auth"
101
+
102
+ # Composite presets
103
+ naide ~~ "shop" # User + Product + Order
104
+ naide ~~ "crm" # User + Contact + Deal + Activity
105
+ naide ~~ "sns" # User + Post + Comment + Message + Notification
106
+ naide ~~ "booking" # User + Event + Reservation
107
+
108
+ # Project mode (generates full directory)
109
+ naide ~~ "e-commerce app with auth" --project
110
+
111
+ # File write mode (merge into existing file)
112
+ naide ~~ "REST API for users" --write app.naide
113
+
114
+ # Japanese
115
+ naide ~~ "ECサイト"
116
+ naide ~~ "ユーザー管理APIを認証付きで"
117
+ ```
118
+
119
+ Generated routes per entity: paginated list, CRUD, soft delete, restore, batch create/delete, nested routes (from relationships), file upload, webhooks. With auth: register, login, profile, admin stats, audit log.
120
+
121
+ Project mode (`--project`) generates: `app.naide`, `package.json`, `.env`, `Dockerfile`, `README.md`, `openapi.json`, `admin.html`, `client.mjs`.
122
+
123
+ API usage:
124
+
125
+ ```javascript
126
+ import { generate, generateProject } from 'naider';
127
+
128
+ const result = generate("users and products with auth");
129
+ console.log(result.entities); // ['User', 'Product']
130
+ console.log(result.relationships); // [{parent:'User', child:'Product', fk:'user_id'}]
131
+ console.log(result.valid); // true
132
+ console.log(result.analysis); // {entities, relationships, plan, ...}
133
+
134
+ const project = generateProject("e-commerce with auth");
135
+ project.files.forEach(f => console.log(f.path));
136
+ ```
137
+
138
+ **Self-healing**: Generated code is validated against the actual NAIDE parser. Parse errors are auto-fixed (up to 5 retries) — missing colons, indent issues, reserved keyword conflicts.
139
+
140
+ **Field normalization**: Smart aliases — `e-mail` → `email`, `pwd` → `password`, `tel` → `phone`, `desc` → `description`. Field types are auto-inferred from names (`email` → `str + email`, `age` → `int`, `done` → `bool`).
141
+
142
+ <details>
143
+ <summary>Keyword Cheat Sheet</summary>
144
+
145
+ | Category | Keywords |
146
+ |----------|----------|
147
+ | Intent | `server` `api` `rest` `bot` `cli` `page` `test` `database` `ai` `crud` `auth` `websocket` `mail` `graphql` |
148
+ | Composite | `todo` `blog` `chat` `shop` `fullstack` `board` `crm` `inventory` `booking` `sns` |
149
+ | Platform | `discord` `slack` `telegram` `line` |
150
+ | DB Type | `sqlite` `postgres` |
151
+ | JP Intent | `サーバー` `認証` `ログイン` `会員` `CRUD` `管理` `データベース` `ボット` `テスト` `ページ` `メール` |
152
+ | JP Entity | `ユーザー` `商品` `記事` `タスク` `注文` `コメント` `イベント` `問い合わせ` `通知` `カテゴリ` `掲示板` `決済` `予約` `社員` |
153
+ | JP Composite | `管理システム` `やることリスト` `ブログ` `チャットアプリ` `ECサイト` `掲示板` |
154
+ | NL Phrases | `"users can comment"` `"admin manage"` `"upload"` `"search"` `"notification"` `"deploy"` `"seed"` |
155
+ | Fields | `"with name email age"` — auto-inferred types & validators |
156
+
157
+ </details>
158
+
87
159
  ### REPL
88
160
 
89
161
  ```
90
162
  $ naide
91
- NAIDE REPL v1.11.0 — type NAIDE code, see JavaScript output
163
+ NAIDE REPL v1.21.0 — type NAIDE code, see JavaScript output
92
164
  Type .exit to quit, .eval to toggle eval mode
93
165
 
94
166
  >>> str name = "hello"
package/bin/naide.js CHANGED
@@ -8,7 +8,7 @@ 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';
11
+ const NAIDE_VERSION = '1.21.1';
12
12
 
13
13
  function crashReport(err, context = {}) {
14
14
  const info = [
@@ -114,6 +114,9 @@ const flags = {
114
114
  check: false,
115
115
  target: 'node',
116
116
  expand: false,
117
+ project: false,
118
+ write: null,
119
+ replace: false,
117
120
  };
118
121
 
119
122
  const files = [];
@@ -133,6 +136,9 @@ for (let i = 0; i < args.length; i++) {
133
136
  case '--check': flags.check = true; flags.run = false; break;
134
137
  case '--target': case '-t': flags.target = args[++i]; break;
135
138
  case '--expand': flags.expand = true; flags.run = false; break;
139
+ case '--project': case '-p': flags.project = true; break;
140
+ case '--write': flags.write = args[++i]; break;
141
+ case '--replace': flags.replace = true; break;
136
142
  default: files.push(arg);
137
143
  }
138
144
  }
@@ -142,25 +148,41 @@ if (files[0] === 'gen' || files[0] === '~~') {
142
148
  const instruction = files.slice(1).join(' ');
143
149
  if (!instruction) {
144
150
  console.log(`
145
- NAIDE Code Generator (~~)
151
+ NAIDE Agent Coder (~~)
146
152
 
147
153
  Usage:
148
154
  naide ~~ "REST API for users with auth"
149
155
  naide gen "todo app with database"
150
- naide gen "Discord bot with hello command"
156
+ naide gen "users and products and orders with auth"
157
+ naide ~~ "ECサイト" --project
151
158
 
152
- Generates valid NAIDE code from natural language instructions.
153
- No AI, no network — pure pattern matching with self-healing validation.
159
+ Autonomous code generator with analysis, multi-entity support,
160
+ relationship detection, and full auth routes. No AI, no network.
154
161
 
155
162
  Examples:
156
163
  naide ~~ "REST API for products with name price stock"
157
- naide ~~ "blog app with auth and database"
164
+ naide ~~ "users and products with auth" # multi-entity
165
+ naide ~~ "SNS app" # User+Post+Comment
166
+ naide ~~ "ECサイト" # User+Product+Order
167
+ naide ~~ "予約システム" # User+Reservation
158
168
  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 ~~ "掲示板アプリ"
169
+ naide ~~ "ユーザーと商品と注文の管理APIを認証付きで" # JP multi-entity
170
+
171
+ Project Mode (--project):
172
+ naide ~~ "e-commerce app with auth" --project
173
+ # Creates: app.naide, package.json, .env, .gitignore,
174
+ # Dockerfile, .dockerignore, README.md, openapi.json,
175
+ # admin.html, client.mjs
176
+
177
+ Update existing project (re-run --project in same dir):
178
+ naide ~~ "add users with auth" --project -o my-app
179
+ naide ~~ "add products" --project -o my-app
180
+ # Merges new entities, regenerates all supporting files
181
+
182
+ File Write Mode:
183
+ naide ~~ "add auth" app.naide # merge into existing file
184
+ naide ~~ "add websocket" --write app.naide # explicit --write
185
+ naide ~~ "REST API" --write app.naide --replace # overwrite file
164
186
 
165
187
  In .naide files:
166
188
  ~~ "REST API for users with auth"
@@ -170,15 +192,18 @@ if (files[0] === 'gen' || files[0] === '~~') {
170
192
  naide --expand app.naide Show ~~ expansion results
171
193
 
172
194
  API:
173
- import { generate } from 'naider';
174
- const result = generate("REST API for users");
175
- console.log(result.code);
195
+ import { generate, generateProject, writeToFile } from 'naider';
196
+ const result = generate("users and products with auth");
197
+ console.log(result.analysis); // agent analysis
198
+ console.log(result.entities); // ['User', 'Product']
199
+ writeToFile("app.naide", "add auth"); // merge into file
176
200
 
177
201
  ── Keyword Cheat Sheet ──────────────────────────────────────
178
202
 
179
203
  Intent server, api, rest, bot, cli, page, test, database,
180
204
  ai, crud, auth, websocket, mail, graphql
181
- Composite todo, blog, chat, shop, fullstack, board
205
+ Composite todo, blog, chat, shop, fullstack, board,
206
+ crm, inventory, booking, sns
182
207
  Platform discord, slack, telegram, line
183
208
  DB Type sqlite, postgres
184
209
  JP Intent サーバー, 認証, ログイン, 会員, CRUD, 管理, データベース,
@@ -187,25 +212,130 @@ if (files[0] === 'gen' || files[0] === '~~') {
187
212
  問い合わせ, 通知, カテゴリ, プロジェクト, 掲示板, 決済
188
213
  Fields "with name email age" — auto-inferred types & validators
189
214
  Field Alias e-mail→email, pwd→password, tel→phone, desc→description
215
+ Relations Auto-detected: User→Post, User→Order, Product→Order, etc.
190
216
 
191
217
  ────────────────────────────────────────────────────────────
192
218
  `);
193
219
  process.exit(0);
194
220
  }
195
221
 
196
- const { generate } = await import('../src/gen.js');
222
+ const { generate, generateProject, updateProject, writeToFile } = await import('../src/gen.js');
223
+
224
+ // Write mode: inject into existing .naide/.nx file
225
+ const targetFile = instruction.match(/\S+\.(?:naide|nx)$/)?.[0];
226
+ if (targetFile || flags.write) {
227
+ const file = flags.write || targetFile;
228
+ const cleanInstruction = targetFile ? instruction.replace(/\s+\S+\.(?:naide|nx)$/, '') : instruction;
229
+ const mode = flags.replace ? 'replace' : 'append';
230
+ const result = writeToFile(resolve(file), cleanInstruction, { mode });
231
+ const a = result.analysis;
232
+ process.stderr.write('\n ── NAIDE Agent ──────────────────────────────────────────\n');
233
+ process.stderr.write(` Input: "${a.instruction}"\n`);
234
+ process.stderr.write(` Action: ${result.action} → ${file}\n`);
235
+ if (a.entities.length > 0) {
236
+ process.stderr.write(` Entities: ${a.entities.map(e => `${e.name} (${e.fieldCount} fields)`).join(', ')}\n`);
237
+ }
238
+ process.stderr.write(' ────────────────────────────────────────────────────────\n\n');
239
+ console.log(result.code);
240
+ process.stderr.write(` ── ${result.action}: ${file} (valid: ${result.valid}) ──\n`);
241
+ process.exit(0);
242
+ }
243
+
244
+ // Project mode: generate or update project directory
245
+ if (flags.project) {
246
+ const isCurrentDir = instruction === '.' || instruction === './';
247
+ let dir, result;
248
+
249
+ if (isCurrentDir) {
250
+ // naide gen . --project → update current directory
251
+ dir = '.';
252
+ const outDir = resolve(dir);
253
+ if (!existsSync(resolve(outDir, 'app.naide'))) {
254
+ process.stderr.write(' Error: no app.naide found in current directory.\n');
255
+ process.stderr.write(' Use naide ~~ "instruction" --project to create a new project.\n');
256
+ process.exit(1);
257
+ }
258
+ process.stderr.write(' Error: use naide ~~ "instruction" --project in an existing project dir to update.\n');
259
+ process.exit(1);
260
+ }
261
+
262
+ const primaryGuess = instruction.split(/\s+/)[0].toLowerCase().replace(/[^a-z0-9]/g, '') || 'app';
263
+ dir = flags.output || (primaryGuess + '-app');
264
+ const outDir = resolve(dir);
265
+ const isUpdate = existsSync(resolve(outDir, 'app.naide'));
266
+
267
+ if (isUpdate) {
268
+ result = updateProject(outDir, instruction);
269
+ } else {
270
+ result = generateProject(instruction);
271
+ }
272
+
273
+ const primaryName = (result.entities[0] || 'app').toLowerCase().replace(/[^a-z0-9]/g, '');
274
+ if (!flags.output && !isUpdate) dir = primaryName + '-app';
275
+ const finalDir = resolve(dir);
276
+ if (!existsSync(finalDir)) mkdirSync(finalDir, { recursive: true });
277
+ for (const f of result.files) {
278
+ const fp = resolve(finalDir, f.path);
279
+ writeFileSync(fp, f.content, 'utf-8');
280
+ }
281
+ const a = result.analysis;
282
+ const mode = isUpdate ? 'Updated' : 'Created';
283
+ process.stderr.write(`\n ── NAIDE Agent (${mode}) ────────────────────────────────\n`);
284
+ process.stderr.write(` Input: "${a.instruction}"\n`);
285
+ if (a.entities.length > 0) {
286
+ process.stderr.write(` Entities: ${a.entities.map(e => `${e.name} (${e.fieldCount} fields)`).join(', ')}\n`);
287
+ }
288
+ if (a.relationships && a.relationships.length > 0) {
289
+ for (const r of a.relationships) process.stderr.write(` Relation: ${r.parent} 1→N ${r.child} (${r.fk})\n`);
290
+ }
291
+ if (a.added && a.added.length > 0) {
292
+ process.stderr.write(` Added: ${a.added.join(', ')}\n`);
293
+ }
294
+ process.stderr.write(` Plan:\n`);
295
+ for (const step of a.plan) process.stderr.write(` + ${step}\n`);
296
+ process.stderr.write(' ────────────────────────────────────────────────────────\n\n');
297
+ console.log(` Project ${isUpdate ? 'updated' : 'created'}: ${dir}/`);
298
+ for (const f of result.files) console.log(` ${f.path}`);
299
+ if (!isUpdate) console.log(`\n cd ${dir} && npm install && npm run dev\n`);
300
+ else console.log(`\n Files regenerated. Run: npm run dev\n`);
301
+ process.exit(0);
302
+ }
303
+
197
304
  const result = generate(instruction);
198
305
 
199
306
  if (flags.output) {
200
307
  writeFileSync(flags.output, result.code, 'utf-8');
201
308
  console.log(` Generated: ${flags.output} (${result.intents.join(' + ')})`);
202
309
  } else {
310
+ // Agent-style analysis header
311
+ const a = result.analysis;
312
+ process.stderr.write('\n ── NAIDE Agent ──────────────────────────────────────────\n');
313
+ process.stderr.write(` Input: "${a.instruction}"\n`);
314
+ if (a.entities.length > 0) {
315
+ process.stderr.write(` Entities: ${a.entities.map(e => `${e.name} (${e.fieldCount} fields)`).join(', ')}\n`);
316
+ }
317
+ if (a.relationships.length > 0) {
318
+ for (const r of a.relationships) {
319
+ process.stderr.write(` Relation: ${r.parent} 1→N ${r.child} (${r.fk})\n`);
320
+ }
321
+ }
322
+ process.stderr.write(` Plan:\n`);
323
+ for (const step of a.plan) {
324
+ process.stderr.write(` + ${step}\n`);
325
+ }
326
+ process.stderr.write(' ────────────────────────────────────────────────────────\n\n');
327
+
203
328
  console.log(result.code);
329
+
204
330
  const meta = [`[${result.intents.join(' + ')}]`];
205
- if (result.schema) meta.push(`→ ${result.schema}`);
331
+ if (result.entities && result.entities.length > 1) {
332
+ meta.push(`→ ${result.entities.join(', ')}`);
333
+ } else if (result.schema) {
334
+ meta.push(`→ ${result.schema}`);
335
+ }
206
336
  meta.push(`valid: ${result.valid}`);
207
337
  if (result.fixed) meta.push('(auto-fixed)');
208
- process.stderr.write(`\n ── gen ~~ ${meta.join(' ')} ──\n`);
338
+ process.stderr.write(` ── gen ~~ ${meta.join(' ')} ──\n`);
209
339
  if (result.repairs.length > 0) {
210
340
  process.stderr.write(' Repairs:\n');
211
341
  for (const r of result.repairs) process.stderr.write(` - ${r}\n`);
package/mcp/server.js CHANGED
@@ -192,7 +192,7 @@ async function handleMessage(msg) {
192
192
  respond(msg.id, {
193
193
  protocolVersion: '2024-11-05',
194
194
  capabilities: { tools: {} },
195
- serverInfo: { name: 'naide-mcp', version: '1.20.0' }
195
+ serverInfo: { name: 'naide-mcp', version: '1.21.1' }
196
196
  });
197
197
  break;
198
198
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "naider",
3
- "version": "1.20.0",
3
+ "version": "1.21.1",
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": {