kangentic 0.35.0 → 0.37.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/README.md +3 -3
- package/bin/kangentic.js +81 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ One command to install and launch [Kangentic](https://github.com/Kangentic/kange
|
|
|
10
10
|
npx kangentic
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
This downloads the pre-built binary for your platform from GitHub Releases, installs it, and launches the app. After the first run, the app manages its own updates automatically
|
|
13
|
+
This downloads the pre-built binary for your platform from GitHub Releases, installs it, and launches the app. After the first run, the app manages its own updates automatically on every platform.
|
|
14
14
|
|
|
15
15
|
### Open a specific project
|
|
16
16
|
|
|
@@ -26,7 +26,7 @@ npx kangentic /path/to/your/project
|
|
|
26
26
|
- **Windows:** Runs NSIS installer silently to `%LOCALAPPDATA%\Programs\Kangentic\`
|
|
27
27
|
- **macOS:** Extracts .zip to `~/Applications/Kangentic.app`
|
|
28
28
|
- **Linux:** Installs .rpm on RPM-family systems (`sudo dnf install` on Fedora/RHEL,
|
|
29
|
-
`sudo zypper install` on openSUSE, falling back to `sudo rpm -
|
|
29
|
+
`sudo zypper install` on openSUSE, falling back to `sudo rpm -Uvh`) or .deb elsewhere
|
|
30
30
|
(`sudo apt install`, falling back to `sudo dpkg -i`); prompts for password
|
|
31
31
|
4. Launches the app
|
|
32
32
|
|
|
@@ -36,7 +36,7 @@ After the initial install, you generally don't need to run `npx kangentic` again
|
|
|
36
36
|
|
|
37
37
|
- **Windows:** electron-updater installs new versions silently on restart.
|
|
38
38
|
- **macOS:** Built-in auto-updater downloads in the background and prompts to restart. (Requires code signing.)
|
|
39
|
-
- **Linux:**
|
|
39
|
+
- **Linux:** The app downloads the new deb/rpm and installs it when you click "Restart to update", asking for your password once. If that fails (no polkit agent, for example), re-run `npx kangentic@latest` (the `@latest` matters: a cached launcher reinstalls its own version), then quit and reopen the app.
|
|
40
40
|
|
|
41
41
|
### Install a specific version
|
|
42
42
|
|
package/bin/kangentic.js
CHANGED
|
@@ -201,6 +201,49 @@ function commandExists(command) {
|
|
|
201
201
|
}
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
+
/**
|
|
205
|
+
* Best-effort check for an already-running Kangentic on Linux.
|
|
206
|
+
*
|
|
207
|
+
* Only ever used to SKIP a redundant launch, never to gate the install or the
|
|
208
|
+
* advice printed after it. That asymmetry is deliberate: `pgrep -x` matches a
|
|
209
|
+
* 15-character-truncated comm name and is a heuristic, so a false negative must
|
|
210
|
+
* cost no more than one extra launch that focuses the existing window. Anything
|
|
211
|
+
* that made the user-facing message conditional on this would degrade a false
|
|
212
|
+
* negative straight back into silence.
|
|
213
|
+
*/
|
|
214
|
+
function isAppRunning(platformInfo) {
|
|
215
|
+
if (platformInfo.platform !== 'linux') return false;
|
|
216
|
+
if (!commandExists('pgrep')) return false;
|
|
217
|
+
try {
|
|
218
|
+
// Scoped to THIS user where possible: an unscoped match would see another
|
|
219
|
+
// account's Kangentic on a shared machine and skip a launch the invoking
|
|
220
|
+
// user needs. A false positive costs a silent no-op, which is worse than
|
|
221
|
+
// the extra launch a false negative costs. `process.getuid` is POSIX-only,
|
|
222
|
+
// so it is guarded rather than assumed even on this Linux-only path.
|
|
223
|
+
const userScope = typeof process.getuid === 'function' ? ['-U', String(process.getuid())] : [];
|
|
224
|
+
execFileSync('pgrep', ['-x', ...userScope, 'kangentic'], { stdio: 'ignore' });
|
|
225
|
+
return true;
|
|
226
|
+
} catch {
|
|
227
|
+
// Exit 1 means no match; any other failure is equally "not confirmed".
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Whether to tell the user to quit and reopen the app after installing.
|
|
234
|
+
*
|
|
235
|
+
* True only for a Linux UPGRADE. Windows and macOS relaunch into the new
|
|
236
|
+
* version from here, so there is nothing left to finish; and a first-time
|
|
237
|
+
* install on any platform has no older copy still open to replace.
|
|
238
|
+
*
|
|
239
|
+
* Deliberately NOT gated on isAppRunning(): within Linux this must hold
|
|
240
|
+
* whether or not the pgrep probe confirmed anything, so a false negative costs
|
|
241
|
+
* one redundant launch rather than restoring the silence it exists to fix.
|
|
242
|
+
*/
|
|
243
|
+
function shouldAdviseReopen(platformInfo, wasInstalled) {
|
|
244
|
+
return platformInfo.platform === 'linux' && wasInstalled;
|
|
245
|
+
}
|
|
246
|
+
|
|
204
247
|
function installLinux(artifactPath) {
|
|
205
248
|
console.log('Installing Kangentic...');
|
|
206
249
|
if (artifactPath.endsWith('.deb')) {
|
|
@@ -222,8 +265,17 @@ function installLinux(artifactPath) {
|
|
|
222
265
|
console.log('Running: sudo zypper install (you may be prompted for your password)');
|
|
223
266
|
execFileSync('sudo', ['zypper', '--non-interactive', 'install', artifactPath], { stdio: 'inherit' });
|
|
224
267
|
} else {
|
|
225
|
-
|
|
226
|
-
|
|
268
|
+
// -U, not -i: `rpm -i` fails with "package is already installed" on any
|
|
269
|
+
// version-to-version upgrade, so on a distro with neither dnf nor zypper
|
|
270
|
+
// a repeat `npx kangentic` could never actually update.
|
|
271
|
+
//
|
|
272
|
+
// --replacepkgs because the app now self-updates on Linux, so it can
|
|
273
|
+
// already be at the version this launcher is about to install while the
|
|
274
|
+
// launcher's own version marker still says otherwise. Without it that
|
|
275
|
+
// reinstall exits non-zero and main() bails before ever launching. dnf
|
|
276
|
+
// and zypper already no-op in that case; this makes the fallback match.
|
|
277
|
+
console.log('Running: sudo rpm -U (you may be prompted for your password)');
|
|
278
|
+
execFileSync('sudo', ['rpm', '-Uvh', '--replacepkgs', artifactPath], { stdio: 'inherit' });
|
|
227
279
|
}
|
|
228
280
|
}
|
|
229
281
|
console.log('Installation complete.');
|
|
@@ -413,6 +465,16 @@ async function main() {
|
|
|
413
465
|
process.exit(1);
|
|
414
466
|
}
|
|
415
467
|
|
|
468
|
+
// Both sampled BEFORE installing, since the install itself changes the answers.
|
|
469
|
+
// wasInstalled separates an upgrade from a first-time install: there is
|
|
470
|
+
// nothing to "finish updating" when the app was never on the machine. This
|
|
471
|
+
// deliberately checks the binary's presence (fs.existsSync), not
|
|
472
|
+
// isInstalled(): isInstalled() also compares the version marker and would
|
|
473
|
+
// read false on exactly the upgrade this advice exists to announce, since
|
|
474
|
+
// the marker still names the OLD version at this point in main().
|
|
475
|
+
const wasInstalled = fs.existsSync(getInstallPath(platformInfo));
|
|
476
|
+
const wasRunning = isAppRunning(platformInfo);
|
|
477
|
+
|
|
416
478
|
// Install
|
|
417
479
|
try {
|
|
418
480
|
install(platformInfo, artifactPath);
|
|
@@ -430,6 +492,21 @@ async function main() {
|
|
|
430
492
|
// ignore cleanup errors
|
|
431
493
|
}
|
|
432
494
|
|
|
495
|
+
// A running instance is the case the user cannot otherwise detect: the app
|
|
496
|
+
// enforces a single-instance lock, so a launch from here would exit(0) and
|
|
497
|
+
// merely focus the OLD, pre-upgrade window with nothing to show that
|
|
498
|
+
// anything happened.
|
|
499
|
+
if (shouldAdviseReopen(platformInfo, wasInstalled)) {
|
|
500
|
+
// Phrased as a conditional because this fires for every Linux upgrade, not
|
|
501
|
+
// only a confirmed-running one. When nothing is running the launch below
|
|
502
|
+
// opens the new version directly, and an unconditional "quit and reopen"
|
|
503
|
+
// would be telling the user to undo what just happened.
|
|
504
|
+
console.log('If Kangentic is already open, quit and reopen it to finish updating.');
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// Only skip the launch when a running instance was positively confirmed.
|
|
508
|
+
if (wasRunning) return;
|
|
509
|
+
|
|
433
510
|
// Launch
|
|
434
511
|
launch(platformInfo, targetDir, dataDir, extraArgs);
|
|
435
512
|
}
|
|
@@ -452,4 +529,6 @@ module.exports = {
|
|
|
452
529
|
getPlatformInfo,
|
|
453
530
|
getArtifactFilename,
|
|
454
531
|
installLinux,
|
|
532
|
+
isAppRunning,
|
|
533
|
+
shouldAdviseReopen,
|
|
455
534
|
};
|