oneurai-cli 1.0.2
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/index.js +354 -0
- package/oneurai-cli-1.0.0.tgz +0 -0
- package/oneurai-cli-1.0.1.tgz +0 -0
- package/oneurai-cli-1.0.2.tgz +0 -0
- package/oneurai.json +9 -0
- package/package.json +27 -0
package/bin/index.js
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import inquirer from 'inquirer';
|
|
6
|
+
import axios from 'axios';
|
|
7
|
+
import Conf from 'conf';
|
|
8
|
+
import ora from 'ora';
|
|
9
|
+
import fs from 'fs';
|
|
10
|
+
import path from 'path';
|
|
11
|
+
import archiver from 'archiver';
|
|
12
|
+
import FormData from 'form-data';
|
|
13
|
+
import { execSync } from 'child_process'; // 👈 ضف هذا السطر
|
|
14
|
+
import { createRequire } from 'module'; // 👈 وهذا عشان نقرأ إصدارنا الحالي
|
|
15
|
+
const require = createRequire(import.meta.url);
|
|
16
|
+
const packageJson = require('../package.json'); // قراءة ملف package
|
|
17
|
+
import AdmZip from 'adm-zip';
|
|
18
|
+
|
|
19
|
+
const program = new Command();
|
|
20
|
+
const config = new Conf({ projectName: 'one-cli' });
|
|
21
|
+
|
|
22
|
+
const API_URL = 'https://oneurai.com/api';
|
|
23
|
+
|
|
24
|
+
// --- دالة مساعدة لجلب بيانات المستخدم ---
|
|
25
|
+
async function ensureUsername(token) {
|
|
26
|
+
let username = config.get('username');
|
|
27
|
+
if (username) return username;
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const response = await axios.get(`${API_URL}/user`, {
|
|
31
|
+
headers: { Authorization: `Bearer ${token}`, Accept: 'application/json' }
|
|
32
|
+
});
|
|
33
|
+
username = response.data.username || response.data.name;
|
|
34
|
+
config.set('username', username);
|
|
35
|
+
return username;
|
|
36
|
+
} catch (error) {
|
|
37
|
+
return 'user';
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
program
|
|
42
|
+
.name('one')
|
|
43
|
+
.description('Oneurai CLI - Official Tool')
|
|
44
|
+
.version('1.0.0');
|
|
45
|
+
|
|
46
|
+
// --- HELLO ---
|
|
47
|
+
program
|
|
48
|
+
.command('hello')
|
|
49
|
+
.description('Check connection')
|
|
50
|
+
.action(async () => {
|
|
51
|
+
console.log(chalk.green.bold('Welcome to Oneurai CLI! 🚀'));
|
|
52
|
+
const token = config.get('auth_token');
|
|
53
|
+
|
|
54
|
+
if (!token) {
|
|
55
|
+
console.log(chalk.yellow('Not logged in. Run: one login'));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const spinner = ora('Checking connection...').start();
|
|
60
|
+
try {
|
|
61
|
+
config.delete('username');
|
|
62
|
+
const username = await ensureUsername(token);
|
|
63
|
+
spinner.succeed(chalk.cyan(`Connected as: ${chalk.bold(username)} ✅`));
|
|
64
|
+
} catch (error) {
|
|
65
|
+
spinner.fail(chalk.red('Connection failed.'));
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// --- LOGIN ---
|
|
70
|
+
program
|
|
71
|
+
.command('login')
|
|
72
|
+
.description('Authenticate')
|
|
73
|
+
.action(async () => {
|
|
74
|
+
console.log(chalk.blue.bold('🔐 Authenticate with Oneurai.com'));
|
|
75
|
+
|
|
76
|
+
const answers = await inquirer.prompt([
|
|
77
|
+
{
|
|
78
|
+
type: 'password',
|
|
79
|
+
name: 'token',
|
|
80
|
+
message: 'Paste your Access Token:',
|
|
81
|
+
validate: input => input.length > 5 || 'Invalid token.'
|
|
82
|
+
}
|
|
83
|
+
]);
|
|
84
|
+
|
|
85
|
+
const spinner = ora('Verifying...').start();
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const response = await axios.get(`${API_URL}/user`, {
|
|
89
|
+
headers: {
|
|
90
|
+
'Authorization': `Bearer ${answers.token}`,
|
|
91
|
+
'Accept': 'application/json'
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
config.set('auth_token', answers.token);
|
|
96
|
+
|
|
97
|
+
const username = response.data.username || response.data.name;
|
|
98
|
+
config.set('username', username);
|
|
99
|
+
|
|
100
|
+
spinner.succeed(chalk.green(`Success! Logged in as ${chalk.bold(username)}`));
|
|
101
|
+
|
|
102
|
+
} catch (error) {
|
|
103
|
+
spinner.fail(chalk.red('Login failed.'));
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// --- LOGOUT ---
|
|
108
|
+
program.command('logout').action(() => {
|
|
109
|
+
config.delete('auth_token');
|
|
110
|
+
config.delete('username');
|
|
111
|
+
console.log(chalk.green('Logged out.'));
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// --- INIT (المعدل والمضمون) ---
|
|
115
|
+
program
|
|
116
|
+
.command('init')
|
|
117
|
+
.description('Create project')
|
|
118
|
+
.action(async () => {
|
|
119
|
+
const token = config.get('auth_token');
|
|
120
|
+
if (!token) return console.log(chalk.red('Please login first.'));
|
|
121
|
+
|
|
122
|
+
if (fs.existsSync('./oneurai.json')) {
|
|
123
|
+
return console.log(chalk.yellow('⚠️ oneurai.json already exists.'));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const username = await ensureUsername(token);
|
|
127
|
+
|
|
128
|
+
console.log(chalk.blue.bold('⚡ Create New Oneurai Project'));
|
|
129
|
+
|
|
130
|
+
const answers = await inquirer.prompt([
|
|
131
|
+
{
|
|
132
|
+
type: 'input',
|
|
133
|
+
name: 'title',
|
|
134
|
+
message: 'Project Title:',
|
|
135
|
+
validate: input => input.length > 2 || 'Min 2 chars.'
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
type: 'input',
|
|
139
|
+
name: 'slug',
|
|
140
|
+
message: 'Project Slug:',
|
|
141
|
+
default: (answers) => answers.title.toLowerCase().replace(/ /g, '-'),
|
|
142
|
+
validate: input => /^[a-z0-9-_]+$/.test(input) || 'Use letters, numbers, dashes.'
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
type: 'confirm',
|
|
146
|
+
name: 'is_public',
|
|
147
|
+
message: 'Is this project Public (Open Source)?',
|
|
148
|
+
default: true
|
|
149
|
+
}
|
|
150
|
+
]);
|
|
151
|
+
|
|
152
|
+
const spinner = ora('Creating...').start();
|
|
153
|
+
|
|
154
|
+
try {
|
|
155
|
+
const response = await axios.post(`${API_URL}/projects/create`, {
|
|
156
|
+
title: answers.title,
|
|
157
|
+
slug: answers.slug,
|
|
158
|
+
is_public: answers.is_public
|
|
159
|
+
}, {
|
|
160
|
+
headers: { Authorization: `Bearer ${token}`, Accept: 'application/json' }
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
const projectConfig = {
|
|
164
|
+
name: response.data.project.slug,
|
|
165
|
+
id: response.data.project.id,
|
|
166
|
+
created_at: new Date().toISOString(),
|
|
167
|
+
// ✅ تم إضافة oneurai.json للقائمة الافتراضية هنا
|
|
168
|
+
ignore: ['node_modules', '.git', '.env', 'storage', 'vendor', '*.zip', 'oneurai.json']
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
fs.writeFileSync('./oneurai.json', JSON.stringify(projectConfig, null, 2));
|
|
172
|
+
|
|
173
|
+
spinner.succeed(chalk.green(`Created: ${response.data.project.title}`));
|
|
174
|
+
|
|
175
|
+
console.log(chalk.cyan(`🔗 Link: https://oneurai.com/project/${username}/${response.data.project.slug}`));
|
|
176
|
+
console.log(chalk.gray('Run "one push" to deploy.'));
|
|
177
|
+
|
|
178
|
+
} catch (error) {
|
|
179
|
+
spinner.fail(chalk.red('Failed.'));
|
|
180
|
+
if (error.response && error.response.data.errors) {
|
|
181
|
+
console.error(chalk.red(JSON.stringify(error.response.data.errors)));
|
|
182
|
+
} else if (error.response) {
|
|
183
|
+
console.error(chalk.red(JSON.stringify(error.response.data)));
|
|
184
|
+
} else {
|
|
185
|
+
console.error(chalk.red(error.message));
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// --- PUSH ---
|
|
191
|
+
program
|
|
192
|
+
.command('push')
|
|
193
|
+
.description('Deploy files')
|
|
194
|
+
.action(async () => {
|
|
195
|
+
const token = config.get('auth_token');
|
|
196
|
+
if (!token) return console.log(chalk.red('Please login first.'));
|
|
197
|
+
|
|
198
|
+
if (!fs.existsSync('./oneurai.json')) return console.log(chalk.red('Run: one init'));
|
|
199
|
+
|
|
200
|
+
const username = await ensureUsername(token);
|
|
201
|
+
const projectConfig = JSON.parse(fs.readFileSync('./oneurai.json', 'utf-8'));
|
|
202
|
+
console.log(chalk.blue.bold(`🚀 Deploying ${projectConfig.name}...`));
|
|
203
|
+
|
|
204
|
+
const spinner = ora('Compressing...').start();
|
|
205
|
+
|
|
206
|
+
const output = fs.createWriteStream('project.zip');
|
|
207
|
+
const archive = archiver('zip', { zlib: { level: 9 } });
|
|
208
|
+
|
|
209
|
+
output.on('close', async () => {
|
|
210
|
+
spinner.text = 'Uploading...';
|
|
211
|
+
|
|
212
|
+
try {
|
|
213
|
+
const form = new FormData();
|
|
214
|
+
form.append('project_name', projectConfig.name);
|
|
215
|
+
form.append('file', fs.createReadStream('project.zip'));
|
|
216
|
+
|
|
217
|
+
await axios.post(`${API_URL}/deploy`, form, {
|
|
218
|
+
headers: { ...form.getHeaders(), 'Authorization': `Bearer ${token}` },
|
|
219
|
+
maxContentLength: Infinity,
|
|
220
|
+
maxBodyLength: Infinity
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
fs.unlinkSync('project.zip');
|
|
224
|
+
spinner.succeed(chalk.green('Deployed successfully! ☁️'));
|
|
225
|
+
|
|
226
|
+
console.log(chalk.cyan(`\n🔗 View project: https://oneurai.com/project/${username}/${projectConfig.name}`));
|
|
227
|
+
|
|
228
|
+
} catch (error) {
|
|
229
|
+
if (fs.existsSync('project.zip')) fs.unlinkSync('project.zip');
|
|
230
|
+
spinner.fail(chalk.red('Deployment failed ❌'));
|
|
231
|
+
if(error.response) console.error(chalk.red(error.response.data.message));
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
archive.on('error', (err) => { throw err; });
|
|
236
|
+
archive.pipe(output);
|
|
237
|
+
|
|
238
|
+
// ✅ التعديل هنا: دمج قائمة التجاهل مع oneurai.json وإجبار استبعاده
|
|
239
|
+
const ignoreList = projectConfig.ignore || ['node_modules/**', '.git/**'];
|
|
240
|
+
|
|
241
|
+
// نضيف oneurai.json للقائمة إذا لم يكن موجوداً
|
|
242
|
+
if (!ignoreList.includes('oneurai.json')) {
|
|
243
|
+
ignoreList.push('oneurai.json');
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
archive.glob('**/*', {
|
|
247
|
+
cwd: process.cwd(),
|
|
248
|
+
ignore: ignoreList
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
archive.finalize();
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
program
|
|
255
|
+
.command('update')
|
|
256
|
+
.description('Update CLI to the latest version')
|
|
257
|
+
.action(async () => {
|
|
258
|
+
console.log(chalk.blue.bold('🔄 Checking for updates...'));
|
|
259
|
+
const spinner = ora('Contacting server...').start();
|
|
260
|
+
|
|
261
|
+
try {
|
|
262
|
+
// 1. جلب رقم الإصدار الأحدث من السيرفر
|
|
263
|
+
// تأكد أنك أنشأت الملف في سيرفرك في المسار public/cli/version.json
|
|
264
|
+
const response = await axios.get('https://oneurai.com/cli/version.json');
|
|
265
|
+
const latestVersion = response.data.version;
|
|
266
|
+
const currentVersion = packageJson.version;
|
|
267
|
+
|
|
268
|
+
if (latestVersion === currentVersion) {
|
|
269
|
+
spinner.succeed(chalk.green('You are already on the latest version! ✅'));
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
spinner.info(chalk.yellow(`New version found: ${latestVersion} (Current: ${currentVersion})`));
|
|
274
|
+
spinner.start('Installing update...');
|
|
275
|
+
|
|
276
|
+
// 2. تنفيذ أمر التحديث السحري
|
|
277
|
+
// هذا الأمر يخلي npm يحمل الملف من سيرفرك ويثبته فوق النسخة الحالية
|
|
278
|
+
execSync('npm install -g https://oneurai.com/cli/one-latest.tgz', { stdio: 'inherit' });
|
|
279
|
+
|
|
280
|
+
spinner.succeed(chalk.green(`Successfully updated to v${latestVersion} 🚀`));
|
|
281
|
+
console.log(chalk.gray('Please restart your terminal to apply changes.'));
|
|
282
|
+
|
|
283
|
+
} catch (error) {
|
|
284
|
+
spinner.fail(chalk.red('Update failed.'));
|
|
285
|
+
if (error.response && error.response.status === 404) {
|
|
286
|
+
console.error(chalk.red('Update server not found (404). Check files on server.'));
|
|
287
|
+
} else {
|
|
288
|
+
console.error(chalk.red(error.message));
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
program
|
|
294
|
+
.command('get <slug>')
|
|
295
|
+
.description('Download (Clone) a project from Oneurai')
|
|
296
|
+
.action(async (slug) => {
|
|
297
|
+
const token = config.get('auth_token');
|
|
298
|
+
if (!token) return console.log(chalk.red('Please login first.'));
|
|
299
|
+
|
|
300
|
+
// التحقق هل المجلد موجود مسبقاً؟
|
|
301
|
+
if (fs.existsSync(slug)) {
|
|
302
|
+
return console.log(chalk.red(`❌ Directory "${slug}" already exists. Please delete it or choose another location.`));
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const spinner = ora(`Fetching project "${slug}"...`).start();
|
|
306
|
+
|
|
307
|
+
try {
|
|
308
|
+
// 1. طلب الملف المضغوط
|
|
309
|
+
const response = await axios({
|
|
310
|
+
method: 'get',
|
|
311
|
+
url: `${API_URL}/projects/${slug}/download`,
|
|
312
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
313
|
+
responseType: 'arraybuffer'
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
spinner.text = 'Unzipping files...';
|
|
317
|
+
|
|
318
|
+
// 2. إنشاء المجلد
|
|
319
|
+
fs.mkdirSync(slug);
|
|
320
|
+
|
|
321
|
+
// 3. حفظ الملف وفك الضغط
|
|
322
|
+
const zipPath = path.join(slug, 'temp_project.zip');
|
|
323
|
+
fs.writeFileSync(zipPath, response.data);
|
|
324
|
+
|
|
325
|
+
const zip = new AdmZip(zipPath);
|
|
326
|
+
zip.extractAllTo(slug, true);
|
|
327
|
+
|
|
328
|
+
// 4. تنظيف
|
|
329
|
+
fs.unlinkSync(zipPath);
|
|
330
|
+
|
|
331
|
+
// ✅ حذفنا كود إنشاء oneurai.json من هنا
|
|
332
|
+
|
|
333
|
+
spinner.succeed(chalk.green(`Successfully downloaded "${slug}"! 📦`));
|
|
334
|
+
|
|
335
|
+
// تعليمات واضحة للمستخدم
|
|
336
|
+
console.log(chalk.cyan(`\nNext steps:`));
|
|
337
|
+
console.log(chalk.white(` 1. cd ${slug}`));
|
|
338
|
+
console.log(chalk.white(` 2. one init (to link this folder)`)); // 👈 تذكير بالـ init
|
|
339
|
+
|
|
340
|
+
} catch (error) {
|
|
341
|
+
if (fs.existsSync(slug)) {
|
|
342
|
+
fs.rmSync(slug, { recursive: true, force: true });
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
spinner.fail(chalk.red('Download failed.'));
|
|
346
|
+
|
|
347
|
+
if (error.response && error.response.status === 404) {
|
|
348
|
+
console.error(chalk.red('❌ Project not found or access denied.'));
|
|
349
|
+
} else {
|
|
350
|
+
console.error(chalk.red(error.message));
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
program.parse(process.argv);
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/oneurai.json
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "oneurai-cli",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "Oneurai CLI Tool",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"one": "./bin/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [],
|
|
14
|
+
"author": "",
|
|
15
|
+
"license": "ISC",
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"adm-zip": "^0.5.16",
|
|
18
|
+
"archiver": "^7.0.1",
|
|
19
|
+
"axios": "^1.13.2",
|
|
20
|
+
"chalk": "^5.6.2",
|
|
21
|
+
"commander": "^14.0.2",
|
|
22
|
+
"conf": "^15.0.2",
|
|
23
|
+
"form-data": "^4.0.5",
|
|
24
|
+
"inquirer": "^13.1.0",
|
|
25
|
+
"ora": "^9.0.0"
|
|
26
|
+
}
|
|
27
|
+
}
|