library.dr-conversion 0.3.2 ā 0.3.3
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/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +471 -0
- package/dist/cli.js.map +1 -0
- package/dist/providers/discord/provider.js.map +1 -1
- package/package.json +4 -4
- package/cli.js +0 -869
package/cli.js
DELETED
|
@@ -1,869 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* CLI tool for Library.DR-Conversion
|
|
5
|
-
* Provides utilities for bot development
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const { program } = require('commander');
|
|
9
|
-
const fs = require('fs');
|
|
10
|
-
const path = require('path');
|
|
11
|
-
const { execSync } = require('child_process');
|
|
12
|
-
const readline = require('readline');
|
|
13
|
-
const crypto = require('crypto');
|
|
14
|
-
|
|
15
|
-
// Generate a UUID v4
|
|
16
|
-
function generateUUID() {
|
|
17
|
-
return crypto.randomUUID();
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// Detect platform from package.json dependencies
|
|
21
|
-
function detectPlatform() {
|
|
22
|
-
try {
|
|
23
|
-
const pkgPath = path.join(process.cwd(), 'package.json');
|
|
24
|
-
if (!fs.existsSync(pkgPath)) {
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
29
|
-
const allDeps = {
|
|
30
|
-
...pkg.dependencies,
|
|
31
|
-
...pkg.devDependencies,
|
|
32
|
-
...pkg.peerDependencies
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
// Check for Root platforms
|
|
36
|
-
if (allDeps['@rootsdk/server-bot']) {
|
|
37
|
-
return 'root';
|
|
38
|
-
}
|
|
39
|
-
if (allDeps['@rootsdk/client-app']) {
|
|
40
|
-
return 'root-app';
|
|
41
|
-
}
|
|
42
|
-
if (allDeps['discord.js']) {
|
|
43
|
-
return 'discord';
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return null;
|
|
47
|
-
} catch (error) {
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Validate a root manifest object against minimal Root requirements
|
|
53
|
-
function validateManifestObject(manifest) {
|
|
54
|
-
const errors = [];
|
|
55
|
-
if (!manifest || typeof manifest !== 'object') {
|
|
56
|
-
errors.push('Manifest must be a JSON object');
|
|
57
|
-
return { valid: false, errors };
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (!manifest.id || typeof manifest.id !== 'string') {
|
|
61
|
-
errors.push('Missing or invalid "id" (string)');
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (!manifest.version || typeof manifest.version !== 'string') {
|
|
65
|
-
errors.push('Missing or invalid "version" (string)');
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (!manifest.package || typeof manifest.package !== 'object') {
|
|
69
|
-
errors.push('Missing "package" object');
|
|
70
|
-
} else {
|
|
71
|
-
if (manifest.package.server) {
|
|
72
|
-
const server = manifest.package.server;
|
|
73
|
-
if (!server.launch || typeof server.launch !== 'string') {
|
|
74
|
-
errors.push('package.server.launch is required and must be a string');
|
|
75
|
-
}
|
|
76
|
-
if (!Array.isArray(server.deploy) || server.deploy.length === 0) {
|
|
77
|
-
errors.push('package.server.deploy must be a non-empty array');
|
|
78
|
-
}
|
|
79
|
-
if (!Array.isArray(server.node_modules) || server.node_modules.length === 0) {
|
|
80
|
-
errors.push('package.server.node_modules must be a non-empty array');
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (manifest.package.client) {
|
|
85
|
-
const client = manifest.package.client;
|
|
86
|
-
// accept either entry or deploy
|
|
87
|
-
if (!client.entry && (!Array.isArray(client.deploy) || client.deploy.length === 0)) {
|
|
88
|
-
errors.push('package.client.entry or package.client.deploy is required');
|
|
89
|
-
}
|
|
90
|
-
if (client.assets && !Array.isArray(client.assets)) {
|
|
91
|
-
errors.push('package.client.assets must be an array if provided');
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
return { valid: errors.length === 0, errors };
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
program
|
|
100
|
-
.name('library.dr-conversion')
|
|
101
|
-
.description('CLI tools for Library.DR-Conversion v0.2.9')
|
|
102
|
-
.version('0.2.9');
|
|
103
|
-
|
|
104
|
-
program
|
|
105
|
-
.command('init')
|
|
106
|
-
.description('Initialize a new bot project')
|
|
107
|
-
.option('-p, --platform <type>', 'Platform (discord, root, root-app)', 'discord')
|
|
108
|
-
.option('-n, --name <name>', 'Project name', 'my-bot')
|
|
109
|
-
.action((options) => {
|
|
110
|
-
console.log(`š Initializing ${options.name} for ${options.platform}...`);
|
|
111
|
-
|
|
112
|
-
const projectDir = path.join(process.cwd(), options.name);
|
|
113
|
-
|
|
114
|
-
if (fs.existsSync(projectDir)) {
|
|
115
|
-
console.error(`ā Directory ${options.name} already exists`);
|
|
116
|
-
process.exit(1);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
fs.mkdirSync(projectDir, { recursive: true });
|
|
120
|
-
|
|
121
|
-
// Create package.json
|
|
122
|
-
const packageJson = {
|
|
123
|
-
name: options.name,
|
|
124
|
-
version: '1.0.0',
|
|
125
|
-
description: `A ${options.platform} bot`,
|
|
126
|
-
main: 'dist/index.js',
|
|
127
|
-
scripts: {
|
|
128
|
-
build: 'tsc',
|
|
129
|
-
start: 'node dist/index.js',
|
|
130
|
-
dev: 'ts-node src/index.ts',
|
|
131
|
-
},
|
|
132
|
-
dependencies: {
|
|
133
|
-
'library.dr-conversion': '^0.2.8',
|
|
134
|
-
},
|
|
135
|
-
devDependencies: {
|
|
136
|
-
typescript: '^5.3.0',
|
|
137
|
-
'ts-node': '^10.9.0',
|
|
138
|
-
'@types/node': '^20.0.0',
|
|
139
|
-
},
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
if (options.platform === 'discord') {
|
|
143
|
-
packageJson.dependencies['discord.js'] = '^14.14.1';
|
|
144
|
-
} else if (options.platform === 'root') {
|
|
145
|
-
packageJson.dependencies['@rootsdk/server-bot'] = '^0.17.0';
|
|
146
|
-
} else if (options.platform === 'root-app') {
|
|
147
|
-
packageJson.dependencies['@rootsdk/client-app'] = '^0.17.0';
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
fs.writeFileSync(
|
|
151
|
-
path.join(projectDir, 'package.json'),
|
|
152
|
-
JSON.stringify(packageJson, null, 2)
|
|
153
|
-
);
|
|
154
|
-
|
|
155
|
-
// Create tsconfig.json
|
|
156
|
-
const tsConfig = {
|
|
157
|
-
compilerOptions: {
|
|
158
|
-
target: 'ES2020',
|
|
159
|
-
module: 'commonjs',
|
|
160
|
-
outDir: './dist',
|
|
161
|
-
rootDir: './src',
|
|
162
|
-
strict: true,
|
|
163
|
-
esModuleInterop: true,
|
|
164
|
-
skipLibCheck: true,
|
|
165
|
-
forceConsistentCasingInFileNames: true,
|
|
166
|
-
},
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
fs.writeFileSync(
|
|
170
|
-
path.join(projectDir, 'tsconfig.json'),
|
|
171
|
-
JSON.stringify(tsConfig, null, 2)
|
|
172
|
-
);
|
|
173
|
-
|
|
174
|
-
// Create .env.example
|
|
175
|
-
let envExample = '';
|
|
176
|
-
if (options.platform === 'discord') {
|
|
177
|
-
envExample = 'DISCORD_TOKEN=your-bot-token-here\n';
|
|
178
|
-
} else if (options.platform === 'root') {
|
|
179
|
-
envExample = 'ROOT_TOKEN=your-bot-token-here\n';
|
|
180
|
-
} else if (options.platform === 'root-app') {
|
|
181
|
-
envExample = '# Root Apps use Root client authentication - no token needed\n';
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
fs.writeFileSync(path.join(projectDir, '.env.example'), envExample);
|
|
185
|
-
|
|
186
|
-
// Create .gitignore
|
|
187
|
-
const gitignore = `node_modules/
|
|
188
|
-
dist/
|
|
189
|
-
.env
|
|
190
|
-
*.log
|
|
191
|
-
`;
|
|
192
|
-
fs.writeFileSync(path.join(projectDir, '.gitignore'), gitignore);
|
|
193
|
-
|
|
194
|
-
// Create src directory
|
|
195
|
-
fs.mkdirSync(path.join(projectDir, 'src'), { recursive: true });
|
|
196
|
-
|
|
197
|
-
// Create main bot file based on platform
|
|
198
|
-
let botCode = '';
|
|
199
|
-
|
|
200
|
-
if (options.platform === 'discord') {
|
|
201
|
-
botCode = `import { UnifiedClient } from 'library.dr-conversion';
|
|
202
|
-
|
|
203
|
-
const client = new UnifiedClient({
|
|
204
|
-
platform: 'discord',
|
|
205
|
-
config: {
|
|
206
|
-
token: process.env.DISCORD_TOKEN!
|
|
207
|
-
}
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
client.on('ready', () => {
|
|
211
|
-
console.log('Bot is ready!');
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
client.on('message', async (message) => {
|
|
215
|
-
if (message.author.bot) return;
|
|
216
|
-
|
|
217
|
-
if (message.content === '!ping') {
|
|
218
|
-
await message.reply('Pong!');
|
|
219
|
-
}
|
|
220
|
-
});
|
|
221
|
-
|
|
222
|
-
client.connect();
|
|
223
|
-
`;
|
|
224
|
-
} else if (options.platform === 'root') {
|
|
225
|
-
botCode = `import { UnifiedClient } from 'library.dr-conversion';
|
|
226
|
-
|
|
227
|
-
const client = new UnifiedClient({
|
|
228
|
-
platform: 'root',
|
|
229
|
-
config: {
|
|
230
|
-
token: process.env.ROOT_TOKEN!
|
|
231
|
-
}
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
client.on('ready', (data) => {
|
|
235
|
-
console.log('Bot is ready!');
|
|
236
|
-
console.log('Connected to community:', data.communityId);
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
client.on('message', async (message) => {
|
|
240
|
-
if (message.author.bot) return;
|
|
241
|
-
|
|
242
|
-
if (message.content === '!ping') {
|
|
243
|
-
await message.reply('Pong!');
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
client.connect();
|
|
248
|
-
`;
|
|
249
|
-
} else if (options.platform === 'root-app') {
|
|
250
|
-
botCode = `import { UnifiedClient } from 'library.dr-conversion';
|
|
251
|
-
|
|
252
|
-
const client = new UnifiedClient({
|
|
253
|
-
platform: 'root-app',
|
|
254
|
-
config: {
|
|
255
|
-
// Root Apps use Root client authentication
|
|
256
|
-
}
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
client.on('ready', () => {
|
|
260
|
-
console.log('Root App is ready!');
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
client.on('message', async (message) => {
|
|
264
|
-
if (message.author.bot) return;
|
|
265
|
-
|
|
266
|
-
if (message.content === '!ping') {
|
|
267
|
-
await message.reply('Pong from Root App!');
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// Add your app logic here
|
|
271
|
-
// Root Apps can use GUI components and client-side features
|
|
272
|
-
});
|
|
273
|
-
|
|
274
|
-
client.connect();
|
|
275
|
-
`;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
fs.writeFileSync(path.join(projectDir, 'src', 'index.ts'), botCode);
|
|
279
|
-
|
|
280
|
-
// Create root-manifest.json for Root Bots
|
|
281
|
-
if (options.platform === 'root') {
|
|
282
|
-
const manifest = {
|
|
283
|
-
id: generateUUID(),
|
|
284
|
-
version: '1.0.0',
|
|
285
|
-
package: {
|
|
286
|
-
server: {
|
|
287
|
-
launch: 'dist/index.js',
|
|
288
|
-
deploy: ['dist'],
|
|
289
|
-
node_modules: ['node_modules']
|
|
290
|
-
}
|
|
291
|
-
},
|
|
292
|
-
settings: {
|
|
293
|
-
groups: []
|
|
294
|
-
},
|
|
295
|
-
permissions: {
|
|
296
|
-
community: {},
|
|
297
|
-
channel: {
|
|
298
|
-
CreateMessage: true,
|
|
299
|
-
ReadMessage: true
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
};
|
|
303
|
-
|
|
304
|
-
fs.writeFileSync(
|
|
305
|
-
path.join(projectDir, 'root-manifest.json'),
|
|
306
|
-
JSON.stringify(manifest, null, 2)
|
|
307
|
-
);
|
|
308
|
-
|
|
309
|
-
// Create README explaining manifest
|
|
310
|
-
const manifestReadme = `# Root Bot Manifest
|
|
311
|
-
|
|
312
|
-
Your bot's root-manifest.json defines how it integrates with Root.
|
|
313
|
-
|
|
314
|
-
## Important:
|
|
315
|
-
- The 'id' field is unique to your bot - don't change it after publishing
|
|
316
|
-
- Update 'version' following semantic versioning when you make changes
|
|
317
|
-
- Add permissions your bot needs to 'permissions.community' or 'permissions.channel'
|
|
318
|
-
- See docs/ROOT_BOT_MANIFEST.md for full documentation
|
|
319
|
-
|
|
320
|
-
## Publishing:
|
|
321
|
-
\`\`\`bash
|
|
322
|
-
npm run build
|
|
323
|
-
npx @rootsdk/cli publish
|
|
324
|
-
\`\`\`
|
|
325
|
-
`;
|
|
326
|
-
fs.writeFileSync(path.join(projectDir, 'MANIFEST.md'), manifestReadme);
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
// Create root-app-manifest.json for Root Apps (client-side)
|
|
330
|
-
if (options.platform === 'root-app') {
|
|
331
|
-
const appManifest = {
|
|
332
|
-
id: generateUUID(),
|
|
333
|
-
version: '1.0.0',
|
|
334
|
-
name: options.name,
|
|
335
|
-
description: `${options.name} - Root App`,
|
|
336
|
-
author: '',
|
|
337
|
-
homepage: '',
|
|
338
|
-
package: {
|
|
339
|
-
client: {
|
|
340
|
-
entry: 'dist/index.html',
|
|
341
|
-
assets: ['dist'],
|
|
342
|
-
node_modules: ['node_modules']
|
|
343
|
-
}
|
|
344
|
-
},
|
|
345
|
-
settings: {
|
|
346
|
-
ui: []
|
|
347
|
-
},
|
|
348
|
-
permissions: {
|
|
349
|
-
channel: {
|
|
350
|
-
CreateMessage: true,
|
|
351
|
-
ReadMessage: true
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
};
|
|
355
|
-
|
|
356
|
-
fs.writeFileSync(
|
|
357
|
-
path.join(projectDir, 'root-manifest.json'),
|
|
358
|
-
JSON.stringify(appManifest, null, 2)
|
|
359
|
-
);
|
|
360
|
-
|
|
361
|
-
const appManifestReadme = `# Root App Manifest
|
|
362
|
-
|
|
363
|
-
This project includes a generated root-manifest.json to help document your app.
|
|
364
|
-
|
|
365
|
-
This manifest follows the Root App manifest overview and provides the basic fields used by the Root platform:
|
|
366
|
-
- 'id': Unique UUID for the app
|
|
367
|
-
- 'version': Semver version
|
|
368
|
-
- 'package.client.entry': The client entry HTML for the app
|
|
369
|
-
- 'package.client.assets': Client assets to include in the upload
|
|
370
|
-
- 'permissions': Channel-level permissions used by the app
|
|
371
|
-
|
|
372
|
-
Notes:
|
|
373
|
-
- Update 'version' following semantic versioning when you make changes.
|
|
374
|
-
- Review permissions and remove any that aren't needed.
|
|
375
|
-
- Configure UI settings in the 'settings.ui' array (see Root docs for details):
|
|
376
|
-
https://docs.rootapp.com/docs/app-docs/configure/manifest-overview/
|
|
377
|
-
|
|
378
|
-
Deployment:
|
|
379
|
-
Build your app and follow the Root platform instructions to upload or register it.
|
|
380
|
-
`;
|
|
381
|
-
|
|
382
|
-
fs.writeFileSync(path.join(projectDir, 'MANIFEST.md'), appManifestReadme);
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
console.log(`ā
Created ${options.name}`);
|
|
386
|
-
console.log(`\nš Next steps:`);
|
|
387
|
-
console.log(` cd ${options.name}`);
|
|
388
|
-
console.log(` npm install`);
|
|
389
|
-
|
|
390
|
-
if (options.platform === 'root') {
|
|
391
|
-
console.log(` cp .env.example .env`);
|
|
392
|
-
console.log(` # Edit .env with your bot token`);
|
|
393
|
-
console.log(` # Edit root-manifest.json - change the 'id' to a unique value`);
|
|
394
|
-
console.log(` # See MANIFEST.md for manifest documentation`);
|
|
395
|
-
} else if (options.platform === 'discord') {
|
|
396
|
-
console.log(` cp .env.example .env`);
|
|
397
|
-
console.log(` # Edit .env with your bot token`);
|
|
398
|
-
} else if (options.platform === 'root-app') {
|
|
399
|
-
console.log(` # Root Apps run in the Root client - no token needed`);
|
|
400
|
-
console.log(` # Configure your app in the Root platform`);
|
|
401
|
-
}
|
|
402
|
-
console.log(` npm run dev`);
|
|
403
|
-
});
|
|
404
|
-
|
|
405
|
-
program
|
|
406
|
-
.command('validate')
|
|
407
|
-
.description('Validate bot configuration')
|
|
408
|
-
.action(() => {
|
|
409
|
-
console.log('š Validating configuration...');
|
|
410
|
-
|
|
411
|
-
if (!fs.existsSync('package.json')) {
|
|
412
|
-
console.error('ā package.json not found');
|
|
413
|
-
process.exit(1);
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
|
|
417
|
-
|
|
418
|
-
if (!pkg.dependencies || !pkg.dependencies['library.dr-conversion']) {
|
|
419
|
-
console.error('ā library.dr-conversion not found in dependencies');
|
|
420
|
-
process.exit(1);
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
if (!fs.existsSync('.env') && !process.env.BOT_TOKEN) {
|
|
424
|
-
console.warn('ā ļø No .env file or BOT_TOKEN environment variable found');
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
console.log('ā
Configuration is valid');
|
|
428
|
-
});
|
|
429
|
-
|
|
430
|
-
program
|
|
431
|
-
.command('validate-manifest')
|
|
432
|
-
.description('Validate root-manifest.json in the current folder')
|
|
433
|
-
.option('-f, --file <path>', 'Manifest file path', 'root-manifest.json')
|
|
434
|
-
.action((options) => {
|
|
435
|
-
const file = options.file || 'root-manifest.json';
|
|
436
|
-
if (!fs.existsSync(file)) {
|
|
437
|
-
console.error(`ā Manifest not found: ${file}`);
|
|
438
|
-
process.exit(1);
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
let raw;
|
|
442
|
-
try {
|
|
443
|
-
raw = fs.readFileSync(file, 'utf8');
|
|
444
|
-
} catch (err) {
|
|
445
|
-
console.error('ā Failed to read manifest:', err.message);
|
|
446
|
-
process.exit(1);
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
let manifest;
|
|
450
|
-
try {
|
|
451
|
-
manifest = JSON.parse(raw);
|
|
452
|
-
} catch (err) {
|
|
453
|
-
console.error('ā Manifest is not valid JSON:', err.message);
|
|
454
|
-
process.exit(1);
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
const result = validateManifestObject(manifest);
|
|
458
|
-
if (!result.valid) {
|
|
459
|
-
console.error('ā Manifest validation failed:');
|
|
460
|
-
for (const e of result.errors) console.error(' -', e);
|
|
461
|
-
process.exit(1);
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
console.log('ā
Manifest is valid');
|
|
465
|
-
});
|
|
466
|
-
|
|
467
|
-
program
|
|
468
|
-
.command('generate-manifest')
|
|
469
|
-
.description('Generate a manifest file for Root Bots or Root Apps (auto-detects platform)')
|
|
470
|
-
.option('-i, --interactive', 'Interactive mode with prompts')
|
|
471
|
-
.option('-p, --platform <type>', 'Platform type (root, root-app) - auto-detected if not specified')
|
|
472
|
-
.action(async (options) => {
|
|
473
|
-
// Auto-detect platform if not specified
|
|
474
|
-
const platform = options.platform || detectPlatform();
|
|
475
|
-
|
|
476
|
-
if (!platform || (platform !== 'root' && platform !== 'root-app')) {
|
|
477
|
-
console.error('ā Could not detect Root platform.');
|
|
478
|
-
console.error(' Make sure you have @rootsdk/server-bot or @rootsdk/client-app installed,');
|
|
479
|
-
console.error(' or specify the platform: --platform root or --platform root-app');
|
|
480
|
-
process.exit(1);
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
const isRootBot = platform === 'root';
|
|
484
|
-
const manifestFile = 'root-manifest.json';
|
|
485
|
-
|
|
486
|
-
console.log(`\nš Detected platform: ${isRootBot ? 'Root Bot (server-side)' : 'Root App (client-side)'}`);
|
|
487
|
-
|
|
488
|
-
// Check if manifest already exists
|
|
489
|
-
if (fs.existsSync(manifestFile)) {
|
|
490
|
-
console.log(`ā ļø ${manifestFile} already exists ā it will be overwritten.`);
|
|
491
|
-
if (options.interactive) {
|
|
492
|
-
console.log('Interactive mode will update fields and overwrite the manifest.');
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
let manifest;
|
|
497
|
-
|
|
498
|
-
if (isRootBot) {
|
|
499
|
-
// Root Bot manifest (server-side)
|
|
500
|
-
manifest = {
|
|
501
|
-
id: generateUUID(),
|
|
502
|
-
version: '1.0.0',
|
|
503
|
-
package: {
|
|
504
|
-
server: {
|
|
505
|
-
launch: 'dist/index.js',
|
|
506
|
-
deploy: ['dist'],
|
|
507
|
-
node_modules: ['node_modules']
|
|
508
|
-
}
|
|
509
|
-
},
|
|
510
|
-
settings: {
|
|
511
|
-
groups: []
|
|
512
|
-
},
|
|
513
|
-
permissions: {
|
|
514
|
-
community: {},
|
|
515
|
-
channel: {}
|
|
516
|
-
}
|
|
517
|
-
};
|
|
518
|
-
} else {
|
|
519
|
-
// Root App manifest (client-side)
|
|
520
|
-
manifest = {
|
|
521
|
-
id: generateUUID(),
|
|
522
|
-
version: '1.0.0',
|
|
523
|
-
name: '',
|
|
524
|
-
description: '',
|
|
525
|
-
author: '',
|
|
526
|
-
homepage: '',
|
|
527
|
-
package: {
|
|
528
|
-
client: {
|
|
529
|
-
entry: 'dist/index.html',
|
|
530
|
-
assets: ['dist'],
|
|
531
|
-
node_modules: ['node_modules']
|
|
532
|
-
}
|
|
533
|
-
},
|
|
534
|
-
settings: {
|
|
535
|
-
ui: []
|
|
536
|
-
},
|
|
537
|
-
permissions: {
|
|
538
|
-
channel: {}
|
|
539
|
-
}
|
|
540
|
-
};
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
if (options.interactive) {
|
|
544
|
-
const rl = readline.createInterface({
|
|
545
|
-
input: process.stdin,
|
|
546
|
-
output: process.stdout
|
|
547
|
-
});
|
|
548
|
-
|
|
549
|
-
function question(prompt) {
|
|
550
|
-
return new Promise((resolve) => {
|
|
551
|
-
rl.question(prompt, resolve);
|
|
552
|
-
});
|
|
553
|
-
}
|
|
554
|
-
|
|
555
|
-
console.log('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
556
|
-
console.log(`ā Root ${isRootBot ? 'Bot' : 'App'} Manifest Generator${' '.repeat(isRootBot ? 25 : 24)}ā`);
|
|
557
|
-
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
558
|
-
|
|
559
|
-
// Version
|
|
560
|
-
const version = await question('Version (default: 1.0.0): ');
|
|
561
|
-
if (version.trim()) manifest.version = version.trim();
|
|
562
|
-
|
|
563
|
-
if (isRootBot) {
|
|
564
|
-
// Root Bot specific fields
|
|
565
|
-
// Launch file
|
|
566
|
-
const launch = await question('Launch file (default: dist/index.js): ');
|
|
567
|
-
if (launch.trim()) manifest.package.server.launch = launch.trim();
|
|
568
|
-
|
|
569
|
-
// Permissions
|
|
570
|
-
console.log('\nš Bot Permissions:\n');
|
|
571
|
-
console.log('Community permissions:');
|
|
572
|
-
} else {
|
|
573
|
-
// Root App specific fields
|
|
574
|
-
const name = await question('App name: ');
|
|
575
|
-
if (name.trim()) manifest.name = name.trim();
|
|
576
|
-
|
|
577
|
-
const description = await question('App description: ');
|
|
578
|
-
if (description.trim()) manifest.description = description.trim();
|
|
579
|
-
|
|
580
|
-
const author = await question('Author: ');
|
|
581
|
-
if (author.trim()) manifest.author = author.trim();
|
|
582
|
-
|
|
583
|
-
const homepage = await question('Homepage URL (optional): ');
|
|
584
|
-
if (homepage.trim()) manifest.homepage = homepage.trim();
|
|
585
|
-
|
|
586
|
-
console.log('\nš App Permissions:\n');
|
|
587
|
-
console.log('Channel permissions (Root Apps run in browser):');
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
if (isRootBot) {
|
|
591
|
-
// Community permissions only for Root Bots
|
|
592
|
-
console.log('Community permissions:');
|
|
593
|
-
const manageRoles = await question(' Need to manage roles? (y/n): ');
|
|
594
|
-
if (manageRoles.toLowerCase() === 'y') {
|
|
595
|
-
manifest.permissions.community.ManageRoles = true;
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
const manageCommunity = await question(' Need to manage community settings? (y/n): ');
|
|
599
|
-
if (manageCommunity.toLowerCase() === 'y') {
|
|
600
|
-
manifest.permissions.community.ManageCommunity = true;
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
const manageChannels = await question(' Need to manage channels? (y/n): ');
|
|
604
|
-
if (manageChannels.toLowerCase() === 'y') {
|
|
605
|
-
manifest.permissions.community.ManageChannels = true;
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
console.log('\nChannel permissions:');
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
// Channel permissions (both Root Bot and Root App)
|
|
612
|
-
const createMsg = await question(' Need to send messages? (y/n): ');
|
|
613
|
-
if (createMsg.toLowerCase() === 'y') {
|
|
614
|
-
manifest.permissions.channel.CreateMessage = true;
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
const readMsg = await question(' Need to read messages? (y/n): ');
|
|
618
|
-
if (readMsg.toLowerCase() === 'y') {
|
|
619
|
-
manifest.permissions.channel.ReadMessage = true;
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
const deleteMsg = await question(' Need to delete messages? (y/n): ');
|
|
623
|
-
if (deleteMsg.toLowerCase() === 'y') {
|
|
624
|
-
manifest.permissions.channel.DeleteMessage = true;
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
const managePins = await question(' Need to manage pins? (y/n): ');
|
|
628
|
-
if (managePins.toLowerCase() === 'y') {
|
|
629
|
-
manifest.permissions.channel.ManagePins = true;
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
rl.close();
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
// Write manifest file (overwrite if exists)
|
|
636
|
-
fs.writeFileSync(
|
|
637
|
-
manifestFile,
|
|
638
|
-
JSON.stringify(manifest, null, 2)
|
|
639
|
-
);
|
|
640
|
-
|
|
641
|
-
// Validate generated manifest
|
|
642
|
-
const validation = validateManifestObject(manifest);
|
|
643
|
-
if (!validation.valid) {
|
|
644
|
-
console.error('\nā Generated manifest failed validation:');
|
|
645
|
-
for (const e of validation.errors) console.error(' -', e);
|
|
646
|
-
process.exit(1);
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
console.log(`\nā
Generated and validated ${manifestFile} successfully!\n`);
|
|
650
|
-
console.log('š Manifest Details:');
|
|
651
|
-
console.log(` Platform: ${isRootBot ? 'Root Bot (server-side)' : 'Root App (client-side)'}`);
|
|
652
|
-
console.log(` ID: ${manifest.id}`);
|
|
653
|
-
console.log(` Version: ${manifest.version}`);
|
|
654
|
-
if (isRootBot) {
|
|
655
|
-
console.log(` Launch: ${manifest.package.server.launch}`);
|
|
656
|
-
} else {
|
|
657
|
-
console.log(` Name: ${manifest.name || '(not set)'}`);
|
|
658
|
-
}
|
|
659
|
-
console.log('');
|
|
660
|
-
console.log('ā ļø Important:');
|
|
661
|
-
console.log(' - The ID is unique to your ' + (isRootBot ? 'bot' : 'app') + ' - never change it after publishing');
|
|
662
|
-
console.log(' - Update version when you make changes (follow semver)');
|
|
663
|
-
if (isRootBot) {
|
|
664
|
-
console.log(' - See docs/ROOT_APP_MANIFEST.md for full documentation');
|
|
665
|
-
}
|
|
666
|
-
console.log('');
|
|
667
|
-
console.log('š Next steps:');
|
|
668
|
-
console.log(` 1. Review and customize ${manifestFile}`);
|
|
669
|
-
if (isRootBot) {
|
|
670
|
-
console.log(' 2. Build your bot: npm run build');
|
|
671
|
-
console.log(' 3. Publish: npx @rootsdk/cli publish');
|
|
672
|
-
} else {
|
|
673
|
-
console.log(' 2. Build your app: npm run build');
|
|
674
|
-
console.log(' 3. Deploy through Root platform interface');
|
|
675
|
-
}
|
|
676
|
-
console.log('');
|
|
677
|
-
});
|
|
678
|
-
|
|
679
|
-
program
|
|
680
|
-
.command('publish')
|
|
681
|
-
.description('Validate and publish the current root-manifest.json using @rootsdk/cli')
|
|
682
|
-
.option('-f, --file <path>', 'Manifest file to publish', 'root-manifest.json')
|
|
683
|
-
.option('--no-validate', 'Skip manifest validation step')
|
|
684
|
-
.action((options) => {
|
|
685
|
-
const file = options.file || 'root-manifest.json';
|
|
686
|
-
if (!fs.existsSync(file)) {
|
|
687
|
-
console.error(`ā Manifest not found: ${file}`);
|
|
688
|
-
process.exit(1);
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
if (options.validate !== false) {
|
|
692
|
-
let manifest;
|
|
693
|
-
try {
|
|
694
|
-
manifest = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
695
|
-
} catch (err) {
|
|
696
|
-
console.error('ā Failed to parse manifest:', err.message);
|
|
697
|
-
process.exit(1);
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
const result = validateManifestObject(manifest);
|
|
701
|
-
if (!result.valid) {
|
|
702
|
-
console.error('ā Manifest validation failed:');
|
|
703
|
-
for (const e of result.errors) console.error(' -', e);
|
|
704
|
-
process.exit(1);
|
|
705
|
-
}
|
|
706
|
-
console.log('ā
Manifest validation passed');
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
try {
|
|
710
|
-
console.log('š Running publish via @rootsdk/cli...');
|
|
711
|
-
execSync('npx @rootsdk/cli publish', { stdio: 'inherit' });
|
|
712
|
-
} catch (err) {
|
|
713
|
-
console.error('ā Publish failed:', err.message);
|
|
714
|
-
process.exit(1);
|
|
715
|
-
}
|
|
716
|
-
});
|
|
717
|
-
|
|
718
|
-
program
|
|
719
|
-
.command('setup')
|
|
720
|
-
.description('Interactive setup wizard to install only the dependencies you need')
|
|
721
|
-
.action(async () => {
|
|
722
|
-
const rl = readline.createInterface({
|
|
723
|
-
input: process.stdin,
|
|
724
|
-
output: process.stdout
|
|
725
|
-
});
|
|
726
|
-
|
|
727
|
-
function question(prompt) {
|
|
728
|
-
return new Promise((resolve) => {
|
|
729
|
-
rl.question(prompt, resolve);
|
|
730
|
-
});
|
|
731
|
-
}
|
|
732
|
-
|
|
733
|
-
const PLATFORMS = {
|
|
734
|
-
'1': {
|
|
735
|
-
name: 'Discord Bot',
|
|
736
|
-
package: 'discord.js',
|
|
737
|
-
platform: 'discord',
|
|
738
|
-
description: 'Build a Discord bot using discord.js'
|
|
739
|
-
},
|
|
740
|
-
'2': {
|
|
741
|
-
name: 'Root Bot (Server-side)',
|
|
742
|
-
package: '@rootsdk/server-bot',
|
|
743
|
-
platform: 'root',
|
|
744
|
-
description: 'Build a Root bot that runs on servers'
|
|
745
|
-
},
|
|
746
|
-
'3': {
|
|
747
|
-
name: 'Root App (Client-side)',
|
|
748
|
-
package: '@rootsdk/client-app',
|
|
749
|
-
platform: 'root-app',
|
|
750
|
-
description: 'Build a Root app with GUI in the Root client'
|
|
751
|
-
},
|
|
752
|
-
'4': {
|
|
753
|
-
name: 'Multiple Platforms',
|
|
754
|
-
package: 'all',
|
|
755
|
-
platform: 'multi',
|
|
756
|
-
description: 'Install dependencies for multiple platforms'
|
|
757
|
-
}
|
|
758
|
-
};
|
|
759
|
-
|
|
760
|
-
console.log('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
761
|
-
console.log('ā Library.DR-Conversion Setup Wizard ā');
|
|
762
|
-
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
763
|
-
console.log('This wizard will help you install only the dependencies');
|
|
764
|
-
console.log('you need for your target platform(s).\n');
|
|
765
|
-
|
|
766
|
-
// Show platform options
|
|
767
|
-
console.log('Choose your target platform:\n');
|
|
768
|
-
Object.entries(PLATFORMS).forEach(([key, info]) => {
|
|
769
|
-
console.log(` ${key}. ${info.name}`);
|
|
770
|
-
console.log(` ${info.description}\n`);
|
|
771
|
-
});
|
|
772
|
-
|
|
773
|
-
const choice = await question('Enter your choice (1-4): ');
|
|
774
|
-
|
|
775
|
-
if (!PLATFORMS[choice]) {
|
|
776
|
-
console.log('\nā Invalid choice. Exiting.');
|
|
777
|
-
rl.close();
|
|
778
|
-
return;
|
|
779
|
-
}
|
|
780
|
-
|
|
781
|
-
const selected = PLATFORMS[choice];
|
|
782
|
-
console.log(`\nā Selected: ${selected.name}\n`);
|
|
783
|
-
|
|
784
|
-
// Determine packages to install
|
|
785
|
-
let packagesToInstall = [];
|
|
786
|
-
|
|
787
|
-
if (selected.package === 'all') {
|
|
788
|
-
console.log('Select which platforms to install (comma-separated):');
|
|
789
|
-
console.log(' 1. Discord (discord.js)');
|
|
790
|
-
console.log(' 2. Root Bot (@rootsdk/server-bot)');
|
|
791
|
-
console.log(' 3. Root App (@rootsdk/client-app)\n');
|
|
792
|
-
|
|
793
|
-
const multiChoice = await question('Enter choices (e.g., 1,2): ');
|
|
794
|
-
const choices = multiChoice.split(',').map(c => c.trim());
|
|
795
|
-
|
|
796
|
-
if (choices.includes('1')) packagesToInstall.push('discord.js');
|
|
797
|
-
if (choices.includes('2')) packagesToInstall.push('@rootsdk/server-bot');
|
|
798
|
-
if (choices.includes('3')) packagesToInstall.push('@rootsdk/client-app');
|
|
799
|
-
} else {
|
|
800
|
-
packagesToInstall = [selected.package];
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
if (packagesToInstall.length === 0) {
|
|
804
|
-
console.log('\nā No packages selected. Exiting.');
|
|
805
|
-
rl.close();
|
|
806
|
-
return;
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
// Confirm installation
|
|
810
|
-
console.log('\nThe following packages will be installed:');
|
|
811
|
-
packagesToInstall.forEach(pkg => console.log(` - ${pkg}`));
|
|
812
|
-
console.log('');
|
|
813
|
-
|
|
814
|
-
const confirm = await question('Proceed with installation? (y/n): ');
|
|
815
|
-
|
|
816
|
-
if (confirm.toLowerCase() !== 'y' && confirm.toLowerCase() !== 'yes') {
|
|
817
|
-
console.log('\nā Installation cancelled.');
|
|
818
|
-
rl.close();
|
|
819
|
-
return;
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
// Install packages
|
|
823
|
-
console.log('\nš¦ Installing packages...\n');
|
|
824
|
-
|
|
825
|
-
try {
|
|
826
|
-
const installCmd = `npm install ${packagesToInstall.join(' ')}`;
|
|
827
|
-
console.log(`Running: ${installCmd}\n`);
|
|
828
|
-
execSync(installCmd, { stdio: 'inherit', cwd: process.cwd() });
|
|
829
|
-
|
|
830
|
-
console.log('\nā
Packages installed successfully!\n');
|
|
831
|
-
} catch (error) {
|
|
832
|
-
console.error('\nā Installation failed:', error.message);
|
|
833
|
-
rl.close();
|
|
834
|
-
return;
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
// Show next steps
|
|
838
|
-
console.log('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
839
|
-
console.log('ā Setup Complete! ā');
|
|
840
|
-
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
841
|
-
console.log('Next steps:\n');
|
|
842
|
-
|
|
843
|
-
if (packagesToInstall.includes('discord.js')) {
|
|
844
|
-
console.log('Discord Bot Setup:');
|
|
845
|
-
console.log(' - Get your bot token from: https://discord.com/developers/applications');
|
|
846
|
-
console.log(' - Set environment variable: DISCORD_TOKEN=your_token_here');
|
|
847
|
-
console.log(' - Use: npx library.dr-conversion init -p discord -n my-discord-bot\n');
|
|
848
|
-
}
|
|
849
|
-
|
|
850
|
-
if (packagesToInstall.includes('@rootsdk/server-bot')) {
|
|
851
|
-
console.log('Root Bot Setup:');
|
|
852
|
-
console.log(' - Configure your Root bot in the Root platform');
|
|
853
|
-
console.log(' - Set environment variable: ROOT_TOKEN=your_token_here');
|
|
854
|
-
console.log(' - Use: npx library.dr-conversion init -p root -n my-root-bot\n');
|
|
855
|
-
}
|
|
856
|
-
|
|
857
|
-
if (packagesToInstall.includes('@rootsdk/client-app')) {
|
|
858
|
-
console.log('Root App Setup:');
|
|
859
|
-
console.log(' - Root Apps run in the Root client (browser environment)');
|
|
860
|
-
console.log(' - No token needed - uses Root client authentication');
|
|
861
|
-
console.log(' - Use: npx library.dr-conversion init -p root-app -n my-root-app\n');
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
console.log('Documentation: https://github.com/Shad0wcrushers/Library.shadow-DR-Conversion\n');
|
|
865
|
-
|
|
866
|
-
rl.close();
|
|
867
|
-
});
|
|
868
|
-
|
|
869
|
-
program.parse();
|