Add btop and pacman terminal commands

This commit is contained in:
SirBlob committed 2026-10-31 23:07:12 -04:00
1 parent 201a1e0914
commit dcf27d90b9
3 files changed
+152 -3

No files matched your search

+9 -1
View File
@@ -3,6 +3,7 @@ import { allSitePages } from '#lib/site/pages';
import { blankLine, errorLine, line, span } from '../output';
import { infoCommands } from './info';
import { systemCommands } from './system';
import { pacmanCommand } from './pacman';
import type { Command, CommandContext } from './types';
export type { Command, CommandContext } from './types';
@@ -38,7 +39,14 @@ const socialShortcuts: Command[] = profile.socials.map((social) => ({
run: (_args, context) => context.openUrl(social.url)
}));
export const commands: Command[] = [helpCommand, ...infoCommands, ...systemCommands, ...pageShortcuts, ...socialShortcuts];
export const commands: Command[] = [
helpCommand,
...infoCommands,
...systemCommands,
pacmanCommand,
...pageShortcuts,
...socialShortcuts
];
export function findCommand(name: string): Command | undefined {
const lowerName = name.toLowerCase();
+132
View File
@@ -0,0 +1,132 @@
import { profile } from '#lib/content';
import { blankLine, errorLine, line, span, type OutputBlock } from '../output';
import type { Command, CommandContext } from './types';
const stepDelay = 350;
const progressBarWidth = 24;
const jokePackages: Record<string, OutputBlock[]> = {
girlfriend: [errorLine('target not found: girlfriend')],
money: [errorLine('target not found: money'), line(span('hint: ', 'yellow'), 'try the Ko-fi icon in the top bar')],
sleep: [
line(span(':: ', 'blue', { bold: true }), 'sleep and energy-drinks are in conflict. Remove energy-drinks? [y/N] n'),
errorLine('unresolvable package conflicts detected')
],
windows: [errorLine('windows is not available for Arch Linux. Nice try.')],
job: [errorLine('job requires entry-level-position>=5-years-experience, which cannot be satisfied')],
internship: [errorLine('internship requires internship-experience, which requires internship')]
};
function packageVersion(name: string): string {
const seed = [...name].reduce((sum, character) => sum + character.charCodeAt(0), 0);
return `${(seed % 9) + 1}.${seed % 13}.${seed % 7}-1`;
}
function packageSize(name: string): string {
return `${(name.length * 1.37 + 0.42).toFixed(2)} MiB`;
}
function progressLine(index: number, total: number, action: string, name: string): OutputBlock {
const counter = `(${index}/${total})`;
return line(
span(`${counter} ${action} ${name}`.padEnd(38), 'foreground'),
span(`[${'#'.repeat(progressBarWidth)}]`, 'green'),
span(' 100%', 'muted')
);
}
function printOverTime(context: CommandContext, blocks: OutputBlock[]) {
blocks.forEach((block, index) => setTimeout(() => context.print(block), index * stepDelay));
}
function installPackages(context: CommandContext, packages: string[]) {
const jokeName = packages.find((name) => name in jokePackages);
if (jokeName) {
printOverTime(context, [line(span('resolving dependencies...', 'muted')), ...jokePackages[jokeName]]);
return;
}
const total = packages.length;
printOverTime(context, [
line(span('resolving dependencies...', 'muted')),
line(span('looking for conflicting packages...', 'muted')),
blankLine,
line(span(`Packages (${total}) `, 'foreground', { bold: true }), packages.map((name) => `${name}-${packageVersion(name)}`).join(' ')),
blankLine,
line(span('Total Installed Size: ', 'foreground', { bold: true }), packageSize(packages.join(''))),
blankLine,
line(span(':: ', 'blue', { bold: true }), 'Proceed with installation? [Y/n] y'),
...packages.map((name, index) => progressLine(index + 1, total, 'installing', name)),
line(span(':: ', 'blue', { bold: true }), 'Running post-transaction hooks...'),
progressLine(1, 1, 'Reloading', profile.username),
blankLine,
line(span('(this is a website, nothing was actually installed, but it felt good right?)', 'muted'))
]);
}
function systemUpgrade(context: CommandContext) {
printOverTime(context, [
line(span(':: ', 'blue', { bold: true }), 'Synchronizing package databases...'),
line(' core is up to date'),
line(' extra is up to date'),
line(span(':: ', 'blue', { bold: true }), 'Starting full system upgrade...'),
line(' there is nothing to do'),
line(span('btw, I use Arch.', 'accent'))
]);
}
function listInstalled(context: CommandContext) {
const installed = Object.values(profile.skills)
.flat()
.map((skill) => skill.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, ''));
context.print(...installed.map((name) => line(span(name, 'foreground', { bold: true }), ' ', span(packageVersion(name), 'green'))));
}
function removePackages(context: CommandContext, packages: string[]) {
const name = packages[0];
context.print(line(span('checking dependencies...', 'muted')), errorLine(`failed to prepare transaction: ${name} is required by ${profile.username}`));
}
function printHelp(context: CommandContext) {
context.print(
line('usage: pacman <operation> [...]'),
line('operations:'),
line(' pacman -S <package> install packages'),
line(' pacman -Syu upgrade the system'),
line(' pacman -Q list installed packages'),
line(' pacman -R <package> remove packages')
);
}
function runPacman(args: string[], context: CommandContext) {
const [operation, ...packages] = args;
if (!operation) {
context.print(errorLine('no operation specified (use -h for help)'));
return;
}
if (operation === '-h' || operation === '--help') return printHelp(context);
if (operation.startsWith('-Sy') && packages.length === 0) return systemUpgrade(context);
if (operation.startsWith('-Q')) return listInstalled(context);
if (packages.length === 0) {
context.print(errorLine('no targets specified (use -h for help)'));
return;
}
if (operation.startsWith('-S')) return installPackages(context, packages.map((name) => name.toLowerCase()));
if (operation.startsWith('-R')) return removePackages(context, packages);
context.print(errorLine(`invalid option '${operation}'`));
}
export const pacmanCommand: Command = {
name: 'pacman',
hidden: true,
description: 'Arch Linux package manager',
run: runPacman
};
export function runAsRoot(args: string[], context: CommandContext): boolean {
if (args[0] !== 'pacman') return false;
context.print(line(span(`[sudo] password for ${profile.username}: `, 'muted'), '********'));
runPacman(args.slice(1), context);
return true;
}
+11 -2
View File
@@ -2,6 +2,7 @@ import { profile } from '#lib/content';
import { themes } from '#lib/theme/themes';
import { allSitePages, findSitePage, sitePages } from '#lib/site/pages';
import { blankLine, errorLine, line, span } from '../output';
import { runAsRoot } from './pacman';
import type { Command } from './types';
function cowsay(message: string): string[] {
@@ -122,8 +123,16 @@ export const systemCommands: Command[] = [
name: 'sudo',
hidden: true,
description: 'Elevated privileges',
run: (_args, context) =>
context.print(errorLine(`${profile.username} is not in the sudoers file. This incident will be reported.`))
run: (args, context) => {
if (runAsRoot(args, context)) return;
context.print(errorLine(`${profile.username} is not in the sudoers file. This incident will be reported.`));
}
},
{
name: 'btop',
aliases: ['htop', 'top'],
description: 'Open the system monitor',
run: (_args, context) => context.openApp('btop')
},
{
name: 'pwd',