dolphin-server-modules 2.8.0 → 2.9.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/dist/adapters/mongoose/index.js +1 -4
- package/dist/adapters/mongoose/index.js.map +1 -1
- package/dist/adapters/mongoose/index.test.js +2 -4
- package/dist/adapters/mongoose/index.test.js.map +1 -1
- package/dist/adapters/mongoose/integration.test.js +19 -54
- package/dist/adapters/mongoose/integration.test.js.map +1 -1
- package/dist/auth/auth.js +23 -29
- package/dist/auth/auth.js.map +1 -1
- package/dist/auth/auth.test.js +5 -10
- package/dist/auth/auth.test.js.map +1 -1
- package/dist/authController/authController.js +8 -48
- package/dist/authController/authController.js.map +1 -1
- package/dist/authController/authController.test.js +121 -123
- package/dist/authController/authController.test.js.map +1 -1
- package/dist/bin/cli.js +233 -625
- package/dist/bin/cli.js.map +1 -1
- package/dist/controller/controller.js +4 -11
- package/dist/controller/controller.js.map +1 -1
- package/dist/controller/controller.test.js +4 -6
- package/dist/controller/controller.test.js.map +1 -1
- package/dist/curd/crud.js +4 -11
- package/dist/curd/crud.js.map +1 -1
- package/dist/curd/crud.test.js +2 -4
- package/dist/curd/crud.test.js.map +1 -1
- package/dist/demo-server.js +21 -59
- package/dist/demo-server.js.map +1 -1
- package/dist/djson/djson.js +10 -22
- package/dist/djson/djson.js.map +1 -1
- package/dist/djson/djson.test.js +149 -184
- package/dist/djson/djson.test.js.map +1 -1
- package/dist/dolphin-bench.js +4 -9
- package/dist/dolphin-bench.js.map +1 -1
- package/dist/hard-performance-test.js +9 -14
- package/dist/hard-performance-test.js.map +1 -1
- package/dist/index.js +4 -20
- package/dist/index.js.map +1 -1
- package/dist/middleware/zod.js +9 -15
- package/dist/middleware/zod.js.map +1 -1
- package/dist/middleware/zod.test.js +12 -14
- package/dist/middleware/zod.test.js.map +1 -1
- package/dist/performance-test.js +9 -14
- package/dist/performance-test.js.map +1 -1
- package/dist/real-test-mongoose.js +17 -22
- package/dist/real-test-mongoose.js.map +1 -1
- package/dist/realtime/codec.js +3 -8
- package/dist/realtime/codec.js.map +1 -1
- package/dist/realtime/core.js +20 -64
- package/dist/realtime/core.js.map +1 -1
- package/dist/realtime/index.js +4 -20
- package/dist/realtime/index.js.map +1 -1
- package/dist/realtime/plugins.js +6 -12
- package/dist/realtime/plugins.js.map +1 -1
- package/dist/realtime/realtime.test.js +10 -45
- package/dist/realtime/realtime.test.js.map +1 -1
- package/dist/realtime/trie.js +1 -5
- package/dist/realtime/trie.js.map +1 -1
- package/dist/router/router.js +1 -4
- package/dist/router/router.js.map +1 -1
- package/dist/router/router.test.js +9 -11
- package/dist/router/router.test.js.map +1 -1
- package/dist/server/server.js +12 -18
- package/dist/server/server.js.map +1 -1
- package/dist/server/server.test.js +21 -26
- package/dist/server/server.test.js.map +1 -1
- package/dist/services/ai-service.d.ts +16 -0
- package/dist/services/ai-service.js +141 -0
- package/dist/services/ai-service.js.map +1 -0
- package/dist/signaling/index.js +4 -9
- package/dist/signaling/index.js.map +1 -1
- package/dist/signaling/signaling.test.js +13 -15
- package/dist/signaling/signaling.test.js.map +1 -1
- package/dist/swagger/swagger.js +3 -8
- package/dist/swagger/swagger.js.map +1 -1
- package/dist/swagger/swagger.test.js +10 -12
- package/dist/swagger/swagger.test.js.map +1 -1
- package/dist/templates/index.d.ts +9 -0
- package/dist/templates/index.js +112 -0
- package/dist/templates/index.js.map +1 -0
- package/dist/test-2fa-real.js +6 -11
- package/dist/test-2fa-real.js.map +1 -1
- package/dist/test-dolphin.js +6 -8
- package/dist/test-dolphin.js.map +1 -1
- package/dist/utils/ui.d.ts +10 -0
- package/dist/utils/ui.js +36 -0
- package/dist/utils/ui.js.map +1 -0
- package/package.json +2 -1
- package/scripts/client.js +3 -1
package/dist/bin/cli.js
CHANGED
|
@@ -1,675 +1,283 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
Object.defineProperty(o, k2, desc);
|
|
10
|
-
}) : (function(o, m, k, k2) {
|
|
11
|
-
if (k2 === undefined) k2 = k;
|
|
12
|
-
o[k2] = m[k];
|
|
13
|
-
}));
|
|
14
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
-
}) : function(o, v) {
|
|
17
|
-
o["default"] = v;
|
|
18
|
-
});
|
|
19
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
-
var ownKeys = function(o) {
|
|
21
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
-
var ar = [];
|
|
23
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
-
return ar;
|
|
25
|
-
};
|
|
26
|
-
return ownKeys(o);
|
|
27
|
-
};
|
|
28
|
-
return function (mod) {
|
|
29
|
-
if (mod && mod.__esModule) return mod;
|
|
30
|
-
var result = {};
|
|
31
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
-
__setModuleDefault(result, mod);
|
|
33
|
-
return result;
|
|
34
|
-
};
|
|
35
|
-
})();
|
|
36
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
37
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
38
|
-
};
|
|
39
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
-
const fs_1 = __importDefault(require("fs"));
|
|
41
|
-
const path_1 = __importDefault(require("path"));
|
|
42
|
-
const https_1 = __importDefault(require("https"));
|
|
43
|
-
const server_1 = require("../server/server");
|
|
44
|
-
const core_1 = require("../realtime/core");
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { createServer } from 'http';
|
|
5
|
+
import { AIService } from '../services/ai-service.js';
|
|
6
|
+
import { CLIUI } from '../utils/ui.js';
|
|
7
|
+
import { TEMPLATES } from '../templates/index.js';
|
|
45
8
|
const args = process.argv.slice(2);
|
|
46
|
-
const command = args[0];
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
export async function connectDB(models = {}) {
|
|
58
|
-
const uri = process.env.MONGO_URI || 'mongodb://localhost:27017/dolphin_db';
|
|
59
|
-
await mongoose.connect(uri);
|
|
60
|
-
console.log('✅ MongoDB Connected');
|
|
61
|
-
|
|
62
|
-
return createMongooseAdapter({
|
|
63
|
-
models: { ...models }
|
|
64
|
-
});
|
|
65
|
-
}`,
|
|
66
|
-
sequelize: `import { Sequelize } from 'sequelize';
|
|
67
|
-
// Note: This is a skeleton for Dolphin Sequelize Adapter
|
|
68
|
-
export async function connectDB() {
|
|
69
|
-
const sequelize = new Sequelize(process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASS, {
|
|
70
|
-
host: process.env.DB_HOST,
|
|
71
|
-
dialect: 'mysql' // or 'postgres', 'sqlite'
|
|
9
|
+
const command = args[0] || 'help';
|
|
10
|
+
// Simple .env loader
|
|
11
|
+
const envPath = path.join(process.cwd(), '.env');
|
|
12
|
+
if (fs.existsSync(envPath)) {
|
|
13
|
+
const envContent = fs.readFileSync(envPath, 'utf8');
|
|
14
|
+
envContent.split('\n').forEach(line => {
|
|
15
|
+
const [key, ...valueParts] = line.split('=');
|
|
16
|
+
if (key && valueParts.length > 0) {
|
|
17
|
+
process.env[key.trim()] = valueParts.join('=').trim();
|
|
18
|
+
}
|
|
72
19
|
});
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
console.error('❌ Unable to connect to the database:', error);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
return sequelize;
|
|
82
|
-
}`,
|
|
83
|
-
auth: `import { createDolphinAuthController } from 'dolphin-server-modules/auth-controller';
|
|
84
|
-
import { createDolphinRouter } from 'dolphin-server-modules/router';
|
|
85
|
-
|
|
86
|
-
export function setupAuth(dbAdapter, config) {
|
|
87
|
-
const router = createDolphinRouter();
|
|
88
|
-
const auth = createDolphinAuthController(dbAdapter, config);
|
|
89
|
-
|
|
90
|
-
router.post('/register', auth.register);
|
|
91
|
-
router.post('/login', auth.login);
|
|
92
|
-
router.post('/refresh', auth.refresh);
|
|
93
|
-
router.get('/me', auth.requireAuth, (ctx) => ctx.json(ctx.req.user));
|
|
94
|
-
|
|
95
|
-
return router;
|
|
96
|
-
}`,
|
|
97
|
-
crud: (name) => `import { createCRUD } from 'dolphin-server-modules/crud';
|
|
98
|
-
|
|
99
|
-
export function setup${name}CRUD(dbAdapter) {
|
|
100
|
-
const service = createCRUD(dbAdapter, { enforceOwnership: false });
|
|
101
|
-
const COLLECTION = '${name}';
|
|
102
|
-
|
|
103
|
-
return {
|
|
104
|
-
getAll: async (ctx) => ctx.json(await service.read(COLLECTION, ctx.query)),
|
|
105
|
-
getOne: async (ctx) => ctx.json(await service.readOne(COLLECTION, ctx.params.id)),
|
|
106
|
-
create: async (ctx) => ctx.json(await service.create(COLLECTION, ctx.body)),
|
|
107
|
-
update: async (ctx) => ctx.json(await service.updateOne(COLLECTION, ctx.params.id, ctx.body)),
|
|
108
|
-
delete: async (ctx) => ctx.json(await service.deleteOne(COLLECTION, ctx.params.id))
|
|
109
|
-
};
|
|
110
|
-
}`,
|
|
111
|
-
authModel: `import mongoose from 'mongoose';
|
|
112
|
-
|
|
113
|
-
const UserSchema = new mongoose.Schema({
|
|
114
|
-
email: { type: String, required: true, unique: true },
|
|
115
|
-
password: { type: String, required: true },
|
|
116
|
-
name: { type: String },
|
|
117
|
-
role: { type: String, default: 'user' },
|
|
118
|
-
is2FAEnabled: { type: Boolean, default: false },
|
|
119
|
-
twoFASecret: { type: String },
|
|
120
|
-
recoveryCodes: [{ type: String }],
|
|
121
|
-
createdAt: { type: Date, default: Date.now }
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
const RefreshTokenSchema = new mongoose.Schema({
|
|
125
|
-
userId: { type: mongoose.Schema.Types.ObjectId, ref: 'User', required: true },
|
|
126
|
-
token: { type: String, required: true },
|
|
127
|
-
expiresAt: { type: Date, required: true },
|
|
128
|
-
createdAt: { type: Date, default: Date.now }
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
export const User = mongoose.model('User', UserSchema);
|
|
132
|
-
export const RefreshToken = mongoose.model('RefreshToken', RefreshTokenSchema);`
|
|
20
|
+
}
|
|
21
|
+
const aiConfig = {
|
|
22
|
+
apiKey: (process.env.DOLPHIN_AI_KEY || process.env.GEMINI_API_KEY || '').trim(),
|
|
23
|
+
baseUrl: process.env.DOLPHIN_AI_BASE_URL,
|
|
24
|
+
model: process.env.DOLPHIN_AI_MODEL
|
|
133
25
|
};
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
const content = fs_1.default.readFileSync(envPath, 'utf8');
|
|
138
|
-
content.split(/\r?\n/).forEach(line => {
|
|
139
|
-
const trimmedLine = line.trim();
|
|
140
|
-
if (!trimmedLine || trimmedLine.startsWith('#'))
|
|
141
|
-
return;
|
|
142
|
-
const [key, ...valueParts] = trimmedLine.split('=');
|
|
143
|
-
if (key && valueParts.length > 0) {
|
|
144
|
-
const value = valueParts.join('=').trim().replace(/^["']|["']$/g, '');
|
|
145
|
-
process.env[key.trim()] = value;
|
|
146
|
-
}
|
|
147
|
-
});
|
|
148
|
-
}
|
|
26
|
+
if (!aiConfig.apiKey && ['generate', 'generate-full', 'chat'].includes(command)) {
|
|
27
|
+
CLIUI.error('API Key not found! Please set DOLPHIN_AI_KEY or GEMINI_API_KEY in your .env file.');
|
|
28
|
+
process.exit(1);
|
|
149
29
|
}
|
|
30
|
+
const ai = new AIService(aiConfig);
|
|
150
31
|
async function run() {
|
|
151
|
-
loadEnv();
|
|
152
32
|
switch (command) {
|
|
33
|
+
case 'serve':
|
|
34
|
+
const port = parseInt(args.find(arg => arg.startsWith('--port='))?.split('=')[1] || '3000');
|
|
35
|
+
CLIUI.heading(`Dolphin Dev Server starting on port ${port}`);
|
|
36
|
+
const server = createServer((req, res) => {
|
|
37
|
+
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
|
38
|
+
res.end('Dolphin Server is swimming!\n');
|
|
39
|
+
});
|
|
40
|
+
server.listen(port, () => {
|
|
41
|
+
CLIUI.success(`Server is live at http://localhost:${port}`);
|
|
42
|
+
});
|
|
43
|
+
break;
|
|
153
44
|
case 'generate':
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
45
|
+
const prompt = args.slice(1).join(' ');
|
|
46
|
+
if (!prompt)
|
|
47
|
+
return CLIUI.error('Usage: dolphin generate "your prompt"');
|
|
48
|
+
CLIUI.startSpinner('AI is generating code');
|
|
49
|
+
try {
|
|
50
|
+
const response = await ai.request(prompt, "Return ONLY raw JavaScript code. No markdown.");
|
|
51
|
+
const cleanCode = response.replace(/```javascript|```js|```/g, '').trim();
|
|
52
|
+
fs.writeFileSync(path.join(process.cwd(), 'ai-generated.js'), cleanCode);
|
|
53
|
+
CLIUI.stopSpinner(true, 'File generated: ai-generated.js');
|
|
161
54
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
break;
|
|
55
|
+
catch (e) {
|
|
56
|
+
CLIUI.stopSpinner(false, e.message);
|
|
165
57
|
}
|
|
166
|
-
const fallbackModels = ['gemini-flash-latest', 'gemini-2.0-flash', 'gemini-2.5-flash', 'gemini-pro-latest'];
|
|
167
|
-
const modelsToTry = [requestedModel, ...fallbackModels.filter(m => m !== requestedModel)];
|
|
168
|
-
const versions = ['v1beta', 'v1'];
|
|
169
|
-
const tryGenerate = (modelIndex, versionIndex) => {
|
|
170
|
-
if (modelIndex >= modelsToTry.length) {
|
|
171
|
-
console.log('❌ All AI models failed. Please ensure Generative Language API is enabled in Google AI Studio for your key.');
|
|
172
|
-
return;
|
|
173
|
-
}
|
|
174
|
-
if (versionIndex >= versions.length) {
|
|
175
|
-
return tryGenerate(modelIndex + 1, 0);
|
|
176
|
-
}
|
|
177
|
-
const currentModel = modelsToTry[modelIndex];
|
|
178
|
-
const currentVersion = versions[versionIndex];
|
|
179
|
-
console.log(`🤖 AI (${currentModel} via ${currentVersion}) is swimming with Dolphin...`);
|
|
180
|
-
const aiData = JSON.stringify({
|
|
181
|
-
contents: [{ parts: [{ text: `Generate a production-ready Node.js file using dolphin-server-modules.
|
|
182
|
-
Rules:
|
|
183
|
-
1. Use ESM 'import' instead of 'require'.
|
|
184
|
-
2. Use 'const app = createDolphinServer();' from 'dolphin-server-modules/server'.
|
|
185
|
-
3. Use unified context '(ctx) => { ... }' instead of '(req, res)'.
|
|
186
|
-
4. Return objects directly for JSON response.
|
|
187
|
-
5. No markdown backticks, no explanations.
|
|
188
|
-
Context: ${prompt}. Return ONLY raw JS code.` }] }]
|
|
189
|
-
});
|
|
190
|
-
const options = {
|
|
191
|
-
hostname: 'generativelanguage.googleapis.com',
|
|
192
|
-
path: `/${currentVersion}/models/${currentModel}:generateContent?key=${encodeURIComponent(apiKey)}`,
|
|
193
|
-
method: 'POST',
|
|
194
|
-
headers: { 'Content-Type': 'application/json' }
|
|
195
|
-
};
|
|
196
|
-
const req = https_1.default.request(options, (res) => {
|
|
197
|
-
let body = '';
|
|
198
|
-
res.on('data', (d) => body += d);
|
|
199
|
-
res.on('end', () => {
|
|
200
|
-
try {
|
|
201
|
-
const json = JSON.parse(body);
|
|
202
|
-
if (json.error) {
|
|
203
|
-
console.log(`⚠️ ${currentModel} (${currentVersion}) unavailable. Error: ${json.error.status}. Trying next...`);
|
|
204
|
-
tryGenerate(modelIndex, versionIndex + 1);
|
|
205
|
-
return;
|
|
206
|
-
}
|
|
207
|
-
const rawCode = json.candidates?.[0]?.content?.parts?.[0]?.text || '';
|
|
208
|
-
if (rawCode) {
|
|
209
|
-
const codeMatch = rawCode.match(/(\/\*[\s\S]*?\*\/|\/\/.*|[\s\S])*?(import|const|let|var|app|function)[\s\S]*/);
|
|
210
|
-
const code = (codeMatch ? codeMatch[0] : rawCode).replace(/```javascript|```js|```/g, '').trim();
|
|
211
|
-
fs_1.default.writeFileSync(path_1.default.join(process.cwd(), 'ai-generated-app.js'), code);
|
|
212
|
-
console.log(`✅ Success! Code generated using ${currentModel} in ai-generated-app.js`);
|
|
213
|
-
}
|
|
214
|
-
else {
|
|
215
|
-
tryGenerate(modelIndex, versionIndex + 1);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
catch (e) {
|
|
219
|
-
tryGenerate(modelIndex, versionIndex + 1);
|
|
220
|
-
}
|
|
221
|
-
});
|
|
222
|
-
});
|
|
223
|
-
req.on('error', () => tryGenerate(modelIndex, versionIndex + 1));
|
|
224
|
-
req.write(aiData);
|
|
225
|
-
req.end();
|
|
226
|
-
};
|
|
227
|
-
tryGenerate(0, 0);
|
|
228
58
|
break;
|
|
229
59
|
case 'generate-full':
|
|
230
|
-
const
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
60
|
+
const fullPrompt = args.slice(1).join(' ');
|
|
61
|
+
if (!fullPrompt)
|
|
62
|
+
return CLIUI.error('Usage: dolphin generate-full "project description"');
|
|
63
|
+
CLIUI.startSpinner('Architecting full project structure');
|
|
64
|
+
try {
|
|
65
|
+
const systemPrompt = `You are a Dolphin Framework expert. Generate a production-ready backend project.
|
|
66
|
+
Dolphin Patterns:
|
|
67
|
+
- controllers/ (Logic)
|
|
68
|
+
- models/ (Schemas: can be Mongoose or Sequelize)
|
|
69
|
+
- config/db.js (DB connection logic)
|
|
70
|
+
- .env (Environment variables)
|
|
71
|
+
Dolphin supports both Mongoose (MongoDB) and Sequelize (MySQL/PostgreSQL).
|
|
72
|
+
Choose the appropriate adapter based on the user's request.
|
|
73
|
+
Return ONLY a JSON object where keys are file paths and values are code content. No markdown.`;
|
|
74
|
+
const response = await ai.request(fullPrompt, systemPrompt);
|
|
75
|
+
const files = JSON.parse(response.replace(/```json|```/g, '').trim());
|
|
76
|
+
Object.entries(files).forEach(([fPath, content]) => {
|
|
77
|
+
const fullPath = path.join(process.cwd(), fPath);
|
|
78
|
+
// Don't overwrite existing .env files to protect API keys
|
|
79
|
+
if (fPath === '.env' && fs.existsSync(fullPath)) {
|
|
80
|
+
console.log(` ⚠️ Skipped: .env (file already exists)`);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
fs.mkdirSync(path.dirname(fullPath), { recursive: true });
|
|
84
|
+
fs.writeFileSync(fullPath, content);
|
|
85
|
+
console.log(` 📄 Created: ${fPath}`);
|
|
86
|
+
});
|
|
87
|
+
CLIUI.stopSpinner(true, 'Project architected successfully!');
|
|
236
88
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
break;
|
|
89
|
+
catch (e) {
|
|
90
|
+
CLIUI.stopSpinner(false, e.message);
|
|
240
91
|
}
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
12. Include folders: models, controllers, routes, middleware, config, services.
|
|
270
|
-
13. Ensure 'app.js' connects everything: DB -> Adapter -> Auth/CRUD -> Router -> Server.
|
|
271
|
-
Context: ${fullPrompt}.
|
|
272
|
-
Return ONLY the JSON. No markdown backticks, no text before or after.` }] }]
|
|
273
|
-
});
|
|
274
|
-
const options = {
|
|
275
|
-
hostname: 'generativelanguage.googleapis.com',
|
|
276
|
-
path: `/${currentVersion}/models/${currentModel}:generateContent?key=${encodeURIComponent(fullApiKey)}`,
|
|
277
|
-
method: 'POST',
|
|
278
|
-
headers: { 'Content-Type': 'application/json' }
|
|
279
|
-
};
|
|
280
|
-
const req = https_1.default.request(options, (res) => {
|
|
281
|
-
let body = '';
|
|
282
|
-
res.on('data', (d) => body += d);
|
|
283
|
-
res.on('end', () => {
|
|
92
|
+
break;
|
|
93
|
+
case 'chat':
|
|
94
|
+
CLIUI.heading('🐬 Dolphin Autonomous Agent Mode');
|
|
95
|
+
const readline = await import('readline');
|
|
96
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
97
|
+
const agentSystemPrompt = `You are the Dolphin Autonomous Agent.
|
|
98
|
+
You have FULL ACCESS to the filesystem and shell.
|
|
99
|
+
To perform actions, return a JSON block with "tool" and "params".
|
|
100
|
+
Available Tools:
|
|
101
|
+
1. {"tool": "read", "path": "file_path"} - Read a file
|
|
102
|
+
2. {"tool": "write", "path": "path", "content": "..."} - Create/Edit a file
|
|
103
|
+
3. {"tool": "list", "path": "dir"} - List files
|
|
104
|
+
4. {"tool": "shell", "cmd": "..."} - Run a terminal command
|
|
105
|
+
5. {"tool": "done", "msg": "..."} - Final answer
|
|
106
|
+
|
|
107
|
+
Rules:
|
|
108
|
+
- Always check the folder structure before writing.
|
|
109
|
+
- If you see an error, fix it using the "write" tool.
|
|
110
|
+
- You can call multiple tools one after another.
|
|
111
|
+
- Use ESM (import/export).`;
|
|
112
|
+
const chatLoop = () => {
|
|
113
|
+
rl.question('\n💬 You: ', async (input) => {
|
|
114
|
+
if (input.toLowerCase() === 'exit')
|
|
115
|
+
return rl.close();
|
|
116
|
+
let currentPrompt = input;
|
|
117
|
+
let isRunning = true;
|
|
118
|
+
while (isRunning) {
|
|
119
|
+
CLIUI.startSpinner('Agent is thinking');
|
|
284
120
|
try {
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
121
|
+
const response = await ai.request(currentPrompt, agentSystemPrompt);
|
|
122
|
+
CLIUI.stopSpinner();
|
|
123
|
+
// Try to parse tool call(s)
|
|
124
|
+
let toolCalls = [];
|
|
125
|
+
try {
|
|
126
|
+
const jsonMatch = response.match(/\[[\s\S]*\]|\{[\s\S]*\}/);
|
|
127
|
+
if (jsonMatch) {
|
|
128
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
129
|
+
toolCalls = Array.isArray(parsed) ? parsed : [parsed];
|
|
130
|
+
}
|
|
289
131
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
132
|
+
catch (e) { }
|
|
133
|
+
if (toolCalls.length > 0) {
|
|
134
|
+
let results = '';
|
|
135
|
+
for (const toolCall of toolCalls) {
|
|
136
|
+
if (!toolCall.tool)
|
|
137
|
+
continue;
|
|
138
|
+
switch (toolCall.tool) {
|
|
139
|
+
case 'read':
|
|
140
|
+
const rPath = path.join(process.cwd(), toolCall.path);
|
|
141
|
+
if (fs.existsSync(rPath)) {
|
|
142
|
+
const content = fs.readFileSync(rPath, 'utf8');
|
|
143
|
+
console.log(`📖 Read ${toolCall.path}`);
|
|
144
|
+
results += `Content of ${toolCall.path}:\n${content}\n\n`;
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
results += `Error: ${toolCall.path} not found.\n`;
|
|
148
|
+
}
|
|
149
|
+
break;
|
|
150
|
+
case 'write':
|
|
151
|
+
const wPath = path.join(process.cwd(), toolCall.path);
|
|
152
|
+
fs.mkdirSync(path.dirname(wPath), { recursive: true });
|
|
153
|
+
fs.writeFileSync(wPath, toolCall.content);
|
|
154
|
+
console.log(`📝 Wrote to ${toolCall.path}`);
|
|
155
|
+
results += `Successfully wrote ${toolCall.path}.\n`;
|
|
156
|
+
break;
|
|
157
|
+
case 'list':
|
|
158
|
+
const lPath = path.join(process.cwd(), toolCall.path || '.');
|
|
159
|
+
if (fs.existsSync(lPath)) {
|
|
160
|
+
const files = fs.readdirSync(lPath);
|
|
161
|
+
console.log(`📁 Files in ${toolCall.path || '.'}: ${files.join(', ')}`);
|
|
162
|
+
results += `Files in ${toolCall.path || '.'}:\n${files.join('\n')}\n`;
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
results += `Error: Directory ${toolCall.path} not found.\n`;
|
|
166
|
+
}
|
|
167
|
+
break;
|
|
168
|
+
case 'shell':
|
|
169
|
+
console.log(`💻 Running: ${toolCall.cmd}`);
|
|
170
|
+
const { execSync } = await import('child_process');
|
|
171
|
+
try {
|
|
172
|
+
const output = execSync(toolCall.cmd).toString();
|
|
173
|
+
results += `Shell Output of "${toolCall.cmd}":\n${output}\n`;
|
|
174
|
+
}
|
|
175
|
+
catch (err) {
|
|
176
|
+
results += `Shell Error of "${toolCall.cmd}":\n${err.message}\n`;
|
|
177
|
+
}
|
|
178
|
+
break;
|
|
179
|
+
case 'done':
|
|
180
|
+
console.log(`✔ ${toolCall.msg || 'Task complete'}`);
|
|
181
|
+
isRunning = false;
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
306
184
|
}
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
185
|
+
if (results) {
|
|
186
|
+
currentPrompt = `Results of actions:\n${results}\n\nWhat next?`;
|
|
187
|
+
continue; // Let the agent think again with results
|
|
310
188
|
}
|
|
311
189
|
}
|
|
312
190
|
else {
|
|
313
|
-
console.log(
|
|
314
|
-
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
catch (e) {
|
|
318
|
-
console.log('❌ Unexpected error. Trying next model...');
|
|
319
|
-
tryGenerateFull(modelIndex, versionIndex + 1);
|
|
320
|
-
}
|
|
321
|
-
});
|
|
322
|
-
});
|
|
323
|
-
req.on('error', () => tryGenerateFull(modelIndex, versionIndex + 1));
|
|
324
|
-
req.write(aiData);
|
|
325
|
-
req.end();
|
|
326
|
-
};
|
|
327
|
-
tryGenerateFull(0, 0);
|
|
328
|
-
break;
|
|
329
|
-
case 'modify':
|
|
330
|
-
const fileToModify = args[1];
|
|
331
|
-
const modifyPrompt = args.slice(2).join(' ');
|
|
332
|
-
const modifyApiKey = (process.env.GEMINI_API_KEY || '').trim();
|
|
333
|
-
if (!modifyApiKey || !fileToModify || !modifyPrompt) {
|
|
334
|
-
console.log('❌ Usage: dolphin modify <filename> "your instructions"');
|
|
335
|
-
break;
|
|
336
|
-
}
|
|
337
|
-
const filePath = path_1.default.join(process.cwd(), fileToModify);
|
|
338
|
-
if (!fs_1.default.existsSync(filePath)) {
|
|
339
|
-
console.log(`❌ File not found: ${fileToModify}`);
|
|
340
|
-
break;
|
|
341
|
-
}
|
|
342
|
-
const currentCode = fs_1.default.readFileSync(filePath, 'utf8');
|
|
343
|
-
console.log(`🛠️ Modifying ${fileToModify}...`);
|
|
344
|
-
const tryModify = (modelIndex, versionIndex) => {
|
|
345
|
-
const models = ['gemini-1.5-flash-latest', 'gemini-flash-latest', 'gemini-1.5-pro-latest'];
|
|
346
|
-
const versions = ['v1beta', 'v1'];
|
|
347
|
-
if (modelIndex >= models.length) {
|
|
348
|
-
console.log('❌ Modification failed after trying all models.');
|
|
349
|
-
return;
|
|
350
|
-
}
|
|
351
|
-
if (versionIndex >= versions.length) {
|
|
352
|
-
return tryModify(modelIndex + 1, 0);
|
|
353
|
-
}
|
|
354
|
-
const model = models[modelIndex];
|
|
355
|
-
const version = versions[versionIndex];
|
|
356
|
-
const aiData = JSON.stringify({
|
|
357
|
-
contents: [{ parts: [{ text: `You are an expert Dolphin Framework developer.
|
|
358
|
-
Task: Modify the following code based on the instructions.
|
|
359
|
-
Instructions: ${modifyPrompt}
|
|
360
|
-
Current Code:
|
|
361
|
-
${currentCode}
|
|
362
|
-
|
|
363
|
-
Rules:
|
|
364
|
-
1. Return ONLY the updated code.
|
|
365
|
-
2. No markdown, no explanations.
|
|
366
|
-
3. Maintain Dolphin Framework standards (ctx usage, createDolphinServer, etc.).` }] }]
|
|
367
|
-
});
|
|
368
|
-
const options = {
|
|
369
|
-
hostname: 'generativelanguage.googleapis.com',
|
|
370
|
-
path: `/${version}/models/${model}:generateContent?key=${encodeURIComponent(modifyApiKey)}`,
|
|
371
|
-
method: 'POST',
|
|
372
|
-
headers: { 'Content-Type': 'application/json' }
|
|
373
|
-
};
|
|
374
|
-
const req = https_1.default.request(options, (res) => {
|
|
375
|
-
let body = '';
|
|
376
|
-
res.on('data', (d) => body += d);
|
|
377
|
-
res.on('end', () => {
|
|
378
|
-
try {
|
|
379
|
-
const json = JSON.parse(body);
|
|
380
|
-
if (json.error) {
|
|
381
|
-
return tryModify(modelIndex, versionIndex + 1);
|
|
382
|
-
}
|
|
383
|
-
const rawCode = json.candidates?.[0]?.content?.parts?.[0]?.text || '';
|
|
384
|
-
if (rawCode) {
|
|
385
|
-
const newCode = rawCode.replace(/```javascript|```js|```/g, '').trim();
|
|
386
|
-
fs_1.default.writeFileSync(filePath, newCode);
|
|
387
|
-
console.log(`✅ ${fileToModify} updated successfully!`);
|
|
388
|
-
}
|
|
389
|
-
else {
|
|
390
|
-
tryModify(modelIndex, versionIndex + 1);
|
|
191
|
+
console.log(`🤖 AI: ${response}`);
|
|
192
|
+
isRunning = false;
|
|
391
193
|
}
|
|
392
194
|
}
|
|
393
195
|
catch (e) {
|
|
394
|
-
|
|
196
|
+
CLIUI.stopSpinner(false, e.message);
|
|
197
|
+
isRunning = false;
|
|
395
198
|
}
|
|
396
|
-
}
|
|
199
|
+
}
|
|
200
|
+
chatLoop();
|
|
397
201
|
});
|
|
398
|
-
req.on('error', () => tryModify(modelIndex, versionIndex + 1));
|
|
399
|
-
req.write(aiData);
|
|
400
|
-
req.end();
|
|
401
202
|
};
|
|
402
|
-
|
|
403
|
-
break;
|
|
404
|
-
case 'chat':
|
|
405
|
-
console.log('🐬 Welcome to Dolphin AI Agent! I can write files and run commands.');
|
|
406
|
-
console.log('💡 Try: "Create a new model for Blog" or "Show me current files"');
|
|
407
|
-
console.log('💬 Type "exit" to quit.\n');
|
|
408
|
-
const agentApiKey = (process.env.GEMINI_API_KEY || '').trim();
|
|
409
|
-
if (!agentApiKey) {
|
|
410
|
-
console.log('❌ GEMINI_API_KEY not set.');
|
|
411
|
-
break;
|
|
412
|
-
}
|
|
413
|
-
Promise.resolve().then(() => __importStar(require('readline'))).then(readline => {
|
|
414
|
-
const rl = readline.createInterface({
|
|
415
|
-
input: process.stdin,
|
|
416
|
-
output: process.stdout
|
|
417
|
-
});
|
|
418
|
-
const ask = () => {
|
|
419
|
-
rl.question('💬 You: ', (input) => {
|
|
420
|
-
if (input.toLowerCase() === 'exit')
|
|
421
|
-
return rl.close();
|
|
422
|
-
const systemPrompt = `You are the Dolphin Framework AI Agent.
|
|
423
|
-
You have access to the user's filesystem and shell.
|
|
424
|
-
|
|
425
|
-
To read a file:
|
|
426
|
-
FILE_READ: <path>
|
|
427
|
-
|
|
428
|
-
To create or modify a file:
|
|
429
|
-
FILE_WRITE: <path>
|
|
430
|
-
<content>
|
|
431
|
-
END_FILE
|
|
432
|
-
|
|
433
|
-
To run a command:
|
|
434
|
-
SHELL_RUN: <command>
|
|
435
|
-
|
|
436
|
-
Current working directory: ${process.cwd()}
|
|
437
|
-
Always use Dolphin Framework standards. If you need to modify a file, READ it first.`;
|
|
438
|
-
const aiData = JSON.stringify({
|
|
439
|
-
contents: [{ parts: [{ text: systemPrompt + "\nUser: " + input }] }]
|
|
440
|
-
});
|
|
441
|
-
const askAI = (modelIndex, versionIndex) => {
|
|
442
|
-
const models = ['gemini-flash-latest', 'gemini-1.5-flash', 'gemini-pro-latest'];
|
|
443
|
-
const versions = ['v1beta', 'v1'];
|
|
444
|
-
if (modelIndex >= models.length) {
|
|
445
|
-
console.log('🤖 Dolphin: Sorry, I am having trouble connecting right now.');
|
|
446
|
-
return ask();
|
|
447
|
-
}
|
|
448
|
-
if (versionIndex >= versions.length)
|
|
449
|
-
return askAI(modelIndex + 1, 0);
|
|
450
|
-
const currentModel = models[modelIndex];
|
|
451
|
-
const currentVersion = versions[versionIndex];
|
|
452
|
-
const options = {
|
|
453
|
-
hostname: 'generativelanguage.googleapis.com',
|
|
454
|
-
path: `/${currentVersion}/models/${currentModel}:generateContent?key=${encodeURIComponent(agentApiKey)}`,
|
|
455
|
-
method: 'POST',
|
|
456
|
-
headers: { 'Content-Type': 'application/json' }
|
|
457
|
-
};
|
|
458
|
-
const req = https_1.default.request(options, (res) => {
|
|
459
|
-
let body = '';
|
|
460
|
-
res.on('data', (d) => body += d);
|
|
461
|
-
res.on('end', async () => {
|
|
462
|
-
try {
|
|
463
|
-
const json = JSON.parse(body);
|
|
464
|
-
const reply = json.candidates?.[0]?.content?.parts?.[0]?.text || '';
|
|
465
|
-
if (!reply)
|
|
466
|
-
return askAI(modelIndex, versionIndex + 1);
|
|
467
|
-
// Handle FILE_WRITE
|
|
468
|
-
if (reply.includes('FILE_WRITE:')) {
|
|
469
|
-
const match = reply.match(/FILE_WRITE: (.*?)\n([\s\S]*?)END_FILE/);
|
|
470
|
-
if (match) {
|
|
471
|
-
const fPath = match[1].trim();
|
|
472
|
-
const content = match[2].trim().replace(/```javascript|```js|```/g, '');
|
|
473
|
-
const fullPath = path_1.default.join(process.cwd(), fPath);
|
|
474
|
-
const dir = path_1.default.dirname(fullPath);
|
|
475
|
-
if (!fs_1.default.existsSync(dir))
|
|
476
|
-
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
477
|
-
fs_1.default.writeFileSync(fullPath, content);
|
|
478
|
-
console.log(`🤖 Dolphin Agent: Created/Updated file [${fPath}]`);
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
// Handle SHELL_RUN
|
|
482
|
-
if (reply.includes('SHELL_RUN:')) {
|
|
483
|
-
const cmdMatch = reply.match(/SHELL_RUN: (.*)/);
|
|
484
|
-
if (cmdMatch) {
|
|
485
|
-
const cmd = cmdMatch[1].trim();
|
|
486
|
-
console.log(`🤖 Dolphin Agent: Executing [${cmd}]...`);
|
|
487
|
-
try {
|
|
488
|
-
const { execSync } = await Promise.resolve().then(() => __importStar(require('child_process')));
|
|
489
|
-
execSync(cmd, { stdio: 'inherit' });
|
|
490
|
-
}
|
|
491
|
-
catch (e) {
|
|
492
|
-
console.log(`❌ Command failed: ${cmd}`);
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
// Handle FILE_READ
|
|
497
|
-
if (reply.includes('FILE_READ:')) {
|
|
498
|
-
const readMatch = reply.match(/FILE_READ: (.*)/);
|
|
499
|
-
if (readMatch) {
|
|
500
|
-
const rPath = readMatch[1].trim();
|
|
501
|
-
const fullRPath = path_1.default.join(process.cwd(), rPath);
|
|
502
|
-
if (fs_1.default.existsSync(fullRPath)) {
|
|
503
|
-
const content = fs_1.default.readFileSync(fullRPath, 'utf8');
|
|
504
|
-
console.log(`🤖 Dolphin Agent: Read file [${rPath}]`);
|
|
505
|
-
// We send the content back as a follow-up user message
|
|
506
|
-
input = `Content of ${rPath}:\n${content}\nNow proceed with my previous request.`;
|
|
507
|
-
return askAI(0, 0);
|
|
508
|
-
}
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
console.log(`🤖 Dolphin: ${reply.split('FILE_WRITE:')[0].split('SHELL_RUN:')[0].split('FILE_READ:')[0].trim()}\n`);
|
|
512
|
-
ask();
|
|
513
|
-
}
|
|
514
|
-
catch (e) {
|
|
515
|
-
askAI(modelIndex, versionIndex + 1);
|
|
516
|
-
}
|
|
517
|
-
});
|
|
518
|
-
});
|
|
519
|
-
req.on('error', () => askAI(modelIndex, versionIndex + 1));
|
|
520
|
-
req.write(aiData);
|
|
521
|
-
req.end();
|
|
522
|
-
};
|
|
523
|
-
askAI(0, 0);
|
|
524
|
-
});
|
|
525
|
-
};
|
|
526
|
-
ask();
|
|
527
|
-
});
|
|
528
|
-
break;
|
|
529
|
-
case 'clean':
|
|
530
|
-
const filesToClean = ['ai-generated-app.js', 'ai-test-output.js'];
|
|
531
|
-
filesToClean.forEach(file => {
|
|
532
|
-
const filePath = path_1.default.join(process.cwd(), file);
|
|
533
|
-
if (fs_1.default.existsSync(filePath)) {
|
|
534
|
-
fs_1.default.unlinkSync(filePath);
|
|
535
|
-
console.log(`🗑️ Deleted: ${file}`);
|
|
536
|
-
}
|
|
537
|
-
});
|
|
538
|
-
console.log('✅ Cleanup complete.');
|
|
539
|
-
break;
|
|
540
|
-
case 'serve':
|
|
541
|
-
let portStr = args.find(arg => arg.startsWith('--port='))?.split('=')[1];
|
|
542
|
-
if (!portStr) {
|
|
543
|
-
const portIdx = args.indexOf('--port');
|
|
544
|
-
if (portIdx !== -1 && args[portIdx + 1])
|
|
545
|
-
portStr = args[portIdx + 1];
|
|
546
|
-
}
|
|
547
|
-
const port = parseInt(portStr || '3000');
|
|
548
|
-
const rt = new core_1.RealtimeCore({ debug: true });
|
|
549
|
-
const server = (0, server_1.createDolphinServer)({ realtime: rt });
|
|
550
|
-
server.get('/', (ctx) => ctx.html('<h1>Dolphin CLI Static Server</h1>'));
|
|
551
|
-
server.listen(port, () => console.log(`✅ Dolphin Server running at http://localhost:${port}`));
|
|
203
|
+
chatLoop();
|
|
552
204
|
break;
|
|
553
205
|
case 'init':
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
"mongoose": "^8.0.0",
|
|
565
|
-
"zod": "^3.22.0"
|
|
566
|
-
}
|
|
567
|
-
}, null, 2));
|
|
568
|
-
console.log('✅ Created package.json with core dependencies.');
|
|
569
|
-
}
|
|
570
|
-
else {
|
|
571
|
-
console.log('⚠️ package.json already exists. Skipping...');
|
|
572
|
-
}
|
|
573
|
-
if (!fs_1.default.existsSync(path_1.default.join(process.cwd(), '.gitignore'))) {
|
|
574
|
-
fs_1.default.writeFileSync(path_1.default.join(process.cwd(), '.gitignore'), '.env\nnode_modules\ndist\n.DS_Store');
|
|
575
|
-
console.log('✅ Created .gitignore');
|
|
576
|
-
}
|
|
206
|
+
case 'init-prod':
|
|
207
|
+
CLIUI.heading('Scaffolding Production Project');
|
|
208
|
+
const dirs = ['models', 'controllers', 'routes', 'middleware', 'services', 'config'];
|
|
209
|
+
dirs.forEach(dir => {
|
|
210
|
+
const p = path.join(process.cwd(), dir);
|
|
211
|
+
if (!fs.existsSync(p))
|
|
212
|
+
fs.mkdirSync(p, { recursive: true });
|
|
213
|
+
});
|
|
214
|
+
fs.writeFileSync(path.join(process.cwd(), 'app.js'), TEMPLATES.app);
|
|
215
|
+
CLIUI.success('Folders and app.js created.');
|
|
577
216
|
break;
|
|
578
217
|
case 'add':
|
|
579
|
-
const
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
if (
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
console.log('✅ Added Sequelize (SQL) Adapter template to db-sql.js');
|
|
218
|
+
const subCommand = args[1];
|
|
219
|
+
if (subCommand === 'adapter') {
|
|
220
|
+
const type = args[2];
|
|
221
|
+
if (type === 'mongoose') {
|
|
222
|
+
const configDir = path.join(process.cwd(), 'config');
|
|
223
|
+
if (!fs.existsSync(configDir))
|
|
224
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
225
|
+
fs.writeFileSync(path.join(configDir, 'db.js'), TEMPLATES.mongoose);
|
|
226
|
+
CLIUI.success('Mongoose adapter added to config/db.js');
|
|
589
227
|
}
|
|
590
228
|
else {
|
|
591
|
-
|
|
229
|
+
CLIUI.error('Unsupported adapter. Try: dolphin add adapter mongoose');
|
|
592
230
|
}
|
|
593
231
|
}
|
|
594
|
-
else if (
|
|
595
|
-
|
|
596
|
-
|
|
232
|
+
else if (subCommand === 'auth') {
|
|
233
|
+
const controllerDir = path.join(process.cwd(), 'controllers');
|
|
234
|
+
const modelDir = path.join(process.cwd(), 'models');
|
|
235
|
+
if (!fs.existsSync(controllerDir))
|
|
236
|
+
fs.mkdirSync(controllerDir, { recursive: true });
|
|
237
|
+
if (!fs.existsSync(modelDir))
|
|
238
|
+
fs.mkdirSync(modelDir, { recursive: true });
|
|
239
|
+
fs.writeFileSync(path.join(controllerDir, 'auth.js'), TEMPLATES.auth);
|
|
240
|
+
fs.writeFileSync(path.join(modelDir, 'User.js'), TEMPLATES.authModel);
|
|
241
|
+
CLIUI.success('Auth controller and User model added.');
|
|
597
242
|
}
|
|
598
|
-
else if (
|
|
599
|
-
const
|
|
600
|
-
|
|
601
|
-
|
|
243
|
+
else if (subCommand === 'crud') {
|
|
244
|
+
const name = args[2];
|
|
245
|
+
if (!name)
|
|
246
|
+
return CLIUI.error('Usage: dolphin add crud <ModelName>');
|
|
247
|
+
const controllerDir = path.join(process.cwd(), 'controllers');
|
|
248
|
+
const modelDir = path.join(process.cwd(), 'models');
|
|
249
|
+
if (!fs.existsSync(controllerDir))
|
|
250
|
+
fs.mkdirSync(controllerDir, { recursive: true });
|
|
251
|
+
if (!fs.existsSync(modelDir))
|
|
252
|
+
fs.mkdirSync(modelDir, { recursive: true });
|
|
253
|
+
fs.writeFileSync(path.join(controllerDir, `${name.toLowerCase()}.js`), TEMPLATES.crud(name));
|
|
254
|
+
fs.writeFileSync(path.join(modelDir, `${name}.js`), TEMPLATES.crudModel(name));
|
|
255
|
+
CLIUI.success(`CRUD Controller and Model for ${name} generated successfully!`);
|
|
256
|
+
console.log(` 📄 Created: controllers/${name.toLowerCase()}.js`);
|
|
257
|
+
console.log(` 📄 Created: models/${name}.js`);
|
|
602
258
|
}
|
|
603
259
|
else {
|
|
604
|
-
|
|
605
|
-
}
|
|
606
|
-
break;
|
|
607
|
-
case 'mongo-auth-model':
|
|
608
|
-
const modelsDir = path_1.default.join(process.cwd(), 'models');
|
|
609
|
-
if (!fs_1.default.existsSync(modelsDir)) {
|
|
610
|
-
fs_1.default.mkdirSync(modelsDir);
|
|
611
|
-
}
|
|
612
|
-
fs_1.default.writeFileSync(path_1.default.join(modelsDir, 'auth-models.js'), TEMPLATES.authModel);
|
|
613
|
-
console.log('✅ Generated fixed Auth models (User, RefreshToken) in models/auth-models.js');
|
|
614
|
-
break;
|
|
615
|
-
case 'init-prod':
|
|
616
|
-
console.log('🚀 Scaffolding Production-Ready Dolphin Project...');
|
|
617
|
-
const dirs = ['models', 'controllers', 'routes', 'middleware', 'services', 'config'];
|
|
618
|
-
dirs.forEach(dir => {
|
|
619
|
-
const dirPath = path_1.default.join(process.cwd(), dir);
|
|
620
|
-
if (!fs_1.default.existsSync(dirPath)) {
|
|
621
|
-
fs_1.default.mkdirSync(dirPath);
|
|
622
|
-
console.log(`📁 Created: /${dir}`);
|
|
623
|
-
}
|
|
624
|
-
});
|
|
625
|
-
// Create basic files in the structure
|
|
626
|
-
fs_1.default.writeFileSync(path_1.default.join(process.cwd(), 'app.js'), TEMPLATES.app);
|
|
627
|
-
fs_1.default.writeFileSync(path_1.default.join(process.cwd(), 'config', 'db.js'), TEMPLATES.mongoose);
|
|
628
|
-
if (!fs_1.default.existsSync(path_1.default.join(process.cwd(), 'package.json'))) {
|
|
629
|
-
fs_1.default.writeFileSync(path_1.default.join(process.cwd(), 'package.json'), JSON.stringify({
|
|
630
|
-
name: path_1.default.basename(process.cwd()),
|
|
631
|
-
version: '1.0.0',
|
|
632
|
-
main: 'app.js',
|
|
633
|
-
type: 'module',
|
|
634
|
-
dependencies: {
|
|
635
|
-
"dolphin-server-modules": "^2.2.4",
|
|
636
|
-
"mongoose": "^8.0.0",
|
|
637
|
-
"zod": "^3.22.0"
|
|
638
|
-
}
|
|
639
|
-
}, null, 2));
|
|
640
|
-
}
|
|
641
|
-
if (!fs_1.default.existsSync(path_1.default.join(process.cwd(), '.gitignore'))) {
|
|
642
|
-
fs_1.default.writeFileSync(path_1.default.join(process.cwd(), '.gitignore'), '.env\nnode_modules\ndist\n.DS_Store');
|
|
643
|
-
console.log('✅ Created .gitignore');
|
|
260
|
+
CLIUI.error('Usage: dolphin add <adapter|auth|crud>');
|
|
644
261
|
}
|
|
645
|
-
console.log('✅ Production scaffolding complete. Start swimming! 🐬');
|
|
646
262
|
break;
|
|
647
263
|
case 'help':
|
|
648
264
|
default:
|
|
265
|
+
CLIUI.heading('Dolphin Framework CLI');
|
|
649
266
|
console.log(`
|
|
650
|
-
🐬 Dolphin Framework CLI
|
|
651
267
|
Commands:
|
|
652
|
-
serve Start
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
add adapter <type> Add a database adapter (mongoose, sequelize)
|
|
661
|
-
add auth Add a pre-configured Auth controller
|
|
662
|
-
add crud <Name> Add a pre-configured CRUD controller
|
|
663
|
-
mongo-auth-model Generate fixed Mongoose models for Auth (User, RefreshToken)
|
|
664
|
-
generate "prompt" --model=gemini-1.5-pro (Custom AI model support)
|
|
665
|
-
|
|
666
|
-
Options:
|
|
667
|
-
--port=3000 Specify port for serve command
|
|
268
|
+
serve Start development server
|
|
269
|
+
generate <prompt> Quick AI code generation
|
|
270
|
+
generate-full <p> Full project architecture
|
|
271
|
+
chat Interactive AI coding assistant
|
|
272
|
+
init-prod Scaffold production folder structure
|
|
273
|
+
add adapter <t> Add Mongoose/Sequelize adapter
|
|
274
|
+
add auth Add pre-built Auth controller
|
|
275
|
+
add crud <Name> Add CRUD controller for a model
|
|
668
276
|
`);
|
|
669
277
|
break;
|
|
670
278
|
}
|
|
671
279
|
}
|
|
672
280
|
run().catch(err => {
|
|
673
|
-
|
|
281
|
+
CLIUI.error(err.message);
|
|
674
282
|
});
|
|
675
283
|
//# sourceMappingURL=cli.js.map
|