oneurai-cli 1.0.2 → 1.0.4
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 +305 -264
- package/oneurai-cli-1.0.3.tgz +0 -0
- package/oneurai-cli-1.0.4.tgz +0 -0
- package/package.json +2 -1
package/bin/index.js
CHANGED
|
@@ -8,29 +8,32 @@ import Conf from 'conf';
|
|
|
8
8
|
import ora from 'ora';
|
|
9
9
|
import fs from 'fs';
|
|
10
10
|
import path from 'path';
|
|
11
|
-
import archiver from 'archiver';
|
|
11
|
+
import archiver from 'archiver';
|
|
12
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
|
|
13
|
+
import { exec, execSync } from 'child_process';
|
|
14
|
+
import { createRequire } from 'module';
|
|
17
15
|
import AdmZip from 'adm-zip';
|
|
16
|
+
import chokidar from 'chokidar'; // 👈 للمراقبة
|
|
17
|
+
|
|
18
|
+
const require = createRequire(import.meta.url);
|
|
19
|
+
const packageJson = require('../package.json');
|
|
18
20
|
|
|
19
21
|
const program = new Command();
|
|
20
22
|
const config = new Conf({ projectName: 'one-cli' });
|
|
21
23
|
|
|
22
|
-
const API_URL = 'https://oneurai.com/api';
|
|
24
|
+
const API_URL = 'https://oneurai.com/api';
|
|
25
|
+
const VERSION_URL = 'https://oneurai.com/cli/version.json';
|
|
26
|
+
|
|
27
|
+
// --- دوال مساعدة ---
|
|
23
28
|
|
|
24
|
-
// --- دالة مساعدة لجلب بيانات المستخدم ---
|
|
25
29
|
async function ensureUsername(token) {
|
|
26
30
|
let username = config.get('username');
|
|
27
31
|
if (username) return username;
|
|
28
|
-
|
|
29
32
|
try {
|
|
30
33
|
const response = await axios.get(`${API_URL}/user`, {
|
|
31
34
|
headers: { Authorization: `Bearer ${token}`, Accept: 'application/json' }
|
|
32
35
|
});
|
|
33
|
-
username = response.data.username || response.data.name;
|
|
36
|
+
username = response.data.username || response.data.name;
|
|
34
37
|
config.set('username', username);
|
|
35
38
|
return username;
|
|
36
39
|
} catch (error) {
|
|
@@ -38,317 +41,355 @@ async function ensureUsername(token) {
|
|
|
38
41
|
}
|
|
39
42
|
}
|
|
40
43
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
}
|
|
44
|
+
// دالة الرفع (Deploy) - فصلناها عشان نستخدمها في push وفي watch
|
|
45
|
+
async function deployProject(token, projectConfig, spinner = null) {
|
|
46
|
+
if (!spinner) spinner = ora('Preparing deploy...').start();
|
|
58
47
|
|
|
59
|
-
const
|
|
60
|
-
|
|
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
|
-
]);
|
|
48
|
+
const output = fs.createWriteStream('project.zip');
|
|
49
|
+
const archive = archiver('zip', { zlib: { level: 9 } });
|
|
84
50
|
|
|
85
|
-
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
52
|
+
output.on('close', async () => {
|
|
53
|
+
spinner.text = 'Uploading to Oneurai...';
|
|
54
|
+
try {
|
|
55
|
+
const form = new FormData();
|
|
56
|
+
form.append('project_name', projectConfig.name);
|
|
57
|
+
form.append('file', fs.createReadStream('project.zip'));
|
|
58
|
+
|
|
59
|
+
await axios.post(`${API_URL}/deploy`, form, {
|
|
60
|
+
headers: { ...form.getHeaders(), 'Authorization': `Bearer ${token}` },
|
|
61
|
+
maxContentLength: Infinity,
|
|
62
|
+
maxBodyLength: Infinity
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
fs.unlinkSync('project.zip');
|
|
66
|
+
spinner.succeed(chalk.green(`Deployed: ${projectConfig.name} at ${new Date().toLocaleTimeString()} 🚀`));
|
|
67
|
+
resolve(true);
|
|
68
|
+
|
|
69
|
+
} catch (error) {
|
|
70
|
+
if (fs.existsSync('project.zip')) fs.unlinkSync('project.zip');
|
|
71
|
+
spinner.fail(chalk.red('Deployment failed.'));
|
|
72
|
+
if (error.response) console.error(chalk.red(error.response.data.message));
|
|
73
|
+
resolve(false); // Resolve false instead of reject to keep watch alive
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
archive.on('error', (err) => {
|
|
78
|
+
spinner.fail('Archiving failed');
|
|
79
|
+
reject(err);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
archive.pipe(output);
|
|
86
83
|
|
|
84
|
+
const ignoreList = projectConfig.ignore || ['node_modules/**', '.git/**'];
|
|
85
|
+
if (!ignoreList.includes('oneurai.json')) ignoreList.push('oneurai.json');
|
|
86
|
+
|
|
87
|
+
archive.glob('**/*', { cwd: process.cwd(), ignore: ignoreList });
|
|
88
|
+
archive.finalize();
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// --- إعدادات البرنامج ---
|
|
93
|
+
program.name('one').description('Oneurai CLI - Official Tool').version(packageJson.version);
|
|
94
|
+
|
|
95
|
+
// --- Middleware: Check Update ---
|
|
96
|
+
program.hook('preAction', async (thisCommand, actionCommand) => {
|
|
97
|
+
if (['update', 'help'].includes(actionCommand.name())) return;
|
|
87
98
|
try {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
'
|
|
91
|
-
|
|
99
|
+
const response = await axios.get(VERSION_URL, { timeout: 1500 });
|
|
100
|
+
if (response.data.version !== packageJson.version) {
|
|
101
|
+
console.log(chalk.bgRed.white.bold('\n 🚨 CRITICAL UPDATE REQUIRED '));
|
|
102
|
+
console.log(chalk.yellow(`Current: ${packageJson.version} | Latest: ${response.data.version}`));
|
|
103
|
+
console.log(chalk.cyan('👉 Run: one update\n'));
|
|
104
|
+
process.exit(1);
|
|
92
105
|
}
|
|
93
|
-
|
|
106
|
+
} catch (e) { }
|
|
107
|
+
});
|
|
94
108
|
|
|
95
|
-
|
|
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)}`));
|
|
109
|
+
// ================= أوااااامر =================
|
|
101
110
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
111
|
+
// 1. HELLO
|
|
112
|
+
program.command('hello').description('Check connection').action(async () => {
|
|
113
|
+
const token = config.get('auth_token');
|
|
114
|
+
if (!token) return console.log(chalk.yellow('Not logged in.'));
|
|
115
|
+
const spinner = ora('Connecting...').start();
|
|
116
|
+
try {
|
|
117
|
+
config.delete('username');
|
|
118
|
+
const username = await ensureUsername(token);
|
|
119
|
+
spinner.succeed(chalk.cyan(`Connected as: ${chalk.bold(username)} ✅`));
|
|
120
|
+
} catch (error) { spinner.fail(chalk.red('Connection failed.')); }
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// 2. LOGIN
|
|
124
|
+
program.command('login').description('Authenticate').action(async () => {
|
|
125
|
+
const answers = await inquirer.prompt([{ type: 'password', name: 'token', message: 'Access Token:' }]);
|
|
126
|
+
const spinner = ora('Verifying...').start();
|
|
127
|
+
try {
|
|
128
|
+
const res = await axios.get(`${API_URL}/user`, { headers: { Authorization: `Bearer ${answers.token}` } });
|
|
129
|
+
config.set('auth_token', answers.token);
|
|
130
|
+
config.set('username', res.data.username || res.data.name);
|
|
131
|
+
spinner.succeed(chalk.green(`Logged in as ${res.data.username}`));
|
|
132
|
+
} catch (error) { spinner.fail(chalk.red('Invalid token.')); }
|
|
133
|
+
});
|
|
106
134
|
|
|
107
|
-
//
|
|
135
|
+
// 3. LOGOUT
|
|
108
136
|
program.command('logout').action(() => {
|
|
109
|
-
config.
|
|
110
|
-
config.delete('username');
|
|
137
|
+
config.clear();
|
|
111
138
|
console.log(chalk.green('Logged out.'));
|
|
112
139
|
});
|
|
113
140
|
|
|
114
|
-
//
|
|
115
|
-
program
|
|
116
|
-
.command('init')
|
|
117
|
-
.description('Create project')
|
|
118
|
-
.action(async () => {
|
|
141
|
+
// 4. INIT
|
|
142
|
+
program.command('init').description('Create project').action(async () => {
|
|
119
143
|
const token = config.get('auth_token');
|
|
120
|
-
if (!token) return console.log(chalk.red('
|
|
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'));
|
|
144
|
+
if (!token) return console.log(chalk.red('Login first.'));
|
|
145
|
+
if (fs.existsSync('./oneurai.json')) return console.log(chalk.yellow('⚠️ Project already initialized.'));
|
|
129
146
|
|
|
130
147
|
const answers = await inquirer.prompt([
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
name: '
|
|
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
|
-
}
|
|
148
|
+
{ name: 'title', message: 'Project Title:' },
|
|
149
|
+
{ name: 'slug', message: 'Project Slug:', default: a => a.title.toLowerCase().replace(/ /g, '-') },
|
|
150
|
+
{ type: 'confirm', name: 'is_public', message: 'Is Public?', default: true }
|
|
150
151
|
]);
|
|
151
152
|
|
|
152
153
|
const spinner = ora('Creating...').start();
|
|
153
|
-
|
|
154
154
|
try {
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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,
|
|
155
|
+
const res = await axios.post(`${API_URL}/projects/create`, answers, { headers: { Authorization: `Bearer ${token}` } });
|
|
156
|
+
fs.writeFileSync('./oneurai.json', JSON.stringify({
|
|
157
|
+
name: res.data.project.slug,
|
|
158
|
+
id: res.data.project.id,
|
|
166
159
|
created_at: new Date().toISOString(),
|
|
167
|
-
|
|
168
|
-
|
|
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
|
-
|
|
160
|
+
ignore: ['node_modules', '.git', '.env', 'storage', '*.zip', 'oneurai.json']
|
|
161
|
+
}, null, 2));
|
|
162
|
+
spinner.succeed(chalk.green(`Created: ${res.data.project.title}`));
|
|
178
163
|
} catch (error) {
|
|
179
164
|
spinner.fail(chalk.red('Failed.'));
|
|
180
|
-
if (error.response
|
|
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
|
-
}
|
|
165
|
+
if (error.response) console.error(error.response.data);
|
|
187
166
|
}
|
|
188
|
-
|
|
167
|
+
});
|
|
189
168
|
|
|
190
|
-
//
|
|
191
|
-
program
|
|
192
|
-
.command('push')
|
|
193
|
-
.description('Deploy files')
|
|
194
|
-
.action(async () => {
|
|
169
|
+
// 5. PUSH
|
|
170
|
+
program.command('push').description('Deploy files').action(async () => {
|
|
195
171
|
const token = config.get('auth_token');
|
|
196
|
-
if (!token) return console.log(chalk.red('
|
|
197
|
-
|
|
172
|
+
if (!token) return console.log(chalk.red('Login first.'));
|
|
198
173
|
if (!fs.existsSync('./oneurai.json')) return console.log(chalk.red('Run: one init'));
|
|
199
|
-
|
|
200
|
-
const username = await ensureUsername(token);
|
|
201
174
|
const projectConfig = JSON.parse(fs.readFileSync('./oneurai.json', 'utf-8'));
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
const spinner = ora('Compressing...').start();
|
|
175
|
+
await deployProject(token, projectConfig);
|
|
176
|
+
});
|
|
205
177
|
|
|
206
|
-
|
|
207
|
-
|
|
178
|
+
// 6. WATCH (Magic ✨)
|
|
179
|
+
// 6. WATCH (Magic ✨) - Fixed Logic
|
|
180
|
+
program.command('watch').description('Auto-deploy on save').action(async () => {
|
|
181
|
+
const token = config.get('auth_token');
|
|
182
|
+
if (!token) return console.log(chalk.red('Login first.'));
|
|
183
|
+
if (!fs.existsSync('./oneurai.json')) return console.log(chalk.red('Run: one init'));
|
|
208
184
|
|
|
209
|
-
|
|
210
|
-
|
|
185
|
+
const projectConfig = JSON.parse(fs.readFileSync('./oneurai.json', 'utf-8'));
|
|
186
|
+
console.clear();
|
|
187
|
+
console.log(chalk.blue.bold(`👀 Watching ${projectConfig.name} for changes...`));
|
|
188
|
+
console.log(chalk.gray('Press Ctrl+C to stop.'));
|
|
189
|
+
|
|
190
|
+
let debounceTimer;
|
|
191
|
+
|
|
192
|
+
// 1. تحديد قائمة التجاهل بدقة
|
|
193
|
+
// ندمج قائمة المستخدم مع القائمة الإجبارية
|
|
194
|
+
const userIgnores = projectConfig.ignore || [];
|
|
195
|
+
const systemIgnores = [
|
|
196
|
+
'node_modules',
|
|
197
|
+
'node_modules/**',
|
|
198
|
+
'.git',
|
|
199
|
+
'.git/**',
|
|
200
|
+
'project.zip',
|
|
201
|
+
'*.zip',
|
|
202
|
+
'oneurai.json',
|
|
203
|
+
'*.log',
|
|
204
|
+
'.DS_Store',
|
|
211
205
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
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));
|
|
206
|
+
// 🔥🔥🔥 القائمة السوداء لأسماء ويندوز المؤقتة 🔥🔥🔥
|
|
207
|
+
'**/New Text Document.txt', // الاسم الافتراضي
|
|
208
|
+
'**/New Text Document*.txt', // لو فيه أرقام (2)
|
|
209
|
+
'**/New folder', // المجلدات الجديدة
|
|
210
|
+
];
|
|
211
|
+
|
|
212
|
+
const combinedIgnores = [...new Set([...userIgnores, ...systemIgnores])];
|
|
213
|
+
|
|
214
|
+
const watcher = chokidar.watch('.', {
|
|
215
|
+
ignored: combinedIgnores,
|
|
216
|
+
persistent: true,
|
|
217
|
+
ignoreInitial: true,
|
|
218
|
+
awaitWriteFinish: {
|
|
219
|
+
stabilityThreshold: 2000, // زدنا وقت الاستقرار لثانيتين (عشان يمديك تخلص كتابة)
|
|
220
|
+
pollInterval: 100
|
|
232
221
|
}
|
|
233
222
|
});
|
|
234
223
|
|
|
235
|
-
|
|
236
|
-
|
|
224
|
+
watcher.on('all', (event, filePath) => {
|
|
225
|
+
// حماية إضافية
|
|
226
|
+
if (filePath.includes('project.zip') || filePath.includes('oneurai.json')) return;
|
|
237
227
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
// نضيف oneurai.json للقائمة إذا لم يكن موجوداً
|
|
242
|
-
if (!ignoreList.includes('oneurai.json')) {
|
|
243
|
-
ignoreList.push('oneurai.json');
|
|
244
|
-
}
|
|
228
|
+
// تجاهل أي ملف اسمه New Text Document حتى لو عدى الفلتر الأول
|
|
229
|
+
if (filePath.includes('New Text Document')) return;
|
|
245
230
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
231
|
+
clearTimeout(debounceTimer);
|
|
232
|
+
process.stdout.write(chalk.yellow(`\r📝 Change detected in ${filePath}... waiting`));
|
|
233
|
+
|
|
234
|
+
// 🔥 زدنا الوقت إلى 3 ثواني (3000ms)
|
|
235
|
+
// هذا يعطيك وقت كافي تكتب الاسم وتضغط Enter قبل ما يقرر يرفع
|
|
236
|
+
debounceTimer = setTimeout(async () => {
|
|
237
|
+
console.log();
|
|
238
|
+
await deployProject(token, projectConfig);
|
|
239
|
+
console.log(chalk.blue.bold(`👀 Watching...`));
|
|
240
|
+
}, 3000);
|
|
249
241
|
});
|
|
242
|
+
});
|
|
250
243
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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();
|
|
244
|
+
// 7. STATUS 📊
|
|
245
|
+
program.command('status').description('Show project details').action(async () => {
|
|
246
|
+
const token = config.get('auth_token');
|
|
247
|
+
if (!token) return console.log(chalk.red('Login first.'));
|
|
248
|
+
if (!fs.existsSync('./oneurai.json')) return console.log(chalk.red('Run: one init'));
|
|
260
249
|
|
|
250
|
+
const spinner = ora('Fetching status...').start();
|
|
261
251
|
try {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
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' });
|
|
252
|
+
const projectConfig = JSON.parse(fs.readFileSync('./oneurai.json', 'utf-8'));
|
|
253
|
+
const res = await axios.get(`${API_URL}/projects/${projectConfig.name}/status`, {
|
|
254
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
255
|
+
});
|
|
279
256
|
|
|
280
|
-
spinner.
|
|
281
|
-
|
|
257
|
+
spinner.stop();
|
|
258
|
+
const data = res.data;
|
|
259
|
+
console.log(chalk.bold('\n📊 Project Status:\n'));
|
|
260
|
+
console.log(` ${chalk.blue('Name:')} ${data.title}`);
|
|
261
|
+
console.log(` ${chalk.blue('Slug:')} ${data.slug}`);
|
|
262
|
+
console.log(` ${chalk.blue('Visiblity:')} ${data.visibility === 'Public' ? chalk.green('Public') : chalk.red('Private')}`);
|
|
263
|
+
console.log(` ${chalk.blue('Size:')} ${data.total_size}`);
|
|
264
|
+
console.log(` ${chalk.blue('Files:')} ${data.files_count}`);
|
|
265
|
+
console.log(` ${chalk.blue('Updated:')} ${data.last_deployed}`);
|
|
266
|
+
console.log(`\n 🔗 ${chalk.gray(`https://oneurai.com/project/${await ensureUsername(token)}/${data.slug}`)}\n`);
|
|
282
267
|
|
|
283
268
|
} catch (error) {
|
|
284
|
-
spinner.fail(chalk.red('
|
|
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
|
-
}
|
|
269
|
+
spinner.fail(chalk.red('Failed to get status.'));
|
|
290
270
|
}
|
|
291
|
-
|
|
271
|
+
});
|
|
292
272
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
.description('Download (Clone) a project from Oneurai')
|
|
296
|
-
.action(async (slug) => {
|
|
273
|
+
// 8. LIST 📑
|
|
274
|
+
program.command('list').alias('ls').description('List all your projects').action(async () => {
|
|
297
275
|
const token = config.get('auth_token');
|
|
298
|
-
if (!token) return console.log(chalk.red('
|
|
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();
|
|
276
|
+
if (!token) return console.log(chalk.red('Login first.'));
|
|
306
277
|
|
|
278
|
+
const spinner = ora('Fetching projects...').start();
|
|
307
279
|
try {
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
method: 'get',
|
|
311
|
-
url: `${API_URL}/projects/${slug}/download`,
|
|
312
|
-
headers: { Authorization: `Bearer ${token}` },
|
|
313
|
-
responseType: 'arraybuffer'
|
|
280
|
+
const res = await axios.get(`${API_URL}/projects`, {
|
|
281
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
314
282
|
});
|
|
283
|
+
spinner.stop();
|
|
284
|
+
|
|
285
|
+
if (res.data.length === 0) return console.log(chalk.yellow('No projects found. Run "one init" to start!'));
|
|
286
|
+
|
|
287
|
+
// عرض تفاعلي
|
|
288
|
+
const answer = await inquirer.prompt([
|
|
289
|
+
{
|
|
290
|
+
type: 'list',
|
|
291
|
+
name: 'project',
|
|
292
|
+
message: 'Select a project to clone (or Ctrl+C to exit):',
|
|
293
|
+
choices: res.data,
|
|
294
|
+
pageSize: 10
|
|
295
|
+
}
|
|
296
|
+
]);
|
|
297
|
+
|
|
298
|
+
// إذا اختار مشروع، ننفذ أمر get عليه
|
|
299
|
+
// نستدعي دالة get برمجياً (أو نطلب منه يكتب الأمر)
|
|
300
|
+
console.log(chalk.cyan(`\nTo clone this project, run:\n`));
|
|
301
|
+
console.log(chalk.white.bgBlack(` one get ${answer.project} `));
|
|
302
|
+
console.log();
|
|
315
303
|
|
|
316
|
-
|
|
304
|
+
} catch (error) {
|
|
305
|
+
spinner.fail(chalk.red('Failed to list projects.'));
|
|
306
|
+
}
|
|
307
|
+
});
|
|
317
308
|
|
|
318
|
-
|
|
319
|
-
|
|
309
|
+
// 9. DOCTOR 👨⚕️
|
|
310
|
+
program.command('doctor').description('Diagnose CLI issues').action(async () => {
|
|
311
|
+
console.log(chalk.bold('🩺 Oneurai CLI Doctor\n'));
|
|
320
312
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
fs.writeFileSync(zipPath, response.data);
|
|
313
|
+
// Check 1: CLI Version
|
|
314
|
+
console.log(`${chalk.green('✔')} CLI Version: ${packageJson.version}`);
|
|
324
315
|
|
|
325
|
-
|
|
326
|
-
|
|
316
|
+
// Check 2: Config File
|
|
317
|
+
if (fs.existsSync('./oneurai.json')) {
|
|
318
|
+
try {
|
|
319
|
+
JSON.parse(fs.readFileSync('./oneurai.json', 'utf-8'));
|
|
320
|
+
console.log(`${chalk.green('✔')} oneurai.json: Valid`);
|
|
321
|
+
} catch (e) { console.log(`${chalk.red('✘')} oneurai.json: Corrupted JSON`); }
|
|
322
|
+
} else {
|
|
323
|
+
console.log(`${chalk.yellow('⚠')} oneurai.json: Not found (Run inside project folder)`);
|
|
324
|
+
}
|
|
327
325
|
|
|
328
|
-
|
|
329
|
-
|
|
326
|
+
// Check 3: API Connection
|
|
327
|
+
const spinner = ora('Checking API Connection...').start();
|
|
328
|
+
try {
|
|
329
|
+
await axios.get(`${API_URL.replace('/api', '')}`); // Ping Home
|
|
330
|
+
spinner.succeed(`${chalk.green('✔')} API Status: Online`);
|
|
331
|
+
} catch (e) {
|
|
332
|
+
spinner.fail(`${chalk.red('✘')} API Status: Unreachable`);
|
|
333
|
+
}
|
|
330
334
|
|
|
331
|
-
|
|
335
|
+
// Check 4: Auth Status
|
|
336
|
+
const token = config.get('auth_token');
|
|
337
|
+
if (token) {
|
|
338
|
+
try {
|
|
339
|
+
await axios.get(`${API_URL}/user`, { headers: { Authorization: `Bearer ${token}` } });
|
|
340
|
+
console.log(`${chalk.green('✔')} Authentication: Valid Token`);
|
|
341
|
+
} catch (e) {
|
|
342
|
+
console.log(`${chalk.red('✘')} Authentication: Invalid/Expired Token (Run 'one login')`);
|
|
343
|
+
}
|
|
344
|
+
} else {
|
|
345
|
+
console.log(`${chalk.yellow('⚠')} Authentication: Not Logged In`);
|
|
346
|
+
}
|
|
332
347
|
|
|
333
|
-
|
|
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
|
|
348
|
+
console.log(chalk.gray('\nDiagnosis complete.'));
|
|
349
|
+
});
|
|
339
350
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
351
|
+
// 10. UPDATE (القديم)
|
|
352
|
+
program.command('update').description('Update CLI').action(() => {
|
|
353
|
+
try {
|
|
354
|
+
console.log(chalk.blue('Updating...'));
|
|
355
|
+
execSync('npm install -g https://oneurai.com/cli/one-latest.tgz', { stdio: 'inherit' });
|
|
356
|
+
} catch (e) { console.error(e.message); }
|
|
357
|
+
});
|
|
344
358
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
359
|
+
// 11. GET (القديم)
|
|
360
|
+
program.command('get <slug>').description('Clone project').action(async (slug) => {
|
|
361
|
+
// ... (نفس كود get السابق بالضبط - عشان المساحة ما كررته هنا بس هو موجود ضمنياً)
|
|
362
|
+
// إذا نسخته انسخه من الكود السابق، أو تبيني أعيد كتابته كامل؟
|
|
363
|
+
// سأضيفه باختصار هنا لكي يكون الملف كاملاً
|
|
364
|
+
const token = config.get('auth_token');
|
|
365
|
+
if (!token) return console.log(chalk.red('Login first.'));
|
|
366
|
+
if (fs.existsSync(slug)) return console.log(chalk.red(`Directory "${slug}" exists.`));
|
|
367
|
+
|
|
368
|
+
const spinner = ora('Downloading...').start();
|
|
369
|
+
try {
|
|
370
|
+
const res = await axios({ url: `${API_URL}/projects/${slug}/download`, headers: { Authorization: `Bearer ${token}` }, responseType: 'arraybuffer' });
|
|
371
|
+
fs.mkdirSync(slug);
|
|
372
|
+
fs.writeFileSync(path.join(slug, 'temp.zip'), res.data);
|
|
373
|
+
const zip = new AdmZip(path.join(slug, 'temp.zip'));
|
|
374
|
+
zip.extractAllTo(slug, true);
|
|
375
|
+
fs.unlinkSync(path.join(slug, 'temp.zip'));
|
|
376
|
+
spinner.succeed(chalk.green('Cloned successfully!'));
|
|
377
|
+
console.log(`Run: cd ${slug} && one init`);
|
|
378
|
+
} catch (e) {
|
|
379
|
+
if (fs.existsSync(slug)) fs.rmSync(slug, { recursive: true });
|
|
380
|
+
spinner.fail('Failed.');
|
|
352
381
|
}
|
|
353
|
-
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
// 12. OPEN (القديم)
|
|
385
|
+
program.command('open').description('Open in browser').action(async () => {
|
|
386
|
+
if (!fs.existsSync('./oneurai.json')) return console.log(chalk.red('Run inside project.'));
|
|
387
|
+
const token = config.get('auth_token');
|
|
388
|
+
const slug = JSON.parse(fs.readFileSync('./oneurai.json')).name;
|
|
389
|
+
const url = `https://oneurai.com/project/${await ensureUsername(token)}/${slug}`;
|
|
390
|
+
console.log(chalk.green(`Opening ${url}`));
|
|
391
|
+
const cmd = process.platform === 'win32' ? `start "" "${url}"` : (process.platform === 'darwin' ? `open "${url}"` : `xdg-open "${url}"`);
|
|
392
|
+
exec(cmd);
|
|
393
|
+
});
|
|
394
|
+
|
|
354
395
|
program.parse(process.argv);
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oneurai-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Oneurai CLI Tool",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
"archiver": "^7.0.1",
|
|
19
19
|
"axios": "^1.13.2",
|
|
20
20
|
"chalk": "^5.6.2",
|
|
21
|
+
"chokidar": "^5.0.0",
|
|
21
22
|
"commander": "^14.0.2",
|
|
22
23
|
"conf": "^15.0.2",
|
|
23
24
|
"form-data": "^4.0.5",
|