@werk/befehlswerk (0.1.1)
Installation
@werk:registry=https://gitlab.amandy.love/api/packages/werk/npm/npm install @werk/befehlswerk@0.1.1"@werk/befehlswerk": "0.1.1"About this package
Befehlswerk
Befehlswerk ist eine lokale und remote-fähige Command Execution Library mit einer optionalen CLI.
Das Projekt stellt eine einheitliche, sichere und beobachtbare Schnittstelle bereit, um Befehle kontrolliert auszuführen — lokal oder über SSH. Es bietet Environment-Isolation, Stream-Verarbeitung, Prompt-Erkennung, Status-Zusammenfassungen, Retries mit Backoff, Polling-Logik, Rezepte (sequenziell und parallel) sowie ein strukturiertes Ergebnisobjekt.
Jede Ausführung hat ein Target, eine Policy, Streams, einen Context und ein Result.
Features
- Sicherer Standard (argv): Ausführung ohne Shell-Interpolation verhindert Injections.
- Expliziter Shell-Modus: Shell-Skripte können bewusst über eine definierte Shell (
sh,bash, etc.) ausgeführt werden. - SSH Runner: Führt Befehle remote über SSH aus. Umgebungsvariablen und Arbeitsverzeichnisse werden sicher übertragen.
- Stream-Verarbeitung: Live-Verarbeitung von
stdout/stderr, Zeilenfilterung und ereignisbasierte Reaktionen. - Secret Redaction: Filtert konfigurierte sensible Daten (Passwörter, Token) aus allen Ausgabeströmen, Events und Ergebnissen heraus, bevor diese verarbeitet oder geloggt werden.
- Timeouts: Konfigurierbare Timeouts für die maximale Laufzeit sowie Inaktivitätsgrenzen (Idle Timeout).
- Expect & Wenn-Bedingungen: Reagiert auf Ausgabemuster (z. B. Passwort-Prompts) und erlaubt Interaktivität oder das Schreiben in
stdin. - Polling & Retries: Wiederholt Befehle periodisch bis zum Erfolg oder unternimmt mehrere Versuche bei Fehlschlägen (mit linearem/exponentiellem Backoff).
- Rezepte: Verkettet Befehle sequenziell oder parallel in Gruppen inklusive Fehlerbehandlung.
- Test-Utilities: Enthält eine
FakeRunner-Klasse zur isolierten Simulation und Prüfung von Befehlsausführungen in Unit Tests.
Projekt-Struktur
Das Projekt ist als TypeScript Monorepo mit Bun-Workspaces organisiert:
packages/core: Plattform- und runtime-unabhängige Typen, Schnittstellen,CommandBuilderundRecipeBuilder.packages/node: Serverseitige Prozess-Implementierung (child_process.spawn,sshAnbindung,StreamController).packages/testing: Testwerkzeuge und Mocking-Helfer (FakeRunner).packages/cli: Kommandozeilen-Interface.
Installation & Build
Voraussetzungen
- Bun
Build
Installieren Sie die Abhängigkeiten und bauen Sie das gesamte Monorepo:
bun install
bun run build
Tests ausführen
Führen Sie die Test-Suite aus (verwendet Bun):
bun run test
Verwendung (API)
1. Lokaler Befehl (argv)
import { cmd } from "@befehlswerk/node";
const result = await cmd("git", ["status", "--short"])
.local()
.cwd("~/repos/my-project")
.stdout("capture")
.exec();
if (result.ok && result.stdout.trim()) {
console.log("Repository hat ungespeicherte Änderungen.");
}
2. Remote Befehl über SSH mit Umgebungsvariablen
import { cmd } from "@befehlswerk/node";
const result = await cmd("systemctl", ["--user", "status", "postwerk"])
.ssh({ host: "meow", user: "amelie" })
.env({
set: { LC_ALL: "C" }
})
.summary({
mode: "smart",
keepPatterns: [/Active:/, /Loaded:/]
})
.exec();
3. Reagieren auf Prompts (Expect / Stdin)
import { cmd } from "@befehlswerk/node";
await cmd("sudo", ["systemctl", "restart", "nginx"])
.local()
.stdin("pipe")
.when(/password/i, async (match, ctx) => {
ctx.status("Passwort angefordert; übergebe Terminal...");
await ctx.interactive();
})
.exec();
4. Polling & Checks
import { cmd } from "@befehlswerk/node";
await cmd("curl", ["-fsS", "http://127.0.0.1:3000/health"])
.local()
.check({
every: "2s",
timeout: "30s",
until: (res) => res.ok && res.stdout.includes("ok")
})
.must(); // Wirft eine Exception, falls der Check fehlschlägt
5. Rezepte (Parallel und Sequenziell)
import { recipe, cmd } from "@befehlswerk/node";
const smokeTest = recipe("smoke-test")
.step(cmd("bun", ["run", "lint"]).local())
.parallel([
cmd("bun", ["run", "test:unit"]).local(),
cmd("bun", ["run", "test:integration"]).local()
])
.step(cmd("bun", ["run", "build"]).local());
const result = await smokeTest.exec();
if (result.ok) {
console.log("Smoke Test erfolgreich.");
}
6. Mocking in Unit Tests
import { CommandBuilder } from "@befehlswerk/node";
import { FakeRunner } from "@befehlswerk/testing";
const fake = new FakeRunner();
// Stubben des Ergebnisses
fake.queueResult({
ok: true,
stdout: "mocked output"
});
const res = await new CommandBuilder(
{ kind: "argv", command: "git", args: ["status"] },
fake
).exec();
console.log(res.stdout); // "mocked output"
console.log(fake.history.length); // 1
CLI Verwendung
Die CLI bietet direkten Zugriff auf alle Ausführungsmodi.
Befehl ausführen
bunx befehlswerk run -- git status -s
Remote über SSH ausführen
bunx befehlswerk ssh meow -- uname -a
Shell-Skripte ausführen
bunx befehlswerk shell -- 'git status && bun run test'
Befehle periodisch prüfen (Check)
bunx befehlswerk check --every 2s --timeout 15s -- curl -fsS http://localhost:3000/health
JSON Ausgabe für Automatisierung
bunx befehlswerk run --json -- uname -a
Dependencies
Dependencies
| ID | Version |
|---|---|
| @befehlswerk/core | ^0.1.0 |
| @befehlswerk/node | ^0.1.0 |
Development Dependencies
| ID | Version |
|---|---|
| @types/node | ^20.12.7 |
| typescript | ^5.4.5 |