theamify-cli 2.2.1 → 2.2.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/README.md +25 -3
- package/package.json +1 -1
- package/src/cli.js +7 -0
- package/src/commands/manage.js +33 -26
- package/src/core/engine.js +18 -0
- package/src/lib/self.js +8 -11
- package/vendor/theamify +1 -1
package/README.md
CHANGED
|
@@ -28,25 +28,47 @@ theamify doctor # diagnose install, GRUB, tools & dependencies
|
|
|
28
28
|
theamify upgrade # check for & install the latest npm version
|
|
29
29
|
theamify repair # fix a broken install (re-provision the engine)
|
|
30
30
|
theamify uninstall # remove theamify entirely (incl. npm package)
|
|
31
|
+
theamify version # print the version
|
|
32
|
+
theamify help # show all commands
|
|
31
33
|
```
|
|
32
34
|
|
|
35
|
+
> **Command aliases** — `ls` (list), `show` (info), `get`/`fetch`/`download`, `use`/`apply`/`set`, `rm`/`uncache` (remove), `del`/`delete`, `purge-cache` (clean), `browse`/`wizard`/`install` (wizard). \
|
|
36
|
+
> **Version flags** — `-v`, `-V`, `--version` · **Help flags** — `-h`, `--help`
|
|
37
|
+
|
|
33
38
|
> 💡 Upgrading is the same command — `npm install -g theamify-cli@latest`, and your downloaded themes & registry edits are preserved.
|
|
34
39
|
> 🧰 Zero-install run (no permanent install): `npx -y theamify-cli`
|
|
35
40
|
|
|
36
41
|
---
|
|
37
42
|
|
|
38
|
-
## ✨ What's New (
|
|
43
|
+
## ✨ What's New (v2.2.3 — complete uninstall)
|
|
44
|
+
|
|
45
|
+
| Feature | Details |
|
|
46
|
+
|---|---|
|
|
47
|
+
| 🗑️ **Uninstall removes EVERYTHING** | `theamify uninstall` now removes **every** runtime tree (`~/.local/share/theamify` AND `/usr/local/share/theamify`), all downloaded themes, the applied GRUB theme, the `theamify-cli` npm package **and** `~/.local/bin/theamify` (legacy shadow, file or symlink) plus every PATH marker from `~/.bashrc`/`~/.zshrc` |
|
|
48
|
+
| ✅ **`command not found` guaranteed** | After uninstall, `theamify` shadows nothing on PATH — typing it returns `bash: theamify: command not found`, exactly like any tool you never installed |
|
|
49
|
+
| 🔒 **One confirmation** | A single confirmation covers the whole removal (no more piecemeal "keep the npm package?" prompts) |
|
|
50
|
+
| 🩹 **Regression-tested** | `removeUserBin` (symlink + real-file shadow), runtime-tree removal and rc cleanup are all covered by tests |
|
|
51
|
+
|
|
52
|
+
## ✨ What's New (v2.2.2 — uninstall crash hotfix)
|
|
53
|
+
|
|
54
|
+
| Feature | Details |
|
|
55
|
+
|---|---|
|
|
56
|
+
| 🩹 **`ReferenceError: path is not defined` fixed** | The v2.2.1 uninstall crashed while stripping leftover PATH markers from `~/.bashrc`/`~/.zshrc` — `cleanRcMarkers` used `path`/`os`/`fs` without importing them. Now fixed with proper `node:` imports and guarded by regression tests. |
|
|
57
|
+
| 🔄 **Engine lockstep to v2.2.2** | Bundled engine `VERSION` bumped to match the npm package — no more "update available" nag after a fresh install. |
|
|
58
|
+
|
|
59
|
+
## ✨ What's New (v2.2.1 — release)
|
|
39
60
|
|
|
40
61
|
| Feature | Details |
|
|
41
62
|
|---|---|
|
|
42
63
|
| 🧙 **Interactive wizard** | One command: detect companion tools → pick theme → **preview** → apply |
|
|
43
64
|
| 🧩 **Auto-detected companion tools** | **chafa** (thumbnails) + **grub-customizer** (GUI) are detected first; installed if missing, or **option to update** if present — then it continues on its own |
|
|
44
|
-
| 🖼️ **
|
|
65
|
+
| 🖼️ **Thumbnail by default** | Selecting a cached theme renders its terminal thumbnail **automatically** (no separate “preview” item) |
|
|
45
66
|
| 📦 **npm global install** | Engine provisions itself user-writable (no sudo for downloads) |
|
|
46
67
|
| 🩺 **`theamify doctor`** | Diagnose install, GRUB, active theme, registry, tools & dependencies |
|
|
47
|
-
| 🗑 **
|
|
68
|
+
| 🗑 **Complete uninstall** | Deletes **ALL downloaded themes**, resets GRUB to default, removes the `theamify-cli` npm package **and** strips leftover PATH markers from `~/.bashrc`/`~/.zshrc` — after which `theamify` gives a normal `command not found` |
|
|
48
69
|
| ⌨️ **Ctrl+C / Ctrl+Z safe** | Signal safety net; interactive `sudo` is never frozen |
|
|
49
70
|
| 🔄 **Self-manage (v2.2+)** | `upgrade`, `repair`, auto-update check on every wizard run |
|
|
71
|
+
| 🧹 **Install-flow download-all** | Wizard offers to download every theme up front so each one is instantly previewable/applicable |
|
|
50
72
|
|
|
51
73
|
---
|
|
52
74
|
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -73,6 +73,13 @@ const main = defineCommand({
|
|
|
73
73
|
async run({ args }) {
|
|
74
74
|
const [cmd, ...rest] = args._;
|
|
75
75
|
|
|
76
|
+
// citty parses `-V` as a boolean flag into args.V (never reached via args._);
|
|
77
|
+
// treat it as a version request like the other aliases.
|
|
78
|
+
if (args.V) {
|
|
79
|
+
console.log(`theamify v${pkg.version}`);
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
|
|
76
83
|
// No arguments → the interactive theme browser wizard.
|
|
77
84
|
if (!cmd) return runThemeBrowser();
|
|
78
85
|
|
package/src/commands/manage.js
CHANGED
|
@@ -5,8 +5,10 @@ import pc from 'picocolors';
|
|
|
5
5
|
import { execa, execaSync } from 'execa';
|
|
6
6
|
import {
|
|
7
7
|
findInstalledRuntime,
|
|
8
|
+
SYSTEM_DIR,
|
|
8
9
|
USER_DIR,
|
|
9
|
-
|
|
10
|
+
BIN_NAME,
|
|
11
|
+
removeUserBin,
|
|
10
12
|
repairRuntime,
|
|
11
13
|
resolveEngine,
|
|
12
14
|
} from '../core/engine.js';
|
|
@@ -160,46 +162,51 @@ export async function resetGrubTheme({ grubFile = '/etc/default/grub', asRoot =
|
|
|
160
162
|
return res.exitCode === 0;
|
|
161
163
|
}
|
|
162
164
|
|
|
163
|
-
/** `theamify uninstall` —
|
|
165
|
+
/** `theamify uninstall` — remove EVERY trace of theamify so the command vanishes. */
|
|
164
166
|
export async function runUninstallWizard() {
|
|
165
167
|
p.intro(pc.bgRed(pc.black(' theamify Uninstaller ')));
|
|
168
|
+
|
|
166
169
|
const found = findInstalledRuntime();
|
|
167
|
-
if (
|
|
168
|
-
|
|
169
|
-
let removed = false;
|
|
170
|
-
if (found) {
|
|
171
|
-
const confirm = await p.confirm({
|
|
172
|
-
message: `Remove theamify files at ${found.dir}/? (this deletes ALL downloaded themes)`,
|
|
173
|
-
initialValue: true,
|
|
174
|
-
});
|
|
175
|
-
if (!p.isCancel(confirm) && confirm) {
|
|
176
|
-
removed = await removeRuntimeDir(found.dir);
|
|
177
|
-
if (removed) removeShadowBin();
|
|
178
|
-
else p.log.warn(`Could not remove ${found.dir}.`);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
170
|
+
if (found) p.note(found.dir, 'Installed runtime detected');
|
|
181
171
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
message: 'Remove your applied GRUB theme and reset to the default boot menu?',
|
|
172
|
+
const confirm = await p.confirm({
|
|
173
|
+
message: 'Uninstall theamify completely? This removes the runtime, ALL downloaded themes, the applied GRUB theme, the theamify-cli npm package, ~/.local/bin/theamify and every PATH marker.',
|
|
185
174
|
initialValue: true,
|
|
186
175
|
});
|
|
187
|
-
if (p.isCancel(
|
|
188
|
-
|
|
176
|
+
if (p.isCancel(confirm)) { p.cancel('Aborted.'); process.exit(0); }
|
|
177
|
+
if (!confirm) { p.outro('Nothing was removed.'); return; }
|
|
178
|
+
|
|
179
|
+
// 1. Remove EVERY runtime tree — user AND system. (removeRuntimeDir uses
|
|
180
|
+
// sudo automatically for root-owned dirs like /usr/local/share/theamify.)
|
|
181
|
+
let removedCount = 0;
|
|
182
|
+
for (const dir of [SYSTEM_DIR, USER_DIR]) {
|
|
183
|
+
if (fs.existsSync(path.join(dir, BIN_NAME))) {
|
|
184
|
+
if (await removeRuntimeDir(dir)) removedCount++;
|
|
185
|
+
else p.log.warn(`Could not remove ${dir}.`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// 2. Remove any legacy `~/.local/bin/theamify` shadow — symlink OR real file.
|
|
190
|
+
// This is what KEEPS the command alive when `~/.local/bin` is on PATH.
|
|
191
|
+
if (removeUserBin()) p.log.success('Removed ~/.local/bin/theamify.');
|
|
192
|
+
|
|
193
|
+
// 3. Reset the boot menu back to the default (remove the applied GRUB theme).
|
|
194
|
+
const grubReset = await resetGrubTheme();
|
|
189
195
|
|
|
190
|
-
// Remove the npm package so the `theamify` command
|
|
196
|
+
// 4. Remove the npm package so the `theamify` command truly disappears.
|
|
191
197
|
const npmRemoved = await selfUninstall();
|
|
192
198
|
|
|
193
|
-
// Remove leftover PATH markers from ~/.bashrc / ~/.zshrc so zero traces remain.
|
|
199
|
+
// 5. Remove leftover PATH markers from ~/.bashrc / ~/.zshrc so zero traces remain.
|
|
194
200
|
await cleanRcMarkers();
|
|
195
201
|
|
|
196
202
|
// Companion tools (chafa, grub-customizer) are intentionally LEFT in place —
|
|
197
|
-
//
|
|
203
|
+
// they are not theamify; uninstall only removes theamify itself.
|
|
198
204
|
const themeNote = grubReset
|
|
199
205
|
? 'Boot menu reset to the default theme.'
|
|
200
|
-
:
|
|
206
|
+
: 'GRUB reset could not be completed — remove GRUB_THEME= from /etc/default/grub and rebuild.';
|
|
201
207
|
|
|
202
208
|
p.outro(pc.green(
|
|
203
|
-
`Uninstalled.${
|
|
209
|
+
`Uninstalled.${removedCount ? ` ${removedCount} runtime tree(s) + all downloaded themes removed.` : ''} ${themeNote} ${npmRemoved ? 'theamify-cli npm package removed — the theamify command is gone.' : 'theamify-cli npm package could not be removed automatically — run: npm uninstall -g theamify-cli'} Companion tools (chafa, grub-customizer) were kept for your use.`,
|
|
204
210
|
));
|
|
211
|
+
p.log.message(pc.dim('After uninstall, `theamify` reports: bash: theamify: command not found'));
|
|
205
212
|
}
|
package/src/core/engine.js
CHANGED
|
@@ -44,6 +44,24 @@ export function removeShadowBin() {
|
|
|
44
44
|
} catch { /* nothing to remove */ }
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Remove anything at `~/.local/bin/theamify` — a legacy shadow executable that
|
|
49
|
+
* keeps the `theamify` command alive and SHADOWS the npm CLI after uninstall
|
|
50
|
+
* (because `~/.local/bin` precedes the npm global bin on PATH). Removes BOTH a
|
|
51
|
+
* symlink and a plain-file engine copy left behind by old installs.
|
|
52
|
+
* @param {string} [binPath] override the path (used by tests)
|
|
53
|
+
* @returns {boolean} true when something was removed
|
|
54
|
+
*/
|
|
55
|
+
export function removeUserBin(binPath = USER_BIN_LINK) {
|
|
56
|
+
try {
|
|
57
|
+
if (fs.existsSync(binPath) || fs.lstatSync(binPath)) {
|
|
58
|
+
fs.rmSync(binPath, { force: true });
|
|
59
|
+
return !fs.existsSync(binPath);
|
|
60
|
+
}
|
|
61
|
+
} catch { /* nothing to remove */ }
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
47
65
|
/** Copy the vendored engine script + shared libs into a runtime dir. */
|
|
48
66
|
function copyEngineTo(dir) {
|
|
49
67
|
fs.mkdirSync(path.join(dir, 'lib'), { recursive: true });
|
package/src/lib/self.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { execa } from 'execa';
|
|
2
2
|
import pc from 'picocolors';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
3
6
|
import { createRequire } from 'node:module';
|
|
4
7
|
|
|
5
8
|
const require = createRequire(import.meta.url);
|
|
@@ -34,13 +37,13 @@ export async function getLatestVersion() {
|
|
|
34
37
|
* Remove any leftover `# theamify CLI PATH` + follow-up `export PATH=` line from
|
|
35
38
|
* ~/.bashrc and ~/.zshrc (added by old installs). Called by uninstall so no
|
|
36
39
|
* traces of the tool remain in shell startup files.
|
|
40
|
+
* @param {string} [homeDir] override the home directory (used by tests)
|
|
37
41
|
*/
|
|
38
|
-
export async function cleanRcMarkers() {
|
|
39
|
-
const rcs = ['.bashrc', '.zshrc'].map((f) => path.join(
|
|
42
|
+
export async function cleanRcMarkers(homeDir = os.homedir()) {
|
|
43
|
+
const rcs = ['.bashrc', '.zshrc'].map((f) => path.join(homeDir, f));
|
|
40
44
|
const marker = '# theamify CLI PATH';
|
|
41
45
|
for (const rc of rcs) {
|
|
42
46
|
try {
|
|
43
|
-
const fs = require('node:fs');
|
|
44
47
|
if (!fs.existsSync(rc)) continue;
|
|
45
48
|
const lines = fs.readFileSync(rc, 'utf8').split('\n');
|
|
46
49
|
const out = [];
|
|
@@ -98,18 +101,12 @@ export async function promptSelfUpdate() {
|
|
|
98
101
|
|
|
99
102
|
/**
|
|
100
103
|
* Fully remove the npm package so the `theamify` command disappears from PATH.
|
|
104
|
+
* Uninstall is non-interactive about this — removing the npm package is a core
|
|
105
|
+
* part of "remove everything", not an optional extra.
|
|
101
106
|
* @returns {Promise<boolean>} true when uninstalled
|
|
102
107
|
*/
|
|
103
108
|
export async function selfUninstall() {
|
|
104
109
|
const p = await import('@clack/prompts');
|
|
105
|
-
const want = await p.confirm({
|
|
106
|
-
message: `Also remove the ${NPM_NAME} npm package, so the ${pc.cyan(BIN_NAME)} command is gone from your system?`,
|
|
107
|
-
initialValue: true,
|
|
108
|
-
});
|
|
109
|
-
if (p.isCancel(want) || !want) {
|
|
110
|
-
p.log.message(pc.dim(`Keeping the npm package — the ${BIN_NAME} command will remain.`));
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
110
|
console.log();
|
|
114
111
|
const res = await execa('npm', ['uninstall', '-g', NPM_NAME], { stdio: 'inherit', reject: false });
|
|
115
112
|
if (res.exitCode === 0) {
|
package/vendor/theamify
CHANGED
|
@@ -10,7 +10,7 @@ set -euo pipefail
|
|
|
10
10
|
# -----------------------------------------------------------------------------
|
|
11
11
|
# VERSION & TOOL NAME
|
|
12
12
|
# -----------------------------------------------------------------------------
|
|
13
|
-
readonly VERSION="2.2.
|
|
13
|
+
readonly VERSION="2.2.3"
|
|
14
14
|
readonly TOOL="theamify"
|
|
15
15
|
|
|
16
16
|
# -----------------------------------------------------------------------------
|