@yugenlab/vaayu 0.1.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.
Files changed (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +365 -0
  3. package/chunks/chunk-E5A3SCDJ.js +246 -0
  4. package/chunks/chunk-G5VYCA6O.js +69 -0
  5. package/chunks/chunk-H76V36OF.js +1029 -0
  6. package/chunks/chunk-HAPVUJ6A.js +238 -0
  7. package/chunks/chunk-IEKAYVA3.js +137 -0
  8. package/chunks/chunk-IGKYKEKT.js +43 -0
  9. package/chunks/chunk-IIET2K6D.js +7728 -0
  10. package/chunks/chunk-ITIVYGUG.js +347 -0
  11. package/chunks/chunk-JAWZ7ANC.js +208 -0
  12. package/chunks/chunk-JZU37VQ5.js +714 -0
  13. package/chunks/chunk-KC6NRZ7U.js +198 -0
  14. package/chunks/chunk-KDRROLVN.js +433 -0
  15. package/chunks/chunk-L7JICQBW.js +1006 -0
  16. package/chunks/chunk-MINFB5LT.js +1479 -0
  17. package/chunks/chunk-MJ74G5RB.js +5816 -0
  18. package/chunks/chunk-S4TBVCL2.js +2158 -0
  19. package/chunks/chunk-SMVJRPAH.js +2753 -0
  20. package/chunks/chunk-U6OLJ36B.js +438 -0
  21. package/chunks/chunk-URGEODS5.js +752 -0
  22. package/chunks/chunk-YSU3BWV6.js +123 -0
  23. package/chunks/consolidation-indexer-TOTTDZXW.js +21 -0
  24. package/chunks/day-consolidation-NKO63HZQ.js +24 -0
  25. package/chunks/graphrag-ZI2FSU7S.js +13 -0
  26. package/chunks/hierarchical-temporal-search-ZD46UMKR.js +8 -0
  27. package/chunks/hybrid-search-ZVLZVGFS.js +19 -0
  28. package/chunks/memory-store-KNJPMBLQ.js +17 -0
  29. package/chunks/periodic-consolidation-BPKOZDGB.js +10 -0
  30. package/chunks/postgres-3ZXBYTPC.js +8 -0
  31. package/chunks/recall-GMVHWQWW.js +20 -0
  32. package/chunks/search-7HZETVMZ.js +18 -0
  33. package/chunks/session-store-XKPGKXUS.js +44 -0
  34. package/chunks/sqlite-JPF5TICX.js +152 -0
  35. package/chunks/src-6GVZTUH6.js +12 -0
  36. package/chunks/src-QAXOD5SB.js +273 -0
  37. package/chunks/suncalc-NOHGYHDU.js +186 -0
  38. package/chunks/tree-RSHKDTCR.js +10 -0
  39. package/gateway.js +61944 -0
  40. package/package.json +51 -0
  41. package/pair-cli.js +133 -0
@@ -0,0 +1,1006 @@
1
+ import {
2
+ DatabaseManager,
3
+ initAgentSchema
4
+ } from "./chunk-U6OLJ36B.js";
5
+ import {
6
+ SessionError,
7
+ getChitraguptaHome
8
+ } from "./chunk-KC6NRZ7U.js";
9
+
10
+ // ../chitragupta/packages/smriti/src/session-store.ts
11
+ import fs from "fs";
12
+ import { renameSync as nodeRenameSync } from "node:fs";
13
+ import path from "path";
14
+ import crypto from "crypto";
15
+
16
+ // ../chitragupta/packages/smriti/src/markdown-parser.ts
17
+ function parseFrontmatter(yaml) {
18
+ const result = {};
19
+ const lines = yaml.split("\n");
20
+ let currentKey = null;
21
+ let currentArray = null;
22
+ for (const line of lines) {
23
+ const trimmed = line.trim();
24
+ if (!trimmed || trimmed.startsWith("#")) continue;
25
+ if (trimmed.startsWith("- ") && currentKey && currentArray !== null) {
26
+ currentArray.push(trimmed.slice(2).trim());
27
+ continue;
28
+ }
29
+ if (currentKey && currentArray !== null) {
30
+ result[currentKey] = currentArray;
31
+ currentArray = null;
32
+ currentKey = null;
33
+ }
34
+ const colonIdx = trimmed.indexOf(":");
35
+ if (colonIdx === -1) continue;
36
+ const key = trimmed.slice(0, colonIdx).trim();
37
+ const rawValue = trimmed.slice(colonIdx + 1).trim();
38
+ if (rawValue === "" || rawValue === void 0) {
39
+ currentKey = key;
40
+ currentArray = [];
41
+ continue;
42
+ }
43
+ if (rawValue.startsWith("[") && rawValue.endsWith("]")) {
44
+ const inner = rawValue.slice(1, -1);
45
+ if (inner.trim() === "") {
46
+ result[key] = [];
47
+ } else {
48
+ result[key] = inner.split(",").map((s) => parseScalar(s.trim()));
49
+ }
50
+ continue;
51
+ }
52
+ result[key] = parseScalar(rawValue);
53
+ }
54
+ if (currentKey && currentArray !== null) {
55
+ result[currentKey] = currentArray;
56
+ }
57
+ return result;
58
+ }
59
+ function parseScalar(value) {
60
+ if (value === "null" || value === "~") return null;
61
+ if (value === "true") return true;
62
+ if (value === "false") return false;
63
+ if (value.startsWith('"') && value.endsWith('"')) {
64
+ return value.slice(1, -1).replace(/\\"/g, '"');
65
+ }
66
+ if (value.startsWith("'") && value.endsWith("'")) {
67
+ return value.slice(1, -1);
68
+ }
69
+ const num = Number(value);
70
+ if (!Number.isNaN(num) && value !== "") return num;
71
+ return value;
72
+ }
73
+ function parseSessionMarkdown(content) {
74
+ if (!content || typeof content !== "string") {
75
+ throw new SessionError("Cannot parse empty or non-string session content");
76
+ }
77
+ const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
78
+ if (!fmMatch) {
79
+ throw new SessionError("Session file missing YAML frontmatter (--- delimiters)");
80
+ }
81
+ const rawMeta = parseFrontmatter(fmMatch[1]);
82
+ const meta = buildSessionMeta(rawMeta);
83
+ const body = content.slice(fmMatch[0].length).trim();
84
+ const turns = parseTurns(body);
85
+ return { meta, turns };
86
+ }
87
+ function buildSessionMeta(raw) {
88
+ return {
89
+ id: String(raw.id ?? ""),
90
+ title: String(raw.title ?? "Untitled Session"),
91
+ created: String(raw.created ?? (/* @__PURE__ */ new Date()).toISOString()),
92
+ updated: String(raw.updated ?? (/* @__PURE__ */ new Date()).toISOString()),
93
+ agent: String(raw.agent ?? "chitragupta"),
94
+ model: String(raw.model ?? "unknown"),
95
+ project: String(raw.project ?? ""),
96
+ parent: raw.parent != null ? String(raw.parent) : null,
97
+ branch: raw.branch != null ? String(raw.branch) : null,
98
+ tags: Array.isArray(raw.tags) ? raw.tags.map(String) : [],
99
+ totalCost: Number(raw.totalCost ?? 0),
100
+ totalTokens: Number(raw.totalTokens ?? 0)
101
+ };
102
+ }
103
+ function parseTurns(body) {
104
+ if (!body) return [];
105
+ body = stripFooter(body);
106
+ const turnPattern = /^## Turn (\d+) — (user|assistant)(?:\s+\(([^)]*)\))?/gm;
107
+ const turns = [];
108
+ const matches = [];
109
+ let match;
110
+ while ((match = turnPattern.exec(body)) !== null) {
111
+ matches.push({
112
+ index: match.index,
113
+ turnNumber: parseInt(match[1], 10),
114
+ role: match[2],
115
+ meta: match[3]
116
+ });
117
+ }
118
+ for (let i = 0; i < matches.length; i++) {
119
+ const m = matches[i];
120
+ const headerEnd = body.indexOf("\n", m.index);
121
+ const contentStart = headerEnd + 1;
122
+ const contentEnd = i + 1 < matches.length ? matches[i + 1].index : body.length;
123
+ const rawContent = body.slice(contentStart, contentEnd).trim();
124
+ let agent;
125
+ let model;
126
+ if (m.meta) {
127
+ const parts = m.meta.split(",").map((s) => s.trim());
128
+ for (const part of parts) {
129
+ const [k, v] = part.split(":").map((s) => s.trim());
130
+ if (k === "agent") agent = v;
131
+ if (k === "model") model = v;
132
+ }
133
+ }
134
+ const { content, toolCalls } = parseContentAndToolCalls(rawContent);
135
+ const unescapedContent = content.replace(/^\\(## Turn \d+)/gm, "$1").replace(/^\\---$/gm, "---").replace(/\\<\/(details|summary)>/gi, "</$1>");
136
+ const turn = {
137
+ turnNumber: m.turnNumber,
138
+ role: m.role,
139
+ content: unescapedContent
140
+ };
141
+ if (agent) turn.agent = agent;
142
+ if (model) turn.model = model;
143
+ if (toolCalls.length > 0) turn.toolCalls = toolCalls;
144
+ turns.push(turn);
145
+ }
146
+ return turns;
147
+ }
148
+ function stripFooter(body) {
149
+ const footerPattern = /\n---\n\n\*Session [^*]+\*\s*$/;
150
+ return body.replace(footerPattern, "");
151
+ }
152
+ function parseContentAndToolCalls(raw) {
153
+ const toolPattern = /^### Tool: (.+)$/gm;
154
+ const toolMatches = [];
155
+ let match;
156
+ while ((match = toolPattern.exec(raw)) !== null) {
157
+ toolMatches.push({ index: match.index, name: match[1].trim() });
158
+ }
159
+ if (toolMatches.length === 0) {
160
+ return { content: raw, toolCalls: [] };
161
+ }
162
+ const content = raw.slice(0, toolMatches[0].index).trim();
163
+ const toolCalls = [];
164
+ for (let i = 0; i < toolMatches.length; i++) {
165
+ const tm = toolMatches[i];
166
+ const headerEnd = raw.indexOf("\n", tm.index);
167
+ const sectionStart = headerEnd + 1;
168
+ const sectionEnd = i + 1 < toolMatches.length ? toolMatches[i + 1].index : raw.length;
169
+ const section = raw.slice(sectionStart, sectionEnd).trim();
170
+ toolCalls.push(parseToolCallSection(tm.name, section));
171
+ }
172
+ return { content, toolCalls };
173
+ }
174
+ function parseToolCallSection(name, section) {
175
+ let input = "";
176
+ let result = "";
177
+ let isError = false;
178
+ const inputMatch = section.match(/\*\*Input:\*\*\s*\n```(?:json)?\n([\s\S]*?)```/);
179
+ if (inputMatch) {
180
+ input = inputMatch[1].trim();
181
+ }
182
+ const detailsMatch = section.match(/<details>\s*\n<summary>(.*?)<\/summary>\s*\n([\s\S]*?)<\/details>/);
183
+ if (detailsMatch) {
184
+ const summaryText = detailsMatch[1].trim();
185
+ isError = summaryText.toLowerCase().includes("error");
186
+ const codeMatch = detailsMatch[2].match(/```(?:\w*)\n([\s\S]*?)```/);
187
+ if (codeMatch) {
188
+ result = codeMatch[1].trim();
189
+ } else {
190
+ result = detailsMatch[2].trim();
191
+ }
192
+ }
193
+ const toolCall = { name, input, result };
194
+ if (isError) toolCall.isError = true;
195
+ return toolCall;
196
+ }
197
+
198
+ // ../chitragupta/packages/smriti/src/markdown-writer.ts
199
+ function writeFrontmatter(meta) {
200
+ const lines = [];
201
+ lines.push("---");
202
+ lines.push(`id: ${meta.id}`);
203
+ lines.push(`title: "${meta.title.replace(/"/g, '\\"')}"`);
204
+ lines.push(`created: ${meta.created}`);
205
+ lines.push(`updated: ${meta.updated}`);
206
+ lines.push(`agent: ${meta.agent}`);
207
+ lines.push(`model: ${meta.model}`);
208
+ lines.push(`project: ${meta.project}`);
209
+ lines.push(`parent: ${meta.parent ?? "null"}`);
210
+ lines.push(`branch: ${meta.branch ?? "null"}`);
211
+ if (meta.tags.length === 0) {
212
+ lines.push("tags: []");
213
+ } else {
214
+ lines.push("tags:");
215
+ for (const tag of meta.tags) {
216
+ lines.push(` - ${tag}`);
217
+ }
218
+ }
219
+ lines.push(`totalCost: ${meta.totalCost}`);
220
+ lines.push(`totalTokens: ${meta.totalTokens}`);
221
+ lines.push("---");
222
+ return lines.join("\n");
223
+ }
224
+ function writeToolCall(toolCall) {
225
+ const lines = [];
226
+ lines.push(`### Tool: ${toolCall.name}`);
227
+ lines.push("");
228
+ lines.push("**Input:**");
229
+ lines.push("```json");
230
+ lines.push(toolCall.input);
231
+ lines.push("```");
232
+ lines.push("");
233
+ const summaryLabel = toolCall.isError ? "Error" : "Result";
234
+ lines.push("<details>");
235
+ lines.push(`<summary>${summaryLabel}</summary>`);
236
+ lines.push("");
237
+ lines.push("```");
238
+ lines.push(toolCall.result);
239
+ lines.push("```");
240
+ lines.push("");
241
+ lines.push("</details>");
242
+ return lines.join("\n");
243
+ }
244
+ function writeTurn(turn) {
245
+ const lines = [];
246
+ let heading = `## Turn ${turn.turnNumber} \u2014 ${turn.role}`;
247
+ const metaParts = [];
248
+ if (turn.agent) metaParts.push(`agent: ${turn.agent}`);
249
+ if (turn.model) metaParts.push(`model: ${turn.model}`);
250
+ if (metaParts.length > 0) {
251
+ heading += ` (${metaParts.join(", ")})`;
252
+ }
253
+ lines.push(heading);
254
+ lines.push("");
255
+ const escaped = turn.content.replace(/^(## Turn \d+)/gm, "\\$1").replace(/^---$/gm, "\\---").replace(/<\/(details|summary)>/gi, "\\</$1>");
256
+ lines.push(escaped);
257
+ if (turn.toolCalls && turn.toolCalls.length > 0) {
258
+ lines.push("");
259
+ for (const toolCall of turn.toolCalls) {
260
+ lines.push(writeToolCall(toolCall));
261
+ lines.push("");
262
+ }
263
+ }
264
+ return lines.join("\n");
265
+ }
266
+ function writeFooter(meta) {
267
+ const lines = [];
268
+ lines.push("---");
269
+ lines.push("");
270
+ lines.push(`*Session ${meta.id} | ${meta.agent} | ${meta.model} | Cost: $${meta.totalCost.toFixed(4)} | Tokens: ${meta.totalTokens}*`);
271
+ return lines.join("\n");
272
+ }
273
+ function writeSessionMarkdown(session) {
274
+ const parts = [];
275
+ parts.push(writeFrontmatter(session.meta));
276
+ parts.push("");
277
+ for (const turn of session.turns) {
278
+ parts.push(writeTurn(turn));
279
+ parts.push("");
280
+ }
281
+ parts.push(writeFooter(session.meta));
282
+ parts.push("");
283
+ return parts.join("\n");
284
+ }
285
+ function writeTurnMarkdown(turn) {
286
+ return writeTurn(turn);
287
+ }
288
+
289
+ // ../chitragupta/packages/smriti/src/session-store.ts
290
+ function atomicRename(tmpPath, targetPath) {
291
+ try {
292
+ nodeRenameSync(tmpPath, targetPath);
293
+ } catch {
294
+ fs.writeFileSync(targetPath, fs.readFileSync(tmpPath, "utf-8"), "utf-8");
295
+ try {
296
+ fs.unlinkSync(tmpPath);
297
+ } catch {
298
+ }
299
+ }
300
+ }
301
+ var SESSION_CACHE_MAX = 500;
302
+ var SESSION_CACHE_MAX_BYTES = 25 * 1024 * 1024;
303
+ var sessionCache = /* @__PURE__ */ new Map();
304
+ var sessionCacheSizes = /* @__PURE__ */ new Map();
305
+ var sessionCacheBytes = 0;
306
+ function estimateSessionBytes(session) {
307
+ let bytes = 200;
308
+ for (const turn of session.turns) {
309
+ bytes += Buffer.byteLength(turn.content, "utf-8") + 50;
310
+ }
311
+ return bytes;
312
+ }
313
+ function cacheKey(id, project) {
314
+ return `${id}:${project}`;
315
+ }
316
+ function cacheGet(id, project) {
317
+ const key = cacheKey(id, project);
318
+ const entry = sessionCache.get(key);
319
+ if (!entry) return void 0;
320
+ const size = sessionCacheSizes.get(key) ?? 0;
321
+ sessionCache.delete(key);
322
+ sessionCacheSizes.delete(key);
323
+ sessionCache.set(key, entry);
324
+ sessionCacheSizes.set(key, size);
325
+ return entry;
326
+ }
327
+ function cachePut(id, project, session) {
328
+ const key = cacheKey(id, project);
329
+ const existingSize = sessionCacheSizes.get(key) ?? 0;
330
+ sessionCache.delete(key);
331
+ sessionCacheSizes.delete(key);
332
+ sessionCacheBytes -= existingSize;
333
+ const newSize = estimateSessionBytes(session);
334
+ while ((sessionCache.size >= SESSION_CACHE_MAX || sessionCacheBytes + newSize > SESSION_CACHE_MAX_BYTES) && sessionCache.size > 0) {
335
+ const oldest = sessionCache.keys().next().value;
336
+ if (oldest === void 0) break;
337
+ const evictedSize = sessionCacheSizes.get(oldest) ?? 0;
338
+ sessionCache.delete(oldest);
339
+ sessionCacheSizes.delete(oldest);
340
+ sessionCacheBytes -= evictedSize;
341
+ }
342
+ sessionCache.set(key, session);
343
+ sessionCacheSizes.set(key, newSize);
344
+ sessionCacheBytes += newSize;
345
+ }
346
+ function cacheInvalidate(id, project) {
347
+ const key = cacheKey(id, project);
348
+ const size = sessionCacheSizes.get(key) ?? 0;
349
+ sessionCache.delete(key);
350
+ sessionCacheSizes.delete(key);
351
+ sessionCacheBytes -= size;
352
+ }
353
+ function _resetSessionCache() {
354
+ sessionCache.clear();
355
+ sessionCacheSizes.clear();
356
+ sessionCacheBytes = 0;
357
+ }
358
+ function hashProject(project) {
359
+ return crypto.createHash("sha256").update(project).digest("hex").slice(0, 12);
360
+ }
361
+ function generateSessionId(project) {
362
+ const now = /* @__PURE__ */ new Date();
363
+ const yyyy = now.getFullYear().toString();
364
+ const mm = (now.getMonth() + 1).toString().padStart(2, "0");
365
+ const dd = now.getDate().toString().padStart(2, "0");
366
+ const dateStr = `${yyyy}-${mm}-${dd}`;
367
+ const projHash = hashProject(project).slice(0, 8);
368
+ const baseId = `session-${dateStr}-${projHash}`;
369
+ const projectDir = getProjectSessionDir(project);
370
+ const yearMonthDir = path.join(projectDir, yyyy, mm);
371
+ fs.mkdirSync(yearMonthDir, { recursive: true });
372
+ const basePath = path.join(yearMonthDir, `${baseId}.md`);
373
+ if (!fs.existsSync(basePath)) {
374
+ return {
375
+ id: baseId,
376
+ filePath: path.join("sessions", hashProject(project), yyyy, mm, `${baseId}.md`)
377
+ };
378
+ }
379
+ let counter = 2;
380
+ while (fs.existsSync(path.join(yearMonthDir, `${baseId}-${counter}.md`))) {
381
+ counter++;
382
+ }
383
+ const id = `${baseId}-${counter}`;
384
+ return {
385
+ id,
386
+ filePath: path.join("sessions", hashProject(project), yyyy, mm, `${id}.md`)
387
+ };
388
+ }
389
+ function getSessionsRoot() {
390
+ return path.join(getChitraguptaHome(), "sessions");
391
+ }
392
+ function getProjectSessionDir(project) {
393
+ return path.join(getSessionsRoot(), hashProject(project));
394
+ }
395
+ function resolveSessionPath(id, project) {
396
+ const projectDir = getProjectSessionDir(project);
397
+ const dateMatch = id.match(/^session-(\d{4})-(\d{2})-\d{2}/);
398
+ if (dateMatch) {
399
+ const newPath = path.join(projectDir, dateMatch[1], dateMatch[2], `${id}.md`);
400
+ if (fs.existsSync(newPath)) return newPath;
401
+ }
402
+ const oldPath = path.join(projectDir, `${id}.md`);
403
+ if (fs.existsSync(oldPath)) return oldPath;
404
+ if (dateMatch) {
405
+ return path.join(projectDir, dateMatch[1], dateMatch[2], `${id}.md`);
406
+ }
407
+ return oldPath;
408
+ }
409
+ function patchFrontmatterUpdated(content, updatedIso) {
410
+ const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
411
+ if (!fmMatch) return content;
412
+ const frontmatter = fmMatch[1];
413
+ if (!/^updated:\s/m.test(frontmatter)) return content;
414
+ const patchedFrontmatter = frontmatter.replace(
415
+ /^updated:\s.*$/m,
416
+ `updated: ${updatedIso}`
417
+ );
418
+ if (patchedFrontmatter === frontmatter) return content;
419
+ return `---
420
+ ${patchedFrontmatter}
421
+ ---${content.slice(fmMatch[0].length)}`;
422
+ }
423
+ var _dbInitialized = false;
424
+ var _dbInitError = null;
425
+ function getAgentDb() {
426
+ const dbm = DatabaseManager.instance();
427
+ if (!_dbInitialized) {
428
+ try {
429
+ initAgentSchema(dbm);
430
+ _dbInitialized = true;
431
+ _dbInitError = null;
432
+ } catch (err) {
433
+ _dbInitError = err instanceof Error ? err : new Error(String(err));
434
+ process.stderr.write(`[chitragupta] agent DB schema init failed: ${_dbInitError.message}
435
+ `);
436
+ throw _dbInitError;
437
+ }
438
+ }
439
+ return dbm.get("agent");
440
+ }
441
+ function _resetDbInit() {
442
+ _dbInitialized = false;
443
+ _dbInitError = null;
444
+ }
445
+ function _getDbStatus() {
446
+ return {
447
+ initialized: _dbInitialized,
448
+ error: _dbInitError?.message ?? null
449
+ };
450
+ }
451
+ function sessionMetaToRow(meta, filePath) {
452
+ return {
453
+ id: meta.id,
454
+ project: meta.project,
455
+ title: meta.title,
456
+ created_at: new Date(meta.created).getTime(),
457
+ updated_at: new Date(meta.updated).getTime(),
458
+ turn_count: 0,
459
+ model: meta.model,
460
+ agent: meta.agent,
461
+ cost: meta.totalCost,
462
+ tokens: meta.totalTokens,
463
+ tags: JSON.stringify(meta.tags),
464
+ file_path: filePath,
465
+ parent_id: meta.parent,
466
+ branch: meta.branch,
467
+ metadata: meta.metadata ? JSON.stringify(meta.metadata) : null
468
+ };
469
+ }
470
+ function rowToSessionMeta(row) {
471
+ let tags = [];
472
+ try {
473
+ tags = JSON.parse(row.tags ?? "[]");
474
+ } catch {
475
+ }
476
+ let metadata;
477
+ try {
478
+ metadata = row.metadata ? JSON.parse(row.metadata) : void 0;
479
+ } catch {
480
+ }
481
+ const provider = metadata?.provider;
482
+ const createdAt = row.created_at;
483
+ const updatedAt = row.updated_at;
484
+ return {
485
+ id: row.id,
486
+ title: row.title,
487
+ created: createdAt ? new Date(createdAt).toISOString() : (/* @__PURE__ */ new Date()).toISOString(),
488
+ updated: updatedAt ? new Date(updatedAt).toISOString() : (/* @__PURE__ */ new Date()).toISOString(),
489
+ agent: row.agent ?? "chitragupta",
490
+ model: row.model ?? "unknown",
491
+ provider,
492
+ project: row.project,
493
+ parent: row.parent_id ?? null,
494
+ branch: row.branch ?? null,
495
+ tags,
496
+ totalCost: row.cost ?? 0,
497
+ totalTokens: row.tokens ?? 0,
498
+ metadata
499
+ };
500
+ }
501
+ function upsertSessionToDb(meta, filePath) {
502
+ try {
503
+ const db = getAgentDb();
504
+ const row = sessionMetaToRow(meta, filePath);
505
+ db.prepare(`
506
+ INSERT INTO sessions (id, project, title, created_at, updated_at, turn_count, model, agent, cost, tokens, tags, file_path, parent_id, branch, metadata)
507
+ VALUES (@id, @project, @title, @created_at, @updated_at, @turn_count, @model, @agent, @cost, @tokens, @tags, @file_path, @parent_id, @branch, @metadata)
508
+ ON CONFLICT(id) DO UPDATE SET
509
+ title = @title, updated_at = @updated_at, turn_count = @turn_count,
510
+ model = @model, cost = @cost, tokens = @tokens, tags = @tags, metadata = @metadata
511
+ `).run(row);
512
+ } catch (err) {
513
+ process.stderr.write(`[chitragupta] session upsert failed for ${meta.id}: ${err instanceof Error ? err.message : err}
514
+ `);
515
+ }
516
+ }
517
+ function insertTurnToDb(sessionId, turn) {
518
+ try {
519
+ const db = getAgentDb();
520
+ const now = Date.now();
521
+ const insertTurn = db.transaction(() => {
522
+ const result = db.prepare(`
523
+ INSERT OR IGNORE INTO turns (session_id, turn_number, role, content, agent, model, tool_calls, created_at)
524
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
525
+ `).run(
526
+ sessionId,
527
+ turn.turnNumber,
528
+ turn.role,
529
+ turn.content,
530
+ turn.agent ?? null,
531
+ turn.model ?? null,
532
+ turn.toolCalls ? JSON.stringify(turn.toolCalls) : null,
533
+ now
534
+ );
535
+ if (result.changes > 0) {
536
+ db.prepare("INSERT INTO turns_fts (rowid, content) VALUES (?, ?)").run(
537
+ result.lastInsertRowid,
538
+ turn.content
539
+ );
540
+ }
541
+ db.prepare(
542
+ "UPDATE sessions SET turn_count = turn_count + 1, updated_at = ? WHERE id = ?"
543
+ ).run(now, sessionId);
544
+ });
545
+ insertTurn();
546
+ } catch (err) {
547
+ process.stderr.write(`[chitragupta] turn insert failed for session ${sessionId}: ${err instanceof Error ? err.message : err}
548
+ `);
549
+ }
550
+ }
551
+ function createSession(opts) {
552
+ const now = (/* @__PURE__ */ new Date()).toISOString();
553
+ const { id, filePath } = generateSessionId(opts.project);
554
+ const meta = {
555
+ id,
556
+ title: opts.title ?? "New Session",
557
+ created: now,
558
+ updated: now,
559
+ agent: opts.agent ?? "chitragupta",
560
+ model: opts.model ?? "unknown",
561
+ provider: opts.provider,
562
+ project: opts.project,
563
+ parent: opts.parentSessionId ?? null,
564
+ branch: opts.branch ?? null,
565
+ tags: opts.tags ?? [],
566
+ totalCost: 0,
567
+ totalTokens: 0,
568
+ metadata: opts.metadata
569
+ };
570
+ if (opts.provider) {
571
+ meta.metadata = { ...meta.metadata, provider: opts.provider };
572
+ }
573
+ const session = { meta, turns: [] };
574
+ saveSession(session);
575
+ upsertSessionToDb(meta, filePath);
576
+ return session;
577
+ }
578
+ function saveSession(session) {
579
+ const filePath = resolveSessionPath(session.meta.id, session.meta.project);
580
+ const dir = path.dirname(filePath);
581
+ try {
582
+ fs.mkdirSync(dir, { recursive: true });
583
+ session.meta.updated = (/* @__PURE__ */ new Date()).toISOString();
584
+ const markdown = writeSessionMarkdown(session);
585
+ const tmpPath = `${filePath}.tmp.${process.pid}`;
586
+ fs.writeFileSync(tmpPath, markdown, "utf-8");
587
+ atomicRename(tmpPath, filePath);
588
+ cachePut(session.meta.id, session.meta.project, session);
589
+ } catch (err) {
590
+ throw new SessionError(
591
+ `Failed to save session ${session.meta.id} at ${filePath}: ${err.message}`
592
+ );
593
+ }
594
+ }
595
+ function loadSession(id, project) {
596
+ const cached = cacheGet(id, project);
597
+ if (cached) return cached;
598
+ const filePath = resolveSessionPath(id, project);
599
+ if (!fs.existsSync(filePath)) {
600
+ throw new SessionError(`Session not found: ${id} (project: ${project})`);
601
+ }
602
+ try {
603
+ const content = fs.readFileSync(filePath, "utf-8");
604
+ const session = parseSessionMarkdown(content);
605
+ cachePut(id, project, session);
606
+ return session;
607
+ } catch (err) {
608
+ if (err instanceof SessionError) throw err;
609
+ throw new SessionError(
610
+ `Failed to load session ${id}: ${err.message}`
611
+ );
612
+ }
613
+ }
614
+ function listSessions(project) {
615
+ try {
616
+ const db = getAgentDb();
617
+ let rows;
618
+ if (project) {
619
+ rows = db.prepare(
620
+ "SELECT * FROM sessions WHERE project = ? ORDER BY updated_at DESC"
621
+ ).all(project);
622
+ } else {
623
+ rows = db.prepare(
624
+ "SELECT * FROM sessions ORDER BY updated_at DESC"
625
+ ).all();
626
+ }
627
+ if (rows.length > 0) {
628
+ return rows.map(rowToSessionMeta);
629
+ }
630
+ } catch (err) {
631
+ process.stderr.write(`[chitragupta] listSessions SQLite failed, falling back to filesystem: ${err instanceof Error ? err.message : err}
632
+ `);
633
+ }
634
+ return listSessionsFromFilesystem(project);
635
+ }
636
+ function listSessionsByDate(date, project) {
637
+ const dateMatch = date.match(/^(\d{4})-(\d{2})-(\d{2})$/);
638
+ if (!dateMatch) {
639
+ throw new SessionError(`Invalid date format: ${date}. Expected YYYY-MM-DD.`);
640
+ }
641
+ const startOfDay = (/* @__PURE__ */ new Date(`${date}T00:00:00.000Z`)).getTime();
642
+ const endOfDay = startOfDay + 864e5;
643
+ return listSessionsByDateRange(startOfDay, endOfDay, project);
644
+ }
645
+ function listSessionsByDateRange(startMs, endMs, project) {
646
+ try {
647
+ const db = getAgentDb();
648
+ let rows;
649
+ if (project) {
650
+ rows = db.prepare(
651
+ "SELECT * FROM sessions WHERE project = ? AND created_at >= ? AND created_at < ? ORDER BY created_at ASC"
652
+ ).all(project, startMs, endMs);
653
+ } else {
654
+ rows = db.prepare(
655
+ "SELECT * FROM sessions WHERE created_at >= ? AND created_at < ? ORDER BY created_at ASC"
656
+ ).all(startMs, endMs);
657
+ }
658
+ if (rows.length > 0) {
659
+ return rows.map(rowToSessionMeta);
660
+ }
661
+ } catch {
662
+ }
663
+ const allSessions = listSessionsFromFilesystem(project);
664
+ return allSessions.filter((s) => {
665
+ const created = new Date(s.created).getTime();
666
+ return created >= startMs && created < endMs;
667
+ });
668
+ }
669
+ function listSessionDates(project) {
670
+ try {
671
+ const db = getAgentDb();
672
+ let rows;
673
+ if (project) {
674
+ rows = db.prepare(
675
+ `SELECT DISTINCT date(created_at / 1000, 'unixepoch') as session_date
676
+ FROM sessions WHERE project = ?
677
+ ORDER BY session_date DESC`
678
+ ).all(project);
679
+ } else {
680
+ rows = db.prepare(
681
+ `SELECT DISTINCT date(created_at / 1000, 'unixepoch') as session_date
682
+ FROM sessions
683
+ ORDER BY session_date DESC`
684
+ ).all();
685
+ }
686
+ return rows.map((r) => r.session_date).filter(Boolean);
687
+ } catch {
688
+ const allSessions = listSessionsFromFilesystem(project);
689
+ const dates = /* @__PURE__ */ new Set();
690
+ for (const s of allSessions) {
691
+ dates.add(s.created.slice(0, 10));
692
+ }
693
+ return [...dates].sort().reverse();
694
+ }
695
+ }
696
+ function listSessionProjects() {
697
+ try {
698
+ const db = getAgentDb();
699
+ const rows = db.prepare(
700
+ `SELECT project, COUNT(*) as count, MAX(updated_at) as last_active
701
+ FROM sessions
702
+ GROUP BY project
703
+ ORDER BY last_active DESC`
704
+ ).all();
705
+ return rows.map((r) => ({
706
+ project: r.project,
707
+ sessionCount: r.count,
708
+ lastActive: new Date(r.last_active).toISOString()
709
+ }));
710
+ } catch {
711
+ return [];
712
+ }
713
+ }
714
+ function listSessionsFromFilesystem(project) {
715
+ const sessionsRoot = getSessionsRoot();
716
+ if (!fs.existsSync(sessionsRoot)) return [];
717
+ const results = [];
718
+ if (project) {
719
+ const projectDir = getProjectSessionDir(project);
720
+ if (!fs.existsSync(projectDir)) return [];
721
+ results.push(...scanDirRecursive(projectDir));
722
+ } else {
723
+ const projectDirs = fs.readdirSync(sessionsRoot, { withFileTypes: true });
724
+ for (const entry of projectDirs) {
725
+ if (entry.isDirectory()) {
726
+ results.push(...scanDirRecursive(path.join(sessionsRoot, entry.name)));
727
+ }
728
+ }
729
+ }
730
+ results.sort((a, b) => new Date(b.updated).getTime() - new Date(a.updated).getTime());
731
+ return results;
732
+ }
733
+ function scanDirRecursive(dir) {
734
+ const metas = [];
735
+ try {
736
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
737
+ for (const entry of entries) {
738
+ const fullPath = path.join(dir, entry.name);
739
+ if (entry.isDirectory()) {
740
+ metas.push(...scanDirRecursive(fullPath));
741
+ } else if (entry.name.endsWith(".md")) {
742
+ try {
743
+ const content = fs.readFileSync(fullPath, "utf-8");
744
+ const session = parseSessionMarkdown(content);
745
+ metas.push(session.meta);
746
+ } catch {
747
+ }
748
+ }
749
+ }
750
+ } catch {
751
+ }
752
+ return metas;
753
+ }
754
+ function deleteSession(id, project) {
755
+ const filePath = resolveSessionPath(id, project);
756
+ if (!fs.existsSync(filePath)) {
757
+ throw new SessionError(`Session not found: ${id} (project: ${project})`);
758
+ }
759
+ fs.unlinkSync(filePath);
760
+ cacheInvalidate(id, project);
761
+ let dir = path.dirname(filePath);
762
+ const sessionsRoot = getSessionsRoot();
763
+ while (dir !== sessionsRoot && dir.length > sessionsRoot.length) {
764
+ try {
765
+ const remaining = fs.readdirSync(dir);
766
+ if (remaining.length === 0) {
767
+ fs.rmdirSync(dir);
768
+ dir = path.dirname(dir);
769
+ } else {
770
+ break;
771
+ }
772
+ } catch {
773
+ break;
774
+ }
775
+ }
776
+ try {
777
+ const db = getAgentDb();
778
+ const turns = db.prepare("SELECT id FROM turns WHERE session_id = ?").all(id);
779
+ for (const t of turns) {
780
+ db.prepare("DELETE FROM turns_fts WHERE rowid = ?").run(t.id);
781
+ }
782
+ db.prepare("DELETE FROM turns WHERE session_id = ?").run(id);
783
+ db.prepare("DELETE FROM sessions WHERE id = ?").run(id);
784
+ } catch {
785
+ }
786
+ }
787
+ var sessionWriteQueues = /* @__PURE__ */ new Map();
788
+ function addTurn(sessionId, project, turn) {
789
+ const key = `${sessionId}:${project}`;
790
+ const prev = sessionWriteQueues.get(key) ?? Promise.resolve();
791
+ const next = prev.then(() => {
792
+ const filePath = resolveSessionPath(sessionId, project);
793
+ if (!fs.existsSync(filePath)) {
794
+ throw new SessionError(`Session not found: ${sessionId} (project: ${project})`);
795
+ }
796
+ const fileContent = fs.readFileSync(filePath, "utf-8");
797
+ if (!turn.turnNumber) {
798
+ try {
799
+ const session = parseSessionMarkdown(fileContent);
800
+ turn.turnNumber = session.turns.length + 1;
801
+ } catch {
802
+ turn.turnNumber = getMaxTurnNumber(sessionId) + 1;
803
+ }
804
+ }
805
+ const updatedIso = (/* @__PURE__ */ new Date()).toISOString();
806
+ const patchedContent = patchFrontmatterUpdated(fileContent, updatedIso);
807
+ if (patchedContent !== fileContent) {
808
+ fs.writeFileSync(filePath, patchedContent, "utf-8");
809
+ }
810
+ const turnMd = writeTurnMarkdown(turn);
811
+ fs.appendFileSync(filePath, `
812
+ ${turnMd}
813
+ `, "utf-8");
814
+ cacheInvalidate(sessionId, project);
815
+ insertTurnToDb(sessionId, turn);
816
+ }).catch((err) => {
817
+ throw err;
818
+ }).finally(() => {
819
+ if (sessionWriteQueues.get(key) === next) {
820
+ sessionWriteQueues.delete(key);
821
+ }
822
+ });
823
+ sessionWriteQueues.set(key, next);
824
+ return next;
825
+ }
826
+ function listTurnsWithTimestamps(sessionId, project) {
827
+ try {
828
+ const db = getAgentDb();
829
+ const rows = db.prepare(
830
+ "SELECT turn_number, role, content, agent, model, tool_calls, created_at FROM turns WHERE session_id = ? ORDER BY turn_number ASC"
831
+ ).all(sessionId);
832
+ if (rows.length > 0) {
833
+ return rows.map((row) => ({
834
+ turnNumber: row.turn_number,
835
+ role: row.role,
836
+ content: row.content,
837
+ agent: row.agent ?? void 0,
838
+ model: row.model ?? void 0,
839
+ toolCalls: row.tool_calls ? JSON.parse(row.tool_calls) : void 0,
840
+ createdAt: row.created_at
841
+ }));
842
+ }
843
+ } catch {
844
+ }
845
+ try {
846
+ const session = loadSession(sessionId, project);
847
+ const baseTime = new Date(session.meta.created).getTime();
848
+ return session.turns.map((turn, i) => ({
849
+ ...turn,
850
+ createdAt: baseTime + i * 1e3
851
+ // 1-second spacing
852
+ }));
853
+ } catch {
854
+ return [];
855
+ }
856
+ }
857
+ function updateSessionMeta(sessionId, updates) {
858
+ try {
859
+ const db = getAgentDb();
860
+ const sets = [];
861
+ const params = { id: sessionId };
862
+ if (updates.title !== void 0) {
863
+ sets.push("title = @title");
864
+ params.title = updates.title;
865
+ }
866
+ if (updates.model !== void 0) {
867
+ sets.push("model = @model");
868
+ params.model = updates.model;
869
+ }
870
+ if (updates.metadata !== void 0) {
871
+ sets.push("metadata = @metadata");
872
+ params.metadata = JSON.stringify(updates.metadata);
873
+ }
874
+ if (updates.tags !== void 0) {
875
+ sets.push("tags = @tags");
876
+ params.tags = JSON.stringify(updates.tags);
877
+ }
878
+ if (sets.length === 0) return;
879
+ sets.push("updated_at = @updated_at");
880
+ params.updated_at = Date.now();
881
+ db.prepare(`UPDATE sessions SET ${sets.join(", ")} WHERE id = @id`).run(params);
882
+ } catch {
883
+ }
884
+ }
885
+ function getMaxTurnNumber(sessionId) {
886
+ try {
887
+ const db = getAgentDb();
888
+ const row = db.prepare("SELECT MAX(turn_number) as max_turn FROM turns WHERE session_id = ?").get(sessionId);
889
+ return row?.max_turn ?? 0;
890
+ } catch {
891
+ return 0;
892
+ }
893
+ }
894
+ function findSessionByMetadata(key, value, project) {
895
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) {
896
+ return void 0;
897
+ }
898
+ try {
899
+ const db = getAgentDb();
900
+ const sql = project ? "SELECT * FROM sessions WHERE project = ? AND json_extract(metadata, ?) = ? LIMIT 1" : "SELECT * FROM sessions WHERE json_extract(metadata, ?) = ? LIMIT 1";
901
+ const params = project ? [project, `$.${key}`, value] : [`$.${key}`, value];
902
+ const row = db.prepare(sql).get(...params);
903
+ return row ? rowToSessionMeta(row) : void 0;
904
+ } catch {
905
+ return void 0;
906
+ }
907
+ }
908
+ function migrateExistingSessions(project) {
909
+ const db = getAgentDb();
910
+ const sessionsRoot = getSessionsRoot();
911
+ if (!fs.existsSync(sessionsRoot)) return { migrated: 0, skipped: 0 };
912
+ let migrated = 0;
913
+ let skipped = 0;
914
+ const dirs = project ? [getProjectSessionDir(project)] : fs.readdirSync(sessionsRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => path.join(sessionsRoot, e.name));
915
+ const insertSession = db.prepare(`
916
+ INSERT OR IGNORE INTO sessions (id, project, title, created_at, updated_at, turn_count, model, agent, cost, tokens, tags, file_path, parent_id, branch, metadata)
917
+ VALUES (@id, @project, @title, @created_at, @updated_at, @turn_count, @model, @agent, @cost, @tokens, @tags, @file_path, @parent_id, @branch, @metadata)
918
+ `);
919
+ const insertTurn = db.prepare(`
920
+ INSERT OR IGNORE INTO turns (session_id, turn_number, role, content, agent, model, tool_calls, created_at)
921
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
922
+ `);
923
+ const insertFts = db.prepare(
924
+ "INSERT INTO turns_fts (rowid, content) VALUES (?, ?)"
925
+ );
926
+ const migrateFile = (mdPath, relativePath) => {
927
+ try {
928
+ const content = fs.readFileSync(mdPath, "utf-8");
929
+ const session = parseSessionMarkdown(content);
930
+ const existing = db.prepare("SELECT id FROM sessions WHERE id = ?").get(session.meta.id);
931
+ if (existing) {
932
+ skipped++;
933
+ return;
934
+ }
935
+ const row = sessionMetaToRow(session.meta, relativePath);
936
+ row.turn_count = session.turns.length;
937
+ insertSession.run(row);
938
+ for (const turn of session.turns) {
939
+ const result = insertTurn.run(
940
+ session.meta.id,
941
+ turn.turnNumber,
942
+ turn.role,
943
+ turn.content,
944
+ turn.agent ?? null,
945
+ turn.model ?? null,
946
+ turn.toolCalls ? JSON.stringify(turn.toolCalls) : null,
947
+ new Date(session.meta.created).getTime()
948
+ );
949
+ if (result.changes > 0) {
950
+ insertFts.run(result.lastInsertRowid, turn.content);
951
+ }
952
+ }
953
+ migrated++;
954
+ } catch {
955
+ skipped++;
956
+ }
957
+ };
958
+ const runMigration = db.transaction(() => {
959
+ for (const dir of dirs) {
960
+ if (!fs.existsSync(dir)) continue;
961
+ walkMdFiles(dir, sessionsRoot, migrateFile);
962
+ }
963
+ });
964
+ runMigration();
965
+ return { migrated, skipped };
966
+ }
967
+ function walkMdFiles(dir, sessionsRoot, callback) {
968
+ try {
969
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
970
+ for (const entry of entries) {
971
+ const fullPath = path.join(dir, entry.name);
972
+ if (entry.isDirectory()) {
973
+ walkMdFiles(fullPath, sessionsRoot, callback);
974
+ } else if (entry.name.endsWith(".md")) {
975
+ const relativePath = path.relative(path.dirname(sessionsRoot), fullPath);
976
+ callback(fullPath, relativePath);
977
+ }
978
+ }
979
+ } catch {
980
+ }
981
+ }
982
+
983
+ export {
984
+ parseSessionMarkdown,
985
+ writeSessionMarkdown,
986
+ writeTurnMarkdown,
987
+ _resetSessionCache,
988
+ _resetDbInit,
989
+ _getDbStatus,
990
+ createSession,
991
+ saveSession,
992
+ loadSession,
993
+ listSessions,
994
+ listSessionsByDate,
995
+ listSessionsByDateRange,
996
+ listSessionDates,
997
+ listSessionProjects,
998
+ deleteSession,
999
+ addTurn,
1000
+ listTurnsWithTimestamps,
1001
+ updateSessionMeta,
1002
+ getMaxTurnNumber,
1003
+ findSessionByMetadata,
1004
+ migrateExistingSessions
1005
+ };
1006
+ //# sourceMappingURL=chunk-L7JICQBW.js.map