@jini-ai/sqlite 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 (102) hide show
  1. package/LICENSE +201 -0
  2. package/dist/backend-config.d.ts +42 -0
  3. package/dist/backend-config.d.ts.map +1 -0
  4. package/dist/backend-config.js +57 -0
  5. package/dist/backend-config.js.map +1 -0
  6. package/dist/db/agent-sessions/agent-sessions.d.ts +79 -0
  7. package/dist/db/agent-sessions/agent-sessions.d.ts.map +1 -0
  8. package/dist/db/agent-sessions/agent-sessions.js +121 -0
  9. package/dist/db/agent-sessions/agent-sessions.js.map +1 -0
  10. package/dist/db/agent-sessions/index.d.ts +6 -0
  11. package/dist/db/agent-sessions/index.d.ts.map +1 -0
  12. package/dist/db/agent-sessions/index.js +6 -0
  13. package/dist/db/agent-sessions/index.js.map +1 -0
  14. package/dist/db/capabilities/capabilities.d.ts +39 -0
  15. package/dist/db/capabilities/capabilities.d.ts.map +1 -0
  16. package/dist/db/capabilities/capabilities.js +54 -0
  17. package/dist/db/capabilities/capabilities.js.map +1 -0
  18. package/dist/db/capabilities/index.d.ts +4 -0
  19. package/dist/db/capabilities/index.d.ts.map +1 -0
  20. package/dist/db/capabilities/index.js +4 -0
  21. package/dist/db/capabilities/index.js.map +1 -0
  22. package/dist/db/connection/connection.d.ts +18 -0
  23. package/dist/db/connection/connection.d.ts.map +1 -0
  24. package/dist/db/connection/connection.js +48 -0
  25. package/dist/db/connection/connection.js.map +1 -0
  26. package/dist/db/connection/index.d.ts +3 -0
  27. package/dist/db/connection/index.d.ts.map +1 -0
  28. package/dist/db/connection/index.js +3 -0
  29. package/dist/db/connection/index.js.map +1 -0
  30. package/dist/db/conversations/conversations.d.ts +109 -0
  31. package/dist/db/conversations/conversations.d.ts.map +1 -0
  32. package/dist/db/conversations/conversations.js +274 -0
  33. package/dist/db/conversations/conversations.js.map +1 -0
  34. package/dist/db/conversations/index.d.ts +3 -0
  35. package/dist/db/conversations/index.d.ts.map +1 -0
  36. package/dist/db/conversations/index.js +3 -0
  37. package/dist/db/conversations/index.js.map +1 -0
  38. package/dist/db/core/index.d.ts +6 -0
  39. package/dist/db/core/index.d.ts.map +1 -0
  40. package/dist/db/core/index.js +6 -0
  41. package/dist/db/core/index.js.map +1 -0
  42. package/dist/db/core/json.d.ts +13 -0
  43. package/dist/db/core/json.d.ts.map +1 -0
  44. package/dist/db/core/json.js +22 -0
  45. package/dist/db/core/json.js.map +1 -0
  46. package/dist/db/core/rows.d.ts +18 -0
  47. package/dist/db/core/rows.d.ts.map +1 -0
  48. package/dist/db/core/rows.js +17 -0
  49. package/dist/db/core/rows.js.map +1 -0
  50. package/dist/db/core/types.d.ts +14 -0
  51. package/dist/db/core/types.d.ts.map +1 -0
  52. package/dist/db/core/types.js +2 -0
  53. package/dist/db/core/types.js.map +1 -0
  54. package/dist/db/index.d.ts +18 -0
  55. package/dist/db/index.d.ts.map +1 -0
  56. package/dist/db/index.js +16 -0
  57. package/dist/db/index.js.map +1 -0
  58. package/dist/db/messages/index.d.ts +4 -0
  59. package/dist/db/messages/index.d.ts.map +1 -0
  60. package/dist/db/messages/index.js +4 -0
  61. package/dist/db/messages/index.js.map +1 -0
  62. package/dist/db/messages/messages.d.ts +129 -0
  63. package/dist/db/messages/messages.d.ts.map +1 -0
  64. package/dist/db/messages/messages.js +246 -0
  65. package/dist/db/messages/messages.js.map +1 -0
  66. package/dist/db/projects/index.d.ts +4 -0
  67. package/dist/db/projects/index.d.ts.map +1 -0
  68. package/dist/db/projects/index.js +4 -0
  69. package/dist/db/projects/index.js.map +1 -0
  70. package/dist/db/projects/projects.d.ts +122 -0
  71. package/dist/db/projects/projects.d.ts.map +1 -0
  72. package/dist/db/projects/projects.js +311 -0
  73. package/dist/db/projects/projects.js.map +1 -0
  74. package/dist/db/schema/index.d.ts +3 -0
  75. package/dist/db/schema/index.d.ts.map +1 -0
  76. package/dist/db/schema/index.js +3 -0
  77. package/dist/db/schema/index.js.map +1 -0
  78. package/dist/db/schema/migrate.d.ts +29 -0
  79. package/dist/db/schema/migrate.d.ts.map +1 -0
  80. package/dist/db/schema/migrate.js +78 -0
  81. package/dist/db/schema/migrate.js.map +1 -0
  82. package/dist/db/tool-catalog/index.d.ts +6 -0
  83. package/dist/db/tool-catalog/index.d.ts.map +1 -0
  84. package/dist/db/tool-catalog/index.js +6 -0
  85. package/dist/db/tool-catalog/index.js.map +1 -0
  86. package/dist/db/tool-catalog/tool-catalog.d.ts +70 -0
  87. package/dist/db/tool-catalog/tool-catalog.d.ts.map +1 -0
  88. package/dist/db/tool-catalog/tool-catalog.js +87 -0
  89. package/dist/db/tool-catalog/tool-catalog.js.map +1 -0
  90. package/dist/db-inspect.d.ts +62 -0
  91. package/dist/db-inspect.d.ts.map +1 -0
  92. package/dist/db-inspect.js +153 -0
  93. package/dist/db-inspect.js.map +1 -0
  94. package/dist/event-log.d.ts +33 -0
  95. package/dist/event-log.d.ts.map +1 -0
  96. package/dist/event-log.js +191 -0
  97. package/dist/event-log.js.map +1 -0
  98. package/dist/index.d.ts +12 -0
  99. package/dist/index.d.ts.map +1 -0
  100. package/dist/index.js +12 -0
  101. package/dist/index.js.map +1 -0
  102. package/package.json +49 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../../src/db/capabilities/capabilities.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAqB7C,SAAS,mBAAmB,CAAC,CAAQ;IACnC,OAAO;QACL,EAAE,EAAE,CAAC,CAAC,EAAE;QACR,WAAW,EAAE,CAAC,CAAC,WAAW;QAC1B,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,eAAyB,CAAC;QACpD,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;KAC/B,CAAC;AACJ,CAAC;AAED,qKAAqK;AACrK,MAAM,UAAU,0BAA0B,CAAC,EAAY,EAAE,GAA2E;IAClI,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;IAC9C,EAAE,CAAC,OAAO,CACR;;;;;;wCAMoC,CACrC,CAAC,GAAG,CAAC;QACJ,EAAE,EAAE,GAAG,CAAC,EAAE;QACV,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,eAAe,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC;QAChD,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,SAAS;KACV,CAAC,CAAC;AACL,CAAC;AAED,mEAAmE;AACnE,MAAM,UAAU,yBAAyB,CAAC,EAAY;IACpD,OAAO,IAAI,CACT,EAAE,CAAC,OAAO,CACR;iDAC2C,CAC5C,CAAC,GAAG,EAAE,CACR,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;AAC7B,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,uBAAuB,CAAC,EAAY,EAAE,EAAU;IAC9D,MAAM,CAAC,GAAG,GAAG,CACX,EAAE,CAAC,OAAO,CACR;kDAC4C,CAC7C,CAAC,GAAG,CAAC,EAAE,CAAC,CACV,CAAC;IACF,OAAO,CAAC,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3C,CAAC;AAED,sGAAsG;AACtG,MAAM,UAAU,yBAAyB,CAAC,EAAY,EAAE,MAAiC;IACvF,EAAE,CAAC,OAAO,CACR;;gHAE4G,CAC7G,CAAC,GAAG,CAAC;QACJ,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC;QAC/C,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,UAAU,EAAE,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC;QAC9E,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,IAAI;QAC3B,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,IAAI;KACxC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,4 @@
1
+ /** @module db/capabilities/index
2
+ * Public re-export surface for the capabilities/ concern subdirectory. */
3
+ export * from './capabilities.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/db/capabilities/index.ts"],"names":[],"mappings":"AAAA;0EAC0E;AAC1E,cAAc,mBAAmB,CAAC"}
@@ -0,0 +1,4 @@
1
+ /** @module db/capabilities/index
2
+ * Public re-export surface for the capabilities/ concern subdirectory. */
3
+ export * from './capabilities.js';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/db/capabilities/index.ts"],"names":[],"mappings":"AAAA;0EAC0E;AAC1E,cAAc,mBAAmB,CAAC"}
@@ -0,0 +1,18 @@
1
+ import type { SqliteDb } from '../core/index.js';
2
+ /**
3
+ * Open (or return the cached) project database at `<dataDir>/app.sqlite`, creating the
4
+ * directory if needed, enabling WAL + foreign keys, and running all pending schema migrations.
5
+ * Calling with a different resolved path closes the previous connection first.
6
+ * @param projectRoot - fallback parent directory when `dataDir` is not supplied (uses a `.jini` subfolder)
7
+ * @param options.dataDir - explicit data directory; overrides the default `.jini` subfolder
8
+ * @returns the live `SqliteDb` handle, ready for immediate use
9
+ */
10
+ export declare function openDatabase(projectRoot: string, { dataDir }?: {
11
+ dataDir?: string;
12
+ }): SqliteDb;
13
+ /**
14
+ * Close the active database connection and clear the module-level singleton.
15
+ * Safe to call when no connection is open (no-op in that case).
16
+ */
17
+ export declare function closeDatabase(): void;
18
+ //# sourceMappingURL=connection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../../src/db/connection/connection.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAOjD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,QAAQ,CAalG;AAED;;;GAGG;AACH,wBAAgB,aAAa,SAK5B"}
@@ -0,0 +1,48 @@
1
+ /** @module db/connection/connection
2
+ * Database lifecycle: opens and closes the module-level better-sqlite3 singleton.
3
+ * Reaches the `schema` sibling barrel to run `migrate` immediately after every `openDatabase` call;
4
+ * that is the only cross-concern edge in the db module.
5
+ */
6
+ import Database from 'better-sqlite3';
7
+ import path from 'node:path';
8
+ import fs from 'node:fs';
9
+ import { migrate } from '../schema/index.js';
10
+ /** @internal Module-level singleton tracking the currently-open database handle and its resolved file path. */
11
+ let dbInstance = null;
12
+ let dbFile = null;
13
+ /**
14
+ * Open (or return the cached) project database at `<dataDir>/app.sqlite`, creating the
15
+ * directory if needed, enabling WAL + foreign keys, and running all pending schema migrations.
16
+ * Calling with a different resolved path closes the previous connection first.
17
+ * @param projectRoot - fallback parent directory when `dataDir` is not supplied (uses a `.jini` subfolder)
18
+ * @param options.dataDir - explicit data directory; overrides the default `.jini` subfolder
19
+ * @returns the live `SqliteDb` handle, ready for immediate use
20
+ */
21
+ export function openDatabase(projectRoot, { dataDir } = {}) {
22
+ const dir = dataDir ? path.resolve(dataDir) : path.join(projectRoot, '.jini');
23
+ const file = path.join(dir, 'app.sqlite');
24
+ if (dbInstance && dbFile === file)
25
+ return dbInstance;
26
+ if (dbInstance)
27
+ closeDatabase();
28
+ fs.mkdirSync(dir, { recursive: true });
29
+ const db = new Database(file);
30
+ db.pragma('journal_mode = WAL');
31
+ db.pragma('foreign_keys = ON');
32
+ migrate(db);
33
+ dbInstance = db;
34
+ dbFile = file;
35
+ return db;
36
+ }
37
+ /**
38
+ * Close the active database connection and clear the module-level singleton.
39
+ * Safe to call when no connection is open (no-op in that case).
40
+ */
41
+ export function closeDatabase() {
42
+ if (!dbInstance)
43
+ return;
44
+ dbInstance.close();
45
+ dbInstance = null;
46
+ dbFile = null;
47
+ }
48
+ //# sourceMappingURL=connection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection.js","sourceRoot":"","sources":["../../../src/db/connection/connection.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE7C,+GAA+G;AAC/G,IAAI,UAAU,GAAoB,IAAI,CAAC;AACvC,IAAI,MAAM,GAAkB,IAAI,CAAC;AAEjC;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,WAAmB,EAAE,EAAE,OAAO,KAA2B,EAAE;IACtF,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAC9E,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAC1C,IAAI,UAAU,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,UAAU,CAAC;IACrD,IAAI,UAAU;QAAE,aAAa,EAAE,CAAC;IAChC,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC9B,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAChC,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,CAAC,CAAC;IACZ,UAAU,GAAG,EAAE,CAAC;IAChB,MAAM,GAAG,IAAI,CAAC;IACd,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa;IAC3B,IAAI,CAAC,UAAU;QAAE,OAAO;IACxB,UAAU,CAAC,KAAK,EAAE,CAAC;IACnB,UAAU,GAAG,IAAI,CAAC;IAClB,MAAM,GAAG,IAAI,CAAC;AAChB,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** @module db/connection/index */
2
+ export { openDatabase, closeDatabase } from './connection.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/db/connection/index.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** @module db/connection/index */
2
+ export { openDatabase, closeDatabase } from './connection.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/db/connection/index.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * @module db/conversations/conversations
3
+ * Owns conversation CRUD and list/get queries with per-conversation run summaries and
4
+ * total run-duration aggregation. Imports only the core/ kernel (types + rows helper).
5
+ */
6
+ import type { SqliteDb, DbRow, ChatSessionMode } from '../core/index.js';
7
+ /**
8
+ * Returns all conversations for a project, newest first, each enriched with message count,
9
+ * the latest assistant run summary, and total accumulated run duration across all terminal runs.
10
+ * @param db Open SQLite database handle.
11
+ * @param projectId The project whose conversations to list.
12
+ */
13
+ export declare function listConversations(db: SqliteDb, projectId: string): {
14
+ latestRun: {
15
+ durationMs?: number;
16
+ endedAt?: number | undefined;
17
+ startedAt?: number | undefined;
18
+ status: string;
19
+ } | undefined;
20
+ totalDurationMs?: number;
21
+ id: any;
22
+ projectId: any;
23
+ title: any;
24
+ sessionMode: ChatSessionMode;
25
+ messageCount: number;
26
+ createdAt: number;
27
+ updatedAt: number;
28
+ }[];
29
+ /**
30
+ * Fetches a single conversation by id with its latest run summary and total run duration.
31
+ * Returns null when no matching conversation exists.
32
+ * @param db Open SQLite database handle.
33
+ * @param id Conversation id.
34
+ */
35
+ export declare function getConversation(db: SqliteDb, id: string): {
36
+ totalDurationMs?: number;
37
+ latestRun: {
38
+ durationMs?: number;
39
+ endedAt?: number | undefined;
40
+ startedAt?: number | undefined;
41
+ status: string;
42
+ } | undefined;
43
+ id: any;
44
+ projectId: any;
45
+ title: any;
46
+ sessionMode: ChatSessionMode;
47
+ messageCount: number;
48
+ createdAt: number;
49
+ updatedAt: number;
50
+ } | null;
51
+ /**
52
+ * Coerces an arbitrary database value to a valid ChatSessionMode, defaulting to 'design'.
53
+ * Upholds the invariant that no conversation ever carries an unknown session mode.
54
+ * @param value Raw value read from the session_mode column.
55
+ * @returns A valid ChatSessionMode: 'chat', 'plan', or 'design'.
56
+ */
57
+ export declare function normalizeConversationSessionMode(value: unknown): ChatSessionMode;
58
+ /**
59
+ * Inserts a new conversation row and returns the full conversation record (including run summary).
60
+ * Normalizes sessionMode before persisting so the stored value is always a valid ChatSessionMode.
61
+ * @param db Open SQLite database handle.
62
+ * @param c Conversation fields to insert.
63
+ */
64
+ export declare function insertConversation(db: SqliteDb, c: DbRow): {
65
+ totalDurationMs?: number;
66
+ latestRun: {
67
+ durationMs?: number;
68
+ endedAt?: number | undefined;
69
+ startedAt?: number | undefined;
70
+ status: string;
71
+ } | undefined;
72
+ id: any;
73
+ projectId: any;
74
+ title: any;
75
+ sessionMode: ChatSessionMode;
76
+ messageCount: number;
77
+ createdAt: number;
78
+ updatedAt: number;
79
+ } | null;
80
+ /**
81
+ * Applies a partial patch to an existing conversation, merging with the current record.
82
+ * Returns null when the conversation does not exist; otherwise returns the updated record.
83
+ * @param db Open SQLite database handle.
84
+ * @param id Conversation id to update.
85
+ * @param patch Fields to overwrite; sessionMode and updatedAt are normalized before persisting.
86
+ */
87
+ export declare function updateConversation(db: SqliteDb, id: string, patch: DbRow): {
88
+ totalDurationMs?: number;
89
+ latestRun: {
90
+ durationMs?: number;
91
+ endedAt?: number | undefined;
92
+ startedAt?: number | undefined;
93
+ status: string;
94
+ } | undefined;
95
+ id: any;
96
+ projectId: any;
97
+ title: any;
98
+ sessionMode: ChatSessionMode;
99
+ messageCount: number;
100
+ createdAt: number;
101
+ updatedAt: number;
102
+ } | null;
103
+ /**
104
+ * Removes a conversation row by id. Cascading deletes on messages are handled by the schema.
105
+ * @param db Open SQLite database handle.
106
+ * @param id Conversation id to delete.
107
+ */
108
+ export declare function deleteConversation(db: SqliteDb, id: string): void;
109
+ //# sourceMappingURL=conversations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversations.d.ts","sourceRoot":"","sources":["../../../src/db/conversations/conversations.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAGzE;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM;;;;;;;;;;;;;;;IA4DhE;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM;;;;;;;;;;;;;;;SAevD;AAuBD;;;;;GAKG;AACH,wBAAgB,gCAAgC,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CAEhF;AA6HD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK;;;;;;;;;;;;;;;SAcxD;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK;;;;;;;;;;;;;;;SAgBxE;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,QAE1D"}
@@ -0,0 +1,274 @@
1
+ import { rows } from '../core/index.js';
2
+ /**
3
+ * Returns all conversations for a project, newest first, each enriched with message count,
4
+ * the latest assistant run summary, and total accumulated run duration across all terminal runs.
5
+ * @param db Open SQLite database handle.
6
+ * @param projectId The project whose conversations to list.
7
+ */
8
+ export function listConversations(db, projectId) {
9
+ return rows(db
10
+ .prepare(`WITH project_conversations AS (
11
+ SELECT id, project_id AS projectId, title, session_mode AS sessionMode,
12
+ created_at AS createdAt, updated_at AS updatedAt
13
+ FROM conversations
14
+ WHERE project_id = ?
15
+ ),
16
+ latest_runs AS (
17
+ SELECT conversation_id AS conversationId,
18
+ run_status AS latestRunStatus,
19
+ started_at AS latestRunStartedAt,
20
+ ended_at AS latestRunEndedAt,
21
+ events_json AS latestRunEventsJson
22
+ FROM (
23
+ SELECT m.conversation_id,
24
+ m.run_status,
25
+ m.started_at,
26
+ m.ended_at,
27
+ m.events_json,
28
+ ROW_NUMBER() OVER (
29
+ PARTITION BY m.conversation_id
30
+ ORDER BY m.position DESC
31
+ ) AS rn
32
+ FROM messages m
33
+ JOIN project_conversations c ON c.id = m.conversation_id
34
+ WHERE m.role = 'assistant'
35
+ AND m.run_status IS NOT NULL
36
+ )
37
+ WHERE rn = 1
38
+ ),
39
+ message_counts AS (
40
+ SELECT m.conversation_id AS conversationId,
41
+ COUNT(*) AS messageCount
42
+ FROM messages m
43
+ JOIN project_conversations c ON c.id = m.conversation_id
44
+ GROUP BY m.conversation_id
45
+ ),
46
+ total_run_durations AS (
47
+ SELECT m.conversation_id AS conversationId,
48
+ SUM(${terminalRunDurationSql('m')}) AS totalDurationMs
49
+ FROM messages m
50
+ JOIN project_conversations c ON c.id = m.conversation_id
51
+ WHERE m.role = 'assistant'
52
+ AND m.run_status IN ('succeeded', 'failed', 'canceled')
53
+ GROUP BY m.conversation_id
54
+ )
55
+ SELECT c.id, c.projectId, c.title, c.sessionMode, c.createdAt, c.updatedAt,
56
+ COALESCE(mc.messageCount, 0) AS messageCount,
57
+ lr.latestRunStatus, lr.latestRunStartedAt,
58
+ lr.latestRunEndedAt, lr.latestRunEventsJson,
59
+ trd.totalDurationMs
60
+ FROM project_conversations c
61
+ LEFT JOIN latest_runs lr ON lr.conversationId = c.id
62
+ LEFT JOIN message_counts mc ON mc.conversationId = c.id
63
+ LEFT JOIN total_run_durations trd ON trd.conversationId = c.id
64
+ ORDER BY c.updatedAt DESC`)
65
+ .all(projectId)).map(normalizeConversation);
66
+ }
67
+ /**
68
+ * Fetches a single conversation by id with its latest run summary and total run duration.
69
+ * Returns null when no matching conversation exists.
70
+ * @param db Open SQLite database handle.
71
+ * @param id Conversation id.
72
+ */
73
+ export function getConversation(db, id) {
74
+ const r = db
75
+ .prepare(`SELECT id, project_id AS projectId, title, session_mode AS sessionMode,
76
+ created_at AS createdAt, updated_at AS updatedAt,
77
+ (SELECT COUNT(*) FROM messages WHERE conversation_id = conversations.id) AS messageCount
78
+ FROM conversations WHERE id = ?`)
79
+ .get(id);
80
+ if (!r)
81
+ return null;
82
+ return {
83
+ ...normalizeConversation(r),
84
+ latestRun: latestConversationRunSummary(db, r.id) ?? undefined,
85
+ ...numberProperty('totalDurationMs', totalConversationRunDurationMs(db, r.id)),
86
+ };
87
+ }
88
+ /** @internal Shapes a raw SQLite row into the canonical conversation object, including run summary. */
89
+ function normalizeConversation(r) {
90
+ const latestRun = conversationRunSummaryFromRow({
91
+ runStatus: r.latestRunStatus,
92
+ startedAt: r.latestRunStartedAt,
93
+ endedAt: r.latestRunEndedAt,
94
+ eventsJson: r.latestRunEventsJson,
95
+ });
96
+ return {
97
+ id: r.id,
98
+ projectId: r.projectId,
99
+ title: r.title ?? null,
100
+ sessionMode: normalizeConversationSessionMode(r.sessionMode),
101
+ messageCount: Number(r.messageCount),
102
+ createdAt: Number(r.createdAt),
103
+ updatedAt: Number(r.updatedAt),
104
+ ...numberProperty('totalDurationMs', r.totalDurationMs),
105
+ latestRun: latestRun ?? undefined,
106
+ };
107
+ }
108
+ /**
109
+ * Coerces an arbitrary database value to a valid ChatSessionMode, defaulting to 'design'.
110
+ * Upholds the invariant that no conversation ever carries an unknown session mode.
111
+ * @param value Raw value read from the session_mode column.
112
+ * @returns A valid ChatSessionMode: 'chat', 'plan', or 'design'.
113
+ */
114
+ export function normalizeConversationSessionMode(value) {
115
+ return value === 'chat' || value === 'plan' ? value : 'design';
116
+ }
117
+ /**
118
+ * @internal Produces a single-key object `{ [key]: number }` only when value is a finite number,
119
+ * omitting the key entirely otherwise. Generic over `key` (rather than plain `string`) so the
120
+ * spread of its return type into a caller's object literal carries a real, statically-known
121
+ * optional property instead of collapsing to an index signature the compiler then can't see
122
+ * through at the call site.
123
+ */
124
+ function numberProperty(key, value) {
125
+ const n = value == null ? undefined : Number(value);
126
+ return typeof n === 'number' && Number.isFinite(n)
127
+ ? { [key]: n }
128
+ : {};
129
+ }
130
+ /** @internal Queries the most recent assistant run summary for a conversation (used by getConversation's per-row fetch path). */
131
+ function latestConversationRunSummary(db, conversationId) {
132
+ const row = db
133
+ .prepare(`SELECT run_status AS runStatus,
134
+ started_at AS startedAt,
135
+ ended_at AS endedAt,
136
+ events_json AS eventsJson
137
+ FROM messages
138
+ WHERE conversation_id = ?
139
+ AND role = 'assistant'
140
+ AND run_status IS NOT NULL
141
+ ORDER BY position DESC
142
+ LIMIT 1`)
143
+ .get(conversationId);
144
+ return conversationRunSummaryFromRow(row);
145
+ }
146
+ /** @internal Sums terminal-run duration across all succeeded/failed/canceled assistant messages in a conversation. */
147
+ function totalConversationRunDurationMs(db, conversationId) {
148
+ const row = db
149
+ .prepare(`SELECT SUM(${terminalRunDurationSql()}) AS totalDurationMs
150
+ FROM messages
151
+ WHERE conversation_id = ?
152
+ AND role = 'assistant'
153
+ AND run_status IN ('succeeded', 'failed', 'canceled')`)
154
+ .get(conversationId);
155
+ return row?.totalDurationMs == null ? undefined : Number(row.totalDurationMs);
156
+ }
157
+ /** @internal Emits the SQL CASE expression that resolves a terminal run's duration: wall-clock diff when both timestamps exist, otherwise the latest usage event's durationMs. */
158
+ function terminalRunDurationSql(alias) {
159
+ const p = alias ? `${alias}.` : '';
160
+ return `CASE
161
+ WHEN ${p}started_at IS NOT NULL AND ${p}ended_at IS NOT NULL THEN
162
+ CASE
163
+ WHEN CAST(${p}ended_at AS INTEGER) >= CAST(${p}started_at AS INTEGER)
164
+ THEN CAST(${p}ended_at AS INTEGER) - CAST(${p}started_at AS INTEGER)
165
+ ELSE 0
166
+ END
167
+ ELSE (
168
+ SELECT CASE
169
+ WHEN json_extract(usage_event.value, '$.durationMs') >= 0
170
+ THEN json_extract(usage_event.value, '$.durationMs')
171
+ ELSE 0
172
+ END
173
+ FROM json_each(
174
+ CASE
175
+ WHEN json_valid(${p}events_json) AND json_type(${p}events_json) = 'array'
176
+ THEN ${p}events_json
177
+ ELSE '[]'
178
+ END
179
+ ) AS usage_event
180
+ WHERE usage_event.type = 'object'
181
+ AND json_extract(usage_event.value, '$.kind') = 'usage'
182
+ AND json_type(usage_event.value, '$.durationMs') IN ('integer', 'real')
183
+ ORDER BY CAST(usage_event.key AS INTEGER) DESC
184
+ LIMIT 1
185
+ )
186
+ END`;
187
+ }
188
+ /** @internal Converts a raw message row (runStatus/startedAt/endedAt/eventsJson) into a run summary object, or null when no run status is present. */
189
+ function conversationRunSummaryFromRow(row) {
190
+ if (!row || typeof row.runStatus !== 'string')
191
+ return null;
192
+ const startedAt = row.startedAt == null ? undefined : Number(row.startedAt);
193
+ const endedAt = row.endedAt == null ? undefined : Number(row.endedAt);
194
+ const usageDurationMs = latestUsageDurationMs(row.eventsJson);
195
+ const durationMs = Number.isFinite(startedAt) && Number.isFinite(endedAt)
196
+ ? Math.max(0, endedAt - startedAt)
197
+ : usageDurationMs;
198
+ return {
199
+ status: row.runStatus,
200
+ ...(Number.isFinite(startedAt) ? { startedAt } : {}),
201
+ ...(Number.isFinite(endedAt) ? { endedAt } : {}),
202
+ ...(typeof durationMs === 'number' && Number.isFinite(durationMs)
203
+ ? { durationMs }
204
+ : {}),
205
+ };
206
+ }
207
+ /** @internal Parses events_json to find the most recent usage event's durationMs; returns undefined when events_json is absent or malformed. */
208
+ function latestUsageDurationMs(eventsJson) {
209
+ if (typeof eventsJson !== 'string' || eventsJson.length === 0)
210
+ return undefined;
211
+ try {
212
+ const events = JSON.parse(eventsJson);
213
+ if (!Array.isArray(events))
214
+ return undefined;
215
+ for (let i = events.length - 1; i >= 0; i -= 1) {
216
+ const event = events[i];
217
+ if (event &&
218
+ typeof event === 'object' &&
219
+ event.kind === 'usage' &&
220
+ typeof event.durationMs === 'number' &&
221
+ Number.isFinite(event.durationMs)) {
222
+ return Math.max(0, event.durationMs);
223
+ }
224
+ }
225
+ }
226
+ catch {
227
+ return undefined;
228
+ }
229
+ return undefined;
230
+ }
231
+ /**
232
+ * Inserts a new conversation row and returns the full conversation record (including run summary).
233
+ * Normalizes sessionMode before persisting so the stored value is always a valid ChatSessionMode.
234
+ * @param db Open SQLite database handle.
235
+ * @param c Conversation fields to insert.
236
+ */
237
+ export function insertConversation(db, c) {
238
+ db.prepare(`INSERT INTO conversations
239
+ (id, project_id, title, session_mode, created_at, updated_at)
240
+ VALUES (?, ?, ?, ?, ?, ?)`).run(c.id, c.projectId, c.title ?? null, normalizeConversationSessionMode(c.sessionMode), c.createdAt, c.updatedAt);
241
+ return getConversation(db, c.id);
242
+ }
243
+ /**
244
+ * Applies a partial patch to an existing conversation, merging with the current record.
245
+ * Returns null when the conversation does not exist; otherwise returns the updated record.
246
+ * @param db Open SQLite database handle.
247
+ * @param id Conversation id to update.
248
+ * @param patch Fields to overwrite; sessionMode and updatedAt are normalized before persisting.
249
+ */
250
+ export function updateConversation(db, id, patch) {
251
+ const existing = getConversation(db, id);
252
+ if (!existing)
253
+ return null;
254
+ const merged = {
255
+ ...existing,
256
+ ...patch,
257
+ sessionMode: Object.prototype.hasOwnProperty.call(patch, 'sessionMode')
258
+ ? normalizeConversationSessionMode(patch.sessionMode)
259
+ : existing.sessionMode,
260
+ updatedAt: typeof patch.updatedAt === 'number' ? patch.updatedAt : Date.now(),
261
+ };
262
+ db.prepare(`UPDATE conversations
263
+ SET title = ?, session_mode = ?, updated_at = ? WHERE id = ?`).run(merged.title ?? null, merged.sessionMode, merged.updatedAt, id);
264
+ return getConversation(db, id);
265
+ }
266
+ /**
267
+ * Removes a conversation row by id. Cascading deletes on messages are handled by the schema.
268
+ * @param db Open SQLite database handle.
269
+ * @param id Conversation id to delete.
270
+ */
271
+ export function deleteConversation(db, id) {
272
+ db.prepare(`DELETE FROM conversations WHERE id = ?`).run(id);
273
+ }
274
+ //# sourceMappingURL=conversations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversations.js","sourceRoot":"","sources":["../../../src/db/conversations/conversations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ /** @module db/conversations/index */
2
+ export { listConversations, getConversation, normalizeConversationSessionMode, insertConversation, updateConversation, deleteConversation, } from './conversations.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/db/conversations/index.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,gCAAgC,EAChC,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,3 @@
1
+ /** @module db/conversations/index */
2
+ export { listConversations, getConversation, normalizeConversationSessionMode, insertConversation, updateConversation, deleteConversation, } from './conversations.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/db/conversations/index.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,OAAO,EACL,iBAAiB,EACjB,eAAe,EACf,gCAAgC,EAChC,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,6 @@
1
+ /** @module db/core/index
2
+ * Foundation barrel — re-exports all shared type aliases and pure row/JSON primitives; no side effects and no sibling subdirectory imports. */
3
+ export * from './types.js';
4
+ export * from './json.js';
5
+ export * from './rows.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/db/core/index.ts"],"names":[],"mappings":"AAAA;+IAC+I;AAC/I,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC"}
@@ -0,0 +1,6 @@
1
+ /** @module db/core/index
2
+ * Foundation barrel — re-exports all shared type aliases and pure row/JSON primitives; no side effects and no sibling subdirectory imports. */
3
+ export * from './types.js';
4
+ export * from './json.js';
5
+ export * from './rows.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/db/core/index.ts"],"names":[],"mappings":"AAAA;+IAC+I;AAC/I,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC"}
@@ -0,0 +1,13 @@
1
+ /** @module db/core/json
2
+ * Pure JSON parsing utility that converts SQLite TEXT columns to JS values without throwing.
3
+ * Imports no sibling subdirectory.
4
+ */
5
+ /**
6
+ * Safely parse a SQLite TEXT column value to a JS value.
7
+ * Returns `undefined` instead of throwing for non-string, empty, or malformed JSON —
8
+ * callers should narrow the return type before use.
9
+ * @param s - raw column value as stored in SQLite (typically `string | null`)
10
+ * @returns parsed value, or `undefined` if the input is absent or unparseable
11
+ */
12
+ export declare function parseJsonOrUndef(s: unknown): any;
13
+ //# sourceMappingURL=json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../../src/db/core/json.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,GAAG,GAAG,CAOhD"}
@@ -0,0 +1,22 @@
1
+ /** @module db/core/json
2
+ * Pure JSON parsing utility that converts SQLite TEXT columns to JS values without throwing.
3
+ * Imports no sibling subdirectory.
4
+ */
5
+ /**
6
+ * Safely parse a SQLite TEXT column value to a JS value.
7
+ * Returns `undefined` instead of throwing for non-string, empty, or malformed JSON —
8
+ * callers should narrow the return type before use.
9
+ * @param s - raw column value as stored in SQLite (typically `string | null`)
10
+ * @returns parsed value, or `undefined` if the input is absent or unparseable
11
+ */
12
+ export function parseJsonOrUndef(s) {
13
+ if (typeof s !== 'string' || !s)
14
+ return undefined;
15
+ try {
16
+ return JSON.parse(s);
17
+ }
18
+ catch {
19
+ return undefined;
20
+ }
21
+ }
22
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.js","sourceRoot":"","sources":["../../../src/db/core/json.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,CAAU;IACzC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IAClD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
@@ -0,0 +1,18 @@
1
+ /** @module db/core/rows
2
+ * Helpers that normalize raw better-sqlite3 query results to typed `DbRow` values.
3
+ * Imports no sibling subdirectory; depends only on `core/types`.
4
+ */
5
+ import type { DbRow } from './types.js';
6
+ /**
7
+ * Narrow a single `db.prepare(…).get()` result to `DbRow | null`.
8
+ * Returns `null` for falsy or non-object returns so callers can distinguish "no row" from an empty row.
9
+ * @param value - raw return from better-sqlite3's `.get()`
10
+ */
11
+ export declare function row(value: unknown): DbRow | null;
12
+ /**
13
+ * Map a `db.prepare(…).all()` result array to `DbRow[]`, replacing any falsy or non-object
14
+ * entries with an empty object so the array length is always preserved.
15
+ * @param value - raw return from better-sqlite3's `.all()`
16
+ */
17
+ export declare function rows(value: unknown[]): DbRow[];
18
+ //# sourceMappingURL=rows.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rows.d.ts","sourceRoot":"","sources":["../../../src/db/core/rows.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC;;;;GAIG;AACH,wBAAgB,GAAG,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,GAAG,IAAI,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,CAE9C"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Narrow a single `db.prepare(…).get()` result to `DbRow | null`.
3
+ * Returns `null` for falsy or non-object returns so callers can distinguish "no row" from an empty row.
4
+ * @param value - raw return from better-sqlite3's `.get()`
5
+ */
6
+ export function row(value) {
7
+ return value && typeof value === 'object' ? value : null;
8
+ }
9
+ /**
10
+ * Map a `db.prepare(…).all()` result array to `DbRow[]`, replacing any falsy or non-object
11
+ * entries with an empty object so the array length is always preserved.
12
+ * @param value - raw return from better-sqlite3's `.all()`
13
+ */
14
+ export function rows(value) {
15
+ return value.map((item) => row(item) ?? {});
16
+ }
17
+ //# sourceMappingURL=rows.js.map