@glassnote/client 2.4.2 → 2.4.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/bin/glassnote.js +118 -0
- package/main.js +18 -0
- package/package.json +1 -1
package/bin/glassnote.js
CHANGED
|
@@ -29,6 +29,13 @@ const MARK_B = '# <<< glassnote <<<';
|
|
|
29
29
|
function npmEnv() {
|
|
30
30
|
return Object.assign({}, process.env, {
|
|
31
31
|
PATH: `${mode.BIN_DIR}${path.delimiter}${process.env.PATH || ''}`,
|
|
32
|
+
// Cache propia, bajo ~/.glassnote. Un ~/.npm con archivos de root —herencia de
|
|
33
|
+
// cualquier `sudo npm` viejo— hace que npm muera con EACCES antes de bajar nada,
|
|
34
|
+
// y el usuario tiene que andar con chown. Se pisa a propósito el npm_config_cache
|
|
35
|
+
// heredado: cuando esto corre bajo npx, npm nos pasa el suyo en el entorno, que es
|
|
36
|
+
// justo el que puede estar roto. Para forzar otra: GLASSNOTE_NPM_CACHE.
|
|
37
|
+
npm_config_cache:
|
|
38
|
+
process.env.GLASSNOTE_NPM_CACHE || path.join(mode.HOME_DIR, 'npm-cache'),
|
|
32
39
|
});
|
|
33
40
|
}
|
|
34
41
|
|
|
@@ -284,6 +291,108 @@ function toSpec(arg) {
|
|
|
284
291
|
return looksLikeSpec ? arg : `${mode.PKG_NAME}@${arg}`;
|
|
285
292
|
}
|
|
286
293
|
|
|
294
|
+
const MAC_APP_NAME = 'Glassnote.app';
|
|
295
|
+
|
|
296
|
+
// Instalado por npm queda un comando, no una app: cerrada desde la bandeja no hay forma
|
|
297
|
+
// de volver a abrirla desde el Finder, Spotlight o Launchpad. Esto crea un .app minimo
|
|
298
|
+
// —un envoltorio que llama al CLI instalado— para tener de donde relanzarla.
|
|
299
|
+
function macAppDirs() {
|
|
300
|
+
return [
|
|
301
|
+
path.join('/Applications', MAC_APP_NAME),
|
|
302
|
+
path.join(os.homedir(), 'Applications', MAC_APP_NAME),
|
|
303
|
+
];
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function instalarAppMac() {
|
|
307
|
+
if (process.platform !== 'darwin') return null;
|
|
308
|
+
|
|
309
|
+
// /Applications pide ser admin; si no se puede escribir, la de usuario sirve igual y
|
|
310
|
+
// Spotlight la indexa lo mismo. Nada de sudo: la instalacion entera va sin root.
|
|
311
|
+
const [global, local] = macAppDirs();
|
|
312
|
+
let appDir = local;
|
|
313
|
+
try {
|
|
314
|
+
fs.accessSync('/Applications', fs.constants.W_OK);
|
|
315
|
+
appDir = global;
|
|
316
|
+
} catch (error) {
|
|
317
|
+
/* sin permiso: se usa ~/Applications */
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
const contents = path.join(appDir, 'Contents');
|
|
321
|
+
const cli = path.join(mode.BIN_DIR, mode.BIN_NAME);
|
|
322
|
+
try {
|
|
323
|
+
fs.mkdirSync(path.join(contents, 'MacOS'), { recursive: true });
|
|
324
|
+
fs.mkdirSync(path.join(contents, 'Resources'), { recursive: true });
|
|
325
|
+
|
|
326
|
+
// El ejecutable del bundle solo delega en el CLI, que ya sabe encontrar electron y
|
|
327
|
+
// arrancar desprendido. Asi el .app no se queda viejo cuando el cliente se actualiza.
|
|
328
|
+
const exe = path.join(contents, 'MacOS', 'Glassnote');
|
|
329
|
+
fs.writeFileSync(
|
|
330
|
+
exe,
|
|
331
|
+
[
|
|
332
|
+
'#!/bin/sh',
|
|
333
|
+
"# Generado por 'glassnote install': se reescribe en cada instalacion.",
|
|
334
|
+
`exec "${cli}" start`,
|
|
335
|
+
'',
|
|
336
|
+
].join('\n')
|
|
337
|
+
);
|
|
338
|
+
fs.chmodSync(exe, 0o755);
|
|
339
|
+
|
|
340
|
+
// El icono del bundle tiene que ser .icns; sips viene con macOS. Si falla, el .app
|
|
341
|
+
// queda con el icono generico: molesta, pero no impide relanzar.
|
|
342
|
+
const png = path.join(mode.INSTALLED_PACKAGE_DIR, 'images', 'icon-512.png');
|
|
343
|
+
if (fs.existsSync(png)) {
|
|
344
|
+
spawnSync(
|
|
345
|
+
'sips',
|
|
346
|
+
['-s', 'format', 'icns', png, '--out', path.join(contents, 'Resources', 'glassnote.icns')],
|
|
347
|
+
{ stdio: 'ignore' }
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// LSUIElement, igual que la app: el envoltorio tampoco tiene que dejar icono en el Dock.
|
|
352
|
+
const version = installedVersion() || '0.0.0';
|
|
353
|
+
fs.writeFileSync(
|
|
354
|
+
path.join(contents, 'Info.plist'),
|
|
355
|
+
`<?xml version="1.0" encoding="UTF-8"?>
|
|
356
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
357
|
+
<plist version="1.0">
|
|
358
|
+
<dict>
|
|
359
|
+
<key>CFBundleName</key><string>Glassnote</string>
|
|
360
|
+
<key>CFBundleDisplayName</key><string>Glassnote</string>
|
|
361
|
+
<key>CFBundleIdentifier</key><string>com.glassnote.launcher</string>
|
|
362
|
+
<key>CFBundleExecutable</key><string>Glassnote</string>
|
|
363
|
+
<key>CFBundleIconFile</key><string>glassnote</string>
|
|
364
|
+
<key>CFBundlePackageType</key><string>APPL</string>
|
|
365
|
+
<key>CFBundleShortVersionString</key><string>${version}</string>
|
|
366
|
+
<key>CFBundleVersion</key><string>${version}</string>
|
|
367
|
+
<key>LSUIElement</key><true/>
|
|
368
|
+
</dict>
|
|
369
|
+
</plist>
|
|
370
|
+
`
|
|
371
|
+
);
|
|
372
|
+
|
|
373
|
+
// El Finder cachea el bundle por fecha: sin esto puede seguir mostrando el icono viejo.
|
|
374
|
+
spawnSync('touch', [appDir], { stdio: 'ignore' });
|
|
375
|
+
return appDir;
|
|
376
|
+
} catch (error) {
|
|
377
|
+
// Que no se pueda crear la app no rompe la instalacion: el comando ya funciona.
|
|
378
|
+
log(` (no pude crear ${MAC_APP_NAME}: ${error.message})`);
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function borrarAppMac() {
|
|
384
|
+
if (process.platform !== 'darwin') return;
|
|
385
|
+
for (const dir of macAppDirs()) {
|
|
386
|
+
if (!fs.existsSync(dir)) continue;
|
|
387
|
+
try {
|
|
388
|
+
step(`borrando ${dir}`);
|
|
389
|
+
fs.rmSync(dir, { recursive: true, force: true });
|
|
390
|
+
} catch (error) {
|
|
391
|
+
log(` (no pude borrar ${dir}: ${error.message})`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
287
396
|
function cmdInstall(args) {
|
|
288
397
|
const version = args.find((a) => !a.startsWith('-')) || 'latest';
|
|
289
398
|
const noPath = args.includes('--no-path');
|
|
@@ -323,6 +432,9 @@ function cmdInstall(args) {
|
|
|
323
432
|
}
|
|
324
433
|
}
|
|
325
434
|
|
|
435
|
+
const appMac = instalarAppMac();
|
|
436
|
+
if (appMac) step(`app creada en ${appMac} (para relanzarlo desde el Finder)`);
|
|
437
|
+
|
|
326
438
|
let pathInfo = { touched: [], line: '' };
|
|
327
439
|
if (!noPath) {
|
|
328
440
|
pathInfo = IS_WIN ? addToPathWindows() : addToPathUnix();
|
|
@@ -399,6 +511,10 @@ function cmdUpdate(args) {
|
|
|
399
511
|
}
|
|
400
512
|
|
|
401
513
|
olvidarFalloDeUpdate();
|
|
514
|
+
// Se rehace en cada update: quien ya tenia el cliente instalado de antes no paso
|
|
515
|
+
// por el install, y el .app tiene que aparecerle igual (y con la version al dia).
|
|
516
|
+
const appMac = instalarAppMac();
|
|
517
|
+
if (appMac) step(`app actualizada en ${appMac}`);
|
|
402
518
|
log(`Actualizado a v${installedVersion()}.`);
|
|
403
519
|
if (relaunch) {
|
|
404
520
|
launch({ detach: true });
|
|
@@ -426,6 +542,8 @@ function cmdUninstall() {
|
|
|
426
542
|
step('el PATH de usuario ya no tenía la entrada');
|
|
427
543
|
}
|
|
428
544
|
|
|
545
|
+
borrarAppMac();
|
|
546
|
+
|
|
429
547
|
if (fs.existsSync(mode.HOME_DIR)) {
|
|
430
548
|
step(`borrando ${mode.HOME_DIR}`);
|
|
431
549
|
fs.rmSync(mode.HOME_DIR, { recursive: true, force: true });
|
package/main.js
CHANGED
|
@@ -4,6 +4,7 @@ const {
|
|
|
4
4
|
Notification,
|
|
5
5
|
Tray,
|
|
6
6
|
Menu,
|
|
7
|
+
nativeImage,
|
|
7
8
|
screen,
|
|
8
9
|
} = require('electron');
|
|
9
10
|
const packageJson = require('./package.json');
|
|
@@ -121,6 +122,23 @@ cleanupOldLogs();
|
|
|
121
122
|
createTailUtility(logsDir);
|
|
122
123
|
|
|
123
124
|
app.whenReady().then(() => {
|
|
125
|
+
// macOS: esto es una app de bandeja, se maneja desde la barra de menu. Instalada por
|
|
126
|
+
// npm no hay .app propio, asi que el Dock mostraba el icono por defecto de Electron y
|
|
127
|
+
// una entrada que no sirve para nada. Se saca del Dock, pero antes se le pone el icono
|
|
128
|
+
// de glassnote: si algo lo vuelve a mostrar (un dialogo modal lo hace), que al menos
|
|
129
|
+
// no aparezca como "Electron".
|
|
130
|
+
if (process.platform === 'darwin' && app.dock) {
|
|
131
|
+
try {
|
|
132
|
+
const dockIcon = nativeImage.createFromPath(
|
|
133
|
+
path.join(__dirname, 'images', 'icon-512.png')
|
|
134
|
+
);
|
|
135
|
+
if (!dockIcon.isEmpty()) app.dock.setIcon(dockIcon);
|
|
136
|
+
} catch (error) {
|
|
137
|
+
console.warn('[dock] no se pudo poner el icono:', error.message);
|
|
138
|
+
}
|
|
139
|
+
app.dock.hide();
|
|
140
|
+
}
|
|
141
|
+
|
|
124
142
|
// Configure auto-start - this will handle shortcut creation
|
|
125
143
|
//
|
|
126
144
|
// Corriendo por `npx` no se registra nada: la app vive en la caché de npx, que se
|
package/package.json
CHANGED