@codehourra/llm-iwiki 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/sync.ts DELETED
@@ -1,207 +0,0 @@
1
- import type { LlmIwikiDatabase } from './db'
2
- import { resolveProjectByPath } from './projects'
3
- import { COLLECTORS, type Collector, type RawSession } from './collectors'
4
-
5
- export interface SourceSyncReport {
6
- source: string
7
- new: number
8
- changed: number
9
- unchanged: number
10
- sourceMissing: number
11
- total: number
12
- }
13
-
14
- export interface SyncReport {
15
- bySource: SourceSyncReport[]
16
- }
17
-
18
- export interface SyncOptions {
19
- homeDir: string
20
- projectFilter?: string | null
21
- }
22
-
23
- function hash(value: string): string {
24
- return Bun.hash(value).toString(16)
25
- }
26
-
27
- function sessionPrimaryId(sourceId: string, session: RawSession): string {
28
- return `ses_${hash(`${sourceId}\u0000${session.sourceSessionId}\u0000${session.rawPath}`)}`
29
- }
30
-
31
- function messageContentHash(role: string, content: string): string {
32
- return hash(`${role}\u0000${content}`)
33
- }
34
-
35
- function sessionContentHash(messageHashes: string[]): string {
36
- return hash(`${messageHashes.length}\u0000${messageHashes.join('\u0000')}`)
37
- }
38
-
39
- function upsertSource(db: LlmIwikiDatabase, collector: Collector, now: string): void {
40
- db.query(`
41
- INSERT INTO sources (id, name, enabled, scan_paths, config_json, last_sync_at)
42
- VALUES ($id, $name, 1, NULL, NULL, $now)
43
- ON CONFLICT(id) DO UPDATE SET
44
- name = excluded.name,
45
- last_sync_at = excluded.last_sync_at
46
- `).run({ $id: collector.id, $name: collector.name, $now: now })
47
- }
48
-
49
- function resolveProjectId(db: LlmIwikiDatabase, rawProjectPath: string | null): string | null {
50
- if (!rawProjectPath) return null
51
- try {
52
- return resolveProjectByPath(db, rawProjectPath).id
53
- } catch {
54
- return null
55
- }
56
- }
57
-
58
- function writeSession(
59
- db: LlmIwikiDatabase,
60
- collector: Collector,
61
- session: RawSession,
62
- now: string,
63
- report: SourceSyncReport,
64
- ): string {
65
- const id = sessionPrimaryId(collector.id, session)
66
- const messageHashes = session.messages.map((message) => messageContentHash(message.role, message.content))
67
- const contentHash = sessionContentHash(messageHashes)
68
- const projectId = resolveProjectId(db, session.rawProjectPath)
69
-
70
- const existing = db
71
- .query<{ content_hash: string; first_seen_at: string }, [string]>(
72
- 'SELECT content_hash, first_seen_at FROM sessions WHERE id = ?',
73
- )
74
- .get(id)
75
-
76
- if (existing && existing.content_hash === contentHash) {
77
- db.query('UPDATE sessions SET project_id = $projectId, status = $status, last_seen_at = $now WHERE id = $id').run({
78
- $projectId: projectId,
79
- $status: 'unchanged',
80
- $now: now,
81
- $id: id,
82
- })
83
- report.unchanged += 1
84
- return id
85
- }
86
-
87
- const status = existing ? 'changed' : 'new'
88
- const firstSeenAt = existing?.first_seen_at ?? now
89
-
90
- db.query(`
91
- INSERT INTO sessions (
92
- id, source_id, source_session_id, project_id, checkout_id, raw_project_path, raw_path,
93
- title, message_count, content_hash, status, created_at, updated_at, first_seen_at, last_seen_at
94
- ) VALUES (
95
- $id, $sourceId, $sourceSessionId, $projectId, NULL, $rawProjectPath, $rawPath,
96
- $title, $messageCount, $contentHash, $status, $createdAt, $updatedAt, $firstSeenAt, $now
97
- )
98
- ON CONFLICT(id) DO UPDATE SET
99
- project_id = excluded.project_id,
100
- raw_project_path = excluded.raw_project_path,
101
- title = excluded.title,
102
- message_count = excluded.message_count,
103
- content_hash = excluded.content_hash,
104
- status = excluded.status,
105
- created_at = excluded.created_at,
106
- updated_at = excluded.updated_at,
107
- last_seen_at = excluded.last_seen_at
108
- `).run({
109
- $id: id,
110
- $sourceId: collector.id,
111
- $sourceSessionId: session.sourceSessionId,
112
- $projectId: projectId,
113
- $rawProjectPath: session.rawProjectPath,
114
- $rawPath: session.rawPath,
115
- $title: session.title,
116
- $messageCount: session.messages.length,
117
- $contentHash: contentHash,
118
- $status: status,
119
- $createdAt: session.createdAt,
120
- $updatedAt: session.updatedAt,
121
- $firstSeenAt: firstSeenAt,
122
- $now: now,
123
- })
124
-
125
- db.query('DELETE FROM messages WHERE session_id = ?').run(id)
126
- session.messages.forEach((message, index) => {
127
- db.query(`
128
- INSERT INTO messages (id, session_id, role, content, timestamp, seq_order, content_hash)
129
- VALUES ($id, $sessionId, $role, $content, $timestamp, $seqOrder, $contentHash)
130
- `).run({
131
- $id: `msg_${id}_${index}`,
132
- $sessionId: id,
133
- $role: message.role,
134
- $content: message.content,
135
- $timestamp: message.timestamp,
136
- $seqOrder: index,
137
- $contentHash: messageHashes[index]!,
138
- })
139
- })
140
-
141
- if (status === 'new') report.new += 1
142
- else report.changed += 1
143
- return id
144
- }
145
-
146
- function markMissingSessions(
147
- db: LlmIwikiDatabase,
148
- sourceId: string,
149
- seenIds: Set<string>,
150
- now: string,
151
- report: SourceSyncReport,
152
- ): void {
153
- const rows = db
154
- .query<{ id: string }, [string]>(
155
- "SELECT id FROM sessions WHERE source_id = ? AND status != 'source_missing'",
156
- )
157
- .all(sourceId)
158
-
159
- for (const row of rows) {
160
- if (seenIds.has(row.id)) continue
161
- db.query('UPDATE sessions SET status = $status, last_seen_at = $now WHERE id = $id').run({
162
- $status: 'source_missing',
163
- $now: now,
164
- $id: row.id,
165
- })
166
- report.sourceMissing += 1
167
- }
168
- }
169
-
170
- export function runSync(db: LlmIwikiDatabase, options: SyncOptions): SyncReport {
171
- const now = new Date().toISOString()
172
- const bySource: SourceSyncReport[] = []
173
-
174
- for (const collector of COLLECTORS) {
175
- if (!collector.detect(options.homeDir)) continue
176
-
177
- upsertSource(db, collector, now)
178
- const report: SourceSyncReport = {
179
- source: collector.id,
180
- new: 0,
181
- changed: 0,
182
- unchanged: 0,
183
- sourceMissing: 0,
184
- total: 0,
185
- }
186
-
187
- const sessions = collector.collect(options.homeDir)
188
- const seenIds = new Set<string>()
189
-
190
- const writeAll = db.transaction(() => {
191
- for (const session of sessions) {
192
- if (options.projectFilter && session.rawProjectPath !== options.projectFilter) continue
193
- const id = writeSession(db, collector, session, now, report)
194
- seenIds.add(id)
195
- report.total += 1
196
- }
197
- if (!options.projectFilter) {
198
- markMissingSessions(db, collector.id, seenIds, now, report)
199
- }
200
- })
201
- writeAll()
202
-
203
- bySource.push(report)
204
- }
205
-
206
- return { bySource }
207
- }
package/src/types.ts DELETED
@@ -1,26 +0,0 @@
1
- export type SummaryValue = 'none' | 'low' | 'medium' | 'high'
2
- export type Confidence = 'low' | 'medium' | 'high'
3
-
4
- export interface ParsedSummariesYaml {
5
- projectId: string
6
- summaries: Array<{
7
- sessionId: string
8
- title: string
9
- value: SummaryValue
10
- summaryMarkdown: string
11
- metadata: Record<string, unknown>
12
- }>
13
- }
14
-
15
- export interface ParsedExperiencesYaml {
16
- projectId: string
17
- experiences: Array<{
18
- title: string
19
- slug: string | null
20
- summary: string
21
- bodyMarkdown: string
22
- sourceSessions: string[]
23
- confidence: Confidence | null
24
- metadata: Record<string, unknown>
25
- }>
26
- }