@open-audio-stack/core 0.1.43 → 0.1.45

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.
@@ -178,10 +178,18 @@ export class ManagerLocal extends Manager {
178
178
  const excludedFormats = [];
179
179
  const system = getSystem();
180
180
  if (system === SystemType.Linux) {
181
- if (!(await commandExists('dpkg')))
181
+ const hasDpkg = await commandExists('dpkg');
182
+ const hasRpm = await commandExists('rpm');
183
+ // If both exist, prefer DEB over RPM
184
+ if (hasDpkg && hasRpm) {
185
+ excludedFormats.push(FileFormat.RedHatPackage);
186
+ }
187
+ else if (!hasDpkg) {
182
188
  excludedFormats.push(FileFormat.DebianPackage);
183
- if (!(await commandExists('rpm')))
189
+ }
190
+ else if (!hasRpm) {
184
191
  excludedFormats.push(FileFormat.RedHatPackage);
192
+ }
185
193
  }
186
194
  const files = packageCompatibleFiles(pkgVersion, [getArchitecture()], [getSystem()], excludedFormats);
187
195
  if (!files.length)
@@ -42,15 +42,27 @@ export async function adminInit() {
42
42
  manager.log('adminInit', args);
43
43
  await manager.sync();
44
44
  manager.scan();
45
- if (args.operation === 'install') {
46
- await manager.install(args.id, args.version);
47
- }
48
- else if (args.operation === 'uninstall') {
49
- await manager.uninstall(args.id, args.version);
45
+ try {
46
+ if (args.operation === 'install') {
47
+ await manager.install(args.id, args.version);
48
+ }
49
+ else if (args.operation === 'uninstall') {
50
+ await manager.uninstall(args.id, args.version);
51
+ }
52
+ else if (args.operation === 'installAll') {
53
+ await manager.installAll();
54
+ }
55
+ const result = { status: 'ok', code: 0 };
56
+ process.stdout.write('\n');
57
+ console.log(JSON.stringify(result));
58
+ process.exit(0);
50
59
  }
51
- else if (args.operation === 'installAll') {
52
- await manager.installAll();
60
+ catch (err) {
61
+ const message = err && err.message ? err.message : String(err);
62
+ const errorResult = { status: 'error', code: err && err.code ? err.code : 1, message };
63
+ process.stdout.write('\n');
64
+ console.log(JSON.stringify(errorResult));
65
+ process.exit(typeof errorResult.code === 'number' ? errorResult.code : 1);
53
66
  }
54
- console.log('ADMIN_COMPLETE');
55
67
  }
56
68
  adminInit();
@@ -51,9 +51,12 @@ export async function archiveExtract(filePath, dirPath) {
51
51
  });
52
52
  }
53
53
  else if (ext === '.7z') {
54
- return unpack(filePath, dirPath, err => {
55
- if (err)
56
- throw new Error(`7z extraction failed: ${err.message}`);
54
+ return new Promise((resolve, reject) => {
55
+ unpack(filePath, dirPath, (err2) => {
56
+ if (err2)
57
+ return reject(new Error(`7z extraction failed: ${err2 && err2.message ? err2.message : String(err2)}`));
58
+ return resolve();
59
+ });
57
60
  });
58
61
  }
59
62
  }
@@ -247,10 +250,23 @@ export function fileMove(filePath, newPath) {
247
250
  return false;
248
251
  }
249
252
  export function filesMove(dirSource, dirTarget, dirSub, formatDir) {
250
- // Read all files from source directory, ignoring Mac Contents files.
251
- const allFiles = dirRead(`${dirSource}/**/*`);
252
- const files = allFiles.filter(f => !dirIs(f));
253
+ const filesAndFolders = dirRead(`${dirSource}/**/*`);
254
+ log('filesAndFolders', filesAndFolders);
255
+ const files = filesAndFolders.filter(f => {
256
+ // Include files.
257
+ if (!dirIs(f))
258
+ return true;
259
+ // Include macOS application bundles (directory of files presented as a single file).
260
+ if (fileExists(path.join(f, 'Contents', 'Info.plist')))
261
+ return true;
262
+ // Include LV2 plugin folders.
263
+ if (fileExists(path.join(f, 'manifest.ttl')))
264
+ return true;
265
+ // Otherwise ignore.
266
+ return false;
267
+ });
253
268
  const filesMoved = [];
269
+ log('files', files);
254
270
  // For each file, move to correct folder based on type
255
271
  files.forEach((fileSource) => {
256
272
  const fileExt = path.extname(fileSource).slice(1).toLowerCase();
@@ -373,28 +389,46 @@ export function runCliAsAdmin(args) {
373
389
  const filename = fileURLToPath(import.meta.url).replace('src/', 'build/');
374
390
  const dirPathClean = dirname(filename).replace('app.asar', 'app.asar.unpacked');
375
391
  const script = path.join(dirPathClean, 'admin.js');
376
- // Temp file for logging
377
- const logFile = path.join(dirPathClean, 'admin.log');
378
- writeFileSync(logFile, ''); // Clear previous logs
379
392
  log(`Running as admin: node "${script}" ${args}`);
380
- // Monitor log file for completion
381
- let completed = false;
382
- const tail = spawn('tail', ['-f', logFile]);
383
- tail.stdout.on('data', data => {
384
- const output = data.toString();
385
- log(output);
386
- if (output.includes('ADMIN_COMPLETE')) {
387
- completed = true;
388
- tail.kill();
389
- resolve();
393
+ const cmd = `node "${script}" ${args}`;
394
+ sudoPrompt.exec(cmd, { name: 'Open Audio Stack' }, (error, stdout, stderr) => {
395
+ // Prefer explicit error from sudo-prompt callback
396
+ if (error) {
397
+ const stderrStr = stderr ? (typeof stderr === 'string' ? stderr : stderr.toString()) : '';
398
+ const msg = `runCliAsAdmin: admin command failed: ${error && error.message ? error.message : String(error)}${stderrStr ? `\nstderr: ${stderrStr}` : ''}`;
399
+ const err = new Error(msg);
400
+ err.code = error && error.code ? error.code : undefined;
401
+ return reject(err);
390
402
  }
391
- });
392
- // Run the script with sudoPrompt
393
- sudoPrompt.exec(`node "${script}" ${args} >> "${logFile}" 2>&1`, { name: 'Open Audio Stack' }, error => {
394
- if (error && !completed) {
395
- tail.kill();
396
- reject(error);
403
+ // Convert stdout/stderr buffers to strings for inspection
404
+ const stdoutStr = stdout ? (typeof stdout === 'string' ? stdout : stdout.toString()) : '';
405
+ const stderrStr = stderr ? (typeof stderr === 'string' ? stderr : stderr.toString()) : '';
406
+ const out = stdoutStr + stderrStr;
407
+ log(out);
408
+ // Try to parse structured JSON output from the admin script first.
409
+ // Admin script outputs JSON on its own line after a newline, so look for the last JSON object.
410
+ const lines = out.split('\n');
411
+ let jsonPayload = null;
412
+ for (let i = lines.length - 1; i >= 0; i--) {
413
+ const line = lines[i].trim();
414
+ if (!line)
415
+ continue; // Skip empty lines
416
+ try {
417
+ jsonPayload = JSON.parse(line);
418
+ break; // Found valid JSON, stop searching backwards
419
+ }
420
+ catch {
421
+ // This line is not JSON, continue searching
422
+ }
423
+ }
424
+ if (jsonPayload) {
425
+ if (jsonPayload && (jsonPayload.status === 'ok' || jsonPayload.code === 0)) {
426
+ return resolve();
427
+ }
428
+ const errMsg = jsonPayload && jsonPayload.message ? jsonPayload.message : JSON.stringify(jsonPayload);
429
+ return reject(new Error(`runCliAsAdmin: admin command reported error: ${errMsg}`));
397
430
  }
431
+ return reject(new Error(`runCliAsAdmin: admin command did not report completion. stdout: ${stdoutStr} stderr: ${stderrStr}`));
398
432
  });
399
433
  });
400
434
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-audio-stack/core",
3
- "version": "0.1.43",
3
+ "version": "0.1.45",
4
4
  "description": "Open-source audio plugin management software",
5
5
  "type": "module",
6
6
  "main": "./build/index.js",