npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@celestea/session

v2.8.3

Published

Readme

@celestea/session

The session log: in-memory and JSONL-backed SessionLog implementations, the replay/repair path, the monotonic turn-id owner, and the two message projections (Studio + engine). Depends only on @celestea/core.

Ports (1:1 against the legacy engine):

| TS module | Legacy source | |---|---| | log/derive.ts | crates/session/src/log.rs (derive_messages_from, flush_tool_calls, balance_tool_calls, project) | | log/memory.ts | crates/session/src/log.rs (InMemorySessionLog) | | log/file.ts | crates/session/src/persistent.rs (naming, replay, torn-tail truncation) | | log/persistent.ts | crates/session/src/persistent.rs (PersistentSessionLog) | | turn-id.ts | session_log.rs:94-98 + persistent.rs:382-402 (turn id ownership) | | messages.ts | crates/session/src/log.rs + Studio src/api.rs:94-135 | | replay.ts | P0 replay analysis + SSE transcript derivation |

Public API (via index.ts only)

  • Logs — InMemorySessionLog, PersistentSessionLog.open(dir, sessionId, opts?), defaultPersistentOptions(), PersistentOptions.
  • Plugins — inMemorySessionLogPlugin(), persistentSessionLogPlugin(cfg); both provide the log under core's SESSION_LOG_SERVICE token. Core never imports this package: register the plugin into a Context at compose time.
  • Projections — projectMessages (Studio: per-event, keeps thinking rows, keeps parent_id rows) and deriveMessages (engine: model-visible history — drops turn markers, thinking and parent_id sub-calls, merges consecutive tool calls into one assistant message, balances unanswered calls with a synthetic cancelled result).
  • JSONL — parseSessionJsonl, serializeSessionJsonl, plus re-exports of the serde-exact row codec (validateSessionEvent, parseSessionEvent, serializeSessionEvent, outcomePhase, outcomeError) from core.
  • Files — fileNameFor, filePathFor, replayFile (longest valid prefix + torn record), nextTurnId, nextTurnNumber, auditTurnIds.
  • Analysis — analyzeReplay, deriveSseTranscript (P0 replay toolchain).

Extension points

import { Context, mountPlugins, SESSION_LOG_SERVICE, type SessionLog } from "@celestea/core";
import { persistentSessionLogPlugin } from "@celestea/session";

const ctx = mountPlugins(Context.root(), [
  persistentSessionLogPlugin({ dir: "~/.celestea/sessions", sessionId: "session-1" }),
]);
const log = ctx.require<SessionLog>(SESSION_LOG_SERVICE);
log.append({ type: "user_message", text: "hi" });
log.nextTurnId();      // "turn-0" — owned by the log, monotonic, restored on open
log.deriveMessages();  // engine Message[] (role / content[] / tool_call_id)

Swap in inMemorySessionLogPlugin() for tests; a later mount of the same token wins (patch semantics), so composition never needs editing.

Durability semantics

  • One record == one JSON line; append writes through to the OS immediately (fs.writeSync), so flushEachAppend:false cannot lose a record (documented deviation from the engine's BufWriter, in the safe direction); sync() is the fsync/power-loss durability point and syncEachAppend fsyncs every record.
  • On open the file is replayed and validated: the longest valid prefix is kept and everything from the first unparsable record (a torn tail) is truncated away; blank lines are harmless padding; a missing final newline is repaired before the next append.
  • The turn counter is restored from the max turn-<n> id on disk (+1), so ids are never reused after a restart. clear() truncates the file and resets the counter (legacy behaviour); the in-memory log's counter deliberately never resets.
  • A failed disk write degrades gracefully: the event stays in the in-memory view (deriveMessages keeps working) and writeErrorCount() counts it.

derive_messages contract (engine parity)

derive_messages_from walks the log and: skips TurnStart/TurnEnd; skips ThinkingDelta; accumulates ToolCall rows (skipping parent_id sub-calls) and flushes them into ONE assistant message before any other event and at the end; projects ToolResult as Error: {err} (non-empty error) or the serde_json text of the value; then balance_tool_calls inserts Error: tool call was cancelled before execution (no result recorded) for every unanswered call (engine commit b046564 / W267).

Ported upstream quirks (parity over silent divergence, reported upstream):

  1. balance_tool_calls advances its cursor with i = j + inserted + 1, so the message right after a fully-answered call's results is never balance-checked; an unbalanced trailing call in exactly that position stays unbalanced. Covered by log/derive.test.ts and reproduced against the real engine.
  2. A whitespace-only JSONL line is an unparsable record (record.is_empty()), not padding.

Golden fixtures & the parity test

fixtures/sessions/*/derive-messages-expected.json is a frozen golden: since the engine exposes derive_messages over no HTTP surface, the expected JSON is stored in fixtures/. src/parity.test.ts asserts, per session and field for field: deriveMessages vs that golden, projectMessages vs the frozen HTTP golden, and a byte-identical JSONL round-trip of every event line.

pnpm vitest run packages/session/src/parity.test.ts    # golden parity suite

File layout

src/log/derive.test.ts    184  derive_messages parity suite (legacy tests ported)
src/replay.ts             160  replay analysis + SSE transcript (P0)
src/log/derive.ts         147  derive_messages + balance_tool_calls
src/log/persistent.ts     143  PersistentSessionLog (JSONL, replay, restore)
src/log/file.ts           106  file naming + replay/truncate helpers
src/jsonl.test.ts          99  file-level JSONL contract
src/parity.test.ts         89  golden parity (parity.test.ts)
src/turn-id.ts             83  turn id math + audit
src/jsonl.ts               80  file-level parse/serialize + codec re-exports
src/messages.ts            74  Studio projection + deriveMessages facade
src/log/persistent.test.ts 174 torn tail / blank lines / counter restore
src/log/memory.ts          55  InMemorySessionLog
src/plugin.ts              40  Context registration
src/index.ts               33  the only public entry point