@aurora.purecore.codes/latest 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/aurora.js ADDED
@@ -0,0 +1,703 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { Command } = require('commander');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const os = require('os');
7
+
8
+ const program = new Command();
9
+
10
+ const CACHE_DIR = path.join(os.homedir(), '.aurora_austral', 'packages');
11
+ const BIN_CACHE_DIR = path.join(os.homedir(), '.aurora_austral', 'bin');
12
+ const LOCAL_DIR = path.join(process.cwd(), 'aurora_packages');
13
+ const LOCAL_BIN_DIR = path.join(process.cwd(), '.aurora', 'bin');
14
+ const REPO_OWNER = 'Aurora-Austral';
15
+ const REPO_NAME = 'vault';
16
+ const COMPILER_REPO_OWNER = 'austral';
17
+ const COMPILER_REPO_NAME = 'austral';
18
+ const COMPILER_VERSION = 'v0.2.0';
19
+ const API_URL = `https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/contents/packages`;
20
+
21
+ // Ensure directories exist
22
+ function ensureDirs() {
23
+ if (!fs.existsSync(CACHE_DIR)) fs.mkdirSync(CACHE_DIR, { recursive: true });
24
+ if (!fs.existsSync(BIN_CACHE_DIR)) fs.mkdirSync(BIN_CACHE_DIR, { recursive: true });
25
+ }
26
+
27
+ // Detect platform
28
+ function getPlatform() {
29
+ const platform = os.platform();
30
+ const arch = os.arch();
31
+
32
+ if (platform === 'linux' && arch === 'x64') return 'linux-x64';
33
+ if (platform === 'darwin' && arch === 'x64') return 'darwin-x64';
34
+ if (platform === 'darwin' && arch === 'arm64') return 'darwin-arm64';
35
+ if (platform === 'win32' && arch === 'x64') return 'win32-x64';
36
+
37
+ throw new Error(`Unsupported platform: ${platform}-${arch}`);
38
+ }
39
+
40
+ // Download file using native fetch
41
+ async function downloadFile(url, outputPath) {
42
+ const response = await fetch(url, {
43
+ redirect: 'follow',
44
+ headers: {
45
+ 'User-Agent': 'aurora-npm',
46
+ 'Accept': 'application/octet-stream'
47
+ }
48
+ });
49
+
50
+ if (!response.ok) {
51
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
52
+ }
53
+
54
+ const arrayBuffer = await response.arrayBuffer();
55
+ const buffer = Buffer.from(arrayBuffer);
56
+ fs.writeFileSync(outputPath, buffer);
57
+
58
+ return outputPath;
59
+ }
60
+
61
+ // Download directory from GitHub API
62
+ async function downloadDirectoryFromRepo(owner, repo, repoPath, targetDir) {
63
+ const url = `https://api.github.com/repos/${owner}/${repo}/contents/${repoPath}`;
64
+ const response = await fetch(url, {
65
+ headers: { 'User-Agent': 'aurora-npm' }
66
+ });
67
+
68
+ if (!response.ok) {
69
+ throw new Error(`Failed to fetch ${repoPath}: ${response.statusText}`);
70
+ }
71
+
72
+ const items = await response.json();
73
+
74
+ if (!fs.existsSync(targetDir)) fs.mkdirSync(targetDir, { recursive: true });
75
+
76
+ const downloadPromises = items.map(async (item) => {
77
+ const itemTarget = path.join(targetDir, item.name);
78
+ if (item.type === 'file') {
79
+ const fileResponse = await fetch(item.download_url, {
80
+ headers: { 'User-Agent': 'aurora-npm' }
81
+ });
82
+ if (fileResponse.ok) {
83
+ const arrayBuffer = await fileResponse.arrayBuffer();
84
+ fs.writeFileSync(itemTarget, Buffer.from(arrayBuffer));
85
+ }
86
+ } else if (item.type === 'dir') {
87
+ await downloadDirectoryFromRepo(owner, repo, item.path, itemTarget);
88
+ }
89
+ });
90
+
91
+ await Promise.all(downloadPromises);
92
+ }
93
+
94
+ // Run command
95
+ function runCmd(cmd, cwd, silent = false) {
96
+ let finalCmd = cmd;
97
+ if (process.platform === 'win32') {
98
+ finalCmd = `wsl ${cmd}`;
99
+ }
100
+ try {
101
+ const { execSync } = require('child_process');
102
+ const output = execSync(finalCmd, { cwd, stdio: silent ? 'pipe' : 'inherit', encoding: 'utf-8' });
103
+ return { success: true, message: output };
104
+ } catch (error) {
105
+ return {
106
+ success: false,
107
+ message: error.stdout || error.stderr || error.message
108
+ };
109
+ }
110
+ }
111
+
112
+ // Color output (simple implementation without chalk)
113
+ function colorize(color, text) {
114
+ const colors = {
115
+ cyan: '\x1b[36m',
116
+ green: '\x1b[32m',
117
+ yellow: '\x1b[33m',
118
+ red: '\x1b[31m',
119
+ bold: '\x1b[1m',
120
+ reset: '\x1b[0m'
121
+ };
122
+ return `${colors[color] || ''}${text}${colors.reset}`;
123
+ }
124
+
125
+ // Simple spinner
126
+ class Spinner {
127
+ constructor(text) {
128
+ this.text = text;
129
+ this.interval = null;
130
+ this.frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
131
+ this.i = 0;
132
+ }
133
+
134
+ start() {
135
+ process.stdout.write(`\r${this.frames[this.i]} ${this.text}`);
136
+ this.interval = setInterval(() => {
137
+ this.i = (this.i + 1) % this.frames.length;
138
+ process.stdout.write(`\r${this.frames[this.i]} ${this.text}`);
139
+ }, 80);
140
+ }
141
+
142
+ succeed(message) {
143
+ clearInterval(this.interval);
144
+ process.stdout.write(`\r${colorize('green', '✔')} ${message}\n`);
145
+ }
146
+
147
+ fail(message) {
148
+ clearInterval(this.interval);
149
+ process.stdout.write(`\r${colorize('red', '✖')} ${message}\n`);
150
+ }
151
+
152
+ info(message) {
153
+ clearInterval(this.interval);
154
+ process.stdout.write(`\r${colorize('cyan', 'ℹ')} ${message}\n`);
155
+ }
156
+ }
157
+
158
+ // Partial cleanup
159
+ async function partialCleanup(dir) {
160
+ if (!fs.existsSync(dir)) return;
161
+ const items = fs.readdirSync(dir);
162
+ for (const item of items) {
163
+ const itemPath = path.join(dir, item);
164
+ const stats = fs.statSync(itemPath);
165
+ if (stats.isFile()) {
166
+ const name = item.toLowerCase();
167
+ const shouldKeep = name.endsWith('.html') ||
168
+ name.includes('.test') ||
169
+ name.endsWith('.aui') ||
170
+ name.endsWith('.aum') ||
171
+ name === 'makefile';
172
+ if (!shouldKeep) {
173
+ fs.unlinkSync(itemPath);
174
+ }
175
+ }
176
+ }
177
+ }
178
+
179
+ // Main aurora init command
180
+ async function initCommand(options) {
181
+ console.log(colorize('bold', colorize('cyan', '\n🚀 Initializing Aurora project...\n')));
182
+
183
+ try {
184
+ // Create aurora.json
185
+ const packageJsonPath = path.join(process.cwd(), 'aurora.json');
186
+
187
+ if (fs.existsSync(packageJsonPath)) {
188
+ console.log(colorize('yellow', '⚠️ aurora.json already exists'));
189
+ } else {
190
+ const packageJson = {
191
+ name: path.basename(process.cwd()),
192
+ version: '0.1.0',
193
+ description: 'Aurora Austral project',
194
+ main: 'src/Main.aum',
195
+ scripts: {
196
+ build: 'make',
197
+ test: 'make test',
198
+ clean: 'make clean'
199
+ },
200
+ dependencies: {},
201
+ devDependencies: {},
202
+ aurora: {
203
+ compiler: 'local',
204
+ stdlib: 'local'
205
+ }
206
+ };
207
+
208
+ fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
209
+ console.log(colorize('green', '✓ Created aurora.json'));
210
+ }
211
+
212
+ // Create directory structure
213
+ const srcDir = path.join(process.cwd(), 'src');
214
+ const auroraPackagesDir = path.join(process.cwd(), 'aurora_packages');
215
+ const auroraDir = path.join(process.cwd(), '.aurora');
216
+
217
+ if (!fs.existsSync(srcDir)) fs.mkdirSync(srcDir);
218
+ if (!fs.existsSync(auroraPackagesDir)) fs.mkdirSync(auroraPackagesDir);
219
+ if (!fs.existsSync(auroraDir)) fs.mkdirSync(auroraDir);
220
+
221
+ console.log(colorize('green', '✓ Created project directories'));
222
+
223
+ // Download compiler binary if requested
224
+ if (options.binary !== false) {
225
+ ensureDirs();
226
+
227
+ try {
228
+ const platform = getPlatform();
229
+ const binName = platform.startsWith('win') ? 'austral.exe' : 'austral';
230
+
231
+ const assetMap = {
232
+ 'linux-x64': 'austral-linux',
233
+ 'darwin-x64': 'austral-macos',
234
+ 'darwin-arm64': 'austral-macos',
235
+ 'win32-x64': 'austral-windows.exe'
236
+ };
237
+
238
+ const assetName = assetMap[platform];
239
+ if (!assetName) {
240
+ throw new Error(`No binary available for platform ${platform}`);
241
+ }
242
+
243
+ const downloadUrl = `https://github.com/${COMPILER_REPO_OWNER}/${COMPILER_REPO_NAME}/releases/download/${COMPILER_VERSION}/${assetName}`;
244
+
245
+ const spinner = new Spinner(`Downloading ${assetName} from ${COMPILER_VERSION}...`);
246
+ spinner.start();
247
+
248
+ const binPath = path.join(BIN_CACHE_DIR, binName);
249
+ await downloadFile(downloadUrl, binPath);
250
+ fs.chmodSync(binPath, 0o755);
251
+
252
+ spinner.succeed(`Compiler ${COMPILER_VERSION} downloaded: ${binPath}`);
253
+
254
+ // Copy to local .aurora/bin
255
+ const localBinDir = path.join(process.cwd(), '.aurora', 'bin');
256
+ if (!fs.existsSync(localBinDir)) fs.mkdirSync(localBinDir);
257
+ const localBinPath = path.join(localBinDir, binName);
258
+ fs.copyFileSync(binPath, localBinPath);
259
+ fs.chmodSync(localBinPath, 0o755);
260
+
261
+ console.log(colorize('green', `✓ Compiler installed: ${localBinPath}`));
262
+
263
+ // Test if binary works
264
+ const testSpinner = new Spinner('Testing compiler binary...');
265
+ testSpinner.start();
266
+
267
+ const testResult = runCmd(`${localBinPath} --version`, process.cwd(), true);
268
+
269
+ if (!testResult.success) {
270
+ testSpinner.fail('Downloaded binary cannot execute (likely Nix-compiled)');
271
+ console.log(colorize('yellow', '⚠️ The official release binary has Nix dependencies'));
272
+ console.log(colorize('yellow', ' Falling back to system compiler'));
273
+ console.log(colorize('yellow', ' Please ensure "austral" is in your PATH'));
274
+
275
+ fs.unlinkSync(localBinPath);
276
+
277
+ const config = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
278
+ config.aurora.compiler = 'system';
279
+ config.aurora.note = 'Using system-installed austral compiler';
280
+ fs.writeFileSync(packageJsonPath, JSON.stringify(config, null, 2));
281
+ } else {
282
+ testSpinner.succeed('Compiler binary works!');
283
+ }
284
+
285
+ // Download stdlib regardless of binary status
286
+ const stdlibSpinner = new Spinner('Downloading standard library...');
287
+ stdlibSpinner.start();
288
+
289
+ const stdlibPath = path.join(BIN_CACHE_DIR, 'stdlib');
290
+ await downloadDirectoryFromRepo(
291
+ COMPILER_REPO_OWNER,
292
+ COMPILER_REPO_NAME,
293
+ 'standard/src',
294
+ stdlibPath
295
+ );
296
+
297
+ const localStdlibPath = path.join(process.cwd(), '.aurora', 'stdlib');
298
+ if (fs.existsSync(localStdlibPath)) {
299
+ fs.rmSync(localStdlibPath, { recursive: true, force: true });
300
+ }
301
+ fs.renameSync(stdlibPath, localStdlibPath);
302
+
303
+ stdlibSpinner.succeed(`Standard library installed: ${localStdlibPath}`);
304
+
305
+ // Update aurora.json
306
+ const config = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
307
+ if (testResult.success) {
308
+ config.aurora.compiler = 'local';
309
+ config.aurora.compilerPath = `.aurora/bin/${binName}`;
310
+ } else {
311
+ config.aurora.compiler = 'system';
312
+ config.aurora.note = 'Using system-installed austral compiler';
313
+ }
314
+ config.aurora.stdlibPath = '.aurora/stdlib';
315
+ fs.writeFileSync(packageJsonPath, JSON.stringify(config, null, 2));
316
+
317
+ } catch (error) {
318
+ console.log(colorize('yellow', `⚠️ Could not download binaries: ${error.message}`));
319
+ console.log(colorize('yellow', ' You can install the compiler manually or use system installation'));
320
+ }
321
+ }
322
+
323
+ // Create example files
324
+ const mainAui = path.join(srcDir, 'Main.aui');
325
+ if (!fs.existsSync(mainAui)) {
326
+ fs.writeFileSync(mainAui, `module Example.Main is
327
+ function main(): ExitCode;
328
+ end module.
329
+ `);
330
+ console.log(colorize('green', '✓ Created src/Main.aui'));
331
+ }
332
+
333
+ const mainAum = path.join(srcDir, 'Main.aum');
334
+ if (!fs.existsSync(mainAum)) {
335
+ fs.writeFileSync(mainAum, `module body Example.Main is
336
+ function main(): ExitCode is
337
+ printLn("Hello, Aurora Austral!");
338
+ return ExitSuccess();
339
+ end;
340
+ end module body.
341
+ `);
342
+ console.log(colorize('green', '✓ Created src/Main.aum'));
343
+ }
344
+
345
+ // Create Makefile
346
+ const makefilePath = path.join(process.cwd(), 'Makefile');
347
+ if (!fs.existsSync(makefilePath)) {
348
+ const makefile = `# Aurora Austral Project Makefile
349
+
350
+ # Detect compiler - excluding broken Nix binaries in .local/bin
351
+ AU_COMPILER := $(shell \\
352
+ if [ -x ".aurora/bin/austral" ]; then \\
353
+ echo ".aurora/bin/austral"; \\
354
+ else \\
355
+ for path in $$(echo $$PATH | tr ':' ' '); do \\
356
+ if [ -x "$$path/austral" ] && echo "$$path" | grep -qv "/.local/bin"; then \\
357
+ echo "$$path/austral"; \\
358
+ break; \\
359
+ fi; \\
360
+ done; \\
361
+ fi)
362
+
363
+ ifeq ($(AU_COMPILER),)
364
+ $(error Austral compiler not found. Please install austral in /usr/local/bin)
365
+ endif
366
+
367
+ # Detect stdlib
368
+ ifneq ($(wildcard .aurora/stdlib),)
369
+ AUSTRAL_STDLIB = .aurora/stdlib
370
+ else ifneq ($(wildcard /usr/local/lib/austral/standard/src),)
371
+ AUSTRAL_STDLIB = /usr/local/lib/austral/standard/src
372
+ else ifneq ($(wildcard /usr/lib/austral/standard/src),)
373
+ AUSTRAL_STDLIB = /usr/lib/austral/standard/src
374
+ else
375
+ $(error AUSTRAL_STDLIB not found. Please set AUSTRAL_STDLIB environment variable)
376
+ endif
377
+
378
+ # Standard library modules
379
+ STDLIB := \\
380
+ $(AUSTRAL_STDLIB)/Tuples.aui,$(AUSTRAL_STDLIB)/Tuples.aum \\
381
+ $(AUSTRAL_STDLIB)/Bounded.aui,$(AUSTRAL_STDLIB)/Bounded.aum \\
382
+ $(AUSTRAL_STDLIB)/Equality.aui,$(AUSTRAL_STDLIB)/Equality.aum \\
383
+ $(AUSTRAL_STDLIB)/Order.aui,$(AUSTRAL_STDLIB)/Order.aum \\
384
+ $(AUSTRAL_STDLIB)/Box.aui,$(AUSTRAL_STDLIB)/Box.aum \\
385
+ $(AUSTRAL_STDLIB)/Buffer.aui,$(AUSTRAL_STDLIB)/Buffer.aum \\
386
+ $(AUSTRAL_STDLIB)/String.aui,$(AUSTRAL_STDLIB)/String.aum \\
387
+ $(AUSTRAL_STDLIB)/StringBuilder.aui,$(AUSTRAL_STDLIB)/StringBuilder.aum \\
388
+ $(AUSTRAL_STDLIB)/IO/IO.aui,$(AUSTRAL_STDLIB)/IO/IO.aum \\
389
+ $(AUSTRAL_STDLIB)/IO/Terminal.aui,$(AUSTRAL_STDLIB)/IO/Terminal.aum
390
+
391
+ SRC := src/Main.aui,src/Main.aum
392
+ ENTRY := Example.Main:main
393
+ OUTPUT := main
394
+
395
+ all: build
396
+
397
+ build:
398
+ @echo "Building project..."
399
+ @echo "Using compiler: $(AU_COMPILER)"
400
+ @echo "Using stdlib: $(AUSTRAL_STDLIB)"
401
+ $(AU_COMPILER) compile $(STDLIB) $(SRC) --entrypoint=$(ENTRY) --output=$(OUTPUT)
402
+ @echo "Build successful!"
403
+
404
+ run: build
405
+ ./$(OUTPUT)
406
+
407
+ test:
408
+ @echo "No tests defined yet"
409
+
410
+ clean:
411
+ rm -f $(OUTPUT) calltree.html error.html
412
+
413
+ .PHONY: all build run test clean
414
+ `;
415
+ fs.writeFileSync(makefilePath, makefile);
416
+ console.log(colorize('green', '✓ Created Makefile'));
417
+ }
418
+
419
+ // Create .gitignore
420
+ const gitignorePath = path.join(process.cwd(), '.gitignore');
421
+ if (!fs.existsSync(gitignorePath)) {
422
+ fs.writeFileSync(gitignorePath, `# Aurora Austral
423
+ aurora_packages/
424
+ .aurora/bin/
425
+ .aurora/stdlib/
426
+ main
427
+ *.o
428
+ calltree.html
429
+ error.html
430
+
431
+ # OS
432
+ .DS_Store
433
+ Thumbs.db
434
+ `);
435
+ console.log(colorize('green', '✓ Created .gitignore'));
436
+ }
437
+
438
+ console.log(colorize('bold', colorize('green', '\n✨ Project initialized successfully!\n')));
439
+ console.log(colorize('cyan', 'Next steps:'));
440
+ console.log(colorize('white', ' 1. Edit src/Main.aum'));
441
+ console.log(colorize('white', ' 2. Run: make build'));
442
+ console.log(colorize('white', ' 3. Run: ./main'));
443
+ console.log(colorize('white', ' 4. Install packages: aurora install <package-name>\n'));
444
+
445
+ } catch (error) {
446
+ console.log(colorize('red', `\n✖ Error initializing project: ${error.message}`));
447
+ process.exit(1);
448
+ }
449
+ }
450
+
451
+ // Install package command
452
+ async function installPackage(packageName) {
453
+ ensureDirs();
454
+ const spinner = new Spinner(`Checking for ${packageName}...`);
455
+
456
+ const cachePath = path.join(CACHE_DIR, packageName);
457
+ const localPath = path.join(LOCAL_DIR, packageName);
458
+
459
+ try {
460
+ if (fs.existsSync(cachePath)) {
461
+ spinner.text = `Using cached version of ${packageName}...`;
462
+ if (!fs.existsSync(LOCAL_DIR)) fs.mkdirSync(LOCAL_DIR);
463
+ if (fs.existsSync(localPath)) fs.rmSync(localPath, { recursive: true, force: true });
464
+ fs.renameSync(cachePath, localPath);
465
+ spinner.succeed(`Package ${packageName} installed from cache.`);
466
+ return;
467
+ }
468
+
469
+ spinner.text = `Downloading ${packageName} from GitHub...`;
470
+ if (!fs.existsSync(LOCAL_DIR)) fs.mkdirSync(LOCAL_DIR);
471
+ if (fs.existsSync(localPath)) fs.rmSync(localPath, { recursive: true, force: true });
472
+ await downloadDirectoryFromRepo(REPO_OWNER, REPO_NAME, `packages/${packageName}`, localPath);
473
+
474
+ spinner.stop();
475
+ console.log(colorize('blue', `\n--- Building ${packageName} ---`));
476
+ const buildRes = runCmd('make', localPath, false);
477
+ if (!buildRes.success) {
478
+ await partialCleanup(localPath);
479
+ console.log(colorize('red', `\n✖ Build failed for ${packageName}`));
480
+ process.exit(1);
481
+ }
482
+
483
+ console.log(colorize('blue', `\n--- Testing ${packageName} ---`));
484
+ const testRes = runCmd('make test', localPath, false);
485
+ if (!testRes.success) {
486
+ await partialCleanup(localPath);
487
+ console.log(colorize('red', `\n✖ Test failed for ${packageName}`));
488
+ process.exit(1);
489
+ }
490
+
491
+ spinner.start(`Caching ${packageName}...`);
492
+ fs.renameSync(localPath, cachePath);
493
+
494
+ spinner.succeed(`Package ${packageName} installed successfully.`);
495
+ } catch (error) {
496
+ spinner.fail(`Error installing ${packageName}: ${error.message}`);
497
+ if (fs.existsSync(localPath)) await partialCleanup(localPath);
498
+ process.exit(1);
499
+ }
500
+ }
501
+
502
+ // List packages command
503
+ async function listPackages(options) {
504
+ const spinner = new Spinner('Fetching list...');
505
+ try {
506
+ if (options.local) {
507
+ ensureDirs();
508
+ const files = fs.readdirSync(CACHE_DIR);
509
+ spinner.stop();
510
+ console.log(colorize('bold', 'Local cached packages (~/.aurora_austral/packages):'));
511
+ if (files.length === 0) console.log(' (none)');
512
+ files.forEach(f => console.log(` - ${f}`));
513
+ } else {
514
+ const response = await fetch(API_URL, { headers: { 'User-Agent': 'aurora-npm' } });
515
+ if (!response.ok) throw new Error(`Failed to fetch: ${response.statusText}`);
516
+ const items = await response.json();
517
+ const packages = items.filter(item => item.type === 'dir').map(item => item.name);
518
+ spinner.stop();
519
+ console.log(colorize('bold', 'Remote packages (GitHub):'));
520
+ packages.forEach(p => console.log(` - ${p}`));
521
+ }
522
+ } catch (error) {
523
+ spinner.fail(`Error: ${error.message}`);
524
+ }
525
+ }
526
+
527
+ // Find package command
528
+ async function findPackage(packageName) {
529
+ const spinner = new Spinner(`Searching for ${packageName}...`);
530
+ try {
531
+ const response = await fetch(API_URL, { headers: { 'User-Agent': 'aurora-npm' } });
532
+ if (!response.ok) throw new Error(`Failed to fetch: ${response.statusText}`);
533
+ const items = await response.json();
534
+ const packages = items.filter(item => item.type === 'dir').map(item => item.name);
535
+ const filtered = packages.filter(p => p.toLowerCase().includes(packageName.toLowerCase()));
536
+ spinner.stop();
537
+ if (filtered.length > 0) {
538
+ console.log(colorize('bold', `Found packages matching "${packageName}":`));
539
+ filtered.forEach(p => console.log(` - ${p}`));
540
+ } else {
541
+ console.log(colorize('yellow', `No packages found matching "${packageName}".`));
542
+ }
543
+ } catch (error) {
544
+ spinner.fail(`Error: ${error.message}`);
545
+ }
546
+ }
547
+
548
+ // Uninstall package command
549
+ async function uninstallPackage(packageName) {
550
+ const spinner = new Spinner(`Uninstalling ${packageName}...`);
551
+ try {
552
+ const localPath = path.join(LOCAL_DIR, packageName);
553
+ const cachePath = path.join(CACHE_DIR, packageName);
554
+
555
+ let removed = false;
556
+ if (fs.existsSync(localPath)) {
557
+ fs.rmSync(localPath, { recursive: true, force: true });
558
+ removed = true;
559
+ }
560
+ if (fs.existsSync(cachePath)) {
561
+ fs.rmSync(cachePath, { recursive: true, force: true });
562
+ removed = true;
563
+ }
564
+
565
+ if (removed) {
566
+ spinner.succeed(`Package ${packageName} removed from local and cache.`);
567
+ } else {
568
+ spinner.info(`Package ${packageName} was not found.`);
569
+ }
570
+ } catch (error) {
571
+ spinner.fail(`Error uninstalling ${packageName}: ${error.message}`);
572
+ }
573
+ }
574
+
575
+ // Test package command
576
+ async function testPackage(packageName) {
577
+ const localPath = path.join(LOCAL_DIR, packageName);
578
+ if (!fs.existsSync(localPath)) {
579
+ console.log(colorize('red', `Package ${packageName} is not installed in aurora_packages/.`));
580
+ return;
581
+ }
582
+
583
+ console.log(colorize('blue', `Running "make test" in ${localPath}...`));
584
+ const res = runCmd('make test', localPath);
585
+ if (res.success) {
586
+ console.log(colorize('green', `Tests passed for ${packageName}.`));
587
+ } else {
588
+ console.log(colorize('red', `Tests failed for ${packageName}.`));
589
+ console.log(res.message);
590
+ }
591
+ }
592
+
593
+ // Update package command
594
+ async function updatePackage(packageName) {
595
+ ensureDirs();
596
+ const packagesToUpdate = [];
597
+
598
+ if (packageName) {
599
+ packagesToUpdate.push(packageName);
600
+ } else {
601
+ if (fs.existsSync(LOCAL_DIR)) {
602
+ packagesToUpdate.push(...fs.readdirSync(LOCAL_DIR));
603
+ }
604
+ if (fs.existsSync(CACHE_DIR)) {
605
+ packagesToUpdate.push(...fs.readdirSync(CACHE_DIR));
606
+ }
607
+ }
608
+
609
+ const uniquePackages = [...new Set(packagesToUpdate)];
610
+ if (uniquePackages.length === 0) {
611
+ console.log(colorize('yellow', 'No packages found to update.'));
612
+ return;
613
+ }
614
+
615
+ for (const pkg of uniquePackages) {
616
+ const spinner = new Spinner(`Updating ${pkg}...`);
617
+ try {
618
+ const localPath = path.join(LOCAL_DIR, pkg);
619
+ const cachePath = path.join(CACHE_DIR, pkg);
620
+
621
+ spinner.text = `Downloading latest ${pkg}...`;
622
+ const tempDir = path.join(os.tmpdir(), `aurora-update-${pkg}-${Date.now()}`);
623
+ await downloadDirectoryFromRepo(REPO_OWNER, REPO_NAME, `packages/${pkg}`, tempDir);
624
+
625
+ spinner.stop();
626
+ console.log(colorize('blue', `\n--- Building ${pkg} ---`));
627
+ const buildRes = runCmd('make', tempDir, false);
628
+ if (!buildRes.success) {
629
+ console.log(colorize('red', `\n✖ Update failed for ${pkg} (build error)`));
630
+ fs.rmSync(tempDir, { recursive: true, force: true });
631
+ continue;
632
+ }
633
+
634
+ console.log(colorize('blue', `\n--- Testing ${pkg} ---`));
635
+ const testRes = runCmd('make test', tempDir, false);
636
+ if (!testRes.success) {
637
+ console.log(colorize('red', `\n✖ Update failed for ${pkg} (test error)`));
638
+ fs.rmSync(tempDir, { recursive: true, force: true });
639
+ continue;
640
+ }
641
+
642
+ spinner.start(`Updating ${pkg}...`);
643
+
644
+ if (fs.existsSync(localPath)) {
645
+ fs.rmSync(localPath, { recursive: true, force: true });
646
+ }
647
+ fs.renameSync(tempDir, localPath);
648
+
649
+ if (fs.existsSync(cachePath)) {
650
+ fs.rmSync(cachePath, { recursive: true, force: true });
651
+ }
652
+ fs.renameSync(localPath, cachePath);
653
+
654
+ spinner.succeed(`Package ${pkg} updated.`);
655
+ } catch (error) {
656
+ spinner.fail(`Error updating ${pkg}: ${error.message}`);
657
+ }
658
+ }
659
+ }
660
+
661
+ program
662
+ .name('aurora')
663
+ .description('Aurora Package Manager')
664
+ .version('0.1.0');
665
+
666
+ program
667
+ .command('init')
668
+ .description('Initialize a new Aurora project')
669
+ .option('--no-binary', 'Skip downloading compiler binary')
670
+ .action(initCommand);
671
+
672
+ program
673
+ .command('install <package-name>')
674
+ .description('Install a package')
675
+ .action(installPackage);
676
+
677
+ program
678
+ .command('list')
679
+ .description('List packages')
680
+ .option('--local', 'List locally cached packages')
681
+ .action(listPackages);
682
+
683
+ program
684
+ .command('find <package-name>')
685
+ .description('Find a package')
686
+ .action(findPackage);
687
+
688
+ program
689
+ .command('uninstall <package-name>')
690
+ .description('Uninstall a package from project and cache')
691
+ .action(uninstallPackage);
692
+
693
+ program
694
+ .command('test <package-name>')
695
+ .description('Run tests for a package')
696
+ .action(testPackage);
697
+
698
+ program
699
+ .command('update [package-name]')
700
+ .description('Update packages (project and cache)')
701
+ .action(updatePackage);
702
+
703
+ program.parse(process.argv);