Documentation
¶
Overview ¶
Package execsegment splits a Codex command script into its top-level segments and instruments them for per-segment tracking. The helper that runs inside the command shell and the router that displays it share this split, so their segment indices always agree.
Index ¶
- Constants
- func Hook(tracker string) string
- func OpenPreparedReport(work string, timeout time.Duration) (report, reply *os.File, directory string, err error)
- func OpenReport(channel, directory string, timeout time.Duration) (report, reply *os.File, work string, err error)
- func ReportDirectory(directory, id string) (string, bool)
- func RequestReport(channel, id string) error
- func Rewrite(script string, segments []Segment) string
- func ShOriginal(script string) string
- func ShScript(tracker, script string) string
- func ShTracker(helper, channel, directory string) string
- func Tracker(helper, channel, directory string) string
- type Message
- type Reply
- type Segment
- type Timing
Constants ¶
const ( Hello = "hello" Begin = "b" Output = "o" End = "e" Done = "d" // Lossy reports that the helper stopped reporting output to stay within // its bound; statuses continue. Lossy = "lossy" )
Message types.
const Guard = "MEKUGI_EXEC_TRACK"
Guard marks a shell that already decided whether to track its command, so nested command shells started by that command are never tracked.
const Protocol = 3
Protocol is the helper-to-router message version.
const ShTrackerEnvironment = "MEKUGI_SH_TRACKER"
Variables ¶
This section is empty.
Functions ¶
func Hook ¶
Hook is Bash startup source, read from BASH_ENV, that tracks the command script Codex passed with -c. It decides before any segment runs: only when the helper plans the script and the router matches it to a live Codex command does the shell run the rewrite in place of the script and exit. Otherwise it returns and Bash runs the original script itself, so the command never runs twice.
Codex's own snapshot scripts, including the wrapper that re-executes the command shell, pass through without setting the guard: the snapshot would otherwise record it for every later command.
func OpenPreparedReport ¶ added in v0.2.0
func OpenPreparedReport(work string, timeout time.Duration) (report, reply *os.File, directory string, err error)
OpenPreparedReport opens router-created resources requested earlier by dash.
func OpenReport ¶ added in v0.2.0
func OpenReport(channel, directory string, timeout time.Duration) (report, reply *os.File, work string, err error)
OpenReport sends an atomic request through an existing FIFO, followed by router-created FIFOs. The sandboxed helper only opens files; it creates no filesystem objects. Report has one writer, so output messages need no shared-pipe framing.
func ReportDirectory ¶ added in v0.2.0
ReportDirectory validates a request ID before resolving its private files.
func RequestReport ¶ added in v0.2.0
RequestReport asks the router to create one invocation's existing resources.
func Rewrite ¶
Rewrite wraps each segment in hooks that report its start and exit status. Each wrapper runs in the current shell and returns the segment's status, so && and || chains, $?, and shell state behave as in the original. A hook passes a nonzero status on as the operand of an && list, where errexit ignores it: under set -e, only the segment's own command can end the shell.
func ShOriginal ¶ added in v0.2.0
ShOriginal recognizes only an exact envelope produced by ShScript. Removing its inline boundaries keeps authored newlines and shell error line numbers.
func ShScript ¶ added in v0.2.0
ShScript adds a portable startup call and the existing segment rewrite. Bash's startup hook recognizes this envelope before its DEBUG trap replaces the script. Other shells retain their own execution and no-op boundaries.
func ShTracker ¶ added in v0.2.0
ShTracker runs in dash itself. Only transport differs from Bash: dash has no coprocess, so the existing router also supplies control and ack FIFOs.
func Tracker ¶
Tracker is the Bash source that runs a tracked script. The helper runs as a coprocess: the shell sends it segment boundaries and waits for each acknowledgment, so the helper has relayed a segment's output before the next segment starts. Output reaches Codex unchanged through the helper, which alone keeps the original descriptors. A terminal cannot be relayed without changing what programs detect, so terminal commands report status only.
The rewrite does not run from the startup file, whose errors differ from the script's: a fatal expansion error there would abandon the startup file and run the original script as well. A one-time DEBUG trap instead runs it in place of the script's first command, so error messages, line numbers, and fatal errors behave as in the original. Split accepts only scripts whose first command fires that trap before it has any effect.
Types ¶
type Message ¶
type Message struct {
Timing Timing `json:"timing,omitzero"`
Type string `json:"t"`
Version int `json:"v,omitzero"`
Thread string `json:"thread,omitempty"`
Script string `json:"script,omitempty"`
Segments []string `json:"segments,omitempty"`
Terminal bool `json:"tty,omitzero"`
Index int `json:"i,omitzero"`
Data string `json:"d,omitempty"`
Code *int `json:"c,omitempty"`
}
Message is one line of the helper's report. Hello opens a report and the router answers with Reply; the rest follow in the order the shell and its output produced them.
type Segment ¶
type Segment struct {
Start, End int // Script byte span, excluding terminators and heredoc bodies.
Source string // Display source, including any heredoc body.
}
Segment is one top-level command of a list: a statement, or an operand of a top-level && or || chain. Pipelines and compound commands stay whole.
func Split ¶
Split returns the script's segments when every segment can be tracked without changing the script's behavior. Single commands are observed in place, without a rewrite. It reports false for lists whose first command runs before the shell's DEBUG trap can replace the script, and for scripts whose semantics depend on the shell state the instrumentation touches: job control, traps, top-level returns, process replacement, command tracing, and variables naming the current command.
type Timing ¶
type Timing struct {
Started time.Time `json:"started,omitzero"`
Ended time.Time `json:"ended,omitzero"`
ElapsedNS int64 `json:"elapsed_ns,omitzero"`
}
Timing records helper-observed command boundaries. ElapsedNS is measured with the helper's monotonic clock, independently of wall-clock adjustments.