@kaged/storage

SQLite adapter via bun:sqlite with schema migrations, CRUD for sessions/messages/providers/compactions/task instances, and transcript persistence

5
source files
5
test files
~8.2k
lines
✓ 253 pass
tests
pass
typecheck
clean
lint

Test results 253

sqlite storage compactions > createCompaction + getCompaction round-trip [4.39ms]
sqlite storage compactions > getCompaction returns null for nonexistent id [2.59ms]
sqlite storage compactions > createCompaction duplicate id throws ConstraintError [2.78ms]
sqlite storage compactions > round-trips all trigger types [2.99ms]
sqlite storage compactions > round-trips all strategy types [3.08ms]
sqlite storage compactions > round-trips supersededMessageIds as JSON array [2.70ms]
sqlite storage compactions > round-trips empty supersededMessageIds [2.65ms]
sqlite storage compactions > round-trips pluginsFired with entries [2.62ms]
sqlite storage compactions > round-trips pluginCost when present [2.63ms]
sqlite storage compactions > round-trips pluginCost as null [2.58ms]
sqlite storage compactions > round-trips fallbackOccurred boolean [2.62ms]
sqlite storage compactions > round-trips summary fields [2.61ms]
sqlite storage compactions > round-trips checkpoint linkage [2.60ms]
sqlite storage compactions > round-trips operator feedback fields [2.88ms]
sqlite storage compactions — listCompactions > lists compactions for a session ordered by created_at [3.09ms]
sqlite storage compactions — listCompactions > returns empty list for session with no compactions [2.67ms]
sqlite storage compactions — listCompactions > paginates with cursor [3.04ms]
sqlite storage compactions — listCompactions > does not return compactions from other sessions [2.79ms]
sqlite storage compactions — updateCompaction > updates afterEstimate [2.75ms]
sqlite storage compactions — updateCompaction > updates operator feedback [2.64ms]
sqlite storage compactions — updateCompaction > updates fallback fields [2.67ms]
sqlite storage compactions — updateCompaction > updates supersededMessageIds [2.55ms]
sqlite storage compactions — updateCompaction > updates summary fields [2.63ms]
sqlite storage compactions — updateCompaction > updates checkpointId [2.71ms]
sqlite storage compactions — updateCompaction > no-op update does nothing [2.61ms]
sqlite storage compactions — updateCompaction > throws NotFoundError for nonexistent id [2.62ms]
sqlite storage compactions — updateCompaction > preserves unchanged fields on partial update [2.86ms]
sqlite storage compactions — migration v9 > schema version is 9 [2.68ms]
sqlite storage issues > createIssue + getIssue round-trip [3.06ms]
sqlite storage issues > getIssue returns null for nonexistent id [1.77ms]
sqlite storage issues > getIssueByNumber round-trip [1.82ms]
sqlite storage issues > getIssueByNumber returns null when absent [1.75ms]
sqlite storage issues > createIssue duplicate id throws ConstraintError [1.82ms]
sqlite storage issues > createIssue duplicate project/number throws ConstraintError [1.91ms]
sqlite storage issues > listIssues by projectId [2.05ms]
sqlite storage issues > listIssues filtered by status [2.06ms]
sqlite storage issues > listIssues filtered by createdBy [1.89ms]
sqlite storage issues > listIssues orders by updatedAt descending [1.88ms]
sqlite storage issues > listIssues paginates with cursor + limit [2.05ms]
sqlite storage issues > updateIssue updates title [1.85ms]
sqlite storage issues > updateIssue updates body [1.78ms]
sqlite storage issues > updateIssue updates status assignment resolution fields [1.79ms]
sqlite storage issues > updateIssue preserves originalBody on first edit [1.79ms]
sqlite storage issues > updateIssue does not overwrite originalBody when omitted later [1.73ms]
sqlite storage issues > updateIssue can clear assignment [1.75ms]
sqlite storage issues > updateIssue nonexistent throws NotFoundError [1.74ms]
sqlite storage issues > deleteIssue success [1.95ms]
sqlite storage issues > deleteIssue nonexistent throws NotFoundError [2.94ms]
sqlite storage issues > deleteIssue cascades to issue_updates [2.16ms]
sqlite storage issues > nextIssueNumber starts at 1 [1.90ms]
sqlite storage issues > nextIssueNumber increments per project [2.12ms]
sqlite storage issues > countIssues counts by project [2.12ms]
sqlite storage issues > createIssueUpdate + getIssueUpdate round-trip [2.09ms]
sqlite storage issues > getIssueUpdate returns null for nonexistent id [2.02ms]
sqlite storage issues > createIssueUpdate duplicate id throws ConstraintError [2.43ms]
sqlite storage issues > createIssueUpdate missing issue throws ConstraintError [1.82ms]
sqlite storage issues > listIssueUpdates ordered by created_at ASC [1.97ms]
sqlite storage issues > listIssueUpdates paginates [2.07ms]
sqlite storage issues > listIssueUpdates only returns rows for requested issue [1.91ms]
sqlite storage issues > deleteIssueUpdate success [1.81ms]
sqlite storage issues > deleteIssueUpdate nonexistent throws NotFoundError [1.73ms]
sqlite storage issues > metadata round-trip JSON [1.85ms]
sqlite storage issues > visibility values persist for all and operator_only [2.13ms]
initialization > sqlite storage > creates database with WAL mode [5.21ms]
initialization > sqlite storage > creates schema_version table with current version [4.23ms]
initialization > sqlite storage > creates all 24 tables [4.32ms]
initialization > sqlite storage > idempotent — opening same DB twice does not fail [4.29ms]
initialization > sqlite storage > foreign keys are enforced [3.90ms]
sessions > sqlite storage > create and get session [3.99ms]
sessions > sqlite storage > get non-existent session returns null [3.81ms]
sessions > sqlite storage > duplicate session id throws ConstraintError [19.92ms]
sessions > sqlite storage > update session state [4.03ms]
sessions > sqlite storage > update session endedAt [3.96ms]
sessions > sqlite storage > update session name [3.90ms]
sessions > sqlite storage > clear session name with null [3.92ms]
sessions > sqlite storage > create session with name [3.78ms]
sessions > sqlite storage > update non-existent session throws NotFoundError [3.81ms]
sessions > sqlite storage > list sessions returns all [3.99ms]
sessions > sqlite storage > list sessions filters by projectId [4.03ms]
sessions > sqlite storage > list sessions filters by createdBy [4.00ms]
sessions > sqlite storage > list sessions filters by state [3.98ms]
sessions > sqlite storage > list sessions paginates with cursor [4.26ms]
sessions > sqlite storage > count sessions by project excludes ended sessions [4.19ms]
sessions > sqlite storage > count sessions by operator excludes ended sessions [4.00ms]
sessions > sqlite storage > forkedFrom is persisted [3.93ms]
runs > sqlite storage > create and get run [3.99ms]
runs > sqlite storage > get non-existent run returns null [3.94ms]
runs > sqlite storage > duplicate run id throws ConstraintError [3.95ms]
runs > sqlite storage > update run state and completion [4.81ms]
runs > sqlite storage > update run with error [3.97ms]
runs > sqlite storage > update non-existent run throws NotFoundError [3.90ms]
runs > sqlite storage > list runs for session [4.07ms]
runs > sqlite storage > list runs paginates [25.68ms]
runs > sqlite storage > count runs for session [3.93ms]
runs > sqlite storage > run error round-trips through JSON [3.95ms]
runs > sqlite storage > getProjectStats returns session aggregates, 24h activity, and recent runs [5.60ms]
messages > sqlite storage > create and list messages [4.29ms]
messages > sqlite storage > supersede messages after cursor [4.46ms]
messages > sqlite storage > messages paginate with cursor [4.32ms]
messages > sqlite storage > message metadata round-trips through JSON [4.18ms]
messages > sqlite storage > message with runId [4.09ms]
checkpoints > sqlite storage > create and get checkpoint [4.10ms]
checkpoints > sqlite storage > get non-existent checkpoint returns null [3.93ms]
checkpoints > sqlite storage > update checkpoint resumed [4.40ms]
checkpoints > sqlite storage > update checkpoint rolled back [4.08ms]
checkpoints > sqlite storage > update checkpoint superseded [4.31ms]
checkpoints > sqlite storage > update non-existent checkpoint throws NotFoundError [4.26ms]
checkpoints > sqlite storage > list checkpoints for session [4.49ms]
checkpoints > sqlite storage > count checkpoints [4.27ms]
checkpoints > sqlite storage > rolledBack round-trips as boolean [4.26ms]
checkpoints > sqlite storage > createdBy values persist correctly [4.26ms]
subagent invocations > sqlite storage > create and get subagent invocation [4.35ms]
subagent invocations > sqlite storage > get non-existent returns null [4.18ms]
subagent invocations > sqlite storage > update subagent invocation state [4.36ms]
subagent invocations > sqlite storage > update non-existent throws NotFoundError [4.29ms]
subagent invocations > sqlite storage > list subagent invocations for run [4.43ms]
subagent invocations > sqlite storage > cageId null when uncaged [4.20ms]
tool calls > sqlite storage > create and get tool call [4.35ms]
tool calls > sqlite storage > get non-existent returns null [4.13ms]
tool calls > sqlite storage > update tool call completion [4.35ms]
tool calls > sqlite storage > update non-existent throws NotFoundError [4.19ms]
tool calls > sqlite storage > list tool calls for run [4.54ms]
tool calls > sqlite storage > tool calls paginate [4.56ms]
pty transcripts > sqlite storage > create and list pty transcripts [4.49ms]
pty transcripts > sqlite storage > empty list for unknown run [4.20ms]
pty transcripts > sqlite storage > multiple transcripts per run [4.36ms]
prompt edits > sqlite storage > create and list prompt edits [4.49ms]
prompt edits > sqlite storage > empty list for unknown checkpoint [4.24ms]
prompt edits > sqlite storage > multiple edits per checkpoint [4.36ms]
edge cases > sqlite storage > empty updates are no-ops (runs) [4.18ms]
edge cases > sqlite storage > empty updates are no-ops (checkpoints) [4.23ms]
edge cases > sqlite storage > page limit clamped to max 200 [4.26ms]
edge cases > sqlite storage > page limit minimum 1 [4.21ms]
edge cases > sqlite storage > close is idempotent [4.06ms]
edge cases > sqlite storage > supersedeMessagesAfter returns 0 when no messages match [22.07ms]
errors module > sqlite storage > StorageError has correct name [4.06ms]
errors module > sqlite storage > NotFoundError includes entity info [4.07ms]
errors module > sqlite storage > ConstraintError preserves cause [4.77ms]
task instances > sqlite storage > create and get task instance [4.50ms]
task instances > sqlite storage > get returns null for missing instance [4.15ms]
task instances > sqlite storage > duplicate create throws ConstraintError [4.20ms]
task instances > sqlite storage > update task instance state and exit [4.38ms]
task instances > sqlite storage > update nonexistent instance throws NotFoundError [4.10ms]
task instances > sqlite storage > update with empty changes is no-op [4.14ms]
task instances > sqlite storage > update tmux fields [4.24ms]
task instances > sqlite storage > delete task instance [4.28ms]
task instances > sqlite storage > delete nonexistent instance throws NotFoundError [4.13ms]
task instances > sqlite storage > list task instances by project [4.53ms]
task instances > sqlite storage > list task instances by state [4.31ms]
task instances > sqlite storage > list task instances respects pagination limit [4.40ms]
task instances > sqlite storage > count task instances by project [4.25ms]
task instances > sqlite storage > stores and retrieves all fields including nulls [4.18ms]
task instances > sqlite storage > stores and retrieves instance with all null optional fields [4.36ms]
task transcripts > sqlite storage > create and list task transcript [4.46ms]
task transcripts > sqlite storage > empty list for unknown task instance [4.19ms]
task transcripts > sqlite storage > multiple transcripts per task instance [4.31ms]
task transcripts > sqlite storage > duplicate id throws ConstraintError [4.23ms]
task transcripts > sqlite storage > foreign key to nonexistent task instance fails [4.24ms]
task transcripts > sqlite storage > large transcript blob round-trips correctly [6.39ms]
guests > sqlite storage > createGuest + getGuest round-trip [4.32ms]
guests > sqlite storage > getGuestByHandle [4.19ms]
guests > sqlite storage > listGuests with status filter and pagination [4.56ms]
guests > sqlite storage > updateGuest handle, displayName, passwordHash, status changes [4.36ms]
guests > sqlite storage > updateGuest throws ConstraintError on duplicate handle [4.37ms]
guests > sqlite storage > deleteGuest + cascade to invites, sessions, grants [5.01ms]
guests > sqlite storage > createGuest throws ConstraintError on duplicate userId [4.26ms]
guests > sqlite storage > createGuest throws ConstraintError on duplicate handle [4.56ms]
guests > sqlite storage > getGuest returns null for missing [4.09ms]
guest invites > sqlite storage > createGuestInvite + getGuestInvite round-trip [4.26ms]
guest invites > sqlite storage > deleteGuestInvite [4.24ms]
guest invites > sqlite storage > deleteGuestInvitesByUser [4.46ms]
guest invites > sqlite storage > deleteExpiredGuestInvites returns count of deleted [4.40ms]
guest invites > sqlite storage > getGuestInvite returns null for missing [4.06ms]
guest sessions > sqlite storage > createGuestSession + getGuestSession round-trip [4.22ms]
guest sessions > sqlite storage > updateGuestSession lastActiveAt [4.29ms]
guest sessions > sqlite storage > deleteGuestSession [4.20ms]
guest sessions > sqlite storage > deleteGuestSessionsByUser [4.42ms]
guest sessions > sqlite storage > updateGuestSession throws NotFoundError for missing [4.08ms]
guest sessions > sqlite storage > getGuestSession returns null for missing [4.07ms]
project guest grants > sqlite storage > createProjectGuestGrant + getProjectGuestGrant round-trip [4.28ms]
project guest grants > sqlite storage > JSON round-trip for permissionSet [4.24ms]
project guest grants > sqlite storage > listProjectGuestGrants by project [4.43ms]
project guest grants > sqlite storage > listGuestGrants by user [4.32ms]
project guest grants > sqlite storage > updateProjectGuestGrant new permissionSet, notes [4.47ms]
project guest grants > sqlite storage > deleteProjectGuestGrant [4.35ms]
project guest grants > sqlite storage > deleteProjectGuestGrant throws NotFoundError for missing [4.08ms]
project guest grants > sqlite storage > getProjectGuestGrant returns null for missing [4.06ms]
model overrides > sqlite storage > getModelOverrides returns empty for no overrides [4.15ms]
model overrides > sqlite storage > upsert and get single override [4.24ms]
model overrides > sqlite storage > upsert multiple overrides for same model [4.22ms]
model overrides > sqlite storage > upsert replaces existing override (idempotent) [4.19ms]
model overrides > sqlite storage > overrides are isolated per provider [4.23ms]
model overrides > sqlite storage > overrides are isolated per model [4.27ms]
model overrides > sqlite storage > deleteModelOverride removes single field [4.33ms]
model overrides > sqlite storage > deleteModelOverride throws NotFoundError for missing [4.16ms]
model overrides > sqlite storage > deleteAllModelOverrides removes all fields for a model [4.26ms]
model overrides > sqlite storage > deleteAllModelOverrides returns 0 when none exist [4.13ms]
provider spend limits > sqlite storage > getSpendLimit returns null when not set [4.14ms]
provider spend limits > sqlite storage > upsert and get spend limit [4.19ms]
provider spend limits > sqlite storage > upsert replaces existing spend limit [4.22ms]
provider spend limits > sqlite storage > spend limit with percentage-based windows [4.14ms]
provider spend limits > sqlite storage > deleteSpendLimit removes the limit [4.16ms]
provider spend limits > sqlite storage > deleteSpendLimit throws NotFoundError for missing [4.13ms]
provider spend limits > sqlite storage > limits are isolated per provider [4.25ms]
provider spend events > sqlite storage > createSpendEvent and sumSpendByWindow [4.42ms]
provider spend events > sqlite storage > sumSpendByWindow returns null when no events [4.16ms]
provider spend events > sqlite storage > sumSpendByWindow isolates by provider [4.29ms]
provider spend events > sqlite storage > sumSpendByWindow isolates by window key [4.28ms]
provider spend events > sqlite storage > sumSpendByWindow7d with 7-day window [4.24ms]
provider spend events > sqlite storage > sumSpendByWindow7d returns null when no events [4.05ms]
provider usage cache > sqlite storage > getUsageCache returns null when not cached [4.11ms]
provider usage cache > sqlite storage > setUsageCache and getUsageCache [4.19ms]
provider usage cache > sqlite storage > setUsageCache replaces existing cache [4.12ms]
provider usage cache > sqlite storage > deleteUsageCache removes the cache [4.14ms]
provider usage cache > sqlite storage > deleteUsageCache is idempotent for missing provider [4.08ms]
provider usage cache > sqlite storage > usage cache is isolated per provider [4.15ms]
session boundIssue > sqlite storage issue todos and links > create session with boundIssue and getSession returns it [9.54ms]
session boundIssue > sqlite storage issue todos and links > update session boundIssue persists new issue id [4.10ms]
session boundIssue > sqlite storage issue todos and links > update session boundIssue can clear to null [4.00ms]
issue_todos > sqlite storage issue todos and links > create and get issue todo [4.38ms]
issue_todos > sqlite storage issue todos and links > get non-existent issue todo returns null [3.93ms]
issue_todos > sqlite storage issue todos and links > duplicate issue todo id throws ConstraintError [4.08ms]
issue_todos > sqlite storage issue todos and links > list issue todos returns position order ascending [4.34ms]
issue_todos > sqlite storage issue todos and links > list issue todos breaks position ties by id [4.16ms]
issue_todos > sqlite storage issue todos and links > list issue todos filters by status [4.10ms]
issue_todos > sqlite storage issue todos and links > list issue todos filters by kind [4.10ms]
issue_todos > sqlite storage issue todos and links > list issue todos filters by phase [4.08ms]
issue_todos > sqlite storage issue todos and links > list issue todos combines status kind and phase filters [4.24ms]
issue_todos > sqlite storage issue todos and links > update issue todo persists mutable fields [4.19ms]
issue_todos > sqlite storage issue todos and links > update non-existent issue todo throws NotFoundError [3.97ms]
issue_todos > sqlite storage issue todos and links > delete issue todo removes it [4.06ms]
issue_todos > sqlite storage issue todos and links > delete non-existent issue todo throws NotFoundError [3.94ms]
issue_todos > sqlite storage issue todos and links > count issue todos counts only matching issue [4.12ms]
issue_todos > sqlite storage issue todos and links > nextIssueTodoPosition starts at one for empty issue [3.90ms]
issue_todos > sqlite storage issue todos and links > nextIssueTodoPosition uses max position plus one [7.30ms]
issue_todos > sqlite storage issue todos and links > storage allows multiple in_progress (handler enforces single-in_progress) [4.15ms]
issue_todos > sqlite storage issue todos and links > another todo can become in_progress after current one completes [4.16ms]
issue_links > sqlite storage issue todos and links > create and get issue link [5.62ms]
issue_links > sqlite storage issue todos and links > get non-existent issue link returns null [4.37ms]
issue_links > sqlite storage issue todos and links > duplicate issue link id throws ConstraintError [4.50ms]
issue_links > sqlite storage issue todos and links > listIssueLinksFrom returns links ordered by createdAt [4.47ms]
issue_links > sqlite storage issue todos and links > listIssueLinksTo returns links ordered by createdAt [4.48ms]
issue_links > sqlite storage issue todos and links > listIssueLinksForProject returns only matching project links [4.51ms]
issue_links > sqlite storage issue todos and links > listIssueLinksForProject paginates by cursor [4.74ms]
issue_links > sqlite storage issue todos and links > delete issue link removes it [4.49ms]
issue_links > sqlite storage issue todos and links > delete non-existent issue link throws NotFoundError [4.33ms]
cascade delete > sqlite storage issue todos and links > deleting an issue cascades to issue_todos [7.94ms]
cascade delete > sqlite storage issue todos and links > deleting an issue cascades to outgoing and incoming issue_links [4.61ms]
sqlite storage guest activity > listGuestActivity returns issues opened by the guest [6.52ms]
sqlite storage guest activity > listGuestActivity returns comments made by the guest [2.56ms]
sqlite storage guest activity > listGuestActivity returns grant events for the guest [2.57ms]
sqlite storage guest activity > listGuestActivity filters by projectId [2.55ms]
sqlite storage guest activity > listGuestActivity paginates with cursor + limit [3.25ms]

Mentioned in

Type Document
adr ADR-0024: Context compaction is kaged-owned, layered, observable, and operator-tunable
adr ADR-0026: Cost management, model metadata overrides, and provider usage tracking
spec Spec: Agent Harness
spec Spec: Guests and Project Grants
spec Spec: Issues
spec Spec: LLM Provider Interface
spec Spec: Operational Logging
spec Spec: Session Manager