dsh-calendar
Session-interaction calendar plugin for DeepSeek Harness: a root-scope calendar surface that aggregates every session's interaction events across the whole harness. A sidebar-foot action opens a full-viewport month grid; each day cell carries a badge with that day's active-session count, and selecting a day lists one row per active session — the session's title, its day-scoped duration, and its event count — expandable to the raw event list. Live appends stream into the open calendar in real time.
English | 中文
Features
- Whole-harness view — one calendar for every session (user messages, assistant replies, tool calls, turn boundaries), not just the current one.
- Real-time — host-side SSE channel pushes new events into the open calendar the moment they are appended.
- Historical backfill — seeds already-live sessions at startup and best-effort reads the persisted log through
sessionPersistence. - Merge-extensible — unknown (plugin-merged) event types fall back to their type name; no per-type registry to maintain.
- Bounded memory — rolling 90-day window, capped at 2000 events per day across all sessions.
Installation
The plugin targets the DeepSeek Harness web surface (
dsh web).
Install it into a profile with dsh plugin (which forwards to pnpm inside the
profile directory). The package declares dsh.bundle, so dsh appends it to
the profile's dsh.profile.bundles list automatically:
dsh plugin --profile web add @necokeine/dsh-calendar
Restart dsh web and refresh the page — a Calendar entry appears at the
bottom of the sidebar. The bundle contributes one uniquely named Loader row;
current @deepseek-ai/dsh-web-app compositions do not include a calendar row
that needs to be disabled or replaced.
Remove it again with:
dsh plugin --profile web remove @necokeine/dsh-calendar
Other install forms also work:
- Local checkout —
dsh plugin --profile web add ./path/to/dsh-calendar(orlink:./path/to/dsh-calendar). - Tarball —
pnpm packthendsh plugin --profile web add ./necokeine-dsh-calendar-0.1.1.tgz; prebuiltlib/, no build permission needed. - Git —
dsh plugin --profile web add github:necokeine/dsh-calendar#<sha>; this fetches sources (nolib/), so pnpm ≥10 blocks the build until you allowlist the package underallowBuildsin the profile'spnpm-workspace.yaml, and the checkout must producelib/itself.
Development
pnpm install
pnpm test # vitest: node half + browser-half data layer + component specs
pnpm build # tsc -b && tsdown → lib/ (node half + browser client bundle)
pnpm lint # oxlint (src + tests)
pnpm pack # build (via prepack) + tarball for `dsh plugin add ./….tgz`
The standalone suite uses a small createSnapshotStore contract stub because
the published runtime client is itself a browser loader artifact. It still
executes the real calendar apply function against a contract-shaped context,
including locale/slot registration and controller teardown; host aggregation,
route semantics, request races, SSE folding, component behavior, and package
manifest/patch contracts are covered separately.
The package is a split plugin like the harness's own dsh-client-hmr:
- Node half (
src/index.ts) — a host plugin injectingsessions+webServer. It subscribes to thesession/eventfirehose, summarizes every event into a short wire record{ sessionId, seq, time, type, summary }(Chinese product copy, host-authored), folds each session's title from itssession/titleevents (foldSessionTitle), and aggregates everything per-session-per-day — each day bucket lists oneCalendarSessionWireper active session with its title, day-scoped time span, event count, and (for the expanded view) its raw event list. It registers two routes:GET /calendar/events?from=YYYY-MM-DD&to=YYYY-MM-DD— JSON per-session day buckets for a local-day range.GET /calendar/stream— SSE channel: a backlog frame on connect, then oneeventframe per live append (the browser folds them into the matching session rows).
- Browser half (
src/client/index.ts) — registers thesidebar.footer.actionentry plus thecalendarlocale namespace. Its privateCalendarControllerowns the view store (bound touseCalendar), the per-month/calendar/eventsfetch, and the/calendar/streamEventSource lifecycle; the component receives only the observable hook and plain action callbacks. The month grid shows per-day active-session counts; the day-detail area lists session rows (title + duration + event count) that expand to the raw event list — expanded state is component-local.
Repository layout
src/
index.ts # node half: aggregator, index, routes, SSE
events.ts # shared wire protocol (both halves)
invariant.ts # package invariant companion
client/
index.ts # browser half entry (footer action registration)
calendar-controller.ts # store + wire calls + SSE lifecycle
CalendarAction.tsx # footer trigger + month grid + day detail
calendar-action.module.css
locales.ts # zh/en dictionaries
tests/ # vitest specs (node half, controller, component)
cordis.patch.yml # bundle patch (`dsh.bundle.patch`): inserts this
# package under a unique Loader row id
tsdown.config.ts # independent build (CSS modules inline + loader banner)
Model Experience
The plugin adds no tools, prompt sections, schemas, or model-visible messages. It passively indexes durable session events and exposes the result only to the Web calendar UI, so installing it does not change model input or KV-cache behavior.
License
MIT
No comments yet. Be the first to write one.