zidane 4.1.9 → 5.0.0
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.
- package/README.md +11 -2
- package/dist/{agent-CMIhYhDz.d.ts → agent-JhicgLOV.d.ts} +78 -4
- package/dist/agent-JhicgLOV.d.ts.map +1 -0
- package/dist/chat.d.ts +336 -6
- package/dist/chat.d.ts.map +1 -1
- package/dist/chat.js +2 -2
- package/dist/{index-DAaKyadO.d.ts → index-2yLUyTbc.d.ts} +34 -4
- package/dist/{index-DAaKyadO.d.ts.map → index-2yLUyTbc.d.ts.map} +1 -1
- package/dist/{index-D6Dd6Kc0.d.ts → index-t_W9i7Ql.d.ts} +8 -3
- package/dist/index-t_W9i7Ql.d.ts.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -4
- package/dist/{interpolate-BydkV1eT.js → interpolate-Ck970-61.js} +9 -2
- package/dist/{interpolate-BydkV1eT.js.map → interpolate-Ck970-61.js.map} +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/presets-BRFH2qsQ.js +90 -0
- package/dist/presets-BRFH2qsQ.js.map +1 -0
- package/dist/presets.d.ts +3 -2
- package/dist/presets.js +2 -2
- package/dist/providers.d.ts +1 -1
- package/dist/session/sqlite.d.ts +1 -1
- package/dist/session/sqlite.d.ts.map +1 -1
- package/dist/session/sqlite.js +28 -13
- package/dist/session/sqlite.js.map +1 -1
- package/dist/{session-B1RN0uoi.js → session-791hhrFa.js} +24 -1
- package/dist/session-791hhrFa.js.map +1 -0
- package/dist/session.d.ts +1 -1
- package/dist/session.js +1 -1
- package/dist/skills.d.ts +2 -2
- package/dist/skills.js +1 -1
- package/dist/theme-pJv47erq.d.ts +1202 -0
- package/dist/theme-pJv47erq.d.ts.map +1 -0
- package/dist/{tools-BdQENveS.js → tools-CLazLRb4.js} +81 -21
- package/dist/tools-CLazLRb4.js.map +1 -0
- package/dist/tools.d.ts +2 -2
- package/dist/tools.js +1 -1
- package/dist/tui.d.ts +258 -30
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +2957 -499
- package/dist/tui.js.map +1 -1
- package/dist/turn-operations-5aQu4dJg.js +3587 -0
- package/dist/turn-operations-5aQu4dJg.js.map +1 -0
- package/dist/types.d.ts +2 -2
- package/package.json +1 -1
- package/dist/agent-CMIhYhDz.d.ts.map +0 -1
- package/dist/index-D6Dd6Kc0.d.ts.map +0 -1
- package/dist/presets-4zCJzCYw.js +0 -39
- package/dist/presets-4zCJzCYw.js.map +0 -1
- package/dist/session-B1RN0uoi.js.map +0 -1
- package/dist/theme-Caf4AvTO.d.ts +0 -637
- package/dist/theme-Caf4AvTO.d.ts.map +0 -1
- package/dist/theme-context-DQM2lx4U.js +0 -1853
- package/dist/theme-context-DQM2lx4U.js.map +0 -1
- package/dist/tools-BdQENveS.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sqlite.js","names":[],"sources":["../../src/session/sqlite.ts"],"sourcesContent":["/**\n * SQLite session store using Bun's built-in bun:sqlite.\n *\n * Concurrency model\n * -----------------\n * Mutating methods (`appendTurns`, `updateRun`, `updateStatus`) read the\n * existing row, mutate the parsed `SessionData`, and write it back. Under\n * `maxConcurrent > 1` spawns with `persist: true` two child runs can fire\n * `tool-results:after` on the same session at the same time — both reading\n * version N, both writing N+1, last writer silently clobbering the other.\n *\n * Every mutation here therefore runs inside a `BEGIN IMMEDIATE` transaction\n * via `bun:sqlite`'s `db.transaction(fn).immediate(args)` API. IMMEDIATE\n * acquires the database-level write lock at `BEGIN` time, so the second\n * writer blocks on `BEGIN IMMEDIATE` until the first commits — guaranteeing\n * its `SELECT` sees the freshly-written row.\n *\n * Schema versioning\n * -----------------\n * `PRAGMA user_version` is the canonical place to store schema version in\n * SQLite. `SCHEMA_VERSION` below is bumped whenever the on-disk shape of\n * `SessionData` changes in a way readers need to know about. The constructor\n * runs forward migrations; older databases get upgraded in place. Readers\n * still defensively fall back to `?? 0` etc. since the JSON blob is the\n * authoritative shape — `user_version` is for observability + future\n * structural migrations.\n */\n\nimport type { SessionData, SessionRun, SessionStore } from '.'\nimport type { SessionTurn } from '../types'\nimport { existsSync, mkdirSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { Database } from 'bun:sqlite'\n\n/**\n * Current on-disk schema revision for the SQLite session store.\n *\n * 1 — initial schema (sessions table, no version pragma)\n * 2 — `parentRunId` / `depth` on runs; cache-aware `totalUsage`\n * fields; cache-aware token rendering. Pre-2 rows load via\n * defensive `?? 0` fallbacks.\n */\nconst SCHEMA_VERSION = 2\n\nexport interface SqliteStoreOptions {\n /** Path to the SQLite database file */\n path: string\n}\n\nexport function createSqliteStore(options: SqliteStoreOptions): SessionStore {\n const db = new Database(options.path)\n\n // WAL gives concurrent reads while a writer holds the lock — the\n // BEGIN IMMEDIATE serialization below still applies for writes.\n db.run('PRAGMA journal_mode = WAL')\n\n db.run(`\n CREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n agent_id TEXT,\n data TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n )\n `)\n db.run(`CREATE INDEX IF NOT EXISTS idx_sessions_agent_id ON sessions(agent_id)`)\n\n // Schema version. Forward-only migration: we only ever stamp the current\n // version. There's nothing structural to migrate today — the `?? 0`\n // fallbacks in eventsFromTurns already make pre-2 data render usefully\n // — but seeing `PRAGMA user_version = 1` on disk is a clear signal to a\n // future migration that the row may be missing newer fields.\n const currentVersionRow = db.query('PRAGMA user_version').get() as { user_version: number } | null\n const currentVersion = currentVersionRow?.user_version ?? 0\n if (currentVersion < SCHEMA_VERSION)\n db.run(`PRAGMA user_version = ${SCHEMA_VERSION}`)\n\n const stmtLoad = db.prepare('SELECT data FROM sessions WHERE id = ?')\n const stmtUpsert = db.prepare(`\n INSERT INTO sessions (id, agent_id, data, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?)\n ON CONFLICT(id) DO UPDATE SET\n agent_id = excluded.agent_id,\n data = excluded.data,\n updated_at = excluded.updated_at\n `)\n const stmtDelete = db.prepare('DELETE FROM sessions WHERE id = ?')\n const stmtList = db.prepare('SELECT id FROM sessions ORDER BY updated_at DESC')\n const stmtListLimited = db.prepare('SELECT id FROM sessions ORDER BY updated_at DESC LIMIT ?')\n const stmtListByAgent = db.prepare('SELECT id FROM sessions WHERE agent_id = ? ORDER BY updated_at DESC')\n const stmtListByAgentLimited = db.prepare('SELECT id FROM sessions WHERE agent_id = ? ORDER BY updated_at DESC LIMIT ?')\n\n // --- Synchronous primitives used inside transactions ----------------------\n //\n // bun:sqlite statements are synchronous; `db.transaction(fn).immediate(...)`\n // requires `fn` to be sync. Wrapping these as standalone helpers makes both\n // the transactional and the simple (non-mutating) paths share one\n // implementation.\n const loadSync = (sessionId: string): SessionData | null => {\n const row = stmtLoad.get(sessionId) as { data: string } | null\n if (!row)\n return null\n return JSON.parse(row.data) as SessionData\n }\n const saveSync = (session: SessionData): void => {\n stmtUpsert.run(\n session.id,\n session.agentId ?? null,\n JSON.stringify(session),\n session.createdAt,\n session.updatedAt,\n )\n }\n\n // Mutation transactions. `.immediate(...)` acquires the write lock at\n // `BEGIN IMMEDIATE` time so two concurrent writers serialize on the\n // transaction boundary, not on the (already-too-late) save call.\n const txnAppendTurns = db.transaction((sessionId: string, turns: SessionTurn[]) => {\n const data = loadSync(sessionId)\n if (!data)\n return\n data.turns.push(...turns)\n data.updatedAt = Date.now()\n saveSync(data)\n })\n const txnUpdateRun = db.transaction((sessionId: string, run: SessionRun) => {\n const data = loadSync(sessionId)\n if (!data)\n return\n const idx = data.runs.findIndex(r => r.id === run.id)\n if (idx >= 0)\n data.runs[idx] = run\n data.updatedAt = Date.now()\n saveSync(data)\n })\n const txnUpdateStatus = db.transaction((sessionId: string, status: SessionData['status']) => {\n const data = loadSync(sessionId)\n if (!data)\n return\n data.status = status\n data.updatedAt = Date.now()\n saveSync(data)\n })\n\n const store: SessionStore = {\n async load(sessionId: string) {\n return loadSync(sessionId)\n },\n\n async save(session: SessionData) {\n saveSync(session)\n },\n\n async delete(sessionId: string) {\n stmtDelete.run(sessionId)\n },\n\n async list(filter) {\n // Push LIMIT into the SQL so we don't materialize every row into JS\n // just to slice the first N — meaningful on stores with many sessions.\n const limit = typeof filter?.limit === 'number' && filter.limit > 0 ? filter.limit : undefined\n let rows: { id: string }[]\n\n if (filter?.agentId) {\n rows = (limit\n ? stmtListByAgentLimited.all(filter.agentId, limit)\n : stmtListByAgent.all(filter.agentId)) as { id: string }[]\n }\n else {\n rows = (limit ? stmtListLimited.all(limit) : stmtList.all()) as { id: string }[]\n }\n\n return rows.map(r => r.id)\n },\n\n async appendTurns(sessionId: string, turns: SessionTurn[]) {\n txnAppendTurns.immediate(sessionId, turns)\n },\n\n async getTurns(sessionId: string, from = 0, limit?: number) {\n const data = loadSync(sessionId)\n if (!data)\n return []\n return data.turns.slice(from, limit !== undefined ? from + limit : undefined)\n },\n\n async updateRun(sessionId: string, run: SessionRun) {\n txnUpdateRun.immediate(sessionId, run)\n },\n\n async updateStatus(sessionId: string, status: SessionData['status']) {\n txnUpdateStatus.immediate(sessionId, status)\n },\n }\n\n return store\n}\n\n/**\n * Convenience: open a SQLite store at `dbPath`, creating its parent\n * directory if it doesn't yet exist. Used by the TUI launcher to spin up\n * the default session store at `~/.zidane/sessions.db`.\n *\n * Lives here (and not in `chat/store.ts`) so the renderer-agnostic\n * `zidane/chat` entry stays free of `bun:sqlite` — non-Bun consumers\n * (a future GUI, an SDK) can import `zidane/chat` without pulling in the\n * Bun-only binding.\n */\nexport function createTuiStore(dbPath: string): SessionStore {\n const dir = dirname(dbPath)\n if (!existsSync(dir)) {\n try {\n mkdirSync(dir, { recursive: true })\n }\n catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n throw new Error(\n `Could not create TUI storage directory at \"${dir}\". `\n + `Override the location via \\`runTui({ storageDir, prefix })\\` or the `\n + `\\`ZIDANE_STORAGE_DIR\\` env var. Original error: ${message}`,\n )\n }\n }\n return createSqliteStore({ path: dbPath })\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sqlite.js","names":[],"sources":["../../src/session/sqlite.ts"],"sourcesContent":["/**\n * SQLite session store using Bun's built-in bun:sqlite.\n *\n * Concurrency model\n * -----------------\n * Mutating methods (`appendTurns`, `updateRun`, `updateStatus`) read the\n * existing row, mutate the parsed `SessionData`, and write it back. Under\n * `maxConcurrent > 1` spawns with `persist: true` two child runs can fire\n * `tool-results:after` on the same session at the same time — both reading\n * version N, both writing N+1, last writer silently clobbering the other.\n *\n * Every mutation here therefore runs inside a `BEGIN IMMEDIATE` transaction\n * via `bun:sqlite`'s `db.transaction(fn).immediate(args)` API. IMMEDIATE\n * acquires the database-level write lock at `BEGIN` time, so the second\n * writer blocks on `BEGIN IMMEDIATE` until the first commits — guaranteeing\n * its `SELECT` sees the freshly-written row.\n *\n * Schema versioning\n * -----------------\n * `PRAGMA user_version` is the canonical place to store schema version in\n * SQLite. `SCHEMA_VERSION` below is bumped whenever the on-disk shape of\n * `SessionData` changes in a way readers need to know about. The constructor\n * runs forward migrations; older databases get upgraded in place. Readers\n * still defensively fall back to `?? 0` etc. since the JSON blob is the\n * authoritative shape — `user_version` is for observability + future\n * structural migrations.\n */\n\nimport type { SessionData, SessionRun, SessionStore } from '.'\nimport type { SessionTurn } from '../types'\nimport { existsSync, mkdirSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { Database } from 'bun:sqlite'\n\n/**\n * Current on-disk schema revision for the SQLite session store.\n *\n * 1 — initial schema (sessions table, no version pragma)\n * 2 — `parentRunId` / `depth` on runs; cache-aware `totalUsage`\n * fields; cache-aware token rendering. Pre-2 rows load via\n * defensive `?? 0` fallbacks.\n * 3 — `project_root` column + index. Sessions are tagged with the\n * project they belong to (git root / cwd) so the TUI can list\n * per-project. v2→v3 migration is non-destructive: we add the\n * column NULL, existing rows stay readable as \"untagged\".\n */\nconst SCHEMA_VERSION = 3\n\nexport interface SqliteStoreOptions {\n /** Path to the SQLite database file */\n path: string\n}\n\nexport function createSqliteStore(options: SqliteStoreOptions): SessionStore {\n const db = new Database(options.path)\n\n // WAL gives concurrent reads while a writer holds the lock — the\n // BEGIN IMMEDIATE serialization below still applies for writes.\n db.run('PRAGMA journal_mode = WAL')\n\n db.run(`\n CREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n agent_id TEXT,\n project_root TEXT,\n data TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n )\n `)\n db.run(`CREATE INDEX IF NOT EXISTS idx_sessions_agent_id ON sessions(agent_id)`)\n\n // Schema migration. Forward-only — we only ever ADD columns / indexes.\n //\n // v2 → v3 : adds `project_root` for per-project session filtering.\n // Existing rows get NULL (untagged); they remain readable\n // and load fine — the TUI just hides them from project-\n // scoped lists unless `showAllProjects` is on.\n //\n // `PRAGMA table_info` is the canonical way to feature-detect columns\n // on bun:sqlite without parsing `sqlite_master` text. Idempotent —\n // running it on a fresh DB (where `CREATE TABLE IF NOT EXISTS` above\n // already includes the column) is a no-op.\n const cols = db.query('PRAGMA table_info(sessions)').all() as { name: string }[]\n if (!cols.some(c => c.name === 'project_root'))\n db.run('ALTER TABLE sessions ADD COLUMN project_root TEXT')\n db.run('CREATE INDEX IF NOT EXISTS idx_sessions_project_root ON sessions(project_root)')\n\n const currentVersionRow = db.query('PRAGMA user_version').get() as { user_version: number } | null\n const currentVersion = currentVersionRow?.user_version ?? 0\n if (currentVersion < SCHEMA_VERSION)\n db.run(`PRAGMA user_version = ${SCHEMA_VERSION}`)\n\n const stmtLoad = db.prepare('SELECT data FROM sessions WHERE id = ?')\n const stmtUpsert = db.prepare(`\n INSERT INTO sessions (id, agent_id, project_root, data, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?)\n ON CONFLICT(id) DO UPDATE SET\n agent_id = excluded.agent_id,\n project_root = excluded.project_root,\n data = excluded.data,\n updated_at = excluded.updated_at\n `)\n const stmtDelete = db.prepare('DELETE FROM sessions WHERE id = ?')\n\n // --- Synchronous primitives used inside transactions ----------------------\n //\n // bun:sqlite statements are synchronous; `db.transaction(fn).immediate(...)`\n // requires `fn` to be sync. Wrapping these as standalone helpers makes both\n // the transactional and the simple (non-mutating) paths share one\n // implementation.\n const loadSync = (sessionId: string): SessionData | null => {\n const row = stmtLoad.get(sessionId) as { data: string } | null\n if (!row)\n return null\n return JSON.parse(row.data) as SessionData\n }\n const saveSync = (session: SessionData): void => {\n stmtUpsert.run(\n session.id,\n session.agentId ?? null,\n session.projectRoot ?? null,\n JSON.stringify(session),\n session.createdAt,\n session.updatedAt,\n )\n }\n\n // Mutation transactions. `.immediate(...)` acquires the write lock at\n // `BEGIN IMMEDIATE` time so two concurrent writers serialize on the\n // transaction boundary, not on the (already-too-late) save call.\n const txnAppendTurns = db.transaction((sessionId: string, turns: SessionTurn[]) => {\n const data = loadSync(sessionId)\n if (!data)\n return\n data.turns.push(...turns)\n data.updatedAt = Date.now()\n saveSync(data)\n })\n const txnUpdateRun = db.transaction((sessionId: string, run: SessionRun) => {\n const data = loadSync(sessionId)\n if (!data)\n return\n const idx = data.runs.findIndex(r => r.id === run.id)\n if (idx >= 0)\n data.runs[idx] = run\n data.updatedAt = Date.now()\n saveSync(data)\n })\n const txnUpdateStatus = db.transaction((sessionId: string, status: SessionData['status']) => {\n const data = loadSync(sessionId)\n if (!data)\n return\n data.status = status\n data.updatedAt = Date.now()\n saveSync(data)\n })\n\n const store: SessionStore = {\n async load(sessionId: string) {\n return loadSync(sessionId)\n },\n\n async save(session: SessionData) {\n saveSync(session)\n },\n\n async delete(sessionId: string) {\n stmtDelete.run(sessionId)\n },\n\n async list(filter) {\n // Build the SQL on the fly so the filter axes compose cleanly —\n // four prepared statements collapsed into one dynamic query. The\n // shape is always `SELECT id FROM sessions [WHERE …] ORDER BY\n // updated_at DESC [LIMIT N]`; only the WHERE varies.\n //\n // `projectRoot: string` → `WHERE project_root = ?` (excludes untagged).\n // `projectRoot: null` → `WHERE project_root IS NULL` (untagged only).\n // `projectRoot: undefined` → axis omitted (untagged + tagged).\n //\n // The `null` case lets a future \"show legacy\" debug toggle query\n // pre-v3 sessions explicitly without leaking them into normal\n // per-project lists.\n const conditions: string[] = []\n const params: string[] = []\n if (filter?.agentId) {\n conditions.push('agent_id = ?')\n params.push(filter.agentId)\n }\n if ('projectRoot' in (filter ?? {})) {\n const v = filter!.projectRoot\n if (v === null) {\n conditions.push('project_root IS NULL')\n }\n else if (typeof v === 'string') {\n conditions.push('project_root = ?')\n params.push(v)\n }\n }\n const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''\n const limit = typeof filter?.limit === 'number' && filter.limit > 0 ? `LIMIT ${filter.limit}` : ''\n const sql = `SELECT id FROM sessions ${where} ORDER BY updated_at DESC ${limit}`.replace(/\\s+/g, ' ').trim()\n const rows = db.query(sql).all(...params) as { id: string }[]\n return rows.map(r => r.id)\n },\n\n async appendTurns(sessionId: string, turns: SessionTurn[]) {\n txnAppendTurns.immediate(sessionId, turns)\n },\n\n async getTurns(sessionId: string, from = 0, limit?: number) {\n const data = loadSync(sessionId)\n if (!data)\n return []\n return data.turns.slice(from, limit !== undefined ? from + limit : undefined)\n },\n\n async updateRun(sessionId: string, run: SessionRun) {\n txnUpdateRun.immediate(sessionId, run)\n },\n\n async updateStatus(sessionId: string, status: SessionData['status']) {\n txnUpdateStatus.immediate(sessionId, status)\n },\n }\n\n return store\n}\n\n/**\n * Convenience: open a SQLite store at `dbPath`, creating its parent\n * directory if it doesn't yet exist. Used by the TUI launcher to spin up\n * the default session store at `~/.zidane/sessions.db`.\n *\n * Lives here (and not in `chat/store.ts`) so the renderer-agnostic\n * `zidane/chat` entry stays free of `bun:sqlite` — non-Bun consumers\n * (a future GUI, an SDK) can import `zidane/chat` without pulling in the\n * Bun-only binding.\n */\nexport function createTuiStore(dbPath: string): SessionStore {\n const dir = dirname(dbPath)\n if (!existsSync(dir)) {\n try {\n mkdirSync(dir, { recursive: true })\n }\n catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n throw new Error(\n `Could not create TUI storage directory at \"${dir}\". `\n + `Override the location via \\`runTui({ storageDir, prefix })\\` or the `\n + `\\`ZIDANE_STORAGE_DIR\\` env var. Original error: ${message}`,\n )\n }\n }\n return createSqliteStore({ path: dbPath })\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA8CA,MAAM,iBAAiB;AAOvB,SAAgB,kBAAkB,SAA2C;CAC3E,MAAM,KAAK,IAAI,SAAS,QAAQ,KAAK;CAIrC,GAAG,IAAI,4BAA4B;CAEnC,GAAG,IAAI;;;;;;;;;IASL;CACF,GAAG,IAAI,yEAAyE;CAchF,IAAI,CADS,GAAG,MAAM,8BAA8B,CAAC,KAC5C,CAAC,MAAK,MAAK,EAAE,SAAS,eAAe,EAC5C,GAAG,IAAI,oDAAoD;CAC7D,GAAG,IAAI,iFAAiF;CAIxF,KAF0B,GAAG,MAAM,sBAAsB,CAAC,KAClB,EAAE,gBAAgB,KACrC,gBACnB,GAAG,IAAI,yBAAyB,iBAAiB;CAEnD,MAAM,WAAW,GAAG,QAAQ,yCAAyC;CACrE,MAAM,aAAa,GAAG,QAAQ;;;;;;;;IAQ5B;CACF,MAAM,aAAa,GAAG,QAAQ,oCAAoC;CAQlE,MAAM,YAAY,cAA0C;EAC1D,MAAM,MAAM,SAAS,IAAI,UAAU;EACnC,IAAI,CAAC,KACH,OAAO;EACT,OAAO,KAAK,MAAM,IAAI,KAAK;;CAE7B,MAAM,YAAY,YAA+B;EAC/C,WAAW,IACT,QAAQ,IACR,QAAQ,WAAW,MACnB,QAAQ,eAAe,MACvB,KAAK,UAAU,QAAQ,EACvB,QAAQ,WACR,QAAQ,UACT;;CAMH,MAAM,iBAAiB,GAAG,aAAa,WAAmB,UAAyB;EACjF,MAAM,OAAO,SAAS,UAAU;EAChC,IAAI,CAAC,MACH;EACF,KAAK,MAAM,KAAK,GAAG,MAAM;EACzB,KAAK,YAAY,KAAK,KAAK;EAC3B,SAAS,KAAK;GACd;CACF,MAAM,eAAe,GAAG,aAAa,WAAmB,QAAoB;EAC1E,MAAM,OAAO,SAAS,UAAU;EAChC,IAAI,CAAC,MACH;EACF,MAAM,MAAM,KAAK,KAAK,WAAU,MAAK,EAAE,OAAO,IAAI,GAAG;EACrD,IAAI,OAAO,GACT,KAAK,KAAK,OAAO;EACnB,KAAK,YAAY,KAAK,KAAK;EAC3B,SAAS,KAAK;GACd;CACF,MAAM,kBAAkB,GAAG,aAAa,WAAmB,WAAkC;EAC3F,MAAM,OAAO,SAAS,UAAU;EAChC,IAAI,CAAC,MACH;EACF,KAAK,SAAS;EACd,KAAK,YAAY,KAAK,KAAK;EAC3B,SAAS,KAAK;GACd;CAuEF,OAAO;EApEL,MAAM,KAAK,WAAmB;GAC5B,OAAO,SAAS,UAAU;;EAG5B,MAAM,KAAK,SAAsB;GAC/B,SAAS,QAAQ;;EAGnB,MAAM,OAAO,WAAmB;GAC9B,WAAW,IAAI,UAAU;;EAG3B,MAAM,KAAK,QAAQ;GAajB,MAAM,aAAuB,EAAE;GAC/B,MAAM,SAAmB,EAAE;GAC3B,IAAI,QAAQ,SAAS;IACnB,WAAW,KAAK,eAAe;IAC/B,OAAO,KAAK,OAAO,QAAQ;;GAE7B,IAAI,kBAAkB,UAAU,EAAE,GAAG;IACnC,MAAM,IAAI,OAAQ;IAClB,IAAI,MAAM,MACR,WAAW,KAAK,uBAAuB;SAEpC,IAAI,OAAO,MAAM,UAAU;KAC9B,WAAW,KAAK,mBAAmB;KACnC,OAAO,KAAK,EAAE;;;GAKlB,MAAM,MAAM,2BAFE,WAAW,SAAS,IAAI,SAAS,WAAW,KAAK,QAAQ,KAAK,GAE/B,4BAD/B,OAAO,QAAQ,UAAU,YAAY,OAAO,QAAQ,IAAI,SAAS,OAAO,UAAU,KACf,QAAQ,QAAQ,IAAI,CAAC,MAAM;GAE5G,OADa,GAAG,MAAM,IAAI,CAAC,IAAI,GAAG,OACvB,CAAC,KAAI,MAAK,EAAE,GAAG;;EAG5B,MAAM,YAAY,WAAmB,OAAsB;GACzD,eAAe,UAAU,WAAW,MAAM;;EAG5C,MAAM,SAAS,WAAmB,OAAO,GAAG,OAAgB;GAC1D,MAAM,OAAO,SAAS,UAAU;GAChC,IAAI,CAAC,MACH,OAAO,EAAE;GACX,OAAO,KAAK,MAAM,MAAM,MAAM,UAAU,KAAA,IAAY,OAAO,QAAQ,KAAA,EAAU;;EAG/E,MAAM,UAAU,WAAmB,KAAiB;GAClD,aAAa,UAAU,WAAW,IAAI;;EAGxC,MAAM,aAAa,WAAmB,QAA+B;GACnE,gBAAgB,UAAU,WAAW,OAAO;;EAIpC;;;;;;;;;;;;AAad,SAAgB,eAAe,QAA8B;CAC3D,MAAM,MAAM,QAAQ,OAAO;CAC3B,IAAI,CAAC,WAAW,IAAI,EAClB,IAAI;EACF,UAAU,KAAK,EAAE,WAAW,MAAM,CAAC;UAE9B,KAAK;EACV,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;EAChE,MAAM,IAAI,MACR,8CAA8C,IAAI,yHAEG,UACtD;;CAGL,OAAO,kBAAkB,EAAE,MAAM,QAAQ,CAAC"}
|
|
@@ -112,6 +112,11 @@ function createFileMapStore(adapter, options = {}) {
|
|
|
112
112
|
await hydrate();
|
|
113
113
|
if (!cached) return [];
|
|
114
114
|
if (filter?.agentId && cached.agentId !== filter.agentId) return [];
|
|
115
|
+
if (filter && "projectRoot" in filter) {
|
|
116
|
+
const v = filter.projectRoot;
|
|
117
|
+
if (v === null && cached.projectRoot != null) return [];
|
|
118
|
+
if (typeof v === "string" && cached.projectRoot !== v) return [];
|
|
119
|
+
}
|
|
115
120
|
return [cached.id];
|
|
116
121
|
},
|
|
117
122
|
async appendTurns(sessionId, turns) {
|
|
@@ -160,6 +165,11 @@ function createMemoryStore() {
|
|
|
160
165
|
async list(filter) {
|
|
161
166
|
let ids = Array.from(sessions.keys());
|
|
162
167
|
if (filter?.agentId) ids = ids.filter((id) => sessions.get(id)?.agentId === filter.agentId);
|
|
168
|
+
if (filter && "projectRoot" in filter) {
|
|
169
|
+
const v = filter.projectRoot;
|
|
170
|
+
if (v === null) ids = ids.filter((id) => sessions.get(id)?.projectRoot == null);
|
|
171
|
+
else if (typeof v === "string") ids = ids.filter((id) => sessions.get(id)?.projectRoot === v);
|
|
172
|
+
}
|
|
163
173
|
if (filter?.limit) ids = ids.slice(0, filter.limit);
|
|
164
174
|
return ids;
|
|
165
175
|
},
|
|
@@ -236,6 +246,11 @@ function createRemoteStore(options) {
|
|
|
236
246
|
const params = new URLSearchParams();
|
|
237
247
|
if (filter?.agentId) params.set("agentId", filter.agentId);
|
|
238
248
|
if (filter?.limit) params.set("limit", String(filter.limit));
|
|
249
|
+
if (filter && "projectRoot" in filter) {
|
|
250
|
+
const v = filter.projectRoot;
|
|
251
|
+
if (v === null) params.set("projectRoot", "__null__");
|
|
252
|
+
else if (typeof v === "string") params.set("projectRoot", v);
|
|
253
|
+
}
|
|
239
254
|
const query = params.toString();
|
|
240
255
|
const res = await request(query ? `/sessions?${query}` : "/sessions");
|
|
241
256
|
if (!res.ok) throw new Error(`Remote session list failed: ${res.status} ${res.statusText}`);
|
|
@@ -288,6 +303,7 @@ async function createSession(options = {}) {
|
|
|
288
303
|
const data = options._data ?? {
|
|
289
304
|
id: sessionId,
|
|
290
305
|
agentId: options.agentId,
|
|
306
|
+
...options.projectRoot ? { projectRoot: options.projectRoot } : {},
|
|
291
307
|
turns: [],
|
|
292
308
|
runs: [],
|
|
293
309
|
status: "idle",
|
|
@@ -344,6 +360,9 @@ async function createSession(options = {}) {
|
|
|
344
360
|
get agentId() {
|
|
345
361
|
return data.agentId;
|
|
346
362
|
},
|
|
363
|
+
get projectRoot() {
|
|
364
|
+
return data.projectRoot;
|
|
365
|
+
},
|
|
347
366
|
get turns() {
|
|
348
367
|
return data.turns;
|
|
349
368
|
},
|
|
@@ -407,6 +426,10 @@ async function createSession(options = {}) {
|
|
|
407
426
|
data.turns = turns;
|
|
408
427
|
touch();
|
|
409
428
|
},
|
|
429
|
+
setRuns(runs) {
|
|
430
|
+
data.runs = runs;
|
|
431
|
+
touch();
|
|
432
|
+
},
|
|
410
433
|
async updateStatus(status) {
|
|
411
434
|
data.status = status;
|
|
412
435
|
touch();
|
|
@@ -449,4 +472,4 @@ function generateId() {
|
|
|
449
472
|
//#endregion
|
|
450
473
|
export { createFileMapStore as a, createMemoryStore as i, loadSession as n, createRemoteStore as r, createSession as t };
|
|
451
474
|
|
|
452
|
-
//# sourceMappingURL=session-
|
|
475
|
+
//# sourceMappingURL=session-791hhrFa.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-791hhrFa.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 // file-map stores exactly one session, so the projectRoot filter\n // either keeps it (match / axis off) or drops it entirely.\n if (filter && 'projectRoot' in filter) {\n const v = filter.projectRoot\n if (v === null && cached.projectRoot != null)\n return []\n if (typeof v === 'string' && cached.projectRoot !== v)\n return []\n }\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 // `projectRoot` mirrors the SQLite store's tri-state contract:\n // string → only sessions tagged with that root\n // null → only UNTAGGED sessions (legacy / pre-v3 rows)\n // undefined → axis ignored (tagged + untagged both returned)\n if (filter && 'projectRoot' in filter) {\n const v = filter.projectRoot\n if (v === null)\n ids = ids.filter(id => sessions.get(id)?.projectRoot == null)\n else if (typeof v === 'string')\n ids = ids.filter(id => sessions.get(id)?.projectRoot === v)\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=&projectRoot= -> { ids: string[] }\n * `projectRoot=__null__` is the wire encoding for \"untagged only\".\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 if (filter && 'projectRoot' in filter) {\n const v = filter.projectRoot\n if (v === null)\n params.set('projectRoot', '__null__')\n else if (typeof v === 'string')\n params.set('projectRoot', v)\n }\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 /**\n * Absolute path of the project this session belongs to — typically\n * the git root resolved from `cwd` at creation time, falling back to\n * `cwd` itself when not in a git repo. Set ONCE on creation and never\n * mutated thereafter (the session \"belongs\" to that project forever).\n *\n * Used by the TUI's sessions list to filter rows by current project,\n * so the user only sees conversations relevant to where they are\n * working — without needing one `.{prefix}/` directory per project.\n *\n * `undefined` on pre-tagging legacy sessions; the chat layer treats\n * those as \"untagged\" and hides them unless `Settings.showAllProjects`\n * is on.\n */\n projectRoot?: 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 /**\n * List session IDs, optionally filtered. `projectRoot` restricts to\n * sessions whose `SessionData.projectRoot` matches exactly — untagged\n * (legacy) sessions are NOT returned under that filter; pass `null`\n * explicitly to ask for untagged ones, or omit the field to ignore\n * the axis entirely. `agentId` filters by recorded agent; the two\n * conditions AND together when both are set.\n */\n list: (filter?: { agentId?: string, limit?: number, projectRoot?: string | null }) => 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 /**\n * Project this session was created under — see {@link SessionData.projectRoot}.\n * Set once on creation; surfaces here for read-only inspection.\n */\n readonly projectRoot?: 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 /**\n * Replace all runs in-memory (does not persist — use save() for that).\n * Mirrors {@link setTurns} for the fork / restore case: callers that\n * bootstrap a session from an externally-derived snapshot (e.g.\n * `onForkTurn` copying parent runs into a child session) need this so\n * the cloned runs land in `data.runs` before the first `save()`.\n * Production agent runs continue to mutate runs via `startRun` /\n * `completeRun` / `updateRun`; this is the bulk-replace escape hatch.\n */\n setRuns: (runs: SessionRun[]) => 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 /**\n * Project tag — see {@link SessionData.projectRoot}. Stamped once on\n * creation; ignored when `_data` is set (restoring an existing\n * session preserves whatever was already persisted there). The TUI\n * resolves this from `findGitRoot(cwd) ?? cwd` so sessions started\n * from the same repo (no matter which subdir) share one tag.\n */\n projectRoot?: 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 // Stamp the project tag at creation only — restored sessions (the\n // `_data` branch above) keep whatever was already persisted, even\n // if `options.projectRoot` differs. A session's project identity\n // is sticky for its lifetime; loading the same session from a\n // different cwd doesn't re-home it.\n ...(options.projectRoot ? { projectRoot: options.projectRoot } : {}),\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 projectRoot() { return data.projectRoot },\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 setRuns(runs: SessionRun[]) {\n data.runs = runs\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 { A as
|
|
1
|
+
import { A as createSession, B as FileMapAdapter, Ct as SessionContentBlock, D as SessionData, Dt as SessionTurn, E as Session, Et as SessionMessage, F as fromAnthropic, H as createFileMapStore, I as fromOpenAI, L as toAnthropic, M as RemoteStoreOptions, N as createRemoteStore, O as SessionRun, P as autoDetectAndConvert, R as toOpenAI, T as CreateSessionOptions, V as FileMapStoreOptions, j as loadSession, k as SessionStore, z as createMemoryStore } from "./agent-JhicgLOV.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-
|
|
2
|
+
import { a as createFileMapStore, i as createMemoryStore, n as loadSession, r as createRemoteStore, t as createSession } from "./session-791hhrFa.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 { C as
|
|
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-
|
|
1
|
+
import { C as SkillSource, S as SkillResource, b as SkillConfig, c as DeactivationReason, d as createSkillActivationState, l as SkillActivationState, o as ActivationVia, s as ActiveSkill, u as SkillActivationStateOptions, w as SkillsConfig, x as SkillDiagnostic } from "./agent-JhicgLOV.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-t_W9i7Ql.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-
|
|
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-Ck970-61.js";
|
|
2
2
|
//#region src/skills/index.ts
|
|
3
3
|
/**
|
|
4
4
|
* Define an inline skill configuration.
|