@pcircle/evidencemcp-server 0.1.0 → 0.2.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 (56) hide show
  1. package/README.md +27 -297
  2. package/dist/index.d.ts +1 -15
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +55 -123
  5. package/dist/index.js.map +1 -1
  6. package/dist/lib/crypto/decrypt.d.ts +11 -0
  7. package/dist/lib/crypto/decrypt.d.ts.map +1 -0
  8. package/dist/lib/crypto/decrypt.js +30 -0
  9. package/dist/lib/crypto/decrypt.js.map +1 -0
  10. package/dist/lib/crypto/encrypt.d.ts +13 -0
  11. package/dist/lib/crypto/encrypt.d.ts.map +1 -0
  12. package/dist/lib/crypto/encrypt.js +24 -0
  13. package/dist/lib/crypto/encrypt.js.map +1 -0
  14. package/dist/lib/crypto/index.d.ts +6 -0
  15. package/dist/lib/crypto/index.d.ts.map +1 -0
  16. package/dist/lib/crypto/index.js +5 -0
  17. package/dist/lib/crypto/index.js.map +1 -0
  18. package/dist/lib/crypto/key-derivation.d.ts +30 -0
  19. package/dist/lib/crypto/key-derivation.d.ts.map +1 -0
  20. package/dist/lib/crypto/key-derivation.js +63 -0
  21. package/dist/lib/crypto/key-derivation.js.map +1 -0
  22. package/dist/lib/crypto/types.d.ts +22 -0
  23. package/dist/lib/crypto/types.d.ts.map +1 -0
  24. package/dist/lib/crypto/types.js +10 -0
  25. package/dist/lib/crypto/types.js.map +1 -0
  26. package/dist/lib/storage/database.d.ts +66 -0
  27. package/dist/lib/storage/database.d.ts.map +1 -0
  28. package/dist/lib/storage/database.js +195 -0
  29. package/dist/lib/storage/database.js.map +1 -0
  30. package/dist/lib/storage/export.d.ts +26 -0
  31. package/dist/lib/storage/export.d.ts.map +1 -0
  32. package/dist/lib/storage/export.js +113 -0
  33. package/dist/lib/storage/export.js.map +1 -0
  34. package/dist/lib/storage/git.d.ts +16 -0
  35. package/dist/lib/storage/git.d.ts.map +1 -0
  36. package/dist/lib/storage/git.js +55 -0
  37. package/dist/lib/storage/git.js.map +1 -0
  38. package/dist/lib/storage/index.d.ts +6 -0
  39. package/dist/lib/storage/index.d.ts.map +1 -0
  40. package/dist/lib/storage/index.js +5 -0
  41. package/dist/lib/storage/index.js.map +1 -0
  42. package/dist/lib/storage/schema.d.ts +17 -0
  43. package/dist/lib/storage/schema.d.ts.map +1 -0
  44. package/dist/lib/storage/schema.js +103 -0
  45. package/dist/lib/storage/schema.js.map +1 -0
  46. package/dist/lib/storage/types.d.ts +26 -0
  47. package/dist/lib/storage/types.d.ts.map +1 -0
  48. package/dist/lib/storage/types.js +2 -0
  49. package/dist/lib/storage/types.js.map +1 -0
  50. package/dist/test-helpers.d.ts +12 -30
  51. package/dist/test-helpers.d.ts.map +1 -1
  52. package/dist/test-helpers.js +59 -121
  53. package/dist/test-helpers.js.map +1 -1
  54. package/dist/types.d.ts +0 -25
  55. package/dist/types.d.ts.map +1 -1
  56. package/package.json +7 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/lib/crypto/types.ts"],"names":[],"mappings":"AAkBA;;GAEG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAwB;IACrD,MAAM,EAAE,KAAK,EAAO,QAAQ;IAC5B,UAAU,EAAE,CAAC;IACb,WAAW,EAAE,CAAC;IACd,SAAS,EAAE,EAAE;CACd,CAAC"}
@@ -0,0 +1,66 @@
1
+ import type { Evidence } from './types.js';
2
+ /**
3
+ * Evidence database with CRUD operations
4
+ * Manages encrypted evidence storage with SQLite backend
5
+ */
6
+ export declare class EvidenceDatabase {
7
+ private db;
8
+ /**
9
+ * Creates or opens an evidence database
10
+ * @param dbPath - Path to SQLite database file
11
+ */
12
+ constructor(dbPath: string);
13
+ /**
14
+ * Creates a new evidence record
15
+ * @param evidence - Evidence data without id, createdAt, updatedAt
16
+ * @returns UUID of created evidence
17
+ */
18
+ create(evidence: Omit<Evidence, 'id' | 'createdAt' | 'updatedAt'>): string;
19
+ /**
20
+ * Finds evidence by ID
21
+ * @param id - Evidence UUID
22
+ * @returns Evidence or null if not found
23
+ */
24
+ findById(id: string): Evidence | null;
25
+ /**
26
+ * Finds all evidences for a conversation
27
+ * @param conversationId - Conversation identifier
28
+ * @returns Array of evidences (empty if none found)
29
+ */
30
+ findByConversationId(conversationId: string): Evidence[];
31
+ /**
32
+ * Lists evidences with pagination
33
+ * @param options - Pagination options (limit, offset)
34
+ * @returns Array of evidences
35
+ */
36
+ list(options?: {
37
+ limit?: number;
38
+ offset?: number;
39
+ }): Evidence[];
40
+ /**
41
+ * Updates git commit information for an evidence
42
+ * @param id - Evidence UUID
43
+ * @param gitCommitHash - Git commit hash
44
+ * @param gitTimestamp - Git commit timestamp (ISO 8601)
45
+ */
46
+ updateGitInfo(id: string, gitCommitHash: string, gitTimestamp: string): void;
47
+ /**
48
+ * Adds tags to an evidence (appends to existing tags)
49
+ * @param id - Evidence UUID
50
+ * @param tags - Array of tags to add
51
+ */
52
+ addTags(id: string, tags: string[]): void;
53
+ /**
54
+ * Closes the database connection
55
+ * Should be called when done with the database
56
+ */
57
+ close(): void;
58
+ /**
59
+ * Converts database row to Evidence object
60
+ * Handles BLOB to Uint8Array conversion
61
+ * @param row - Raw database row
62
+ * @returns Evidence object
63
+ */
64
+ private rowToEvidence;
65
+ }
66
+ //# sourceMappingURL=database.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../../src/lib/storage/database.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAqB3C;;;GAGG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,EAAE,CAAoB;IAE9B;;;OAGG;gBACS,MAAM,EAAE,MAAM;IAK1B;;;;OAIG;IACH,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,GAAG,WAAW,GAAG,WAAW,CAAC,GAAG,MAAM;IAmC1E;;;;OAIG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI;IAkBrC;;;;OAIG;IACH,oBAAoB,CAAC,cAAc,EAAE,MAAM,GAAG,QAAQ,EAAE;IAiBxD;;;;OAIG;IACH,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,QAAQ,EAAE;IA4B/D;;;;;OAKG;IACH,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI;IAoB5E;;;;OAIG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI;IA4BzC;;;OAGG;IACH,KAAK,IAAI,IAAI;IAIb;;;;;OAKG;IACH,OAAO,CAAC,aAAa;CAiBtB"}
@@ -0,0 +1,195 @@
1
+ import Database from 'better-sqlite3';
2
+ import { createSchema } from './schema.js';
3
+ /**
4
+ * Evidence database with CRUD operations
5
+ * Manages encrypted evidence storage with SQLite backend
6
+ */
7
+ export class EvidenceDatabase {
8
+ db;
9
+ /**
10
+ * Creates or opens an evidence database
11
+ * @param dbPath - Path to SQLite database file
12
+ */
13
+ constructor(dbPath) {
14
+ this.db = new Database(dbPath);
15
+ createSchema(this.db);
16
+ }
17
+ /**
18
+ * Creates a new evidence record
19
+ * @param evidence - Evidence data without id, createdAt, updatedAt
20
+ * @returns UUID of created evidence
21
+ */
22
+ create(evidence) {
23
+ const id = crypto.randomUUID();
24
+ const now = new Date().toISOString();
25
+ try {
26
+ const stmt = this.db.prepare(`
27
+ INSERT INTO evidences (
28
+ id, timestamp, conversationId, llmProvider,
29
+ encryptedContent, nonce, contentHash, messageCount,
30
+ gitCommitHash, gitTimestamp, tags, createdAt, updatedAt
31
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
32
+ `);
33
+ stmt.run(id, evidence.timestamp, evidence.conversationId, evidence.llmProvider, Buffer.from(evidence.encryptedContent), Buffer.from(evidence.nonce), evidence.contentHash, evidence.messageCount, evidence.gitCommitHash, evidence.gitTimestamp, evidence.tags, now, now);
34
+ return id;
35
+ }
36
+ catch (error) {
37
+ throw new Error(`Failed to create evidence: ${error instanceof Error ? error.message : String(error)}`);
38
+ }
39
+ }
40
+ /**
41
+ * Finds evidence by ID
42
+ * @param id - Evidence UUID
43
+ * @returns Evidence or null if not found
44
+ */
45
+ findById(id) {
46
+ try {
47
+ const stmt = this.db.prepare(`
48
+ SELECT * FROM evidences WHERE id = ?
49
+ `);
50
+ const row = stmt.get(id);
51
+ if (!row) {
52
+ return null;
53
+ }
54
+ return this.rowToEvidence(row);
55
+ }
56
+ catch (error) {
57
+ // Don't swallow database errors - re-throw with context
58
+ throw new Error(`Failed to find evidence by ID: ${error instanceof Error ? error.message : String(error)}`);
59
+ }
60
+ }
61
+ /**
62
+ * Finds all evidences for a conversation
63
+ * @param conversationId - Conversation identifier
64
+ * @returns Array of evidences (empty if none found)
65
+ */
66
+ findByConversationId(conversationId) {
67
+ try {
68
+ const stmt = this.db.prepare(`
69
+ SELECT * FROM evidences
70
+ WHERE conversationId = ?
71
+ ORDER BY timestamp ASC
72
+ `);
73
+ const rows = stmt.all(conversationId);
74
+ return rows.map((row) => this.rowToEvidence(row));
75
+ }
76
+ catch (error) {
77
+ throw new Error(`Failed to find evidences by conversationId: ${error instanceof Error ? error.message : String(error)}`);
78
+ }
79
+ }
80
+ /**
81
+ * Lists evidences with pagination
82
+ * @param options - Pagination options (limit, offset)
83
+ * @returns Array of evidences
84
+ */
85
+ list(options) {
86
+ try {
87
+ const limit = options?.limit;
88
+ const offset = options?.offset ?? 0;
89
+ let query = 'SELECT * FROM evidences ORDER BY timestamp DESC';
90
+ const params = [];
91
+ if (limit !== undefined) {
92
+ query += ' LIMIT ?';
93
+ params.push(limit);
94
+ if (offset > 0) {
95
+ query += ' OFFSET ?';
96
+ params.push(offset);
97
+ }
98
+ }
99
+ else if (offset > 0) {
100
+ query += ' LIMIT -1 OFFSET ?';
101
+ params.push(offset);
102
+ }
103
+ const stmt = this.db.prepare(query);
104
+ const rows = stmt.all(...params);
105
+ return rows.map((row) => this.rowToEvidence(row));
106
+ }
107
+ catch (error) {
108
+ throw new Error(`Failed to list evidences: ${error instanceof Error ? error.message : String(error)}`);
109
+ }
110
+ }
111
+ /**
112
+ * Updates git commit information for an evidence
113
+ * @param id - Evidence UUID
114
+ * @param gitCommitHash - Git commit hash
115
+ * @param gitTimestamp - Git commit timestamp (ISO 8601)
116
+ */
117
+ updateGitInfo(id, gitCommitHash, gitTimestamp) {
118
+ try {
119
+ const stmt = this.db.prepare(`
120
+ UPDATE evidences
121
+ SET gitCommitHash = ?,
122
+ gitTimestamp = ?,
123
+ updatedAt = ?
124
+ WHERE id = ?
125
+ `);
126
+ const result = stmt.run(gitCommitHash, gitTimestamp, new Date().toISOString(), id);
127
+ if (result.changes === 0) {
128
+ throw new Error(`Evidence with id ${id} not found`);
129
+ }
130
+ }
131
+ catch (error) {
132
+ throw new Error(`Failed to update git info: ${error instanceof Error ? error.message : String(error)}`);
133
+ }
134
+ }
135
+ /**
136
+ * Adds tags to an evidence (appends to existing tags)
137
+ * @param id - Evidence UUID
138
+ * @param tags - Array of tags to add
139
+ */
140
+ addTags(id, tags) {
141
+ try {
142
+ // First, get existing tags
143
+ const evidence = this.findById(id);
144
+ if (!evidence) {
145
+ throw new Error(`Evidence with id ${id} not found`);
146
+ }
147
+ // Parse existing tags or create empty array
148
+ const existingTags = evidence.tags ? JSON.parse(evidence.tags) : [];
149
+ // Merge tags
150
+ const mergedTags = [...existingTags, ...tags];
151
+ // Update database
152
+ const stmt = this.db.prepare(`
153
+ UPDATE evidences
154
+ SET tags = ?,
155
+ updatedAt = ?
156
+ WHERE id = ?
157
+ `);
158
+ stmt.run(JSON.stringify(mergedTags), new Date().toISOString(), id);
159
+ }
160
+ catch (error) {
161
+ throw new Error(`Failed to add tags: ${error instanceof Error ? error.message : String(error)}`);
162
+ }
163
+ }
164
+ /**
165
+ * Closes the database connection
166
+ * Should be called when done with the database
167
+ */
168
+ close() {
169
+ this.db.close();
170
+ }
171
+ /**
172
+ * Converts database row to Evidence object
173
+ * Handles BLOB to Uint8Array conversion
174
+ * @param row - Raw database row
175
+ * @returns Evidence object
176
+ */
177
+ rowToEvidence(row) {
178
+ return {
179
+ id: row.id,
180
+ timestamp: row.timestamp,
181
+ conversationId: row.conversationId,
182
+ llmProvider: row.llmProvider,
183
+ encryptedContent: new Uint8Array(row.encryptedContent),
184
+ nonce: new Uint8Array(row.nonce),
185
+ contentHash: row.contentHash,
186
+ messageCount: row.messageCount,
187
+ gitCommitHash: row.gitCommitHash,
188
+ gitTimestamp: row.gitTimestamp,
189
+ tags: row.tags,
190
+ createdAt: row.createdAt,
191
+ updatedAt: row.updatedAt
192
+ };
193
+ }
194
+ }
195
+ //# sourceMappingURL=database.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.js","sourceRoot":"","sources":["../../../src/lib/storage/database.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ import type { EvidenceDatabase } from './database.js';
2
+ export interface ExportOptions {
3
+ evidenceIds?: string[];
4
+ includeGitInfo?: boolean;
5
+ password?: string;
6
+ }
7
+ export interface ExportResult {
8
+ filename: string;
9
+ zipData: Uint8Array;
10
+ checksum: string;
11
+ evidenceCount: number;
12
+ }
13
+ /**
14
+ * Export evidences to a ZIP archive with encrypted data and metadata.
15
+ *
16
+ * ⚠️ **Memory Warning**: Entire ZIP is generated in-memory. For large exports
17
+ * (>1000 evidences or >100MB encrypted data), consider exporting in batches
18
+ * to avoid memory exhaustion.
19
+ *
20
+ * @param db - EvidenceDatabase instance
21
+ * @param options - Export options
22
+ * @returns Export result with ZIP data and metadata
23
+ * @throws Error if database operations fail, IDs not found, or ZIP generation fails
24
+ */
25
+ export declare function exportEvidences(db: EvidenceDatabase, options?: ExportOptions): Promise<ExportResult>;
26
+ //# sourceMappingURL=export.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../../src/lib/storage/export.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEtD,MAAM,WAAW,aAAa;IAC5B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,UAAU,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB;AAYD;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CACnC,EAAE,EAAE,gBAAgB,EACpB,OAAO,GAAE,aAAkB,GAC1B,OAAO,CAAC,YAAY,CAAC,CAiHvB"}
@@ -0,0 +1,113 @@
1
+ import JSZip from 'jszip';
2
+ import { createHash } from 'node:crypto';
3
+ // Export format version constant
4
+ const EXPORT_FORMAT_VERSION = '1.0.0';
5
+ /**
6
+ * Export evidences to a ZIP archive with encrypted data and metadata.
7
+ *
8
+ * ⚠️ **Memory Warning**: Entire ZIP is generated in-memory. For large exports
9
+ * (>1000 evidences or >100MB encrypted data), consider exporting in batches
10
+ * to avoid memory exhaustion.
11
+ *
12
+ * @param db - EvidenceDatabase instance
13
+ * @param options - Export options
14
+ * @returns Export result with ZIP data and metadata
15
+ * @throws Error if database operations fail, IDs not found, or ZIP generation fails
16
+ */
17
+ export async function exportEvidences(db, options = {}) {
18
+ try {
19
+ const { evidenceIds, includeGitInfo = false } = options;
20
+ // Get evidences to export - validate IDs if specified
21
+ let evidences;
22
+ if (evidenceIds) {
23
+ // Validate all IDs exist first
24
+ const notFound = evidenceIds.filter(id => !db.findById(id));
25
+ if (notFound.length > 0) {
26
+ throw new Error(`Evidence IDs not found: ${notFound.join(', ')}`);
27
+ }
28
+ evidences = evidenceIds.map(id => db.findById(id));
29
+ }
30
+ else {
31
+ evidences = db.list();
32
+ }
33
+ // Create ZIP archive
34
+ const zip = new JSZip();
35
+ // Add manifest.json
36
+ const manifest = {
37
+ version: EXPORT_FORMAT_VERSION,
38
+ exportDate: new Date().toISOString(),
39
+ evidenceCount: evidences.length,
40
+ includeGitInfo,
41
+ };
42
+ zip.file('manifest.json', JSON.stringify(manifest, null, 2));
43
+ // Add each evidence
44
+ const checksumEntries = [];
45
+ for (const evidence of evidences) {
46
+ const evidenceFolder = `evidences/${evidence.id}`;
47
+ // Add encrypted-data
48
+ zip.file(`${evidenceFolder}/encrypted-data`, evidence.encryptedContent);
49
+ // Calculate checksum for encrypted data
50
+ const dataChecksum = createHash('sha256')
51
+ .update(evidence.encryptedContent)
52
+ .digest('hex');
53
+ checksumEntries.push(`${dataChecksum} ${evidenceFolder}/encrypted-data`);
54
+ // Add metadata.json
55
+ const metadata = {
56
+ id: evidence.id,
57
+ timestamp: evidence.timestamp,
58
+ conversationId: evidence.conversationId,
59
+ llmProvider: evidence.llmProvider,
60
+ contentHash: evidence.contentHash,
61
+ messageCount: evidence.messageCount,
62
+ tags: evidence.tags,
63
+ nonce: Array.from(evidence.nonce), // Convert Uint8Array to array for JSON
64
+ };
65
+ const metadataJson = JSON.stringify(metadata, null, 2);
66
+ zip.file(`${evidenceFolder}/metadata.json`, metadataJson);
67
+ const metadataChecksum = createHash('sha256')
68
+ .update(metadataJson)
69
+ .digest('hex');
70
+ checksumEntries.push(`${metadataChecksum} ${evidenceFolder}/metadata.json`);
71
+ // Add git-info.json if requested and available
72
+ if (includeGitInfo && evidence.gitCommitHash && evidence.gitTimestamp) {
73
+ const gitInfo = {
74
+ gitCommitHash: evidence.gitCommitHash,
75
+ gitTimestamp: evidence.gitTimestamp,
76
+ };
77
+ const gitInfoJson = JSON.stringify(gitInfo, null, 2);
78
+ zip.file(`${evidenceFolder}/git-info.json`, gitInfoJson);
79
+ const gitChecksum = createHash('sha256').update(gitInfoJson).digest('hex');
80
+ checksumEntries.push(`${gitChecksum} ${evidenceFolder}/git-info.json`);
81
+ }
82
+ }
83
+ // Add checksum.txt
84
+ const checksumContent = [
85
+ 'SHA-256 Checksums',
86
+ '=================',
87
+ '',
88
+ ...checksumEntries,
89
+ ].join('\n');
90
+ zip.file('checksum.txt', checksumContent);
91
+ // Generate ZIP data
92
+ const zipData = await zip.generateAsync({
93
+ type: 'uint8array',
94
+ compression: 'DEFLATE',
95
+ compressionOptions: { level: 9 },
96
+ });
97
+ // Calculate ZIP checksum
98
+ const zipChecksum = createHash('sha256').update(zipData).digest('hex');
99
+ // Generate filename
100
+ const timestamp = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
101
+ const filename = `evidence-export-${timestamp}.zip`;
102
+ return {
103
+ filename,
104
+ zipData,
105
+ checksum: zipChecksum,
106
+ evidenceCount: evidences.length,
107
+ };
108
+ }
109
+ catch (error) {
110
+ throw new Error(`Failed to export evidences: ${error instanceof Error ? error.message : 'Unknown error'}`);
111
+ }
112
+ }
113
+ //# sourceMappingURL=export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.js","sourceRoot":"","sources":["../../../src/lib/storage/export.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Git commit information
3
+ */
4
+ export interface GitInfo {
5
+ commitHash: string;
6
+ timestamp: string;
7
+ message?: string;
8
+ author?: string;
9
+ }
10
+ /**
11
+ * Get current Git commit information
12
+ * @param dir - Directory path (defaults to process.cwd())
13
+ * @returns GitInfo or null if not a git repository
14
+ */
15
+ export declare function getCurrentCommit(dir?: string): Promise<GitInfo | null>;
16
+ //# sourceMappingURL=git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../../src/lib/storage/git.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAsBD;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,GAAE,MAAsB,GAC1B,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CA+BzB"}
@@ -0,0 +1,55 @@
1
+ import git from 'isomorphic-git';
2
+ import fs from 'fs';
3
+ import path from 'path';
4
+ /**
5
+ * Find git root directory by walking up the directory tree
6
+ * @param startDir - Starting directory
7
+ * @returns Git root directory or null if not found
8
+ */
9
+ async function findGitRoot(startDir) {
10
+ let currentDir = path.resolve(startDir);
11
+ const root = path.parse(currentDir).root;
12
+ while (currentDir !== root) {
13
+ const gitDir = path.join(currentDir, '.git');
14
+ if (fs.existsSync(gitDir)) {
15
+ return currentDir;
16
+ }
17
+ currentDir = path.dirname(currentDir);
18
+ }
19
+ return null;
20
+ }
21
+ /**
22
+ * Get current Git commit information
23
+ * @param dir - Directory path (defaults to process.cwd())
24
+ * @returns GitInfo or null if not a git repository
25
+ */
26
+ export async function getCurrentCommit(dir = process.cwd()) {
27
+ try {
28
+ // Find git root directory
29
+ const gitRoot = await findGitRoot(dir);
30
+ if (!gitRoot) {
31
+ return null;
32
+ }
33
+ // Get current commit SHA
34
+ const commits = await git.log({
35
+ fs,
36
+ dir: gitRoot,
37
+ depth: 1,
38
+ });
39
+ if (commits.length === 0) {
40
+ return null;
41
+ }
42
+ const commit = commits[0];
43
+ return {
44
+ commitHash: commit.oid,
45
+ timestamp: new Date(commit.commit.committer.timestamp * 1000).toISOString(),
46
+ message: commit.commit.message,
47
+ author: commit.commit.author.name,
48
+ };
49
+ }
50
+ catch (error) {
51
+ // Not a git repository or other git error
52
+ return null;
53
+ }
54
+ }
55
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../../../src/lib/storage/git.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,gBAAgB,CAAC;AACjC,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAYxB;;;;GAIG;AACH,KAAK,UAAU,WAAW,CAAC,QAAgB;IACzC,IAAI,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC;IAEzC,OAAO,UAAU,KAAK,IAAI,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QAC7C,IAAI,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,OAAO,UAAU,CAAC;QACpB,CAAC;QACD,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IACxC,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,MAAc,OAAO,CAAC,GAAG,EAAE;IAE3B,IAAI,CAAC;QACH,0BAA0B;QAC1B,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;QACvC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,IAAI,CAAC;QACd,CAAC;QAED,yBAAyB;QACzB,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC;YAC5B,EAAE;YACF,GAAG,EAAE,OAAO;YACZ,KAAK,EAAE,CAAC;SACT,CAAC,CAAC;QAEH,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QAE1B,OAAO;YACL,UAAU,EAAE,MAAM,CAAC,GAAG;YACtB,SAAS,EAAE,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;YAC3E,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO;YAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI;SAClC,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,0CAA0C;QAC1C,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,6 @@
1
+ export { createSchema, verifySchema } from './schema.js';
2
+ export { EvidenceDatabase } from './database.js';
3
+ export type { Evidence, Metadata } from './types.js';
4
+ export { getCurrentCommit, type GitInfo } from './git.js';
5
+ export { exportEvidences, type ExportOptions, type ExportResult } from './export.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/storage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACjD,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,KAAK,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { createSchema, verifySchema } from './schema.js';
2
+ export { EvidenceDatabase } from './database.js';
3
+ export { getCurrentCommit } from './git.js';
4
+ export { exportEvidences } from './export.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/storage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAE,gBAAgB,EAAgB,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAyC,MAAM,aAAa,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type Database from 'better-sqlite3';
2
+ /**
3
+ * Creates the database schema (tables and indexes)
4
+ * This function is idempotent - safe to run multiple times
5
+ *
6
+ * @param db - SQLite database instance
7
+ */
8
+ export declare function createSchema(db: Database.Database): void;
9
+ /**
10
+ * Verifies that the database schema is valid
11
+ * Checks for existence of required tables
12
+ *
13
+ * @param db - SQLite database instance
14
+ * @returns true if schema is valid, false otherwise
15
+ */
16
+ export declare function verifySchema(db: Database.Database): boolean;
17
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/lib/storage/schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAO3C;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAqDxD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,OAAO,CAqC3D"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Current schema version
3
+ */
4
+ const SCHEMA_VERSION = '1';
5
+ /**
6
+ * Creates the database schema (tables and indexes)
7
+ * This function is idempotent - safe to run multiple times
8
+ *
9
+ * @param db - SQLite database instance
10
+ */
11
+ export function createSchema(db) {
12
+ try {
13
+ // Create evidences table
14
+ db.exec(`
15
+ CREATE TABLE IF NOT EXISTS evidences (
16
+ id TEXT PRIMARY KEY,
17
+ timestamp TEXT NOT NULL,
18
+ conversationId TEXT NOT NULL,
19
+ llmProvider TEXT NOT NULL,
20
+ encryptedContent BLOB NOT NULL,
21
+ nonce BLOB NOT NULL,
22
+ contentHash TEXT NOT NULL,
23
+ messageCount INTEGER NOT NULL DEFAULT 0,
24
+ gitCommitHash TEXT,
25
+ gitTimestamp TEXT,
26
+ tags TEXT,
27
+ createdAt TEXT NOT NULL DEFAULT (datetime('now')),
28
+ updatedAt TEXT NOT NULL DEFAULT (datetime('now'))
29
+ );
30
+ `);
31
+ // Create metadata table for schema versioning
32
+ db.exec(`
33
+ CREATE TABLE IF NOT EXISTS metadata (
34
+ key TEXT PRIMARY KEY,
35
+ value TEXT NOT NULL
36
+ );
37
+ `);
38
+ // Create indexes for common queries
39
+ db.exec(`
40
+ CREATE INDEX IF NOT EXISTS idx_timestamp ON evidences(timestamp);
41
+ `);
42
+ db.exec(`
43
+ CREATE INDEX IF NOT EXISTS idx_conversation_id ON evidences(conversationId);
44
+ `);
45
+ db.exec(`
46
+ CREATE INDEX IF NOT EXISTS idx_content_hash ON evidences(contentHash);
47
+ `);
48
+ // Set schema version (use INSERT OR IGNORE to make it idempotent)
49
+ const stmt = db.prepare(`
50
+ INSERT OR IGNORE INTO metadata (key, value)
51
+ VALUES ('schema_version', ?)
52
+ `);
53
+ stmt.run(SCHEMA_VERSION);
54
+ }
55
+ catch (error) {
56
+ // Clean up database connection on failure to prevent resource leaks
57
+ db.close();
58
+ throw error;
59
+ }
60
+ }
61
+ /**
62
+ * Verifies that the database schema is valid
63
+ * Checks for existence of required tables
64
+ *
65
+ * @param db - SQLite database instance
66
+ * @returns true if schema is valid, false otherwise
67
+ */
68
+ export function verifySchema(db) {
69
+ try {
70
+ // Check if evidences table exists
71
+ const evidencesTableInfo = db.pragma('table_info(evidences)');
72
+ if (!evidencesTableInfo || evidencesTableInfo.length === 0) {
73
+ return false;
74
+ }
75
+ // Check if metadata table exists
76
+ const metadataTableInfo = db.pragma('table_info(metadata)');
77
+ if (!metadataTableInfo || metadataTableInfo.length === 0) {
78
+ return false;
79
+ }
80
+ // Verify required columns exist in evidences table
81
+ const evidencesColumns = evidencesTableInfo.map((col) => col.name);
82
+ const requiredColumns = [
83
+ 'id',
84
+ 'timestamp',
85
+ 'encryptedContent',
86
+ 'nonce',
87
+ 'contentHash',
88
+ 'messageCount',
89
+ 'createdAt',
90
+ 'updatedAt'
91
+ ];
92
+ for (const col of requiredColumns) {
93
+ if (!evidencesColumns.includes(col)) {
94
+ return false;
95
+ }
96
+ }
97
+ return true;
98
+ }
99
+ catch (error) {
100
+ return false;
101
+ }
102
+ }
103
+ //# sourceMappingURL=schema.js.map