outlet-orm 6.5.0 → 7.0.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/init.js +122 -0
- package/bin/mcp.js +78 -0
- package/bin/migrate.js +25 -0
- package/docs/skills/outlet-orm/ADVANCED.md +575 -0
- package/docs/skills/outlet-orm/AI.md +220 -0
- package/docs/skills/outlet-orm/API.md +522 -0
- package/docs/skills/outlet-orm/BACKUP.md +150 -0
- package/docs/skills/outlet-orm/MIGRATIONS.md +605 -0
- package/docs/skills/outlet-orm/MODELS.md +427 -0
- package/docs/skills/outlet-orm/QUERIES.md +345 -0
- package/docs/skills/outlet-orm/RELATIONS.md +555 -0
- package/docs/skills/outlet-orm/SECURITY.md +386 -0
- package/docs/skills/outlet-orm/SEEDS.md +98 -0
- package/docs/skills/outlet-orm/SKILL.md +205 -0
- package/docs/skills/outlet-orm/TYPESCRIPT.md +480 -0
- package/package.json +7 -3
- package/src/AI/AISafetyGuardrails.js +146 -0
- package/src/AI/MCPServer.js +685 -0
- package/src/AI/PromptGenerator.js +318 -0
- package/src/index.js +11 -1
- package/types/index.d.ts +106 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Outlet ORM — Prompt-based Model Generator
|
|
3
|
+
* Parses natural language descriptions and generates models + migrations.
|
|
4
|
+
*
|
|
5
|
+
* Used by `outlet-init --prompt "..."` to bootstrap projects from descriptions.
|
|
6
|
+
*
|
|
7
|
+
* @since 7.0.0
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
|
|
13
|
+
// ─── Domain pattern recognition ──────────────────────────────────
|
|
14
|
+
|
|
15
|
+
const DOMAIN_PATTERNS = {
|
|
16
|
+
// E-commerce
|
|
17
|
+
'e-?commerce|shop|store|product|cart|order|payment|checkout': {
|
|
18
|
+
tables: {
|
|
19
|
+
users: { columns: ['name:string', 'email:string:unique', 'password:string', 'role:string:default(customer)'] },
|
|
20
|
+
products: { columns: ['name:string', 'description:text:nullable', 'price:decimal(10,2)', 'stock:integer:default(0)', 'sku:string:unique', 'category_id:foreignId'] },
|
|
21
|
+
categories: { columns: ['name:string', 'slug:string:unique', 'parent_id:integer:nullable'] },
|
|
22
|
+
orders: { columns: ['user_id:foreignId', 'status:string:default(pending)', 'total:decimal(10,2)', 'shipping_address:text'] },
|
|
23
|
+
order_items:{ columns: ['order_id:foreignId', 'product_id:foreignId', 'quantity:integer', 'price:decimal(10,2)'] },
|
|
24
|
+
payments: { columns: ['order_id:foreignId', 'method:string', 'amount:decimal(10,2)', 'status:string:default(pending)', 'transaction_id:string:nullable'] }
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
// Blog / CMS
|
|
29
|
+
'blog|article|post|cms|content|comment|tag': {
|
|
30
|
+
tables: {
|
|
31
|
+
users: { columns: ['name:string', 'email:string:unique', 'password:string', 'bio:text:nullable', 'avatar:string:nullable'] },
|
|
32
|
+
posts: { columns: ['user_id:foreignId', 'title:string', 'slug:string:unique', 'content:text', 'excerpt:text:nullable', 'status:string:default(draft)', 'published_at:timestamp:nullable'] },
|
|
33
|
+
categories: { columns: ['name:string', 'slug:string:unique', 'description:text:nullable'] },
|
|
34
|
+
tags: { columns: ['name:string', 'slug:string:unique'] },
|
|
35
|
+
post_tag: { columns: ['post_id:foreignId', 'tag_id:foreignId'], pivot: true },
|
|
36
|
+
comments: { columns: ['post_id:foreignId', 'user_id:foreignId:nullable', 'author_name:string:nullable', 'body:text', 'approved:boolean:default(false)'] }
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
// Task / Project management
|
|
41
|
+
'task|project|todo|kanban|board|sprint|ticket': {
|
|
42
|
+
tables: {
|
|
43
|
+
users: { columns: ['name:string', 'email:string:unique', 'password:string', 'avatar:string:nullable'] },
|
|
44
|
+
projects: { columns: ['name:string', 'description:text:nullable', 'owner_id:foreignId', 'status:string:default(active)'] },
|
|
45
|
+
tasks: { columns: ['project_id:foreignId', 'assigned_to:integer:nullable', 'title:string', 'description:text:nullable', 'status:string:default(todo)', 'priority:string:default(medium)', 'due_date:date:nullable'] },
|
|
46
|
+
labels: { columns: ['name:string', 'color:string:default(#3498db)'] },
|
|
47
|
+
task_label: { columns: ['task_id:foreignId', 'label_id:foreignId'], pivot: true }
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
// Social network
|
|
52
|
+
'social|friend|follow|like|feed|profile|message|chat': {
|
|
53
|
+
tables: {
|
|
54
|
+
users: { columns: ['name:string', 'email:string:unique', 'password:string', 'username:string:unique', 'bio:text:nullable', 'avatar:string:nullable'] },
|
|
55
|
+
posts: { columns: ['user_id:foreignId', 'content:text', 'media_url:string:nullable', 'visibility:string:default(public)'] },
|
|
56
|
+
comments: { columns: ['post_id:foreignId', 'user_id:foreignId', 'body:text'] },
|
|
57
|
+
likes: { columns: ['user_id:foreignId', 'likeable_id:integer', 'likeable_type:string'] },
|
|
58
|
+
follows: { columns: ['follower_id:foreignId', 'following_id:foreignId'] },
|
|
59
|
+
messages: { columns: ['sender_id:foreignId', 'receiver_id:foreignId', 'body:text', 'read_at:timestamp:nullable'] }
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
|
|
63
|
+
// SaaS / Multi-tenant
|
|
64
|
+
'saas|tenant|subscription|plan|billing|organization': {
|
|
65
|
+
tables: {
|
|
66
|
+
organizations: { columns: ['name:string', 'slug:string:unique', 'plan_id:foreignId:nullable'] },
|
|
67
|
+
users: { columns: ['organization_id:foreignId', 'name:string', 'email:string:unique', 'password:string', 'role:string:default(member)'] },
|
|
68
|
+
plans: { columns: ['name:string', 'slug:string:unique', 'price:decimal(8,2)', 'features:json:nullable', 'max_users:integer:default(5)'] },
|
|
69
|
+
subscriptions: { columns: ['organization_id:foreignId', 'plan_id:foreignId', 'status:string:default(active)', 'starts_at:timestamp', 'ends_at:timestamp:nullable', 'trial_ends_at:timestamp:nullable'] },
|
|
70
|
+
invoices: { columns: ['subscription_id:foreignId', 'amount:decimal(10,2)', 'status:string:default(pending)', 'paid_at:timestamp:nullable'] }
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
// Habit tracker / Health
|
|
75
|
+
'habit|tracker|health|fitness|goal|streak|log': {
|
|
76
|
+
tables: {
|
|
77
|
+
users: { columns: ['name:string', 'email:string:unique', 'password:string', 'timezone:string:default(UTC)'] },
|
|
78
|
+
habits: { columns: ['user_id:foreignId', 'name:string', 'description:text:nullable', 'frequency:string:default(daily)', 'color:string:default(#3498db)', 'target:integer:default(1)'] },
|
|
79
|
+
logs: { columns: ['habit_id:foreignId', 'date:date', 'completed:boolean:default(false)', 'value:integer:default(0)', 'notes:text:nullable'] },
|
|
80
|
+
goals: { columns: ['user_id:foreignId', 'title:string', 'target_value:integer', 'current_value:integer:default(0)', 'deadline:date:nullable'] }
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
// API / Auth / Generic
|
|
85
|
+
'api|auth|rest|user': {
|
|
86
|
+
tables: {
|
|
87
|
+
users: { columns: ['name:string', 'email:string:unique', 'password:string', 'role:string:default(user)', 'email_verified_at:timestamp:nullable'] },
|
|
88
|
+
tokens: { columns: ['user_id:foreignId', 'token:string:unique', 'type:string:default(api)', 'expires_at:timestamp:nullable'] },
|
|
89
|
+
password_resets:{ columns: ['email:string', 'token:string', 'created_at:timestamp'] }
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// ─── Generator ──────────────────────────────────────────────────
|
|
95
|
+
|
|
96
|
+
class PromptGenerator {
|
|
97
|
+
/**
|
|
98
|
+
* Parse a natural language prompt and return a project blueprint.
|
|
99
|
+
* @param {string} prompt - e.g. "Create a blog application with comments and tags"
|
|
100
|
+
* @returns {{ domain: string, tables: object }}
|
|
101
|
+
*/
|
|
102
|
+
static parse(prompt) {
|
|
103
|
+
const lower = prompt.toLowerCase();
|
|
104
|
+
let bestMatch = null;
|
|
105
|
+
let bestScore = 0;
|
|
106
|
+
|
|
107
|
+
for (const [pattern, blueprint] of Object.entries(DOMAIN_PATTERNS)) {
|
|
108
|
+
const regex = new RegExp(pattern, 'i');
|
|
109
|
+
const keywords = pattern.split('|').map(k => k.replace(/[^a-z]/g, ''));
|
|
110
|
+
let score = 0;
|
|
111
|
+
|
|
112
|
+
for (const kw of keywords) {
|
|
113
|
+
if (lower.includes(kw)) score++;
|
|
114
|
+
}
|
|
115
|
+
if (regex.test(lower)) score += 2;
|
|
116
|
+
|
|
117
|
+
if (score > bestScore) {
|
|
118
|
+
bestScore = score;
|
|
119
|
+
bestMatch = { pattern, blueprint, score };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Default to generic API/Auth if no match
|
|
124
|
+
if (!bestMatch || bestScore < 1) {
|
|
125
|
+
bestMatch = { pattern: 'api|auth', blueprint: DOMAIN_PATTERNS['api|auth|rest|user'], score: 0 };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
domain: bestMatch.pattern.split('|')[0],
|
|
130
|
+
tables: bestMatch.blueprint.tables,
|
|
131
|
+
score: bestMatch.score
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Generate model files from a blueprint.
|
|
137
|
+
* @param {{ tables: object }} blueprint
|
|
138
|
+
* @param {string} outputDir - e.g. process.cwd() + '/models'
|
|
139
|
+
* @returns {string[]} created file paths
|
|
140
|
+
*/
|
|
141
|
+
static generateModels(blueprint, outputDir) {
|
|
142
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
143
|
+
const created = [];
|
|
144
|
+
|
|
145
|
+
for (const [tableName, config] of Object.entries(blueprint.tables)) {
|
|
146
|
+
if (config.pivot) continue; // Skip pivot tables for model files
|
|
147
|
+
|
|
148
|
+
const className = this._toClassName(tableName);
|
|
149
|
+
const fillable = config.columns
|
|
150
|
+
.map(c => c.split(':')[0])
|
|
151
|
+
.filter(c => !['id', 'created_at', 'updated_at'].includes(c));
|
|
152
|
+
|
|
153
|
+
const hidden = fillable.filter(c => c === 'password' || c.includes('token') || c.includes('secret'));
|
|
154
|
+
|
|
155
|
+
const content = `const { Model } = require('outlet-orm');
|
|
156
|
+
|
|
157
|
+
class ${className} extends Model {
|
|
158
|
+
static table = '${tableName}';
|
|
159
|
+
static fillable = ${JSON.stringify(fillable)};${hidden.length > 0 ? `\n static hidden = ${JSON.stringify(hidden)};` : ''}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
module.exports = ${className};
|
|
163
|
+
`;
|
|
164
|
+
|
|
165
|
+
const filePath = path.join(outputDir, `${className}.js`);
|
|
166
|
+
fs.writeFileSync(filePath, content);
|
|
167
|
+
created.push(filePath);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return created;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Generate migration files from a blueprint.
|
|
175
|
+
* @param {{ tables: object }} blueprint
|
|
176
|
+
* @param {string} outputDir - e.g. process.cwd() + '/database/migrations'
|
|
177
|
+
* @returns {string[]} created file paths
|
|
178
|
+
*/
|
|
179
|
+
static generateMigrations(blueprint, outputDir) {
|
|
180
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
181
|
+
const created = [];
|
|
182
|
+
let index = 0;
|
|
183
|
+
|
|
184
|
+
for (const [tableName, config] of Object.entries(blueprint.tables)) {
|
|
185
|
+
index++;
|
|
186
|
+
const timestamp = new Date(Date.now() + index * 1000)
|
|
187
|
+
.toISOString()
|
|
188
|
+
.replace(/[-:]/g, '')
|
|
189
|
+
.replace(/T/, '_')
|
|
190
|
+
.replace(/\..+/, '');
|
|
191
|
+
|
|
192
|
+
const className = `Create${this._toClassName(tableName)}Table`;
|
|
193
|
+
const fileName = `${timestamp}_create_${tableName}_table.js`;
|
|
194
|
+
const filePath = path.join(outputDir, fileName);
|
|
195
|
+
|
|
196
|
+
const columnDefs = config.columns.map(c => this._columnToSchema(c)).join('\n ');
|
|
197
|
+
|
|
198
|
+
const content = `const { Migration } = require('outlet-orm');
|
|
199
|
+
|
|
200
|
+
class ${className} extends Migration {
|
|
201
|
+
async up() {
|
|
202
|
+
const schema = this.getSchema();
|
|
203
|
+
await schema.create('${tableName}', (table) => {
|
|
204
|
+
table.id();
|
|
205
|
+
${columnDefs}
|
|
206
|
+
table.timestamps();
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
async down() {
|
|
211
|
+
const schema = this.getSchema();
|
|
212
|
+
await schema.dropIfExists('${tableName}');
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
module.exports = ${className};
|
|
217
|
+
`;
|
|
218
|
+
|
|
219
|
+
fs.writeFileSync(filePath, content);
|
|
220
|
+
created.push(filePath);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return created;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Generate a seed file from a blueprint.
|
|
228
|
+
* @param {{ tables: object }} blueprint
|
|
229
|
+
* @param {string} outputDir
|
|
230
|
+
* @returns {string}
|
|
231
|
+
*/
|
|
232
|
+
static generateSeeder(blueprint, outputDir) {
|
|
233
|
+
fs.mkdirSync(outputDir, { recursive: true });
|
|
234
|
+
const tables = Object.keys(blueprint.tables);
|
|
235
|
+
|
|
236
|
+
const seedCalls = tables
|
|
237
|
+
.filter(t => !blueprint.tables[t].pivot)
|
|
238
|
+
.map(t => ` // await this.call('${this._toClassName(t)}Seeder');`)
|
|
239
|
+
.join('\n');
|
|
240
|
+
|
|
241
|
+
const content = `const { Seeder } = require('outlet-orm');
|
|
242
|
+
|
|
243
|
+
class DatabaseSeeder extends Seeder {
|
|
244
|
+
async run() {
|
|
245
|
+
${seedCalls}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
module.exports = DatabaseSeeder;
|
|
250
|
+
`;
|
|
251
|
+
|
|
252
|
+
const filePath = path.join(outputDir, 'DatabaseSeeder.js');
|
|
253
|
+
fs.writeFileSync(filePath, content);
|
|
254
|
+
return filePath;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// ─── Helpers ───────────────────────────────────────────────────
|
|
258
|
+
|
|
259
|
+
static _toClassName(tableName) {
|
|
260
|
+
// users -> User, order_items -> OrderItem
|
|
261
|
+
return tableName
|
|
262
|
+
.split('_')
|
|
263
|
+
.map(part => part.charAt(0).toUpperCase() + part.slice(1))
|
|
264
|
+
.join('')
|
|
265
|
+
.replace(/s$/, ''); // naive singularize (plural -> singular)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
static _columnToSchema(columnDef) {
|
|
269
|
+
// Format: name:type:modifier1:modifier2
|
|
270
|
+
// e.g. "email:string:unique", "price:decimal(10,2)", "status:string:default(pending)"
|
|
271
|
+
const parts = columnDef.split(':');
|
|
272
|
+
const name = parts[0];
|
|
273
|
+
const type = parts[1] || 'string';
|
|
274
|
+
const modifiers = parts.slice(2);
|
|
275
|
+
|
|
276
|
+
// Parse type and arguments
|
|
277
|
+
const typeMatch = type.match(/^(\w+)(?:\((.+)\))?$/);
|
|
278
|
+
const typeName = typeMatch ? typeMatch[1] : type;
|
|
279
|
+
const typeArgs = typeMatch && typeMatch[2] ? `, ${typeMatch[2]}` : '';
|
|
280
|
+
|
|
281
|
+
// Map to schema builder methods
|
|
282
|
+
const typeMap = {
|
|
283
|
+
string: 'string',
|
|
284
|
+
text: 'text',
|
|
285
|
+
integer: 'integer',
|
|
286
|
+
int: 'integer',
|
|
287
|
+
boolean: 'boolean',
|
|
288
|
+
bool: 'boolean',
|
|
289
|
+
decimal: 'decimal',
|
|
290
|
+
float: 'float',
|
|
291
|
+
date: 'date',
|
|
292
|
+
timestamp: 'timestamp',
|
|
293
|
+
json: 'json',
|
|
294
|
+
foreignId: 'integer'
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
const schemaType = typeMap[typeName] || 'string';
|
|
298
|
+
let line = `table.${schemaType}('${name}'${typeArgs})`;
|
|
299
|
+
|
|
300
|
+
// Apply modifiers
|
|
301
|
+
for (const mod of modifiers) {
|
|
302
|
+
if (mod === 'unique') line += '.unique()';
|
|
303
|
+
else if (mod === 'nullable') line += '.nullable()';
|
|
304
|
+
else if (mod.startsWith('default(')) {
|
|
305
|
+
const val = mod.match(/default\((.+)\)/)?.[1] || '';
|
|
306
|
+
// Smart quoting: don't quote numbers or booleans
|
|
307
|
+
const isNum = !isNaN(val);
|
|
308
|
+
const isBool = val === 'true' || val === 'false';
|
|
309
|
+
const quoted = isNum || isBool ? val : `'${val}'`;
|
|
310
|
+
line += `.default(${quoted})`;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return line + ';';
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
module.exports = PromptGenerator;
|
package/src/index.js
CHANGED
|
@@ -28,6 +28,11 @@ const BackupEncryption = require('./Backup/BackupEncryption');
|
|
|
28
28
|
const BackupSocketServer = require('./Backup/BackupSocketServer');
|
|
29
29
|
const BackupSocketClient = require('./Backup/BackupSocketClient');
|
|
30
30
|
|
|
31
|
+
// AI (v7.0.0)
|
|
32
|
+
const MCPServer = require('./AI/MCPServer');
|
|
33
|
+
const AISafetyGuardrails = require('./AI/AISafetyGuardrails');
|
|
34
|
+
const PromptGenerator = require('./AI/PromptGenerator');
|
|
35
|
+
|
|
31
36
|
module.exports = {
|
|
32
37
|
// Core
|
|
33
38
|
Model,
|
|
@@ -65,5 +70,10 @@ module.exports = {
|
|
|
65
70
|
BackupScheduler,
|
|
66
71
|
BackupEncryption,
|
|
67
72
|
BackupSocketServer,
|
|
68
|
-
BackupSocketClient
|
|
73
|
+
BackupSocketClient,
|
|
74
|
+
|
|
75
|
+
// AI (v7.0.0)
|
|
76
|
+
MCPServer,
|
|
77
|
+
AISafetyGuardrails,
|
|
78
|
+
PromptGenerator
|
|
69
79
|
};
|
package/types/index.d.ts
CHANGED
|
@@ -937,4 +937,110 @@ declare module 'outlet-orm' {
|
|
|
937
937
|
on(event: 'serverEvent', listener: (payload: Record<string, any>) => void): this;
|
|
938
938
|
on(event: string, listener: (...args: any[]) => void): this;
|
|
939
939
|
}
|
|
940
|
+
|
|
941
|
+
// ==================== AI Integration (v7.0.0) ====================
|
|
942
|
+
|
|
943
|
+
/** MCP tool definition */
|
|
944
|
+
export interface MCPToolDefinition {
|
|
945
|
+
name: string;
|
|
946
|
+
description: string;
|
|
947
|
+
inputSchema: {
|
|
948
|
+
type: 'object';
|
|
949
|
+
properties: Record<string, any>;
|
|
950
|
+
required: string[];
|
|
951
|
+
};
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
/** MCP server options */
|
|
955
|
+
export interface MCPServerOptions {
|
|
956
|
+
/** DatabaseConnection instance (optional, auto-loaded from project) */
|
|
957
|
+
connection?: DatabaseConnection;
|
|
958
|
+
/** Project root directory (default: process.cwd()) */
|
|
959
|
+
projectDir?: string;
|
|
960
|
+
/** Enable AI safety guardrails (default: true) */
|
|
961
|
+
safetyGuardrails?: boolean;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
/** JSON-RPC 2.0 message */
|
|
965
|
+
export interface JSONRPCMessage {
|
|
966
|
+
jsonrpc: '2.0';
|
|
967
|
+
id?: number | string;
|
|
968
|
+
method?: string;
|
|
969
|
+
params?: Record<string, any>;
|
|
970
|
+
result?: any;
|
|
971
|
+
error?: { code: number; message: string };
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
/** MCP Server — exposes ORM capabilities to AI agents via JSON-RPC 2.0 */
|
|
975
|
+
export class MCPServer {
|
|
976
|
+
constructor(options?: MCPServerOptions);
|
|
977
|
+
|
|
978
|
+
/** Project root directory */
|
|
979
|
+
projectDir: string;
|
|
980
|
+
/** Whether safety guardrails are enabled */
|
|
981
|
+
safetyGuardrails: boolean;
|
|
982
|
+
|
|
983
|
+
/** Start the MCP server on stdio */
|
|
984
|
+
start(): void;
|
|
985
|
+
/** Get a programmatic handler function (for testing/embedding) */
|
|
986
|
+
handler(): (message: JSONRPCMessage) => Promise<JSONRPCMessage | null>;
|
|
987
|
+
/** Graceful shutdown */
|
|
988
|
+
close(): Promise<void>;
|
|
989
|
+
|
|
990
|
+
on(event: 'started', listener: () => void): this;
|
|
991
|
+
on(event: 'initialized', listener: () => void): this;
|
|
992
|
+
on(event: 'response', listener: (response: JSONRPCMessage) => void): this;
|
|
993
|
+
on(event: 'close', listener: () => void): this;
|
|
994
|
+
on(event: string, listener: (...args: any[]) => void): this;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
/** Agent detection result */
|
|
998
|
+
export interface AgentDetectionResult {
|
|
999
|
+
/** Whether an AI agent was detected */
|
|
1000
|
+
detected: boolean;
|
|
1001
|
+
/** Name of the detected agent (null if not detected) */
|
|
1002
|
+
agentName: string | null;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
/** Destructive action validation result */
|
|
1006
|
+
export interface DestructiveActionResult {
|
|
1007
|
+
/** Whether the action is allowed */
|
|
1008
|
+
allowed: boolean;
|
|
1009
|
+
/** Message explaining why action was blocked (empty if allowed) */
|
|
1010
|
+
message: string;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
/** AI Safety Guardrails — detects AI agents and protects against destructive operations */
|
|
1014
|
+
export class AISafetyGuardrails {
|
|
1015
|
+
/** Detect if the current process is invoked by an AI agent */
|
|
1016
|
+
static detectAgent(): AgentDetectionResult;
|
|
1017
|
+
/** Check if a CLI command is destructive */
|
|
1018
|
+
static isDestructiveCommand(command: string): boolean;
|
|
1019
|
+
/** Validate whether user consent is present for a destructive operation */
|
|
1020
|
+
static validateDestructiveAction(command: string, flags?: { consent?: string; yes?: boolean; force?: boolean }): DestructiveActionResult;
|
|
1021
|
+
/** The environment variable name for AI consent */
|
|
1022
|
+
static readonly CONSENT_ENV_VAR: string;
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
/** Prompt blueprint — parsed from a natural language description */
|
|
1026
|
+
export interface PromptBlueprint {
|
|
1027
|
+
/** Detected domain (e.g. 'blog', 'e-commerce', 'saas') */
|
|
1028
|
+
domain: string;
|
|
1029
|
+
/** Table definitions */
|
|
1030
|
+
tables: Record<string, { columns: string[]; pivot?: boolean }>;
|
|
1031
|
+
/** Match confidence score */
|
|
1032
|
+
score: number;
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
/** Prompt Generator — generates projects from natural language descriptions */
|
|
1036
|
+
export class PromptGenerator {
|
|
1037
|
+
/** Parse a natural language prompt into a project blueprint */
|
|
1038
|
+
static parse(prompt: string): PromptBlueprint;
|
|
1039
|
+
/** Generate model files from a blueprint */
|
|
1040
|
+
static generateModels(blueprint: PromptBlueprint, outputDir: string): string[];
|
|
1041
|
+
/** Generate migration files from a blueprint */
|
|
1042
|
+
static generateMigrations(blueprint: PromptBlueprint, outputDir: string): string[];
|
|
1043
|
+
/** Generate a seeder file from a blueprint */
|
|
1044
|
+
static generateSeeder(blueprint: PromptBlueprint, outputDir: string): string;
|
|
1045
|
+
}
|
|
940
1046
|
}
|