Package Exports
- @agentprobe/core
- @agentprobe/core/core
- @agentprobe/core/providers/cursor
Readme
@agentprobe/core
@agentprobe/core is a TypeScript library for observing agent/session activity from transcript-like sources.
It is designed in layers:
core: generic runtime + lifecycle diffing (tool-agnostic)providers/cursor: Cursor transcript discovery + parsing adapter
The core observer API is provider-injected and tool-agnostic. Cursor is currently the built-in provider, with support planned for Claude Code, Codex, OpenCode, and custom systems.
Install
npm install @agentprobe/coreQuick Start (Provider-Agnostic)
import { createObserver } from "@agentprobe/core";
const observer = createObserver({
workspacePaths: ["/Users/me/my-project"],
});
observer.subscribeToSnapshots((event) => {
console.log(event.snapshot.at, event.snapshot.agents.length);
});
observer.subscribeToAgentChanges((event) => {
console.log(event.change.kind, event.agent.id);
});
await observer.start();
// later — stop() clears all subscriptions and resets state
await observer.stop();createObserver defaults to the built-in Cursor provider. You can pass a custom provider, debounceMs, or checkIdleDelayMs as needed.
How Runtime Works
The watch runtime (used by createObserver) is built around a state machine and an internal typed event bus that processes events sequentially.
stateDiagram-v2
[*] --> stopped
stopped --> starting : start()
starting --> started : connect + subscribe
starting --> stopped : abort / error
started --> stopping : stop()
stopping --> stopped : disconnect
state started {
[*] --> waiting
waiting --> processing : file‑changed / check‑idle / refresh‑requested
processing --> waiting : snapshot + lifecycle emitted
processing --> waiting : error emitted
state waiting {
[*] --> watchingFS
watchingFS --> idleTimer : check‑idle scheduled
idleTimer --> watchingFS : timer fires
}
}Event bus
Inside the started state, all work flows through a sequential event bus with three event types:
file-changed— dispatched after debounced fs.watch events; reads the snapshot and schedules a check-idle timercheck-idle— fires on a timer (default 2s); re-reads the snapshot to catch time-based status transitions (e.g.running→idle→completed) and self-reschedules while agents existrefresh-requested— dispatched byrefreshNow(); reads the snapshot and resolves waiting callers
Events are processed one at a time (no overlapping reads). Subscribers only receive events when agent statuses actually change (joined, statusChanged, left). Heartbeat-only cycles are silent — the internal polling is invisible to consumers.
Idle checking
Agent statuses depend on time elapsed since last activity. Without periodic re-evaluation, time-based transitions are missed when transcript files stop changing. The check-idle mechanism solves this:
- After every
file-changedorrefresh-requested, a check-idle timer is scheduled - When it fires, the runtime re-reads the snapshot with the current timestamp
- If agents still exist, the timer self-reschedules
- Configurable via
checkIdleDelayMs(default2000, set tofalseto disable)
Lifecycle model
- Internal states:
stopped → starting → started → stopping start()connects to the source, installs optional watch subscriptions, emitsstarted, and dispatches an initialfile-changedeventstop()clears timers/subscriptions/bus queue, rejects in-flight waiters, disconnects, and emitsstopped
Concurrency and race safety
- A monotonic lifecycle token guards all event dispatch
- Every start/stop cycle advances the token
- Events dispatched with a stale token are silently dropped
- The event bus processes handlers sequentially — no overlapping async work
Error and stop semantics
- Snapshot/read failures emit
errorand reject cycle waiters - Calling
refreshNow()while not running rejects withNOT_RUNNING - Stopping during an active refresh rejects pending waiters with
STOPPED_BEFORE_REFRESH_COMPLETED
Watch subscriptions
When a provider exposes subscribeToChanges, runtime subscriptions:
- resolve configured/default watch paths
- normalize paths (trim + drop empty + dedupe)
- debounce bursty events before dispatching
file-changedto the bus - resubscribe with exponential backoff on subscription failures
Public Entry Points
@agentprobe/core— full package (core + Cursor provider,createObserverdefaults to Cursor)@agentprobe/core/core— core runtime, lifecycle, model, and provider types only@agentprobe/core/providers/cursor— Cursor transcript provider only
Development
npm install
npm run check
npm run buildScripts
npm run format- format code with Biomenpm run lint- lint code with Biomenpm run typecheck- run TypeScript checkingnpm run test- run Vitest suitenpm run build- produce dist bundles with tsupnpm run check- biome check + typecheck + test
Examples
See:
examples/provider-observer.ts(provider-injected API)
License
MIT. See LICENSE.