Skip to content

feat: typed helpers for cron.* and sessions.subscribe #21

Description

@clemenshelm

Context

Pinchy is building Scheduled Briefings on top of OpenClaw Cron (heypinchy/pinchy#138). Milestone 1 (PR heypinchy/pinchy#151) ships thin Pinchy-side wrappers around getOpenClawClient().request("cron.*", ...). M3 ("Runtime Capture") needs a persistent sessions.subscribe() socket consumer for cron and session.tool events.

Both shapes currently require the consumer to use client.request() raw, with hand-rolled types and no subscription helper. That works but bleeds protocol shape across the call sites and blocks M3 from landing as a clean change.

Ask

Add typed helpers to openclaw-node:

Cron helpers

client.cron.list(opts?: { namePrefix?: string }): Promise<CronJob[]>
client.cron.add(input: AddCronJobInput): Promise<{ id: string }>
client.cron.update(input: UpdateCronJobInput): Promise<void>
client.cron.remove(opts: { id: string }): Promise<void>
client.cron.run(opts: { id: string; mode: "force" | "normal" }): Promise<{ runId: string }>
client.cron.runs(opts: ListCronRunsOpts): Promise<CronRunEntry[]>
client.cron.status(): Promise<CronStatus>

The Pinchy-side wrappers in packages/web/src/server/openclaw-cron.ts already pin down the input/output shapes Pinchy needs (CronJob, CronRunEntry with full usage, CronStatus). Those types should move upstream into this package; Pinchy should then consume them and shed the local copies.

Sessions subscription helper

```ts
client.sessions.subscribe(handlers: {
onCron?: (e: CronEvent) => void
onSessionTool?: (e: SessionToolEvent) => void
onReconnect?: () => void
}): Subscription
```

Auto-reconnect with exponential backoff, heartbeat/ping to detect dead sockets, and idempotent delivery (replays via `cron.runs({fromMs})` are Pinchy's job, not the helper's). One process holds one socket — multiplexing happens on the consumer side.

Why now

M3 is blocked on this. Without it Pinchy either ships a hand-rolled WS subscriber (duplication that other openclaw-node consumers will redo) or merges raw `client.request("sessions.subscribe", ...)` plus a custom event loop into Pinchy's server bundle. Neither is the right place for it.

Acceptance

  • `cron.*` helpers exposed and typed; types match the OpenClaw Gateway protocol payloads (esp. `cron` event payload with `usage`, `delivered`, `nextRunAtMs`)
  • `sessions.subscribe()` returns a `Subscription` with `close()` and surfaces `onReconnect`
  • Released to npm before Pinchy starts M3
  • Pinchy's `openclaw-cron.ts` wrappers can be deleted (or shrunk to wafer-thin org/business-logic shims)

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions