diff --git a/README.md b/README.md index e13c9d9..9ca2749 100644 --- a/README.md +++ b/README.md @@ -113,6 +113,7 @@ the script — always as a discrete argv element or env var, never interpolated | `triggershell service install [--system]` | Install a systemd unit that runs `triggershell start` (per-user by default, Linux only) | | `triggershell service uninstall [--system]` | Stop, disable, and remove the systemd unit | | `triggershell service status [--system]` | Show the systemd unit's status | +| `triggershell service logs [-n LINES] [--no-follow] [--system]` | Tail the systemd unit's logs (wraps `journalctl`) | ### Running scripts from the CLI diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 693f4e3..07ce22e 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -74,9 +74,9 @@ installs a per-user unit (`~/.config/systemd/user/triggershell.service`, no root targets `/etc/systemd/system/` instead and prints the `sudo` commands to run if not already root. `install` reloads the systemd daemon but does not enable/start the unit itself — that's a separate, explicit `systemctl --user enable --now triggershell`, since it's the point where the service -actually starts listening and running scripts. `triggershell service status`/`uninstall` are thin -wrappers around `systemctl`; log tailing is just `journalctl --user -u triggershell -f` — not -reimplemented. +actually starts listening and running scripts. `triggershell service status`/`uninstall`/`logs` are +thin wrappers around `systemctl`/`journalctl` respectively - no unit-file parsing or log storage of +our own, journald already does that. ## Cross-module-graph state diff --git a/src/cli/commands/service.ts b/src/cli/commands/service.ts index d62b45c..eb42cdf 100644 --- a/src/cli/commands/service.ts +++ b/src/cli/commands/service.ts @@ -126,3 +126,24 @@ export async function serviceStatusCommand( }); process.exitCode = result.exitCode ?? 1; } + +export interface ServiceLogsOptions extends ServiceScopeOptions { + follow?: boolean; + lines?: number; +} + +export async function serviceLogsCommand( + opts: ServiceLogsOptions, +): Promise { + const scope = scopeOf(opts); + const args = scope === "user" ? ["--user"] : []; + args.push("-u", SERVICE_NAME); + if (opts.follow !== false) args.push("-f"); + if (opts.lines !== undefined) args.push("-n", String(opts.lines)); + + const result = await execa("journalctl", args, { + stdio: "inherit", + reject: false, + }); + process.exitCode = result.exitCode ?? 1; +} diff --git a/src/cli/index.ts b/src/cli/index.ts index 961b80f..c538bfc 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -5,6 +5,7 @@ import { runCommand } from "./commands/run"; import { scriptsListCommand, scriptsShowCommand } from "./commands/scripts"; import { serviceInstallCommand, + serviceLogsCommand, serviceStatusCommand, serviceUninstallCommand, } from "./commands/service"; @@ -180,6 +181,25 @@ service ) .action(serviceStatusCommand); +service + .command("logs") + .description("Tail the systemd unit's logs (journalctl).") + .option( + "-n, --lines ", + "Number of recent log lines to show.", + (v) => Number(v), + ) + .option( + "--no-follow", + "Print recent logs and exit instead of tailing continuously.", + ) + .option( + "--system", + "Target the system-wide unit instead of the per-user one.", + false, + ) + .action(serviceLogsCommand); + if (process.argv.length <= 2) { program.outputHelp(); process.exit(1);