3.3 KiB
name, description
| name | description |
|---|---|
| omp-extension-event-probe | Prove which lifecycle events the omp harness actually dispatches to extensions, with a throwaway timestamping probe plugin, instead of inferring delivery from side effects. |
Prove harness→extension event delivery with a probe plugin
Use when an extension handler seems never to fire, or when you must know when an event arrives relative to another (mid-run vs settle). Never infer dispatch from the feature's side effects: async work in the handler (LLM rewrites, synthesis, network) lags seconds and destroys the timing signal.
Shape (no build step needed)
/tmp/probe/package.json — the installer validates the declared entry on disk:
{
"name": "event-probe",
"version": "0.0.0",
"type": "module",
"exports": "./index.js",
"pi": { "extensions": ["./index.js"] }
}
/tmp/probe/index.js — append arrival times, not counts:
import { appendFileSync } from "node:fs";
const LOG = "/tmp/probe.log";
const stamp = (line) => appendFileSync(LOG, `${new Date().toISOString().slice(11, 23)} ${line}\n`);
export default function probe(pi) {
pi.on("agent_start", () => stamp("agent_start"));
pi.on("turn_end", (e) => stamp(`turn_end turn=${e.turnIndex} toolResults=${(e.toolResults ?? []).length}`));
pi.on("agent_end", (e) => stamp(`agent_end messages=${(e.messages ?? []).length} willContinue=${String(e.willContinue)}`));
}
Run
cd ~/.omp/plugins && omp plugin link /tmp/probe(link, never editnode_modules), thenomp plugin doctor→ expect a✔ plugin:event-probeline.- Launch a fresh TUI session in a pty (
omp --cwd /tmp/probe-run,pty: true). Extensions load at startup only — an already-running session never sees the probe. - PTY gotcha: input sent before the splash clears is swallowed. Read the screen
first, then submit text and finish with a separate write containing a bare
\r(LF alone left the text sitting in the composer). - Drive a task with ≥2 tool rounds so turns and settles separate in time (sequential reads work and need no approval; ask for steps "strictly one after the other" or the model parallelises them into one turn).
- Wait for a terminal line with an async bounded loop (
grep -q agent_end,sleep 1inside one backgrounded bash call) — never poll across turns.
Read
turn_end timestamps strictly earlier than agent_end ⇒ per-turn delivery
works. willContinue=true on agent_end marks a non-terminal settle (harness
maps isTerminal === false to it) — handlers that return on it never speak.
Teardown (mandatory)
omp plugin uninstall event-probe; omp plugin doctor; delete /tmp/probe*.
The link writes into ~/.omp/plugins/package.json (tracked, live tier) —
uninstall restores it; confirm with grep for the probe name returning nothing.
Ground truth read for free
Event union + payloads: ~/.omp/plugins/node_modules/@oh-my-pi/pi-coding-agent/dist/types/extensibility/shared-events.d.ts;
the session→extension mapping lives in src/extensibility/extensions/lifecycle-mirror.ts
(extensionEventFromSessionEvent). Extension-level turn_end carries
turnIndex/message/toolResults but no willContinue — that field exists
only on agent_end, so "is this the last turn" cannot be decided from turn_end.