zidane 4.1.7 → 4.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/dist/{index-bgh-k8Mv.d.ts → agent-CMIhYhDz.d.ts} +2032 -1993
  2. package/dist/agent-CMIhYhDz.d.ts.map +1 -0
  3. package/dist/chat.d.ts +7 -6
  4. package/dist/chat.d.ts.map +1 -1
  5. package/dist/chat.js +2 -2
  6. package/dist/contexts.d.ts +1 -1
  7. package/dist/{index-BB4kuRh3.d.ts → index-CXVvqTQj.d.ts} +1 -1
  8. package/dist/{index-BB4kuRh3.d.ts.map → index-CXVvqTQj.d.ts.map} +1 -1
  9. package/dist/{index-Ds5YpvfZ.d.ts → index-D6Dd6Kc0.d.ts} +3 -3
  10. package/dist/{index-Ds5YpvfZ.d.ts.map → index-D6Dd6Kc0.d.ts.map} +1 -1
  11. package/dist/{index-DRoG_udt.d.ts → index-DAaKyadO.d.ts} +2 -2
  12. package/dist/{index-DRoG_udt.d.ts.map → index-DAaKyadO.d.ts.map} +1 -1
  13. package/dist/index.d.ts +4 -4
  14. package/dist/index.js +6 -6
  15. package/dist/{interpolate-CukJwP2G.js → interpolate-BydkV1eT.js} +3 -1
  16. package/dist/interpolate-BydkV1eT.js.map +1 -0
  17. package/dist/{mcp-8wClKY-3.js → mcp-Dw-fRPVk.js} +61 -65
  18. package/dist/mcp-Dw-fRPVk.js.map +1 -0
  19. package/dist/mcp.d.ts +1 -1
  20. package/dist/mcp.js +1 -1
  21. package/dist/{presets-BzkJDW1K.js → presets-4zCJzCYw.js} +2 -2
  22. package/dist/{presets-BzkJDW1K.js.map → presets-4zCJzCYw.js.map} +1 -1
  23. package/dist/presets.d.ts +1 -1
  24. package/dist/presets.js +1 -1
  25. package/dist/providers.d.ts +1 -1
  26. package/dist/session/sqlite.d.ts +13 -2
  27. package/dist/session/sqlite.d.ts.map +1 -1
  28. package/dist/session/sqlite.js +70 -27
  29. package/dist/session/sqlite.js.map +1 -1
  30. package/dist/{session-Cn68UASv.js → session-B1RN0uoi.js} +42 -30
  31. package/dist/{session-Cn68UASv.js.map → session-B1RN0uoi.js.map} +1 -1
  32. package/dist/session.d.ts +1 -1
  33. package/dist/session.js +1 -1
  34. package/dist/skills.d.ts +2 -2
  35. package/dist/skills.js +1 -1
  36. package/dist/{stats-BT9l57RS.js → stats-DZIsGqzu.js} +15 -5
  37. package/dist/stats-DZIsGqzu.js.map +1 -0
  38. package/dist/{theme-BlXO6yHe.d.ts → theme-Caf4AvTO.d.ts} +147 -13
  39. package/dist/theme-Caf4AvTO.d.ts.map +1 -0
  40. package/dist/{theme-context-MungM3SY.js → theme-context-DQM2lx4U.js} +212 -72
  41. package/dist/theme-context-DQM2lx4U.js.map +1 -0
  42. package/dist/{tools-C8kDot0H.js → tools-BdQENveS.js} +409 -312
  43. package/dist/tools-BdQENveS.js.map +1 -0
  44. package/dist/tools.d.ts +2 -2
  45. package/dist/tools.js +1 -1
  46. package/dist/tui.d.ts +64 -7
  47. package/dist/tui.d.ts.map +1 -1
  48. package/dist/tui.js +481 -143
  49. package/dist/tui.js.map +1 -1
  50. package/dist/types.d.ts +3 -3
  51. package/dist/types.js +1 -1
  52. package/package.json +6 -1
  53. package/dist/index-bgh-k8Mv.d.ts.map +0 -1
  54. package/dist/interpolate-CukJwP2G.js.map +0 -1
  55. package/dist/mcp-8wClKY-3.js.map +0 -1
  56. package/dist/stats-BT9l57RS.js.map +0 -1
  57. package/dist/theme-BlXO6yHe.d.ts.map +0 -1
  58. package/dist/theme-context-MungM3SY.js.map +0 -1
  59. package/dist/tools-C8kDot0H.js.map +0 -1
@@ -301,6 +301,42 @@ async function createSession(options = {}) {
301
301
  function findRun(runId) {
302
302
  return data.runs.find((r) => r.id === runId);
303
303
  }
304
+ /**
305
+ * Apply per-run usage stats onto a SessionRun. Shared by `completeRun`,
306
+ * `abortRun`, and `errorRun` so the on-disk shape stays consistent across
307
+ * exit paths — historically only `completeRun` filled these in, and
308
+ * aborted/errored runs rendered `0 in / 0 out` on reload regardless of
309
+ * how much was actually consumed.
310
+ */
311
+ function applyRunStats(run, stats) {
312
+ run.turns = stats.turns;
313
+ run.tokensIn = stats.tokensIn;
314
+ run.tokensOut = stats.tokensOut;
315
+ if (stats.turnUsage) {
316
+ run.turnUsage = stats.turnUsage;
317
+ const total = stats.turnUsage.reduce((acc, t) => ({
318
+ input: acc.input + t.input,
319
+ output: acc.output + t.output,
320
+ cacheCreation: (acc.cacheCreation ?? 0) + (t.cacheCreation ?? 0),
321
+ cacheRead: (acc.cacheRead ?? 0) + (t.cacheRead ?? 0),
322
+ thinking: (acc.thinking ?? 0) + (t.thinking ?? 0)
323
+ }), {
324
+ input: 0,
325
+ output: 0,
326
+ cacheCreation: 0,
327
+ cacheRead: 0,
328
+ thinking: 0
329
+ });
330
+ run.totalUsage = {
331
+ input: total.input,
332
+ output: total.output,
333
+ ...total.cacheCreation ? { cacheCreation: total.cacheCreation } : {},
334
+ ...total.cacheRead ? { cacheRead: total.cacheRead } : {},
335
+ ...total.thinking ? { thinking: total.thinking } : {}
336
+ };
337
+ }
338
+ if (stats.cost !== void 0) run.cost = stats.cost;
339
+ }
304
340
  return {
305
341
  get id() {
306
342
  return data.id;
@@ -339,50 +375,26 @@ async function createSession(options = {}) {
339
375
  if (run) {
340
376
  run.status = "completed";
341
377
  run.endedAt = Date.now();
342
- run.turns = stats.turns;
343
- run.tokensIn = stats.tokensIn;
344
- run.tokensOut = stats.tokensOut;
345
- if (stats.turnUsage) {
346
- run.turnUsage = stats.turnUsage;
347
- const total = stats.turnUsage.reduce((acc, t) => ({
348
- input: acc.input + t.input,
349
- output: acc.output + t.output,
350
- cacheCreation: (acc.cacheCreation ?? 0) + (t.cacheCreation ?? 0),
351
- cacheRead: (acc.cacheRead ?? 0) + (t.cacheRead ?? 0),
352
- thinking: (acc.thinking ?? 0) + (t.thinking ?? 0)
353
- }), {
354
- input: 0,
355
- output: 0,
356
- cacheCreation: 0,
357
- cacheRead: 0,
358
- thinking: 0
359
- });
360
- run.totalUsage = {
361
- input: total.input,
362
- output: total.output,
363
- ...total.cacheCreation ? { cacheCreation: total.cacheCreation } : {},
364
- ...total.cacheRead ? { cacheRead: total.cacheRead } : {},
365
- ...total.thinking ? { thinking: total.thinking } : {}
366
- };
367
- }
368
- if (stats.cost !== void 0) run.cost = stats.cost;
378
+ applyRunStats(run, stats);
369
379
  }
370
380
  touch();
371
381
  },
372
- abortRun(runId) {
382
+ abortRun(runId, stats) {
373
383
  const run = findRun(runId);
374
384
  if (run) {
375
385
  run.status = "aborted";
376
386
  run.endedAt = Date.now();
387
+ if (stats) applyRunStats(run, stats);
377
388
  }
378
389
  touch();
379
390
  },
380
- errorRun(runId, error) {
391
+ errorRun(runId, error, stats) {
381
392
  const run = findRun(runId);
382
393
  if (run) {
383
394
  run.status = "error";
384
395
  run.endedAt = Date.now();
385
396
  run.error = error;
397
+ if (stats) applyRunStats(run, stats);
386
398
  }
387
399
  touch();
388
400
  },
@@ -437,4 +449,4 @@ function generateId() {
437
449
  //#endregion
438
450
  export { createFileMapStore as a, createMemoryStore as i, loadSession as n, createRemoteStore as r, createSession as t };
439
451
 
440
- //# sourceMappingURL=session-Cn68UASv.js.map
452
+ //# sourceMappingURL=session-B1RN0uoi.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"session-Cn68UASv.js","names":[],"sources":["../src/session/file-map.ts","../src/session/memory.ts","../src/session/remote.ts","../src/session/index.ts"],"sourcesContent":["/**\n * File-map session store.\n *\n * Wraps a narrow 3-method adapter (`get` / `save` / `delete`) that exchanges a flat\n * map of filename → string content. Useful for embedding zidane sessions inside\n * host-provided session backends that only speak in file maps (not zidane's native\n * `SessionStore` shape).\n *\n * Serialization format:\n * - `turns.jsonl` — one `SessionTurn` per line.\n * - `meta.json` — session metadata (id, agentId, status, runs, metadata, timestamps).\n *\n * JSONL for turns keeps history inspectable with tools like `jq` and resilient to\n * partial corruption — parse up to the first bad line and you still have a valid\n * prefix. Metadata lives in its own file so large turn logs don't bloat the\n * metadata path.\n *\n * Scope: each `createFileMapStore` handles a **single session** — the adapter's\n * file map holds at most one zidane session at a time. This matches how host SDKs\n * scope their session stores per conversation.\n *\n * Divergences from the built-in memory / sqlite stores:\n * - `appendTurns` / `updateStatus` / `updateRun` auto-create a minimal `SessionData`\n * record on first write, instead of silently no-oping when the session hasn't been\n * explicitly `save()`-ed. This matches the host-SDK integration path where\n * `createSession(...)` → `agent.run(...)` directly without an explicit `save()` call.\n * - `updateRun` inserts the run if not found in the cached record (rather than\n * silently dropping). Run records therefore always reach the adapter.\n */\n\nimport type { SessionData, SessionRun, SessionStore } from '.'\nimport type { SessionTurn } from '../types'\n\n/**\n * Host-provided file-map adapter. Three methods exchanging `Record<string, string>`\n * payloads — the whole persistence surface the wrapper needs.\n */\nexport interface FileMapAdapter {\n /** Load the current file map. Returns an empty `files` record when nothing is persisted. */\n get: () => Promise<{ files: Record<string, string> }>\n /** Replace the persisted file map. Full-rewrite semantics. */\n save: (files: Record<string, string>) => Promise<void>\n /** Delete all persisted state. */\n delete: () => Promise<void>\n}\n\nexport interface FileMapStoreOptions {\n /** Filename for the JSONL turns log. Default: `turns.jsonl`. */\n turnsFile?: string\n /** Filename for the metadata JSON. Default: `meta.json`. */\n metaFile?: string\n}\n\ninterface MetaShape {\n id: string\n agentId?: string\n runs: SessionRun[]\n status: SessionData['status']\n metadata: Record<string, unknown>\n createdAt: number\n updatedAt: number\n}\n\nfunction toMeta(data: SessionData): MetaShape {\n return {\n id: data.id,\n agentId: data.agentId,\n runs: data.runs,\n status: data.status,\n metadata: data.metadata,\n createdAt: data.createdAt,\n updatedAt: data.updatedAt,\n }\n}\n\nfunction toData(meta: MetaShape, turns: SessionTurn[]): SessionData {\n return {\n id: meta.id,\n agentId: meta.agentId,\n turns,\n runs: meta.runs,\n status: meta.status,\n metadata: meta.metadata,\n createdAt: meta.createdAt,\n updatedAt: meta.updatedAt,\n }\n}\n\nfunction parseTurnsJsonl(jsonl: string): SessionTurn[] {\n if (!jsonl)\n return []\n const turns: SessionTurn[] = []\n for (const line of jsonl.split('\\n')) {\n const trimmed = line.trim()\n if (!trimmed)\n continue\n try {\n turns.push(JSON.parse(trimmed) as SessionTurn)\n }\n catch {\n // Skip malformed lines — preserves the valid prefix on partial corruption.\n }\n }\n return turns\n}\n\nfunction serializeTurnsJsonl(turns: SessionTurn[]): string {\n if (turns.length === 0)\n return ''\n return `${turns.map(t => JSON.stringify(t)).join('\\n')}\\n`\n}\n\n/**\n * Create a single-session `SessionStore` backed by a file-map adapter.\n *\n * @example\n * ```ts\n * const session = await createSession({\n * store: createFileMapStore(hostSessionStore),\n * })\n * ```\n */\nexport function createFileMapStore(\n adapter: FileMapAdapter,\n options: FileMapStoreOptions = {},\n): SessionStore {\n const turnsFile = options.turnsFile ?? 'turns.jsonl'\n const metaFile = options.metaFile ?? 'meta.json'\n\n // Cached view of the persisted session. Populated lazily on first access so the\n // factory itself doesn't do I/O.\n let cached: SessionData | null = null\n let hydrated = false\n\n async function hydrate(): Promise<void> {\n if (hydrated)\n return\n const { files } = await adapter.get()\n const metaRaw = files[metaFile]\n if (metaRaw) {\n let meta: MetaShape | null = null\n try {\n meta = JSON.parse(metaRaw) as MetaShape\n }\n catch {\n meta = null\n }\n if (meta) {\n cached = toData(meta, parseTurnsJsonl(files[turnsFile] ?? ''))\n }\n }\n hydrated = true\n }\n\n async function persist(data: SessionData): Promise<void> {\n const meta = toMeta(data)\n await adapter.save({\n [metaFile]: JSON.stringify(meta, null, 2),\n [turnsFile]: serializeTurnsJsonl(data.turns),\n })\n }\n\n // Ensure `cached` exists for `sessionId`, creating a minimal record when first written.\n // Returns false when `cached` already holds a different sessionId (request ignored).\n async function ensureCachedFor(sessionId: string): Promise<boolean> {\n await hydrate()\n if (cached) {\n return cached.id === sessionId\n }\n const now = Date.now()\n cached = {\n id: sessionId,\n turns: [],\n runs: [],\n status: 'idle',\n metadata: {},\n createdAt: now,\n updatedAt: now,\n }\n hydrated = true\n return true\n }\n\n return {\n async load(sessionId: string): Promise<SessionData | null> {\n await hydrate()\n if (!cached || cached.id !== sessionId)\n return null\n return structuredClone(cached)\n },\n\n async save(data: SessionData): Promise<void> {\n cached = structuredClone(data)\n hydrated = true\n await persist(cached)\n },\n\n async delete(sessionId: string): Promise<void> {\n await hydrate()\n if (cached && cached.id !== sessionId)\n return\n cached = null\n await adapter.delete()\n },\n\n async list(filter): Promise<string[]> {\n await hydrate()\n if (!cached)\n return []\n if (filter?.agentId && cached.agentId !== filter.agentId)\n return []\n return [cached.id]\n },\n\n async appendTurns(sessionId: string, turns: SessionTurn[]): Promise<void> {\n const ok = await ensureCachedFor(sessionId)\n if (!ok)\n return\n cached!.turns.push(...structuredClone(turns))\n cached!.updatedAt = Date.now()\n await persist(cached!)\n },\n\n async getTurns(sessionId: string, from = 0, limit?: number): Promise<SessionTurn[]> {\n await hydrate()\n if (!cached || cached.id !== sessionId)\n return []\n const slice = cached.turns.slice(from, limit !== undefined ? from + limit : undefined)\n return structuredClone(slice) as SessionTurn[]\n },\n\n async updateRun(sessionId: string, run: SessionRun): Promise<void> {\n const ok = await ensureCachedFor(sessionId)\n if (!ok)\n return\n const idx = cached!.runs.findIndex(r => r.id === run.id)\n if (idx >= 0)\n cached!.runs[idx] = structuredClone(run)\n else\n cached!.runs.push(structuredClone(run))\n cached!.updatedAt = Date.now()\n await persist(cached!)\n },\n\n async updateStatus(sessionId: string, status: SessionData['status']): Promise<void> {\n const ok = await ensureCachedFor(sessionId)\n if (!ok)\n return\n cached!.status = status\n cached!.updatedAt = Date.now()\n await persist(cached!)\n },\n }\n}\n","/**\n * In-memory session store.\n * Useful for development and testing. Data is lost when the process exits.\n */\n\nimport type { SessionData, SessionRun, SessionStore } from '.'\nimport type { SessionTurn } from '../types'\n\nexport function createMemoryStore(): SessionStore {\n const sessions = new Map<string, SessionData>()\n\n return {\n async load(sessionId: string) {\n const data = sessions.get(sessionId)\n return data ? structuredClone(data) : null\n },\n\n async save(session: SessionData) {\n sessions.set(session.id, structuredClone(session))\n },\n\n async delete(sessionId: string) {\n sessions.delete(sessionId)\n },\n\n async list(filter) {\n let ids = Array.from(sessions.keys())\n if (filter?.agentId) {\n ids = ids.filter(id => sessions.get(id)?.agentId === filter.agentId)\n }\n if (filter?.limit) {\n ids = ids.slice(0, filter.limit)\n }\n return ids\n },\n\n async appendTurns(sessionId: string, turns: SessionTurn[]) {\n const data = sessions.get(sessionId)\n if (data) {\n data.turns.push(...structuredClone(turns))\n data.updatedAt = Date.now()\n }\n },\n\n async getTurns(sessionId: string, from = 0, limit?: number) {\n const data = sessions.get(sessionId)\n if (!data)\n return []\n const sliced = data.turns.slice(from, limit !== undefined ? from + limit : undefined)\n return structuredClone(sliced) as SessionTurn[]\n },\n\n async updateRun(sessionId: string, run: SessionRun) {\n const data = sessions.get(sessionId)\n if (data) {\n const idx = data.runs.findIndex(r => r.id === run.id)\n if (idx >= 0) {\n data.runs[idx] = structuredClone(run)\n }\n data.updatedAt = Date.now()\n }\n },\n\n async updateStatus(sessionId: string, status: SessionData['status']) {\n const data = sessions.get(sessionId)\n if (data) {\n data.status = status\n data.updatedAt = Date.now()\n }\n },\n }\n}\n","/**\n * Remote session store via HTTP API.\n *\n * Expects a REST API with:\n * GET {url}/sessions/{id} -> SessionData | 404\n * PUT {url}/sessions/{id} -> save SessionData\n * DELETE {url}/sessions/{id} -> delete\n * GET {url}/sessions?agentId=&limit= -> { ids: string[] }\n * POST {url}/sessions/{id}/turns -> append turns\n * GET {url}/sessions/{id}/turns?from=&limit= -> SessionTurn[]\n * PUT {url}/sessions/{id}/runs/{runId} -> update run\n * PATCH {url}/sessions/{id} -> { status }\n */\n\nimport type { SessionData, SessionRun, SessionStore } from '.'\nimport type { SessionTurn } from '../types'\n\nexport interface RemoteStoreOptions {\n /** Base URL of the session API */\n url: string\n /** Optional headers (e.g. for authentication) */\n headers?: Record<string, string>\n}\n\nconst TRAILING_SLASH = /\\/$/\n\nexport function createRemoteStore(options: RemoteStoreOptions): SessionStore {\n const baseUrl = options.url.replace(TRAILING_SLASH, '')\n const defaultHeaders: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...options.headers,\n }\n\n async function request(path: string, init?: RequestInit): Promise<Response> {\n const url = `${baseUrl}${path}`\n const res = await fetch(url, {\n ...init,\n headers: { ...defaultHeaders, ...init?.headers },\n })\n return res\n }\n\n return {\n async load(sessionId: string) {\n const res = await request(`/sessions/${encodeURIComponent(sessionId)}`)\n if (!res.ok) {\n if (res.status === 404)\n return null\n throw new Error(`Remote session load failed: ${res.status} ${res.statusText}`)\n }\n return await res.json() as SessionData\n },\n\n async save(session: SessionData) {\n const res = await request(`/sessions/${encodeURIComponent(session.id)}`, {\n method: 'PUT',\n body: JSON.stringify(session),\n })\n if (!res.ok) {\n throw new Error(`Remote session save failed: ${res.status} ${res.statusText}`)\n }\n },\n\n async delete(sessionId: string) {\n const res = await request(`/sessions/${encodeURIComponent(sessionId)}`, {\n method: 'DELETE',\n })\n if (!res.ok && res.status !== 404) {\n throw new Error(`Remote session delete failed: ${res.status} ${res.statusText}`)\n }\n },\n\n async list(filter) {\n const params = new URLSearchParams()\n if (filter?.agentId)\n params.set('agentId', filter.agentId)\n if (filter?.limit)\n params.set('limit', String(filter.limit))\n\n const query = params.toString()\n const path = query ? `/sessions?${query}` : '/sessions'\n const res = await request(path)\n\n if (!res.ok) {\n throw new Error(`Remote session list failed: ${res.status} ${res.statusText}`)\n }\n\n const body = await res.json() as { ids: string[] }\n return body.ids\n },\n\n async appendTurns(sessionId: string, turns: SessionTurn[]) {\n const res = await request(`/sessions/${encodeURIComponent(sessionId)}/turns`, {\n method: 'POST',\n body: JSON.stringify(turns),\n })\n if (!res.ok) {\n throw new Error(`Remote appendTurns failed: ${res.status} ${res.statusText}`)\n }\n },\n\n async getTurns(sessionId: string, from = 0, limit?: number) {\n const params = new URLSearchParams()\n if (from)\n params.set('from', String(from))\n if (limit !== undefined)\n params.set('limit', String(limit))\n\n const query = params.toString()\n const path = `/sessions/${encodeURIComponent(sessionId)}/turns${query ? `?${query}` : ''}`\n const res = await request(path)\n\n if (!res.ok) {\n throw new Error(`Remote getTurns failed: ${res.status} ${res.statusText}`)\n }\n\n return await res.json() as SessionTurn[]\n },\n\n async updateRun(sessionId: string, run: SessionRun) {\n const res = await request(\n `/sessions/${encodeURIComponent(sessionId)}/runs/${encodeURIComponent(run.id)}`,\n {\n method: 'PUT',\n body: JSON.stringify(run),\n },\n )\n if (!res.ok) {\n throw new Error(`Remote updateRun failed: ${res.status} ${res.statusText}`)\n }\n },\n\n async updateStatus(sessionId: string, status: SessionData['status']) {\n const res = await request(`/sessions/${encodeURIComponent(sessionId)}`, {\n method: 'PATCH',\n body: JSON.stringify({ status }),\n })\n if (!res.ok) {\n throw new Error(`Remote updateStatus failed: ${res.status} ${res.statusText}`)\n }\n },\n }\n}\n","/**\n * Session management for agents.\n *\n * A session tracks identity, turn history, and run metadata.\n * Plug in any storage backend by implementing the SessionStore interface,\n * or use one of the built-in stores: memory, sqlite, remote.\n */\n\nimport type { SessionTurn, TurnUsage } from '../types'\n\nexport type { SessionContentBlock, SessionMessage, SessionTurn } from '../types'\nexport { createFileMapStore } from './file-map'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface SessionRun {\n id: string\n startedAt: number\n endedAt?: number\n prompt: string\n status: 'running' | 'completed' | 'aborted' | 'error'\n turns?: number\n tokensIn?: number\n tokensOut?: number\n error?: string\n /** Per-turn usage breakdown */\n turnUsage?: TurnUsage[]\n /** Total usage across all turns */\n totalUsage?: TurnUsage\n /** Estimated cost in USD */\n cost?: number\n /**\n * The run that spawned this one, when the agent is a subagent sharing its\n * parent's session. Undefined on top-level `agent.run()`. Consumers can walk\n * `runs` by `parentRunId` to reconstruct the subagent tree.\n */\n parentRunId?: string\n /**\n * Zero-based subagent depth. 0 = top-level run, 1 = direct child, …\n * Recorded here so hosts can query/filter by level without walking the tree.\n */\n depth?: number\n}\n\nexport interface SessionData {\n id: string\n agentId?: string\n turns: SessionTurn[]\n runs: SessionRun[]\n status: 'idle' | 'running' | 'completed' | 'error'\n metadata: Record<string, unknown>\n createdAt: number\n updatedAt: number\n}\n\n// ---------------------------------------------------------------------------\n// SessionStore interface (pluggable backend)\n// ---------------------------------------------------------------------------\n\nexport interface SessionStore {\n /** Optional: generate a session ID server-side (e.g. Supabase UUID). */\n generateSessionId?: () => string | Promise<string>\n\n /** Optional: generate a turn ID server-side. */\n generateTurnId?: () => string | Promise<string>\n\n /** Load a session by ID. Returns null if not found. */\n load: (sessionId: string) => Promise<SessionData | null>\n\n /** Save a session (create or update, full document). */\n save: (session: SessionData) => Promise<void>\n\n /** Delete a session. */\n delete: (sessionId: string) => Promise<void>\n\n /** List session IDs, optionally filtered. */\n list: (filter?: { agentId?: string, limit?: number }) => Promise<string[]>\n\n /** Append new turns to a session (incremental, avoids full re-save). */\n appendTurns: (sessionId: string, turns: SessionTurn[]) => Promise<void>\n\n /** Return a slice of turns for a session. */\n getTurns: (sessionId: string, from?: number, limit?: number) => Promise<SessionTurn[]>\n\n /** Persist an updated run record (called after completeRun / abortRun / errorRun). */\n updateRun: (sessionId: string, run: SessionRun) => Promise<void>\n\n /** Update the top-level status of a session. */\n updateStatus: (sessionId: string, status: SessionData['status']) => Promise<void>\n}\n\n// ---------------------------------------------------------------------------\n// Session (live instance wrapping a SessionData)\n// ---------------------------------------------------------------------------\n\nexport interface Session {\n /** Session ID */\n readonly id: string\n\n /** Agent ID (optional label) */\n readonly agentId?: string\n\n /** Current turn history */\n readonly turns: SessionTurn[]\n\n /**\n * True when this session has no turns yet.\n *\n * Use this as a first-prompt signal when setting up a run — e.g. writing initial\n * configuration only on fresh sessions. Equivalent to `turns.length === 0`.\n */\n readonly isEmpty: boolean\n\n /** Top-level session status */\n readonly status: SessionData['status']\n\n /** All runs in this session */\n readonly runs: SessionRun[]\n\n /** Arbitrary metadata */\n readonly metadata: Record<string, unknown>\n\n /**\n * Start tracking a new run. `extras.parentRunId` + `extras.depth` are\n * populated by the spawn tool when a child agent shares its parent's\n * session; regular top-level `agent.run()` calls omit them.\n */\n startRun: (runId: string, prompt?: string, extras?: { parentRunId?: string, depth?: number }) => void\n\n /** Mark a run as completed */\n completeRun: (runId: string, stats: { turns: number, tokensIn: number, tokensOut: number, turnUsage?: TurnUsage[], cost?: number }) => void\n\n /** Mark a run as aborted */\n abortRun: (runId: string) => void\n\n /** Mark a run as errored */\n errorRun: (runId: string, error: string) => void\n\n /** Append turns to in-memory history AND persist via store.appendTurns (if store present) */\n appendTurns: (turns: SessionTurn[]) => Promise<void>\n\n /** Replace all turns in-memory (does not persist — use save() for that) */\n setTurns: (turns: SessionTurn[]) => void\n\n /** Update the session status in memory AND via store.updateStatus (if store present) */\n updateStatus: (status: SessionData['status']) => Promise<void>\n\n /** Persist an updated run record via store.updateRun (if store present) */\n updateRun: (run: SessionRun) => Promise<void>\n\n /** Generate a turn ID using store.generateTurnId if available, else crypto.randomUUID() */\n generateTurnId: () => string | Promise<string>\n\n /** Set metadata key */\n setMeta: (key: string, value: unknown) => void\n\n /** Persist the full session document to the store */\n save: () => Promise<void>\n\n /** Serialize to SessionData */\n toJSON: () => SessionData\n}\n\n// ---------------------------------------------------------------------------\n// createSession\n// ---------------------------------------------------------------------------\n\nexport interface CreateSessionOptions {\n /** Session ID. If omitted and store provides generateSessionId, that is used. */\n id?: string\n /** Agent ID label */\n agentId?: string\n /** Initial metadata */\n metadata?: Record<string, unknown>\n /** Storage backend (optional, enables save/load) */\n store?: SessionStore\n // @internal: restore from existing data (bypasses id/agentId/metadata options)\n _data?: SessionData\n}\n\n/**\n * Create a new session.\n * Async so stores that generate IDs server-side (e.g. Supabase) can be supported.\n */\nexport async function createSession(options: CreateSessionOptions = {}): Promise<Session> {\n const store = options.store\n const now = Date.now()\n\n let sessionId = options.id\n if (!sessionId && store?.generateSessionId) {\n sessionId = await store.generateSessionId()\n }\n if (!sessionId) {\n sessionId = generateId()\n }\n\n const data: SessionData = options._data ?? {\n id: sessionId,\n agentId: options.agentId,\n turns: [],\n runs: [],\n status: 'idle',\n metadata: options.metadata ?? {},\n createdAt: now,\n updatedAt: now,\n }\n\n function touch() {\n data.updatedAt = Date.now()\n }\n\n function findRun(runId: string): SessionRun | undefined {\n return data.runs.find(r => r.id === runId)\n }\n\n const session: Session = {\n get id() { return data.id },\n get agentId() { return data.agentId },\n get turns() { return data.turns },\n get isEmpty() { return data.turns.length === 0 },\n get status() { return data.status },\n get runs() { return data.runs },\n get metadata() { return data.metadata },\n\n startRun(runId: string, prompt?: string, extras?: { parentRunId?: string, depth?: number }) {\n data.runs.push({\n id: runId,\n startedAt: Date.now(),\n prompt: prompt ?? '',\n status: 'running',\n ...(extras?.parentRunId ? { parentRunId: extras.parentRunId } : {}),\n ...(typeof extras?.depth === 'number' ? { depth: extras.depth } : {}),\n })\n touch()\n },\n\n completeRun(runId: string, stats: { turns: number, tokensIn: number, tokensOut: number, turnUsage?: TurnUsage[], cost?: number }) {\n const run = findRun(runId)\n if (run) {\n run.status = 'completed'\n run.endedAt = Date.now()\n run.turns = stats.turns\n run.tokensIn = stats.tokensIn\n run.tokensOut = stats.tokensOut\n if (stats.turnUsage) {\n run.turnUsage = stats.turnUsage\n const total = stats.turnUsage.reduce((acc, t) => ({\n input: acc.input + t.input,\n output: acc.output + t.output,\n cacheCreation: (acc.cacheCreation ?? 0) + (t.cacheCreation ?? 0),\n cacheRead: (acc.cacheRead ?? 0) + (t.cacheRead ?? 0),\n thinking: (acc.thinking ?? 0) + (t.thinking ?? 0),\n }), { input: 0, output: 0, cacheCreation: 0, cacheRead: 0, thinking: 0 })\n run.totalUsage = {\n input: total.input,\n output: total.output,\n ...(total.cacheCreation ? { cacheCreation: total.cacheCreation } : {}),\n ...(total.cacheRead ? { cacheRead: total.cacheRead } : {}),\n ...(total.thinking ? { thinking: total.thinking } : {}),\n }\n }\n if (stats.cost !== undefined)\n run.cost = stats.cost\n }\n touch()\n },\n\n abortRun(runId: string) {\n const run = findRun(runId)\n if (run) {\n run.status = 'aborted'\n run.endedAt = Date.now()\n }\n touch()\n },\n\n errorRun(runId: string, error: string) {\n const run = findRun(runId)\n if (run) {\n run.status = 'error'\n run.endedAt = Date.now()\n run.error = error\n }\n touch()\n },\n\n async appendTurns(turns: SessionTurn[]) {\n data.turns.push(...turns)\n touch()\n if (store) {\n await store.appendTurns(data.id, turns)\n }\n },\n\n setTurns(turns: SessionTurn[]) {\n data.turns = turns\n touch()\n },\n\n async updateStatus(status: SessionData['status']) {\n data.status = status\n touch()\n if (store) {\n await store.updateStatus(data.id, status)\n }\n },\n\n async updateRun(run: SessionRun) {\n if (store) {\n await store.updateRun(data.id, run)\n }\n },\n\n generateTurnId() {\n if (store?.generateTurnId) {\n return store.generateTurnId()\n }\n return crypto.randomUUID()\n },\n\n setMeta(key: string, value: unknown) {\n data.metadata[key] = value\n touch()\n },\n\n async save() {\n if (!store) {\n throw new Error('No SessionStore configured. Pass a store to createSession() to enable persistence.')\n }\n await store.save(data)\n },\n\n toJSON() {\n return structuredClone(data)\n },\n }\n\n return session\n}\n\n/**\n * Load an existing session from a store.\n */\nexport async function loadSession(store: SessionStore, sessionId: string): Promise<Session | null> {\n const loaded = await store.load(sessionId)\n if (!loaded)\n return null\n\n return createSession({ store, _data: loaded })\n}\n\n// ---------------------------------------------------------------------------\n// Re-export stores\n// ---------------------------------------------------------------------------\n\nexport type { FileMapAdapter, FileMapStoreOptions } from './file-map'\nexport { createMemoryStore } from './memory'\nexport { autoDetectAndConvert, fromAnthropic, fromOpenAI, toAnthropic, toOpenAI } from './messages'\nexport { createRemoteStore } from './remote'\nexport type { RemoteStoreOptions } from './remote'\n\n// NOTE: `createSqliteStore` is intentionally NOT re-exported here. It lives behind\n// the dedicated `zidane/session/sqlite` subpath so that non-Bun consumers don't\n// transitively evaluate `bun:sqlite` when they import from `zidane/session`.\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction generateId(): string {\n return `ses_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"session-B1RN0uoi.js","names":[],"sources":["../src/session/file-map.ts","../src/session/memory.ts","../src/session/remote.ts","../src/session/index.ts"],"sourcesContent":["/**\n * File-map session store.\n *\n * Wraps a narrow 3-method adapter (`get` / `save` / `delete`) that exchanges a flat\n * map of filename → string content. Useful for embedding zidane sessions inside\n * host-provided session backends that only speak in file maps (not zidane's native\n * `SessionStore` shape).\n *\n * Serialization format:\n * - `turns.jsonl` — one `SessionTurn` per line.\n * - `meta.json` — session metadata (id, agentId, status, runs, metadata, timestamps).\n *\n * JSONL for turns keeps history inspectable with tools like `jq` and resilient to\n * partial corruption — parse up to the first bad line and you still have a valid\n * prefix. Metadata lives in its own file so large turn logs don't bloat the\n * metadata path.\n *\n * Scope: each `createFileMapStore` handles a **single session** — the adapter's\n * file map holds at most one zidane session at a time. This matches how host SDKs\n * scope their session stores per conversation.\n *\n * Divergences from the built-in memory / sqlite stores:\n * - `appendTurns` / `updateStatus` / `updateRun` auto-create a minimal `SessionData`\n * record on first write, instead of silently no-oping when the session hasn't been\n * explicitly `save()`-ed. This matches the host-SDK integration path where\n * `createSession(...)` → `agent.run(...)` directly without an explicit `save()` call.\n * - `updateRun` inserts the run if not found in the cached record (rather than\n * silently dropping). Run records therefore always reach the adapter.\n */\n\nimport type { SessionData, SessionRun, SessionStore } from '.'\nimport type { SessionTurn } from '../types'\n\n/**\n * Host-provided file-map adapter. Three methods exchanging `Record<string, string>`\n * payloads — the whole persistence surface the wrapper needs.\n */\nexport interface FileMapAdapter {\n /** Load the current file map. Returns an empty `files` record when nothing is persisted. */\n get: () => Promise<{ files: Record<string, string> }>\n /** Replace the persisted file map. Full-rewrite semantics. */\n save: (files: Record<string, string>) => Promise<void>\n /** Delete all persisted state. */\n delete: () => Promise<void>\n}\n\nexport interface FileMapStoreOptions {\n /** Filename for the JSONL turns log. Default: `turns.jsonl`. */\n turnsFile?: string\n /** Filename for the metadata JSON. Default: `meta.json`. */\n metaFile?: string\n}\n\ninterface MetaShape {\n id: string\n agentId?: string\n runs: SessionRun[]\n status: SessionData['status']\n metadata: Record<string, unknown>\n createdAt: number\n updatedAt: number\n}\n\nfunction toMeta(data: SessionData): MetaShape {\n return {\n id: data.id,\n agentId: data.agentId,\n runs: data.runs,\n status: data.status,\n metadata: data.metadata,\n createdAt: data.createdAt,\n updatedAt: data.updatedAt,\n }\n}\n\nfunction toData(meta: MetaShape, turns: SessionTurn[]): SessionData {\n return {\n id: meta.id,\n agentId: meta.agentId,\n turns,\n runs: meta.runs,\n status: meta.status,\n metadata: meta.metadata,\n createdAt: meta.createdAt,\n updatedAt: meta.updatedAt,\n }\n}\n\nfunction parseTurnsJsonl(jsonl: string): SessionTurn[] {\n if (!jsonl)\n return []\n const turns: SessionTurn[] = []\n for (const line of jsonl.split('\\n')) {\n const trimmed = line.trim()\n if (!trimmed)\n continue\n try {\n turns.push(JSON.parse(trimmed) as SessionTurn)\n }\n catch {\n // Skip malformed lines — preserves the valid prefix on partial corruption.\n }\n }\n return turns\n}\n\nfunction serializeTurnsJsonl(turns: SessionTurn[]): string {\n if (turns.length === 0)\n return ''\n return `${turns.map(t => JSON.stringify(t)).join('\\n')}\\n`\n}\n\n/**\n * Create a single-session `SessionStore` backed by a file-map adapter.\n *\n * @example\n * ```ts\n * const session = await createSession({\n * store: createFileMapStore(hostSessionStore),\n * })\n * ```\n */\nexport function createFileMapStore(\n adapter: FileMapAdapter,\n options: FileMapStoreOptions = {},\n): SessionStore {\n const turnsFile = options.turnsFile ?? 'turns.jsonl'\n const metaFile = options.metaFile ?? 'meta.json'\n\n // Cached view of the persisted session. Populated lazily on first access so the\n // factory itself doesn't do I/O.\n let cached: SessionData | null = null\n let hydrated = false\n\n async function hydrate(): Promise<void> {\n if (hydrated)\n return\n const { files } = await adapter.get()\n const metaRaw = files[metaFile]\n if (metaRaw) {\n let meta: MetaShape | null = null\n try {\n meta = JSON.parse(metaRaw) as MetaShape\n }\n catch {\n meta = null\n }\n if (meta) {\n cached = toData(meta, parseTurnsJsonl(files[turnsFile] ?? ''))\n }\n }\n hydrated = true\n }\n\n async function persist(data: SessionData): Promise<void> {\n const meta = toMeta(data)\n await adapter.save({\n [metaFile]: JSON.stringify(meta, null, 2),\n [turnsFile]: serializeTurnsJsonl(data.turns),\n })\n }\n\n // Ensure `cached` exists for `sessionId`, creating a minimal record when first written.\n // Returns false when `cached` already holds a different sessionId (request ignored).\n async function ensureCachedFor(sessionId: string): Promise<boolean> {\n await hydrate()\n if (cached) {\n return cached.id === sessionId\n }\n const now = Date.now()\n cached = {\n id: sessionId,\n turns: [],\n runs: [],\n status: 'idle',\n metadata: {},\n createdAt: now,\n updatedAt: now,\n }\n hydrated = true\n return true\n }\n\n return {\n async load(sessionId: string): Promise<SessionData | null> {\n await hydrate()\n if (!cached || cached.id !== sessionId)\n return null\n return structuredClone(cached)\n },\n\n async save(data: SessionData): Promise<void> {\n cached = structuredClone(data)\n hydrated = true\n await persist(cached)\n },\n\n async delete(sessionId: string): Promise<void> {\n await hydrate()\n if (cached && cached.id !== sessionId)\n return\n cached = null\n await adapter.delete()\n },\n\n async list(filter): Promise<string[]> {\n await hydrate()\n if (!cached)\n return []\n if (filter?.agentId && cached.agentId !== filter.agentId)\n return []\n return [cached.id]\n },\n\n async appendTurns(sessionId: string, turns: SessionTurn[]): Promise<void> {\n const ok = await ensureCachedFor(sessionId)\n if (!ok)\n return\n cached!.turns.push(...structuredClone(turns))\n cached!.updatedAt = Date.now()\n await persist(cached!)\n },\n\n async getTurns(sessionId: string, from = 0, limit?: number): Promise<SessionTurn[]> {\n await hydrate()\n if (!cached || cached.id !== sessionId)\n return []\n const slice = cached.turns.slice(from, limit !== undefined ? from + limit : undefined)\n return structuredClone(slice) as SessionTurn[]\n },\n\n async updateRun(sessionId: string, run: SessionRun): Promise<void> {\n const ok = await ensureCachedFor(sessionId)\n if (!ok)\n return\n const idx = cached!.runs.findIndex(r => r.id === run.id)\n if (idx >= 0)\n cached!.runs[idx] = structuredClone(run)\n else\n cached!.runs.push(structuredClone(run))\n cached!.updatedAt = Date.now()\n await persist(cached!)\n },\n\n async updateStatus(sessionId: string, status: SessionData['status']): Promise<void> {\n const ok = await ensureCachedFor(sessionId)\n if (!ok)\n return\n cached!.status = status\n cached!.updatedAt = Date.now()\n await persist(cached!)\n },\n }\n}\n","/**\n * In-memory session store.\n * Useful for development and testing. Data is lost when the process exits.\n */\n\nimport type { SessionData, SessionRun, SessionStore } from '.'\nimport type { SessionTurn } from '../types'\n\nexport function createMemoryStore(): SessionStore {\n const sessions = new Map<string, SessionData>()\n\n return {\n async load(sessionId: string) {\n const data = sessions.get(sessionId)\n return data ? structuredClone(data) : null\n },\n\n async save(session: SessionData) {\n sessions.set(session.id, structuredClone(session))\n },\n\n async delete(sessionId: string) {\n sessions.delete(sessionId)\n },\n\n async list(filter) {\n let ids = Array.from(sessions.keys())\n if (filter?.agentId) {\n ids = ids.filter(id => sessions.get(id)?.agentId === filter.agentId)\n }\n if (filter?.limit) {\n ids = ids.slice(0, filter.limit)\n }\n return ids\n },\n\n async appendTurns(sessionId: string, turns: SessionTurn[]) {\n const data = sessions.get(sessionId)\n if (data) {\n data.turns.push(...structuredClone(turns))\n data.updatedAt = Date.now()\n }\n },\n\n async getTurns(sessionId: string, from = 0, limit?: number) {\n const data = sessions.get(sessionId)\n if (!data)\n return []\n const sliced = data.turns.slice(from, limit !== undefined ? from + limit : undefined)\n return structuredClone(sliced) as SessionTurn[]\n },\n\n async updateRun(sessionId: string, run: SessionRun) {\n const data = sessions.get(sessionId)\n if (data) {\n const idx = data.runs.findIndex(r => r.id === run.id)\n if (idx >= 0) {\n data.runs[idx] = structuredClone(run)\n }\n data.updatedAt = Date.now()\n }\n },\n\n async updateStatus(sessionId: string, status: SessionData['status']) {\n const data = sessions.get(sessionId)\n if (data) {\n data.status = status\n data.updatedAt = Date.now()\n }\n },\n }\n}\n","/**\n * Remote session store via HTTP API.\n *\n * Expects a REST API with:\n * GET {url}/sessions/{id} -> SessionData | 404\n * PUT {url}/sessions/{id} -> save SessionData\n * DELETE {url}/sessions/{id} -> delete\n * GET {url}/sessions?agentId=&limit= -> { ids: string[] }\n * POST {url}/sessions/{id}/turns -> append turns\n * GET {url}/sessions/{id}/turns?from=&limit= -> SessionTurn[]\n * PUT {url}/sessions/{id}/runs/{runId} -> update run\n * PATCH {url}/sessions/{id} -> { status }\n */\n\nimport type { SessionData, SessionRun, SessionStore } from '.'\nimport type { SessionTurn } from '../types'\n\nexport interface RemoteStoreOptions {\n /** Base URL of the session API */\n url: string\n /** Optional headers (e.g. for authentication) */\n headers?: Record<string, string>\n}\n\nconst TRAILING_SLASH = /\\/$/\n\nexport function createRemoteStore(options: RemoteStoreOptions): SessionStore {\n const baseUrl = options.url.replace(TRAILING_SLASH, '')\n const defaultHeaders: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...options.headers,\n }\n\n async function request(path: string, init?: RequestInit): Promise<Response> {\n const url = `${baseUrl}${path}`\n const res = await fetch(url, {\n ...init,\n headers: { ...defaultHeaders, ...init?.headers },\n })\n return res\n }\n\n return {\n async load(sessionId: string) {\n const res = await request(`/sessions/${encodeURIComponent(sessionId)}`)\n if (!res.ok) {\n if (res.status === 404)\n return null\n throw new Error(`Remote session load failed: ${res.status} ${res.statusText}`)\n }\n return await res.json() as SessionData\n },\n\n async save(session: SessionData) {\n const res = await request(`/sessions/${encodeURIComponent(session.id)}`, {\n method: 'PUT',\n body: JSON.stringify(session),\n })\n if (!res.ok) {\n throw new Error(`Remote session save failed: ${res.status} ${res.statusText}`)\n }\n },\n\n async delete(sessionId: string) {\n const res = await request(`/sessions/${encodeURIComponent(sessionId)}`, {\n method: 'DELETE',\n })\n if (!res.ok && res.status !== 404) {\n throw new Error(`Remote session delete failed: ${res.status} ${res.statusText}`)\n }\n },\n\n async list(filter) {\n const params = new URLSearchParams()\n if (filter?.agentId)\n params.set('agentId', filter.agentId)\n if (filter?.limit)\n params.set('limit', String(filter.limit))\n\n const query = params.toString()\n const path = query ? `/sessions?${query}` : '/sessions'\n const res = await request(path)\n\n if (!res.ok) {\n throw new Error(`Remote session list failed: ${res.status} ${res.statusText}`)\n }\n\n const body = await res.json() as { ids: string[] }\n return body.ids\n },\n\n async appendTurns(sessionId: string, turns: SessionTurn[]) {\n const res = await request(`/sessions/${encodeURIComponent(sessionId)}/turns`, {\n method: 'POST',\n body: JSON.stringify(turns),\n })\n if (!res.ok) {\n throw new Error(`Remote appendTurns failed: ${res.status} ${res.statusText}`)\n }\n },\n\n async getTurns(sessionId: string, from = 0, limit?: number) {\n const params = new URLSearchParams()\n if (from)\n params.set('from', String(from))\n if (limit !== undefined)\n params.set('limit', String(limit))\n\n const query = params.toString()\n const path = `/sessions/${encodeURIComponent(sessionId)}/turns${query ? `?${query}` : ''}`\n const res = await request(path)\n\n if (!res.ok) {\n throw new Error(`Remote getTurns failed: ${res.status} ${res.statusText}`)\n }\n\n return await res.json() as SessionTurn[]\n },\n\n async updateRun(sessionId: string, run: SessionRun) {\n const res = await request(\n `/sessions/${encodeURIComponent(sessionId)}/runs/${encodeURIComponent(run.id)}`,\n {\n method: 'PUT',\n body: JSON.stringify(run),\n },\n )\n if (!res.ok) {\n throw new Error(`Remote updateRun failed: ${res.status} ${res.statusText}`)\n }\n },\n\n async updateStatus(sessionId: string, status: SessionData['status']) {\n const res = await request(`/sessions/${encodeURIComponent(sessionId)}`, {\n method: 'PATCH',\n body: JSON.stringify({ status }),\n })\n if (!res.ok) {\n throw new Error(`Remote updateStatus failed: ${res.status} ${res.statusText}`)\n }\n },\n }\n}\n","/**\n * Session management for agents.\n *\n * A session tracks identity, turn history, and run metadata.\n * Plug in any storage backend by implementing the SessionStore interface,\n * or use one of the built-in stores: memory, sqlite, remote.\n */\n\nimport type { SessionTurn, TurnUsage } from '../types'\n\nexport type { SessionContentBlock, SessionMessage, SessionTurn } from '../types'\nexport { createFileMapStore } from './file-map'\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface SessionRun {\n id: string\n startedAt: number\n endedAt?: number\n prompt: string\n status: 'running' | 'completed' | 'aborted' | 'error'\n turns?: number\n tokensIn?: number\n tokensOut?: number\n error?: string\n /** Per-turn usage breakdown */\n turnUsage?: TurnUsage[]\n /** Total usage across all turns */\n totalUsage?: TurnUsage\n /** Estimated cost in USD */\n cost?: number\n /**\n * The run that spawned this one, when the agent is a subagent sharing its\n * parent's session. Undefined on top-level `agent.run()`. Consumers can walk\n * `runs` by `parentRunId` to reconstruct the subagent tree.\n */\n parentRunId?: string\n /**\n * Zero-based subagent depth. 0 = top-level run, 1 = direct child, …\n * Recorded here so hosts can query/filter by level without walking the tree.\n */\n depth?: number\n}\n\nexport interface SessionData {\n id: string\n agentId?: string\n turns: SessionTurn[]\n runs: SessionRun[]\n status: 'idle' | 'running' | 'completed' | 'error'\n metadata: Record<string, unknown>\n createdAt: number\n updatedAt: number\n}\n\n// ---------------------------------------------------------------------------\n// SessionStore interface (pluggable backend)\n// ---------------------------------------------------------------------------\n\nexport interface SessionStore {\n /** Optional: generate a session ID server-side (e.g. Supabase UUID). */\n generateSessionId?: () => string | Promise<string>\n\n /** Optional: generate a turn ID server-side. */\n generateTurnId?: () => string | Promise<string>\n\n /** Load a session by ID. Returns null if not found. */\n load: (sessionId: string) => Promise<SessionData | null>\n\n /** Save a session (create or update, full document). */\n save: (session: SessionData) => Promise<void>\n\n /** Delete a session. */\n delete: (sessionId: string) => Promise<void>\n\n /** List session IDs, optionally filtered. */\n list: (filter?: { agentId?: string, limit?: number }) => Promise<string[]>\n\n /** Append new turns to a session (incremental, avoids full re-save). */\n appendTurns: (sessionId: string, turns: SessionTurn[]) => Promise<void>\n\n /** Return a slice of turns for a session. */\n getTurns: (sessionId: string, from?: number, limit?: number) => Promise<SessionTurn[]>\n\n /** Persist an updated run record (called after completeRun / abortRun / errorRun). */\n updateRun: (sessionId: string, run: SessionRun) => Promise<void>\n\n /** Update the top-level status of a session. */\n updateStatus: (sessionId: string, status: SessionData['status']) => Promise<void>\n}\n\n// ---------------------------------------------------------------------------\n// Session (live instance wrapping a SessionData)\n// ---------------------------------------------------------------------------\n\nexport interface Session {\n /** Session ID */\n readonly id: string\n\n /** Agent ID (optional label) */\n readonly agentId?: string\n\n /** Current turn history */\n readonly turns: SessionTurn[]\n\n /**\n * True when this session has no turns yet.\n *\n * Use this as a first-prompt signal when setting up a run — e.g. writing initial\n * configuration only on fresh sessions. Equivalent to `turns.length === 0`.\n */\n readonly isEmpty: boolean\n\n /** Top-level session status */\n readonly status: SessionData['status']\n\n /** All runs in this session */\n readonly runs: SessionRun[]\n\n /** Arbitrary metadata */\n readonly metadata: Record<string, unknown>\n\n /**\n * Start tracking a new run. `extras.parentRunId` + `extras.depth` are\n * populated by the spawn tool when a child agent shares its parent's\n * session; regular top-level `agent.run()` calls omit them.\n */\n startRun: (runId: string, prompt?: string, extras?: { parentRunId?: string, depth?: number }) => void\n\n /** Mark a run as completed */\n completeRun: (runId: string, stats: { turns: number, tokensIn: number, tokensOut: number, turnUsage?: TurnUsage[], cost?: number }) => void\n\n /** Mark a run as aborted */\n /**\n * Optional `stats` lets the agent backfill the run's token totals when\n * the abort happened *after* the loop accumulated meaningful usage —\n * common when the user presses esc mid-streaming. Without it, the run\n * record reads `0 in / 0 out` on reload regardless of how much was\n * spent before the abort. Same shape as `completeRun`'s stats so the\n * persisted `totalUsage` aggregate stays consistent across paths.\n */\n abortRun: (runId: string, stats?: { turns: number, tokensIn: number, tokensOut: number, turnUsage?: TurnUsage[], cost?: number }) => void\n\n /** Mark a run as errored */\n /** Optional `stats` — same rationale as `abortRun.stats`. */\n errorRun: (runId: string, error: string, stats?: { turns: number, tokensIn: number, tokensOut: number, turnUsage?: TurnUsage[], cost?: number }) => void\n\n /** Append turns to in-memory history AND persist via store.appendTurns (if store present) */\n appendTurns: (turns: SessionTurn[]) => Promise<void>\n\n /** Replace all turns in-memory (does not persist — use save() for that) */\n setTurns: (turns: SessionTurn[]) => void\n\n /** Update the session status in memory AND via store.updateStatus (if store present) */\n updateStatus: (status: SessionData['status']) => Promise<void>\n\n /** Persist an updated run record via store.updateRun (if store present) */\n updateRun: (run: SessionRun) => Promise<void>\n\n /** Generate a turn ID using store.generateTurnId if available, else crypto.randomUUID() */\n generateTurnId: () => string | Promise<string>\n\n /** Set metadata key */\n setMeta: (key: string, value: unknown) => void\n\n /** Persist the full session document to the store */\n save: () => Promise<void>\n\n /** Serialize to SessionData */\n toJSON: () => SessionData\n}\n\n// ---------------------------------------------------------------------------\n// createSession\n// ---------------------------------------------------------------------------\n\nexport interface CreateSessionOptions {\n /** Session ID. If omitted and store provides generateSessionId, that is used. */\n id?: string\n /** Agent ID label */\n agentId?: string\n /** Initial metadata */\n metadata?: Record<string, unknown>\n /** Storage backend (optional, enables save/load) */\n store?: SessionStore\n // @internal: restore from existing data (bypasses id/agentId/metadata options)\n _data?: SessionData\n}\n\n/**\n * Create a new session.\n * Async so stores that generate IDs server-side (e.g. Supabase) can be supported.\n */\nexport async function createSession(options: CreateSessionOptions = {}): Promise<Session> {\n const store = options.store\n const now = Date.now()\n\n let sessionId = options.id\n if (!sessionId && store?.generateSessionId) {\n sessionId = await store.generateSessionId()\n }\n if (!sessionId) {\n sessionId = generateId()\n }\n\n const data: SessionData = options._data ?? {\n id: sessionId,\n agentId: options.agentId,\n turns: [],\n runs: [],\n status: 'idle',\n metadata: options.metadata ?? {},\n createdAt: now,\n updatedAt: now,\n }\n\n function touch() {\n data.updatedAt = Date.now()\n }\n\n function findRun(runId: string): SessionRun | undefined {\n return data.runs.find(r => r.id === runId)\n }\n\n /**\n * Apply per-run usage stats onto a SessionRun. Shared by `completeRun`,\n * `abortRun`, and `errorRun` so the on-disk shape stays consistent across\n * exit paths — historically only `completeRun` filled these in, and\n * aborted/errored runs rendered `0 in / 0 out` on reload regardless of\n * how much was actually consumed.\n */\n function applyRunStats(run: SessionRun, stats: { turns: number, tokensIn: number, tokensOut: number, turnUsage?: TurnUsage[], cost?: number }) {\n run.turns = stats.turns\n run.tokensIn = stats.tokensIn\n run.tokensOut = stats.tokensOut\n if (stats.turnUsage) {\n run.turnUsage = stats.turnUsage\n const total = stats.turnUsage.reduce((acc, t) => ({\n input: acc.input + t.input,\n output: acc.output + t.output,\n cacheCreation: (acc.cacheCreation ?? 0) + (t.cacheCreation ?? 0),\n cacheRead: (acc.cacheRead ?? 0) + (t.cacheRead ?? 0),\n thinking: (acc.thinking ?? 0) + (t.thinking ?? 0),\n }), { input: 0, output: 0, cacheCreation: 0, cacheRead: 0, thinking: 0 })\n run.totalUsage = {\n input: total.input,\n output: total.output,\n ...(total.cacheCreation ? { cacheCreation: total.cacheCreation } : {}),\n ...(total.cacheRead ? { cacheRead: total.cacheRead } : {}),\n ...(total.thinking ? { thinking: total.thinking } : {}),\n }\n }\n if (stats.cost !== undefined)\n run.cost = stats.cost\n }\n\n const session: Session = {\n get id() { return data.id },\n get agentId() { return data.agentId },\n get turns() { return data.turns },\n get isEmpty() { return data.turns.length === 0 },\n get status() { return data.status },\n get runs() { return data.runs },\n get metadata() { return data.metadata },\n\n startRun(runId: string, prompt?: string, extras?: { parentRunId?: string, depth?: number }) {\n data.runs.push({\n id: runId,\n startedAt: Date.now(),\n prompt: prompt ?? '',\n status: 'running',\n ...(extras?.parentRunId ? { parentRunId: extras.parentRunId } : {}),\n ...(typeof extras?.depth === 'number' ? { depth: extras.depth } : {}),\n })\n touch()\n },\n\n completeRun(runId: string, stats: { turns: number, tokensIn: number, tokensOut: number, turnUsage?: TurnUsage[], cost?: number }) {\n const run = findRun(runId)\n if (run) {\n run.status = 'completed'\n run.endedAt = Date.now()\n applyRunStats(run, stats)\n }\n touch()\n },\n\n abortRun(runId: string, stats?: { turns: number, tokensIn: number, tokensOut: number, turnUsage?: TurnUsage[], cost?: number }) {\n const run = findRun(runId)\n if (run) {\n run.status = 'aborted'\n run.endedAt = Date.now()\n // Backfill tokens when available so an aborted run's session\n // ledger reflects actual consumption rather than `0 in / 0 out`.\n if (stats)\n applyRunStats(run, stats)\n }\n touch()\n },\n\n errorRun(runId: string, error: string, stats?: { turns: number, tokensIn: number, tokensOut: number, turnUsage?: TurnUsage[], cost?: number }) {\n const run = findRun(runId)\n if (run) {\n run.status = 'error'\n run.endedAt = Date.now()\n run.error = error\n if (stats)\n applyRunStats(run, stats)\n }\n touch()\n },\n\n async appendTurns(turns: SessionTurn[]) {\n data.turns.push(...turns)\n touch()\n if (store) {\n await store.appendTurns(data.id, turns)\n }\n },\n\n setTurns(turns: SessionTurn[]) {\n data.turns = turns\n touch()\n },\n\n async updateStatus(status: SessionData['status']) {\n data.status = status\n touch()\n if (store) {\n await store.updateStatus(data.id, status)\n }\n },\n\n async updateRun(run: SessionRun) {\n if (store) {\n await store.updateRun(data.id, run)\n }\n },\n\n generateTurnId() {\n if (store?.generateTurnId) {\n return store.generateTurnId()\n }\n return crypto.randomUUID()\n },\n\n setMeta(key: string, value: unknown) {\n data.metadata[key] = value\n touch()\n },\n\n async save() {\n if (!store) {\n throw new Error('No SessionStore configured. Pass a store to createSession() to enable persistence.')\n }\n await store.save(data)\n },\n\n toJSON() {\n return structuredClone(data)\n },\n }\n\n return session\n}\n\n/**\n * Load an existing session from a store.\n */\nexport async function loadSession(store: SessionStore, sessionId: string): Promise<Session | null> {\n const loaded = await store.load(sessionId)\n if (!loaded)\n return null\n\n return createSession({ store, _data: loaded })\n}\n\n// ---------------------------------------------------------------------------\n// Re-export stores\n// ---------------------------------------------------------------------------\n\nexport type { FileMapAdapter, FileMapStoreOptions } from './file-map'\nexport { createMemoryStore } from './memory'\nexport { autoDetectAndConvert, fromAnthropic, fromOpenAI, toAnthropic, toOpenAI } from './messages'\nexport { createRemoteStore } from './remote'\nexport type { RemoteStoreOptions } from './remote'\n\n// NOTE: `createSqliteStore` is intentionally NOT re-exported here. It lives behind\n// the dedicated `zidane/session/sqlite` subpath so that non-Bun consumers don't\n// transitively evaluate `bun:sqlite` when they import from `zidane/session`.\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction generateId(): string {\n return `ses_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`\n}\n"],"mappings":"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"}
package/dist/session.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { At as createMemoryStore, Ct as RemoteStoreOptions, Dt as fromOpenAI, Et as fromAnthropic, F as SessionContentBlock, Mt as FileMapStoreOptions, Nt as createFileMapStore, Ot as toAnthropic, R as SessionMessage, St as loadSession, Tt as autoDetectAndConvert, _t as Session, bt as SessionStore, gt as CreateSessionOptions, jt as FileMapAdapter, kt as toOpenAI, vt as SessionData, wt as createRemoteStore, xt as createSession, yt as SessionRun, z as SessionTurn } from "./index-bgh-k8Mv.js";
1
+ import { A as loadSession, B as FileMapStoreOptions, D as SessionRun, E as SessionData, Et as SessionTurn, F as fromOpenAI, I as toAnthropic, L as toOpenAI, M as createRemoteStore, N as autoDetectAndConvert, O as SessionStore, P as fromAnthropic, R as createMemoryStore, St as SessionContentBlock, T as Session, Tt as SessionMessage, V as createFileMapStore, j as RemoteStoreOptions, k as createSession, w as CreateSessionOptions, z as FileMapAdapter } from "./agent-CMIhYhDz.js";
2
2
  export { CreateSessionOptions, FileMapAdapter, FileMapStoreOptions, RemoteStoreOptions, Session, SessionContentBlock, SessionData, SessionMessage, SessionRun, SessionStore, SessionTurn, autoDetectAndConvert, createFileMapStore, createMemoryStore, createRemoteStore, createSession, fromAnthropic, fromOpenAI, loadSession, toAnthropic, toOpenAI };
package/dist/session.js CHANGED
@@ -1,3 +1,3 @@
1
1
  import { a as toOpenAI, i as toAnthropic, n as fromAnthropic, r as fromOpenAI, t as autoDetectAndConvert } from "./messages-z5Pq20p7.js";
2
- import { a as createFileMapStore, i as createMemoryStore, n as loadSession, r as createRemoteStore, t as createSession } from "./session-Cn68UASv.js";
2
+ import { a as createFileMapStore, i as createMemoryStore, n as loadSession, r as createRemoteStore, t as createSession } from "./session-B1RN0uoi.js";
3
3
  export { autoDetectAndConvert, createFileMapStore, createMemoryStore, createRemoteStore, createSession, fromAnthropic, fromOpenAI, loadSession, toAnthropic, toOpenAI };
package/dist/skills.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import { at as ActivationVia, ct as SkillActivationState, dt as SkillConfig, ft as SkillDiagnostic, ht as SkillsConfig, lt as SkillActivationStateOptions, mt as SkillSource, ot as ActiveSkill, pt as SkillResource, st as DeactivationReason, ut as createSkillActivationState } from "./index-bgh-k8Mv.js";
2
- import { S as installAllowedToolsGate, _ as inferSource, a as SkillValidationResult, b as buildCatalog, c as parseAllowedToolPattern, d as validateSkillName, f as resolveSkills, g as getDefaultScanPaths, h as discoverSkills, i as SkillValidationIssue, l as validateResourcePath, m as SourcedScanPath, n as writeSkillToDisk, o as isToolAllowedByUnion, p as interpolateShellCommands, r as writeSkillsToDisk, s as matchesAllowedTool, t as defineSkill, u as validateSkillForWrite, v as parseFrontmatter, x as IMPLICITLY_ALLOWED_SKILL_TOOLS, y as parseSkillFile } from "./index-Ds5YpvfZ.js";
1
+ import { C as SkillsConfig, S as SkillSource, a as ActivationVia, b as SkillDiagnostic, c as SkillActivationState, l as SkillActivationStateOptions, o as ActiveSkill, s as DeactivationReason, u as createSkillActivationState, x as SkillResource, y as SkillConfig } from "./agent-CMIhYhDz.js";
2
+ import { S as installAllowedToolsGate, _ as inferSource, a as SkillValidationResult, b as buildCatalog, c as parseAllowedToolPattern, d as validateSkillName, f as resolveSkills, g as getDefaultScanPaths, h as discoverSkills, i as SkillValidationIssue, l as validateResourcePath, m as SourcedScanPath, n as writeSkillToDisk, o as isToolAllowedByUnion, p as interpolateShellCommands, r as writeSkillsToDisk, s as matchesAllowedTool, t as defineSkill, u as validateSkillForWrite, v as parseFrontmatter, x as IMPLICITLY_ALLOWED_SKILL_TOOLS, y as parseSkillFile } from "./index-D6Dd6Kc0.js";
3
3
  export { ActivationVia, ActiveSkill, DeactivationReason, IMPLICITLY_ALLOWED_SKILL_TOOLS, SkillActivationState, SkillActivationStateOptions, SkillConfig, SkillDiagnostic, SkillResource, SkillSource, SkillValidationIssue, SkillValidationResult, SkillsConfig, SourcedScanPath, buildCatalog, createSkillActivationState, defineSkill, discoverSkills, getDefaultScanPaths, inferSource, installAllowedToolsGate, interpolateShellCommands, isToolAllowedByUnion, matchesAllowedTool, parseAllowedToolPattern, parseFrontmatter, parseSkillFile, resolveSkills, validateResourcePath, validateSkillForWrite, validateSkillName, writeSkillToDisk, writeSkillsToDisk };
package/dist/skills.js CHANGED
@@ -1,4 +1,4 @@
1
- import { _ as validateResourcePath, a as discoverSkills, b as createSkillActivationState, c as parseFrontmatter, f as IMPLICITLY_ALLOWED_SKILL_TOOLS, g as parseAllowedToolPattern, h as matchesAllowedTool, i as writeSkillsToDisk, l as parseSkillFile, m as isToolAllowedByUnion, n as resolveSkills, o as getDefaultScanPaths, p as installAllowedToolsGate, r as writeSkillToDisk, s as inferSource, t as interpolateShellCommands, u as buildCatalog, v as validateSkillForWrite, y as validateSkillName } from "./interpolate-CukJwP2G.js";
1
+ import { _ as validateResourcePath, a as discoverSkills, b as createSkillActivationState, c as parseFrontmatter, f as IMPLICITLY_ALLOWED_SKILL_TOOLS, g as parseAllowedToolPattern, h as matchesAllowedTool, i as writeSkillsToDisk, l as parseSkillFile, m as isToolAllowedByUnion, n as resolveSkills, o as getDefaultScanPaths, p as installAllowedToolsGate, r as writeSkillToDisk, s as inferSource, t as interpolateShellCommands, u as buildCatalog, v as validateSkillForWrite, y as validateSkillName } from "./interpolate-BydkV1eT.js";
2
2
  //#region src/skills/index.ts
3
3
  /**
4
4
  * Define an inline skill configuration.
@@ -1,10 +1,20 @@
1
1
  //#region src/stats.ts
2
+ /**
3
+ * Clamp to a non-negative finite integer. Used to defend display logic
4
+ * against providers that report `NaN`, `Infinity`, or negatives in their
5
+ * usage payloads — the rendered string stays readable instead of leaking
6
+ * `NaN`s into the footer / spawn-end markers.
7
+ */
8
+ function safeNumber(n) {
9
+ if (typeof n !== "number" || !Number.isFinite(n) || n < 0) return 0;
10
+ return n;
11
+ }
2
12
  function normalize(stats) {
3
13
  return {
4
- input: stats.totalIn ?? 0,
5
- output: stats.totalOut ?? 0,
6
- cacheRead: stats.totalCacheRead ?? 0,
7
- cacheCreation: stats.totalCacheCreation ?? 0
14
+ input: safeNumber(stats.totalIn),
15
+ output: safeNumber(stats.totalOut),
16
+ cacheRead: safeNumber(stats.totalCacheRead),
17
+ cacheCreation: safeNumber(stats.totalCacheCreation)
8
18
  };
9
19
  }
10
20
  /**
@@ -87,4 +97,4 @@ function statsByModel(stats) {
87
97
  //#endregion
88
98
  export { formatTokenUsage as n, statsByModel as r, flattenTurns as t };
89
99
 
90
- //# sourceMappingURL=stats-BT9l57RS.js.map
100
+ //# sourceMappingURL=stats-DZIsGqzu.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats-DZIsGqzu.js","names":[],"sources":["../src/stats.ts"],"sourcesContent":["/**\n * Pure derivations over `AgentStats`.\n *\n * Both helpers are tree-shakeable — import only what you need. They never\n * touch agent state, never do I/O, and always operate on the recursive\n * `AgentStats` tree returned by `agent.run()`.\n */\n\nimport type { AgentStats, TurnUsage } from './types'\n\n/**\n * Per-model usage rollup produced by {@link statsByModel}.\n *\n * `turns` counts the number of `TurnUsage` entries attributed to the model\n * across the whole tree (parent loop + every recursively-spawned child).\n * Cache and cost numbers are summed from the same set of turns.\n */\nexport interface ModelUsage {\n input: number\n output: number\n cost: number\n cacheRead: number\n cacheCreation: number\n turns: number\n}\n\n/**\n * Common shape for token-usage helpers. Mirrors `AgentStats`'s cumulative\n * fields. Callers working with `TurnUsage` / `SessionRun.totalUsage`\n * (`input` / `output` / `cacheRead` / `cacheCreation`) map their fields in\n * at the call site — we don't accept both shapes here because\n * `AgentStats.output` is a structured-output payload (`Record<string,\n * unknown>`), not a token count, so the field name `output` is ambiguous.\n */\nexport interface TokenUsageLike {\n totalIn?: number\n totalOut?: number\n totalCacheRead?: number\n totalCacheCreation?: number\n}\n\n/**\n * Clamp to a non-negative finite integer. Used to defend display logic\n * against providers that report `NaN`, `Infinity`, or negatives in their\n * usage payloads — the rendered string stays readable instead of leaking\n * `NaN`s into the footer / spawn-end markers.\n */\nfunction safeNumber(n: number | undefined): number {\n if (typeof n !== 'number' || !Number.isFinite(n) || n < 0)\n return 0\n return n\n}\n\nfunction normalize(stats: TokenUsageLike): {\n input: number\n output: number\n cacheRead: number\n cacheCreation: number\n} {\n return {\n input: safeNumber(stats.totalIn),\n output: safeNumber(stats.totalOut),\n cacheRead: safeNumber(stats.totalCacheRead),\n cacheCreation: safeNumber(stats.totalCacheCreation),\n }\n}\n\n/**\n * Sum of `input + cacheRead + cacheCreation` — i.e. the number of tokens the\n * model actually saw, regardless of how they were billed.\n *\n * With provider prompt caching (Anthropic, OpenRouter→Anthropic, Gemini),\n * `AgentStats.totalIn` only counts **new uncached** tokens per turn; the\n * bulk of an N-turn run's context lives in `totalCacheRead`, plus a smaller\n * `totalCacheCreation` chunk for whichever turns added new breakpoints.\n * Showing only `totalIn` in a per-run summary makes long subagent runs look\n * suspiciously cheap (e.g. \"13 in\" for 8 turns over a large repo).\n *\n * `TurnUsage` / `SessionRun.totalUsage` callers map their fields to the\n * `total*` names at the call site (see {@link TokenUsageLike}).\n */\nexport function effectiveInputTokens(stats: TokenUsageLike): number {\n const { input, cacheRead, cacheCreation } = normalize(stats)\n return input + cacheRead + cacheCreation\n}\n\n/**\n * Render a one-line token summary suitable for spawn-end markers, child\n * tool-result text, and any other per-run \"what did this cost?\" surface.\n *\n * `in 52413 (cache 50000) / 4075 out`\n *\n * The `in` total includes cached reads and cache-creation tokens (see\n * {@link effectiveInputTokens}); the `(cache N)` parenthetical breaks out\n * the cached portion so the user can tell at a glance how much was reused\n * vs new. The parenthetical is omitted when its value is zero, so\n * non-caching providers and brand-new runs read simply as `in N / M out`.\n *\n * Output-side caching is not a concept any current provider exposes —\n * Anthropic's `cacheRead` / `cacheCreation` are both input-billed. If a\n * future provider ships an output cache, extend `TokenUsageLike` with\n * output-cache fields and add a parallel `(cache N)` slot on the `out`\n * side here; today the right side is always plain `${N} out`.\n */\nexport function formatTokenUsage(stats: TokenUsageLike): string {\n const { input, output, cacheRead, cacheCreation } = normalize(stats)\n const inputTotal = input + cacheRead + cacheCreation\n const inputCache = cacheRead + cacheCreation\n const inPart = inputCache > 0\n ? `in ${inputTotal} (cache ${inputCache})`\n : `in ${inputTotal}`\n return `${inPart} / ${output} out`\n}\n\n/**\n * Depth-first walk over the stats tree, returning every `TurnUsage` entry\n * — parent loop first, then each child subtree in completion order.\n *\n * Closes the cache-token aggregation gap: `TurnUsage.cacheRead` /\n * `cacheCreation` live only on per-turn entries, and the top-level\n * `AgentStats` deliberately doesn't carry cumulative forms (one source of\n * truth, no risk of drift). Anything that needs a tree-wide sum walks\n * through this.\n */\nexport function flattenTurns(stats: AgentStats): TurnUsage[] {\n const out: TurnUsage[] = []\n collectTurns(stats, out)\n return out\n}\n\nfunction collectTurns(stats: AgentStats, out: TurnUsage[]): void {\n if (stats.turnUsage)\n out.push(...stats.turnUsage)\n if (stats.children) {\n for (const child of stats.children)\n collectTurns(child.stats, out)\n }\n}\n\n/**\n * Group cumulative usage by `TurnUsage.modelId`. Each entry sums the input,\n * output, cache, cost, and turn-count across every turn the tree attributed\n * to that model — naturally handling cross-model runs (vision-fallback,\n * model-shifted subagents, mixed-provider workflows).\n *\n * Turns missing `modelId` (mock providers, providers that don't echo a model\n * id) are bucketed under the literal string `'(unknown)'`.\n */\nexport function statsByModel(stats: AgentStats): Map<string, ModelUsage> {\n const out = new Map<string, ModelUsage>()\n for (const turn of flattenTurns(stats)) {\n const key = turn.modelId ?? '(unknown)'\n let entry = out.get(key)\n if (!entry) {\n entry = { input: 0, output: 0, cost: 0, cacheRead: 0, cacheCreation: 0, turns: 0 }\n out.set(key, entry)\n }\n entry.input += turn.input\n entry.output += turn.output\n entry.cost += turn.cost ?? 0\n entry.cacheRead += turn.cacheRead ?? 0\n entry.cacheCreation += turn.cacheCreation ?? 0\n entry.turns += 1\n }\n return out\n}\n"],"mappings":";;;;;;;AA+CA,SAAS,WAAW,GAA+B;CACjD,IAAI,OAAO,MAAM,YAAY,CAAC,OAAO,SAAS,EAAE,IAAI,IAAI,GACtD,OAAO;CACT,OAAO;;AAGT,SAAS,UAAU,OAKjB;CACA,OAAO;EACL,OAAO,WAAW,MAAM,QAAQ;EAChC,QAAQ,WAAW,MAAM,SAAS;EAClC,WAAW,WAAW,MAAM,eAAe;EAC3C,eAAe,WAAW,MAAM,mBAAmB;EACpD;;;;;;;;;;;;;;;;;;;;AAwCH,SAAgB,iBAAiB,OAA+B;CAC9D,MAAM,EAAE,OAAO,QAAQ,WAAW,kBAAkB,UAAU,MAAM;CACpE,MAAM,aAAa,QAAQ,YAAY;CACvC,MAAM,aAAa,YAAY;CAI/B,OAAO,GAHQ,aAAa,IACxB,MAAM,WAAW,UAAU,WAAW,KACtC,MAAM,aACO,KAAK,OAAO;;;;;;;;;;;;AAa/B,SAAgB,aAAa,OAAgC;CAC3D,MAAM,MAAmB,EAAE;CAC3B,aAAa,OAAO,IAAI;CACxB,OAAO;;AAGT,SAAS,aAAa,OAAmB,KAAwB;CAC/D,IAAI,MAAM,WACR,IAAI,KAAK,GAAG,MAAM,UAAU;CAC9B,IAAI,MAAM,UACR,KAAK,MAAM,SAAS,MAAM,UACxB,aAAa,MAAM,OAAO,IAAI;;;;;;;;;;;AAapC,SAAgB,aAAa,OAA4C;CACvE,MAAM,sBAAM,IAAI,KAAyB;CACzC,KAAK,MAAM,QAAQ,aAAa,MAAM,EAAE;EACtC,MAAM,MAAM,KAAK,WAAW;EAC5B,IAAI,QAAQ,IAAI,IAAI,IAAI;EACxB,IAAI,CAAC,OAAO;GACV,QAAQ;IAAE,OAAO;IAAG,QAAQ;IAAG,MAAM;IAAG,WAAW;IAAG,eAAe;IAAG,OAAO;IAAG;GAClF,IAAI,IAAI,KAAK,MAAM;;EAErB,MAAM,SAAS,KAAK;EACpB,MAAM,UAAU,KAAK;EACrB,MAAM,QAAQ,KAAK,QAAQ;EAC3B,MAAM,aAAa,KAAK,aAAa;EACrC,MAAM,iBAAiB,KAAK,iBAAiB;EAC7C,MAAM,SAAS;;CAEjB,OAAO"}
@@ -1,8 +1,70 @@
1
- import { G as ToolResultContent, bt as SessionStore, t as Provider, yt as SessionRun, z as SessionTurn } from "./index-bgh-k8Mv.js";
2
- import { t as Preset } from "./index-DRoG_udt.js";
1
+ import { D as SessionRun, Et as SessionTurn, H as Provider, Mt as ToolResultContent, O as SessionStore } from "./agent-CMIhYhDz.js";
2
+ import { t as Preset } from "./index-DAaKyadO.js";
3
3
  import { OAuthProviderInterface } from "@mariozechner/pi-ai/oauth";
4
4
  import { ReactNode } from "react";
5
+ import * as _$react_jsx_runtime0 from "react/jsx-runtime";
5
6
 
7
+ //#region src/chat/agents.d.ts
8
+ /**
9
+ * Theme color token used to accent the active profile in the UI (footer
10
+ * badge, picker highlight). Resolved against `ThemeColors` via
11
+ * `useColors()`; falls back to `accent` when omitted.
12
+ */
13
+ type AgentAccent = 'brand' | 'accent' | 'warn' | 'model';
14
+ interface AgentProfile {
15
+ /** Stable identifier persisted in `TuiState.lastAgent` and shown in keybindings. */
16
+ id: string;
17
+ /** Human-readable label rendered in the picker and footer badge. */
18
+ label: string;
19
+ /** One-line description shown next to the label in the picker. */
20
+ description: string;
21
+ /**
22
+ * Preset applied to `createAgent()` when this profile is active. Profiles
23
+ * are self-contained: the host's chat-level `preset` (if any) is NOT
24
+ * merged underneath. Hosts that want a shared base across profiles
25
+ * should compose it explicitly in each profile's preset.
26
+ */
27
+ preset: Preset;
28
+ /** Theme token used by the picker / footer badge. Defaults to `'accent'`. */
29
+ accent?: AgentAccent;
30
+ }
31
+ type AgentRegistry = Readonly<Record<string, AgentProfile>>;
32
+ /**
33
+ * Build agent — the default profile. Full read/write/shell access plus
34
+ * subagent spawning. Mirrors the legacy `basic` preset so existing TUI
35
+ * behavior is preserved when `agents` is omitted.
36
+ */
37
+ declare const BUILD_AGENT: AgentProfile;
38
+ /**
39
+ * Plan agent — read-only exploration mode. Locked down to file reading and
40
+ * codebase search; no shell, no edits, no spawning. The system prompt
41
+ * frames the conversation as planning rather than execution so the model
42
+ * outputs proposals instead of attempting mutations.
43
+ */
44
+ declare const PLAN_AGENT: AgentProfile;
45
+ /**
46
+ * Default registry shipped with `zidane/tui`. Insertion order = picker order.
47
+ * Hosts that want only one profile can pass `{ agents: { build: BUILD_AGENT } }`,
48
+ * or a fully custom registry of their own profiles.
49
+ */
50
+ declare const BUILTIN_AGENTS: AgentRegistry;
51
+ /** Id of the profile activated on first launch when nothing is persisted. */
52
+ declare const DEFAULT_AGENT_ID = "build";
53
+ /**
54
+ * Resolve an agent id against a registry with sensible fallbacks: the
55
+ * requested id wins when present, then `defaultId`, then the first key.
56
+ * Returns `null` when the registry is empty (host misconfiguration —
57
+ * the caller should surface this rather than silently failing).
58
+ */
59
+ declare function resolveAgentId(registry: AgentRegistry, requestedId: string | undefined, defaultId: string | undefined): string | null;
60
+ /**
61
+ * Wrap a legacy single `Preset` into a single-profile registry. Used by
62
+ * `resolveConfig` when the host passed `preset` without `agents`, so older
63
+ * call sites keep working — they get a one-entry registry whose picker is
64
+ * a no-op (only one option).
65
+ */
66
+ declare function singleAgentRegistry(preset: Preset): AgentRegistry;
67
+ //#endregion
6
68
  //#region src/chat/providers.d.ts
7
69
  /**
8
70
  * Structural model metadata — compatible with pi-ai's `Model` interface but
@@ -229,12 +291,18 @@ interface Settings {
229
291
  }
230
292
  //#endregion
231
293
  //#region src/chat/store.d.ts
232
- declare function createTuiStore(dbPath: string): SessionStore;
233
294
  interface TuiState {
234
295
  lastProvider?: ProviderKey;
235
296
  lastSessionId?: string;
236
297
  /** Per-provider last-used model id. */
237
298
  lastModelByProvider?: Partial<Record<ProviderKey, string>>;
299
+ /**
300
+ * Last-active agent profile id (see {@link AgentRegistry}). Resumed on
301
+ * launch so a returning user lands back in the same mode (Build / Plan /
302
+ * a host profile). Falls back to the host's `defaultAgent` then the first
303
+ * registry key if the id is no longer registered.
304
+ */
305
+ lastAgent?: string;
238
306
  /** User-toggled transcript filters. Persisted so they outlive a launch. */
239
307
  settings?: Partial<Settings>;
240
308
  }
@@ -249,6 +317,11 @@ declare function saveState(path: string, state: TuiState): void;
249
317
  * Load every session and project it to the compact `SessionMeta` shape used by
250
318
  * the picker. Sorted by recency via the underlying store's `list()` contract
251
319
  * (sqlite store returns by `updated_at DESC`).
320
+ *
321
+ * Robust to per-row failures: `Promise.allSettled` so a single corrupt or
322
+ * unreadable row (malformed JSON, partial write, transient I/O error)
323
+ * doesn't take down the entire picker. Failed rows are silently skipped;
324
+ * a stderr line is emitted under `ZIDANE_DEBUG` for diagnosis.
252
325
  */
253
326
  declare function listSessionMeta(store: SessionStore): Promise<SessionMeta[]>;
254
327
  /** Derive a short title from the first user message — returns null when empty. */
@@ -291,7 +364,19 @@ declare function toolResultText(output: string | ToolResultContent[]): string;
291
364
  */
292
365
  declare function stripSpawnTokensLine(text: string): string;
293
366
  /** Effective context size of the most recent assistant turn — drives the footer indicator. */
294
- declare function lastContextSizeFromTurns(turns: SessionTurn[]): number;
367
+ /**
368
+ * Walk from the end of `turns` and return the cache-aware input-token total
369
+ * of the most recent **parent** (depth-0) assistant turn. Subagent turns
370
+ * are skipped because their context window is the child's, not the parent's
371
+ * — surfacing a subagent's `usage.input` as the footer's "context used"
372
+ * after a session ends mid-spawn would be misleading. The next prompt
373
+ * feeds the parent, so the parent's last view is what matters.
374
+ *
375
+ * `runs` is optional for backwards compatibility (older call sites and
376
+ * tests that don't have ancestry info). Without it, this falls back to the
377
+ * pre-fix behavior — depth is unknown so every assistant turn qualifies.
378
+ */
379
+ declare function lastContextSizeFromTurns(turns: SessionTurn[], runs?: readonly SessionRun[]): number;
295
380
  //#endregion
296
381
  //#region src/chat/config.d.ts
297
382
  /**
@@ -331,14 +416,57 @@ interface ChatOptions {
331
416
  */
332
417
  providers?: ProviderRegistry;
333
418
  /**
334
- * Agent preset (tools, system prompt, behavior). Default: `basic`.
419
+ * Legacy single-agent preset (tools, system prompt, behavior). When set
420
+ * **without** {@link ChatOptions.agents}, the resolver wraps this preset
421
+ * into a one-entry {@link AgentRegistry} keyed `default` so existing
422
+ * callers keep working and the picker is effectively hidden.
423
+ *
424
+ * Prefer `agents` for any multi-profile setup. Passing both throws.
335
425
  */
336
426
  preset?: Preset;
337
427
  /**
338
- * Bring your own session store. Default: a SQLite store at
339
- * `<storageDir>/<prefix>/sessions.db`.
428
+ * Agent profile registry keyed by `profile.id`. Each profile bundles a
429
+ * preset with display metadata (label, description, accent). The TUI
430
+ * shows a picker (Ctrl+A) when more than one profile is registered.
431
+ *
432
+ * - Omitted (and `preset` omitted) → {@link BUILTIN_AGENTS} (Build + Plan).
433
+ * - Omitted but `preset` provided → single-entry registry around the preset.
434
+ * - Provided → host owns the registry; pass exactly what you want.
435
+ *
436
+ * Hosts mixing built-ins with their own typically spread:
437
+ * `agents: { ...BUILTIN_AGENTS, debug: myDebugProfile }`.
438
+ */
439
+ agents?: AgentRegistry;
440
+ /**
441
+ * Id of the profile activated on first launch. Resolved against `agents`;
442
+ * unknown ids fall through to the registry's first key. Persisted
443
+ * `state.lastAgent` overrides this on subsequent launches.
444
+ */
445
+ defaultAgent?: string;
446
+ /**
447
+ * Session store — either an instance or a factory called with the
448
+ * resolved storage paths. **Required** at the chat layer so this module
449
+ * stays platform-agnostic (no `bun:sqlite` baked in). Terminal hosts use
450
+ * `createTuiStore` from `zidane/session/sqlite`; a future GUI host can
451
+ * supply a different adapter (IndexedDB, remote API, in-memory) without
452
+ * touching this layer.
453
+ *
454
+ * ```ts
455
+ * import { createTuiStore } from 'zidane/session/sqlite'
456
+ *
457
+ * // Either pass a factory…
458
+ * resolveConfig({ store: paths => createTuiStore(paths.db) })
459
+ *
460
+ * // …or an instance built ahead of time.
461
+ * const store = createTuiStore('/path/to/sessions.db')
462
+ * resolveConfig({ store })
463
+ * ```
340
464
  */
341
- store?: SessionStore;
465
+ store: SessionStore | ((paths: {
466
+ dir: string;
467
+ db: string;
468
+ state: string;
469
+ }) => SessionStore);
342
470
  }
343
471
  interface ResolvedConfig {
344
472
  prefix: string;
@@ -349,7 +477,13 @@ interface ResolvedConfig {
349
477
  state: string;
350
478
  };
351
479
  providers: ProviderRegistry;
352
- preset: Preset;
480
+ /**
481
+ * Resolved profile registry. Always non-empty; the resolver throws when
482
+ * the host passes an empty `agents` map (same contract as `providers`).
483
+ */
484
+ agents: AgentRegistry;
485
+ /** Id of the profile to activate on mount. Guaranteed to key into `agents`. */
486
+ initialAgentId: string;
353
487
  store: SessionStore;
354
488
  stateStore: StateStoreApi;
355
489
  /** Lookup by `ProviderKey` returning the available models for the picker. */
@@ -360,7 +494,7 @@ interface ResolvedConfig {
360
494
  initialPicked: Picked | null;
361
495
  }
362
496
  /** Resolve user options into a fully-bound runtime config. Pure aside from disk reads. */
363
- declare function resolveConfig(options?: ChatOptions): ResolvedConfig;
497
+ declare function resolveConfig(options: ChatOptions): ResolvedConfig;
364
498
  //#endregion
365
499
  //#region src/chat/safe-mode-context.d.ts
366
500
  type ApprovalDecision = 'accept-once' | 'accept-safelist' | 'deny';
@@ -388,7 +522,7 @@ declare function SafeModeProvider({
388
522
  children
389
523
  }: {
390
524
  children: ReactNode;
391
- }): ReactNode;
525
+ }): _$react_jsx_runtime0.JSX.Element;
392
526
  declare function useSafeModeQueue(): readonly ApprovalRequest[];
393
527
  declare function useSafeModeActions(): SafeModeActions;
394
528
  //#endregion
@@ -499,5 +633,5 @@ declare const BUILTIN_THEMES: Readonly<Record<string, Theme>>;
499
633
  /** Resolve a theme id to its full `Theme`, falling back to default on unknown ids. */
500
634
  declare function resolveTheme(id: string | undefined): Theme;
501
635
  //#endregion
502
- export { openrouterDescriptor as $, stripSpawnTokensLine as A, AuthMethod as B, createStateStore as C, listSessionMeta as D, lastContextSizeFromTurns as E, Picked as F, ModelInfo as G, ProviderKey as H, Screen as I, cerebrasDescriptor as J, ProviderDescriptor as K, SessionMeta as L, toolCallPreview as M, toolResultText as N, loadState as O, Owner as P, openaiDescriptor as Q, Settings as R, TuiState as S, eventsFromTurns as T, detectAuth as U, ProviderAuth as V, BUILTIN_PROVIDERS as W, getContextWindow as X, credKeyOf as Y, modelsForDescriptor as Z, ChatOptions as _, Theme as a, resolveConfig as b, ThemeSurfaces as c, ApprovalRequest as d, piIdOf as et, RequestApproval as f, useSafeModeQueue as g, useSafeModeActions as h, SyntaxTokenStyle as i, titleFromTurns as j, saveState as k, resolveTheme as l, SafeModeProvider as m, DEFAULT_THEME as n, ThemeColors as o, SafeModeActions as p, anthropicDescriptor as q, SyntaxStyles as r, ThemeSelect as s, BUILTIN_THEMES as t, ApprovalDecision as u, ProviderRegistry as v, createTuiStore as w, StateStoreApi as x, ResolvedConfig as y, StreamEvent as z };
503
- //# sourceMappingURL=theme-BlXO6yHe.d.ts.map
636
+ export { piIdOf as $, titleFromTurns as A, ProviderAuth as B, createStateStore as C, loadState as D, listSessionMeta as E, Screen as F, ProviderDescriptor as G, detectAuth as H, SessionMeta as I, credKeyOf as J, anthropicDescriptor as K, Settings as L, toolResultText as M, Owner as N, saveState as O, Picked as P, openrouterDescriptor as Q, StreamEvent as R, TuiState as S, lastContextSizeFromTurns as T, BUILTIN_PROVIDERS as U, ProviderKey as V, ModelInfo as W, modelsForDescriptor as X, getContextWindow as Y, openaiDescriptor as Z, ChatOptions as _, Theme as a, DEFAULT_AGENT_ID as at, resolveConfig as b, ThemeSurfaces as c, singleAgentRegistry as ct, ApprovalRequest as d, AgentAccent as et, RequestApproval as f, useSafeModeQueue as g, useSafeModeActions as h, SyntaxTokenStyle as i, BUILTIN_AGENTS as it, toolCallPreview as j, stripSpawnTokensLine as k, resolveTheme as l, SafeModeProvider as m, DEFAULT_THEME as n, AgentRegistry as nt, ThemeColors as o, PLAN_AGENT as ot, SafeModeActions as p, cerebrasDescriptor as q, SyntaxStyles as r, BUILD_AGENT as rt, ThemeSelect as s, resolveAgentId as st, BUILTIN_THEMES as t, AgentProfile as tt, ApprovalDecision as u, ProviderRegistry as v, eventsFromTurns as w, StateStoreApi as x, ResolvedConfig as y, AuthMethod as z };
637
+ //# sourceMappingURL=theme-Caf4AvTO.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme-Caf4AvTO.d.ts","names":[],"sources":["../src/chat/agents.ts","../src/chat/providers.ts","../src/chat/auth.ts","../src/chat/types.ts","../src/chat/store.ts","../src/chat/config.ts","../src/chat/safe-mode-context.tsx","../src/chat/theme.ts"],"mappings":"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"}