Help us shape the future of Go! Take the 2026 Go Developer Survey

shellhook

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 29, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package shellhook runs a user-configured shell script as a pure side effect (§ 结束 Hook): a notification / logging / marking script fired AFTER some unit of work already finished. A hook NEVER produces variables, changes any status, or fails its caller: a non-zero exit, a timeout, or a spawn error is logged at Warn level and otherwise ignored.

It is intentionally simpler than a Shell workflow node (no control file, no output parsing, no helper functions) — it only injects environment and runs the script. Both the Graph engine (Prompt / End node hooks) and the Job service (interactive round end) share this executor so the two entry points keep identical semantics: same timeout, same env rules, same failure handling.

Index

Constants

View Source
const OutputMaxRunes = 4000

OutputMaxRunes bounds each captured stream (stdout/stderr) before it is handed to Request.Emit. A hook is meant for short side effects (a notification, a log line); a runaway script must not be able to bloat a persisted event or a detail panel. Truncation happens in Run so what the caller emits is already bounded.

View Source
const Timeout = 60 * time.Second

Timeout bounds a single hook so a hung script cannot leak a goroutine for the lifetime of the process. The work has already succeeded by the time its hook runs, so the timeout only affects the side effect, never the caller.

Variables

This section is empty.

Functions

func Run

func Run(parent context.Context, req Request)

Run executes a hook script as a pure side effect. It never returns an error: every failure mode (mkdir, tempfile, spawn, non-zero exit, timeout) is logged and swallowed. parent is used only for log correlation — the script runs under its OWN timeout context detached from parent's cancellation, so a caller-level cancel (hard stop, run timeout, worker cancel) cannot kill a side effect that has already been triggered by finished work.

Types

type Outcome

type Outcome struct {
	ExitCode int
	Stdout   string
	Stderr   string
	Message  string // non-empty on failure: human-readable cause
	Failed   bool
}

Outcome is a hook's execution result, handed to Request.Emit so the caller can surface it (as an event, a log line, …). ExitCode is the script's process exit code on a clean run; for a setup failure (mkdir/tempfile/spawn) or a timeout the script never produced a code, so -1 is used.

type Request

type Request struct {
	// Script is the resolved script body. Blank (or whitespace-only) is a
	// deliberate no-op: nothing runs and nothing is emitted.
	Script string
	// Workdir is the directory the script RUNS in; "" leaves the child with the
	// server process's own working directory. It is deliberately not where the
	// script FILE is written — see scriptDir.
	Workdir string
	// Vars are user-defined variables exported as $name. Keys in the reserved
	// QUARTET_ namespace are ignored.
	Vars map[string]string
	// Disabled names render as the empty string regardless of their stored value
	// (and are exported empty even when absent from Vars).
	Disabled map[string]struct{}
	// Context holds the QUARTET_* runtime context variables, exported LAST so a
	// user variable can never shadow them.
	Context map[string]string

	// LogFields is appended to every log line for correlation, e.g.
	// "runId=r-1 nodeId=n-2" or "jobId=j-1 sessionId=s-3".
	LogFields string

	// Emit, when non-nil, receives the hook's result exactly once on every
	// terminal path (success or any failure), so a configured hook always
	// produces a signal, never silence. Invoked from the calling goroutine of
	// Run — the caller must ensure the closure is safe there.
	Emit func(Outcome)
}

Request carries everything a hook script reads. The caller assembles it on its own goroutine (snapshotting any owned state) so Run can execute off-thread without touching shared state.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL