werk

@werk/befehlswerk (0.1.1)

Published 2026-07-26 20:22:04 +02:00 by amelie

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, CommandBuilder und RecipeBuilder.
  • packages/node: Serverseitige Prozess-Implementierung (child_process.spawn, ssh Anbindung, 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
Details
npm
2026-07-26 20:22:04 +02:00
4
latest
24 KiB
Assets (1)
Versions (2) View all
0.1.1 2026-07-26
0.1.0 2026-07-26