sandstream-kit 1.0.1 → 1.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.
- package/README.md +18 -0
- package/dist/check-web-search.js +37 -6
- package/dist/check-web-search.js.map +1 -1
- package/dist/cli.js +520 -2
- package/dist/cli.js.map +1 -1
- package/dist/config.d.ts +2 -0
- package/dist/config.js +1 -0
- package/dist/config.js.map +1 -1
- package/dist/database.d.ts +2 -2
- package/dist/database.js +9 -14
- package/dist/database.js.map +1 -1
- package/dist/lock.js +5 -3
- package/dist/lock.js.map +1 -1
- package/dist/memory/backup 2.d.ts +6 -0
- package/dist/memory/backup 2.js +80 -0
- package/dist/memory/backup 2.js.map +1 -0
- package/dist/memory/backup.d.ts +6 -0
- package/dist/memory/backup.js +80 -0
- package/dist/memory/backup.js.map +1 -0
- package/dist/memory/codex.d.ts +5 -0
- package/dist/memory/codex.js +150 -0
- package/dist/memory/codex.js.map +1 -0
- package/dist/memory/continue.d.ts +5 -0
- package/dist/memory/continue.js +116 -0
- package/dist/memory/continue.js.map +1 -0
- package/dist/memory/db 2.d.ts +40 -0
- package/dist/memory/db 2.js +233 -0
- package/dist/memory/db 2.js.map +1 -0
- package/dist/memory/db.d.ts +51 -0
- package/dist/memory/db.js +275 -0
- package/dist/memory/db.js.map +1 -0
- package/dist/memory/gemini.d.ts +5 -0
- package/dist/memory/gemini.js +176 -0
- package/dist/memory/gemini.js.map +1 -0
- package/dist/memory/hook 2.d.ts +6 -0
- package/dist/memory/hook 2.js +51 -0
- package/dist/memory/hook 2.js.map +1 -0
- package/dist/memory/hook.d.ts +15 -0
- package/dist/memory/hook.js +84 -0
- package/dist/memory/hook.js.map +1 -0
- package/dist/memory/hook.test 2.d.ts +1 -0
- package/dist/memory/hook.test 2.js +35 -0
- package/dist/memory/hook.test 2.js.map +1 -0
- package/dist/memory/install 2.d.ts +8 -0
- package/dist/memory/install 2.js +72 -0
- package/dist/memory/install 2.js.map +1 -0
- package/dist/memory/install.d.ts +8 -0
- package/dist/memory/install.js +73 -0
- package/dist/memory/install.js.map +1 -0
- package/dist/memory/install.test 2.d.ts +1 -0
- package/dist/memory/install.test 2.js +59 -0
- package/dist/memory/install.test 2.js.map +1 -0
- package/dist/memory/merge.d.ts +18 -0
- package/dist/memory/merge.js +109 -0
- package/dist/memory/merge.js.map +1 -0
- package/dist/memory/pal 2.d.ts +47 -0
- package/dist/memory/pal 2.js +154 -0
- package/dist/memory/pal 2.js.map +1 -0
- package/dist/memory/pal.d.ts +47 -0
- package/dist/memory/pal.js +154 -0
- package/dist/memory/pal.js.map +1 -0
- package/dist/memory/parser.d.ts +34 -0
- package/dist/memory/parser.js +195 -0
- package/dist/memory/parser.js.map +1 -0
- package/dist/memory/project 2.d.ts +1 -0
- package/dist/memory/project 2.js +24 -0
- package/dist/memory/project 2.js.map +1 -0
- package/dist/memory/project.d.ts +1 -0
- package/dist/memory/project.js +24 -0
- package/dist/memory/project.js.map +1 -0
- package/dist/memory/scan 2.d.ts +15 -0
- package/dist/memory/scan 2.js +94 -0
- package/dist/memory/scan 2.js.map +1 -0
- package/dist/memory/scan.d.ts +15 -0
- package/dist/memory/scan.js +94 -0
- package/dist/memory/scan.js.map +1 -0
- package/dist/memory/scan.test 2.d.ts +1 -0
- package/dist/memory/scan.test 2.js +55 -0
- package/dist/memory/scan.test 2.js.map +1 -0
- package/dist/memory/shared 2.d.ts +33 -0
- package/dist/memory/shared 2.js +120 -0
- package/dist/memory/shared 2.js.map +1 -0
- package/dist/memory/shared.d.ts +33 -0
- package/dist/memory/shared.js +120 -0
- package/dist/memory/shared.js.map +1 -0
- package/dist/memory/threads 2.d.ts +37 -0
- package/dist/memory/threads 2.js +50 -0
- package/dist/memory/threads 2.js.map +1 -0
- package/dist/memory/threads.d.ts +37 -0
- package/dist/memory/threads.js +50 -0
- package/dist/memory/threads.js.map +1 -0
- package/dist/memory/threads.test 2.d.ts +1 -0
- package/dist/memory/threads.test 2.js +66 -0
- package/dist/memory/threads.test 2.js.map +1 -0
- package/dist/memory/types 2.d.ts +52 -0
- package/dist/memory/types 2.js +5 -0
- package/dist/memory/types 2.js.map +1 -0
- package/dist/memory/types.d.ts +52 -0
- package/dist/memory/types.js +5 -0
- package/dist/memory/types.js.map +1 -0
- package/dist/status.d.ts +9 -0
- package/dist/status.js +119 -0
- package/dist/status.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* kit memory — local SQLite store (node:sqlite + FTS5).
|
|
3
|
+
*
|
|
4
|
+
* Schema is derived from cloudctx (MIT — github.com/chadptk1238/cloudctx): we reuse
|
|
5
|
+
* its proven table layout, PRAGMAs and FTS5 design. Differences: kit is a Node/TS
|
|
6
|
+
* project, so we use the built-in `node:sqlite` driver instead of `bun:sqlite`; we
|
|
7
|
+
* add a `harness` column (kit is harness-agnostic) and a `pending_actions` table
|
|
8
|
+
* (PAL — the structured, actionable layer on top of raw conversation memory).
|
|
9
|
+
*
|
|
10
|
+
* Memory is RAW and append-only: one row per message, no summarisation. Retrieval
|
|
11
|
+
* (FTS5) happens at time of work — store everything raw, search on demand. This DB
|
|
12
|
+
* is secret-dense (it indexes private transcripts): it lives only under ~/.kit/ with
|
|
13
|
+
* 0600 perms and is never committed. Redaction / encryption is stage B7.
|
|
14
|
+
*/
|
|
15
|
+
import { DatabaseSync } from "node:sqlite";
|
|
16
|
+
import { homedir } from "node:os";
|
|
17
|
+
import { join } from "node:path";
|
|
18
|
+
import { existsSync, mkdirSync, chmodSync, statSync } from "node:fs";
|
|
19
|
+
export const SCHEMA_VERSION = 3;
|
|
20
|
+
export function getMemoryDir() {
|
|
21
|
+
return process.env.KIT_MEMORY_DIR ?? join(homedir(), ".kit");
|
|
22
|
+
}
|
|
23
|
+
export function getMemoryDbPath() {
|
|
24
|
+
return process.env.KIT_MEMORY_DB ?? join(getMemoryDir(), "memory.db");
|
|
25
|
+
}
|
|
26
|
+
function ensureMemoryDir() {
|
|
27
|
+
const dir = getMemoryDir();
|
|
28
|
+
if (!existsSync(dir))
|
|
29
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
30
|
+
}
|
|
31
|
+
const SCHEMA_SQL = `
|
|
32
|
+
CREATE TABLE IF NOT EXISTS sessions (
|
|
33
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
34
|
+
session_id TEXT UNIQUE NOT NULL,
|
|
35
|
+
harness TEXT NOT NULL DEFAULT 'claude-code',
|
|
36
|
+
project TEXT,
|
|
37
|
+
first_message_at TEXT,
|
|
38
|
+
last_message_at TEXT,
|
|
39
|
+
message_count INTEGER DEFAULT 0,
|
|
40
|
+
is_agent_sidechain INTEGER DEFAULT 0
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
CREATE TABLE IF NOT EXISTS messages (
|
|
44
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
45
|
+
uuid TEXT UNIQUE,
|
|
46
|
+
session_id TEXT NOT NULL,
|
|
47
|
+
parent_uuid TEXT,
|
|
48
|
+
type TEXT NOT NULL,
|
|
49
|
+
role TEXT,
|
|
50
|
+
content TEXT,
|
|
51
|
+
model TEXT,
|
|
52
|
+
input_tokens INTEGER,
|
|
53
|
+
output_tokens INTEGER,
|
|
54
|
+
timestamp TEXT,
|
|
55
|
+
cwd TEXT,
|
|
56
|
+
git_branch TEXT,
|
|
57
|
+
version TEXT
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
CREATE TABLE IF NOT EXISTS tool_uses (
|
|
61
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
62
|
+
message_uuid TEXT,
|
|
63
|
+
session_id TEXT,
|
|
64
|
+
tool_name TEXT,
|
|
65
|
+
tool_input TEXT,
|
|
66
|
+
timestamp TEXT
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
CREATE TABLE IF NOT EXISTS saved_threads (
|
|
70
|
+
name TEXT PRIMARY KEY,
|
|
71
|
+
session_id TEXT NOT NULL,
|
|
72
|
+
summary TEXT,
|
|
73
|
+
project_path TEXT,
|
|
74
|
+
saved_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
CREATE TABLE IF NOT EXISTS pending_actions (
|
|
78
|
+
id TEXT PRIMARY KEY,
|
|
79
|
+
status TEXT NOT NULL DEFAULT 'open',
|
|
80
|
+
title TEXT NOT NULL,
|
|
81
|
+
detail TEXT,
|
|
82
|
+
scope TEXT,
|
|
83
|
+
kind TEXT NOT NULL DEFAULT 'manual',
|
|
84
|
+
verify_cmd TEXT,
|
|
85
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
86
|
+
next_check TEXT,
|
|
87
|
+
snooze_until TEXT,
|
|
88
|
+
closed_at TEXT,
|
|
89
|
+
verify_passes INTEGER NOT NULL DEFAULT 0
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
CREATE TABLE IF NOT EXISTS file_index (
|
|
93
|
+
path TEXT PRIMARY KEY,
|
|
94
|
+
mtime_ms INTEGER NOT NULL,
|
|
95
|
+
size INTEGER NOT NULL,
|
|
96
|
+
indexed_at TEXT DEFAULT CURRENT_TIMESTAMP
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id);
|
|
100
|
+
CREATE INDEX IF NOT EXISTS idx_messages_type ON messages(type);
|
|
101
|
+
CREATE INDEX IF NOT EXISTS idx_messages_timestamp ON messages(timestamp);
|
|
102
|
+
CREATE INDEX IF NOT EXISTS idx_tool_uses_tool ON tool_uses(tool_name);
|
|
103
|
+
CREATE INDEX IF NOT EXISTS idx_pending_status ON pending_actions(status);
|
|
104
|
+
|
|
105
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS messages_fts USING fts5(
|
|
106
|
+
content,
|
|
107
|
+
content=messages,
|
|
108
|
+
content_rowid=id
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
CREATE TRIGGER IF NOT EXISTS messages_ai AFTER INSERT ON messages BEGIN
|
|
112
|
+
INSERT INTO messages_fts(rowid, content) VALUES (new.id, new.content);
|
|
113
|
+
END;
|
|
114
|
+
CREATE TRIGGER IF NOT EXISTS messages_ad AFTER DELETE ON messages BEGIN
|
|
115
|
+
INSERT INTO messages_fts(messages_fts, rowid, content) VALUES ('delete', old.id, old.content);
|
|
116
|
+
END;
|
|
117
|
+
CREATE TRIGGER IF NOT EXISTS messages_au AFTER UPDATE ON messages BEGIN
|
|
118
|
+
INSERT INTO messages_fts(messages_fts, rowid, content) VALUES ('delete', old.id, old.content);
|
|
119
|
+
INSERT INTO messages_fts(rowid, content) VALUES (new.id, new.content);
|
|
120
|
+
END;
|
|
121
|
+
`;
|
|
122
|
+
function ensureColumn(db, table, column, decl) {
|
|
123
|
+
const cols = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
124
|
+
if (!cols.some((col) => col.name === column)) {
|
|
125
|
+
db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${decl}`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function migrate(db) {
|
|
129
|
+
db.exec("CREATE TABLE IF NOT EXISTS schema_meta (version INTEGER NOT NULL)");
|
|
130
|
+
db.exec(SCHEMA_SQL);
|
|
131
|
+
// v2: pending_actions.verify_passes (N=2 auto-verify confirmation). Add to
|
|
132
|
+
// tables created before this column existed.
|
|
133
|
+
ensureColumn(db, "pending_actions", "verify_passes", "INTEGER NOT NULL DEFAULT 0");
|
|
134
|
+
const row = db.prepare("SELECT version FROM schema_meta LIMIT 1").get();
|
|
135
|
+
if (!row) {
|
|
136
|
+
db.prepare("INSERT INTO schema_meta(version) VALUES (?)").run(SCHEMA_VERSION);
|
|
137
|
+
}
|
|
138
|
+
else if (row.version < SCHEMA_VERSION) {
|
|
139
|
+
db.prepare("UPDATE schema_meta SET version = ?").run(SCHEMA_VERSION);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Open (creating + migrating if needed) the memory database. Pass ":memory:" for
|
|
144
|
+
* an ephemeral in-process DB (tests). Otherwise defaults to ~/.kit/memory.db.
|
|
145
|
+
*/
|
|
146
|
+
export function openMemoryDb(path) {
|
|
147
|
+
const dbPath = path ?? getMemoryDbPath();
|
|
148
|
+
if (dbPath !== ":memory:")
|
|
149
|
+
ensureMemoryDir();
|
|
150
|
+
const db = new DatabaseSync(dbPath);
|
|
151
|
+
db.exec("PRAGMA journal_mode = WAL");
|
|
152
|
+
db.exec("PRAGMA busy_timeout = 5000");
|
|
153
|
+
db.exec("PRAGMA foreign_keys = OFF");
|
|
154
|
+
migrate(db);
|
|
155
|
+
if (dbPath !== ":memory:" && existsSync(dbPath)) {
|
|
156
|
+
try {
|
|
157
|
+
chmodSync(dbPath, 0o600);
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
// best-effort: non-POSIX filesystems may not support chmod
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return db;
|
|
164
|
+
}
|
|
165
|
+
/** Has this file already been indexed at exactly this mtime + size? (incremental index) */
|
|
166
|
+
export function isFileIndexed(db, path, mtimeMs, size) {
|
|
167
|
+
return !!db
|
|
168
|
+
.prepare("SELECT 1 FROM file_index WHERE path = ? AND mtime_ms = ? AND size = ?")
|
|
169
|
+
.get(path, mtimeMs, size);
|
|
170
|
+
}
|
|
171
|
+
/** Record (or refresh) a file's mtime + size after indexing it. */
|
|
172
|
+
export function markFileIndexed(db, path, mtimeMs, size) {
|
|
173
|
+
db.prepare(`INSERT INTO file_index (path, mtime_ms, size, indexed_at)
|
|
174
|
+
VALUES (?, ?, ?, datetime('now'))
|
|
175
|
+
ON CONFLICT(path) DO UPDATE SET mtime_ms = excluded.mtime_ms, size = excluded.size, indexed_at = datetime('now')`).run(path, mtimeMs, size);
|
|
176
|
+
}
|
|
177
|
+
export function upsertSession(db, s) {
|
|
178
|
+
db.prepare(`INSERT INTO sessions (session_id, harness, project, first_message_at, last_message_at, is_agent_sidechain)
|
|
179
|
+
VALUES (?, ?, ?, ?, ?, ?)
|
|
180
|
+
ON CONFLICT(session_id) DO UPDATE SET
|
|
181
|
+
last_message_at = COALESCE(excluded.last_message_at, sessions.last_message_at),
|
|
182
|
+
first_message_at = COALESCE(sessions.first_message_at, excluded.first_message_at),
|
|
183
|
+
project = COALESCE(excluded.project, sessions.project),
|
|
184
|
+
harness = excluded.harness,
|
|
185
|
+
is_agent_sidechain = MAX(sessions.is_agent_sidechain, excluded.is_agent_sidechain)`).run(s.sessionId, s.harness, s.project ?? null, s.firstMessageAt ?? null, s.lastMessageAt ?? null, s.isAgentSidechain ? 1 : 0);
|
|
186
|
+
}
|
|
187
|
+
/** Insert a message idempotently (by uuid). Returns true if a new row was added. */
|
|
188
|
+
export function insertMessage(db, m) {
|
|
189
|
+
const res = db
|
|
190
|
+
.prepare(`INSERT OR IGNORE INTO messages
|
|
191
|
+
(uuid, session_id, parent_uuid, type, role, content, model, input_tokens, output_tokens, timestamp, cwd, git_branch, version)
|
|
192
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
193
|
+
.run(m.uuid, m.sessionId, m.parentUuid ?? null, m.type, m.role ?? null, m.content ?? null, m.model ?? null, m.inputTokens ?? null, m.outputTokens ?? null, m.timestamp ?? null, m.cwd ?? null, m.gitBranch ?? null, m.version ?? null);
|
|
194
|
+
if (Number(res.changes) > 0) {
|
|
195
|
+
db.prepare("UPDATE sessions SET message_count = message_count + 1 WHERE session_id = ?").run(m.sessionId);
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
export function insertToolUse(db, t) {
|
|
201
|
+
db.prepare(`INSERT INTO tool_uses (message_uuid, session_id, tool_name, tool_input, timestamp)
|
|
202
|
+
VALUES (?, ?, ?, ?, ?)`).run(t.messageUuid ?? null, t.sessionId ?? null, t.toolName, t.toolInput ?? null, t.timestamp ?? null);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Full-text search over raw message content (FTS5 MATCH, ranked by `rank`).
|
|
206
|
+
* Pass opts.projectPath to scope to one repo (relevance + blast-radius); omit it
|
|
207
|
+
* for cross-project ("--global") recall over the personal store.
|
|
208
|
+
*/
|
|
209
|
+
export function searchMessages(db, query, opts = {}) {
|
|
210
|
+
const limit = opts.limit ?? 20;
|
|
211
|
+
const params = [query];
|
|
212
|
+
let where = "messages_fts MATCH ?";
|
|
213
|
+
if (opts.projectPath) {
|
|
214
|
+
where += " AND (m.cwd = ? OR m.cwd LIKE ?)";
|
|
215
|
+
params.push(opts.projectPath, `${opts.projectPath}/%`);
|
|
216
|
+
}
|
|
217
|
+
params.push(limit);
|
|
218
|
+
return db
|
|
219
|
+
.prepare(`SELECT m.id AS id, m.uuid AS uuid, m.session_id AS sessionId, m.role AS role,
|
|
220
|
+
m.content AS content, m.timestamp AS timestamp
|
|
221
|
+
FROM messages_fts f
|
|
222
|
+
JOIN messages m ON m.id = f.rowid
|
|
223
|
+
WHERE ${where}
|
|
224
|
+
ORDER BY rank
|
|
225
|
+
LIMIT ?`)
|
|
226
|
+
.all(...params);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Most-recent messages by wall-clock time (newest first) — the basis for session
|
|
230
|
+
* recovery (re-injecting "where you left off" after a compaction/resume). Unlike
|
|
231
|
+
* searchMessages this needs no query; pass opts.projectPath to scope to one repo.
|
|
232
|
+
* Skips empty-content rows so the recovery block stays signal, not blank tool turns.
|
|
233
|
+
*/
|
|
234
|
+
export function recentMessages(db, opts = {}) {
|
|
235
|
+
const limit = opts.limit ?? 10;
|
|
236
|
+
const params = [];
|
|
237
|
+
let where = "content IS NOT NULL AND content != ''";
|
|
238
|
+
if (opts.projectPath) {
|
|
239
|
+
where += " AND (cwd = ? OR cwd LIKE ?)";
|
|
240
|
+
params.push(opts.projectPath, `${opts.projectPath}/%`);
|
|
241
|
+
}
|
|
242
|
+
params.push(limit);
|
|
243
|
+
return db
|
|
244
|
+
.prepare(`SELECT id, uuid, session_id AS sessionId, role, content, timestamp
|
|
245
|
+
FROM messages
|
|
246
|
+
WHERE ${where}
|
|
247
|
+
ORDER BY timestamp DESC, id DESC
|
|
248
|
+
LIMIT ?`)
|
|
249
|
+
.all(...params);
|
|
250
|
+
}
|
|
251
|
+
export function getStats(db) {
|
|
252
|
+
const count = (sql) => {
|
|
253
|
+
const r = db.prepare(sql).get();
|
|
254
|
+
return r ? Number(r.n) : 0;
|
|
255
|
+
};
|
|
256
|
+
const dbPath = getMemoryDbPath();
|
|
257
|
+
let sizeBytes = 0;
|
|
258
|
+
if (dbPath !== ":memory:" && existsSync(dbPath)) {
|
|
259
|
+
try {
|
|
260
|
+
sizeBytes = statSync(dbPath).size;
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
// best-effort: size is informational only
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return {
|
|
267
|
+
sessions: count("SELECT COUNT(*) AS n FROM sessions"),
|
|
268
|
+
messages: count("SELECT COUNT(*) AS n FROM messages"),
|
|
269
|
+
toolUses: count("SELECT COUNT(*) AS n FROM tool_uses"),
|
|
270
|
+
pendingOpen: count("SELECT COUNT(*) AS n FROM pending_actions WHERE status = 'open'"),
|
|
271
|
+
dbPath,
|
|
272
|
+
sizeBytes,
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
//# sourceMappingURL=db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/memory/db.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { DatabaseSync } from "node:sqlite";
|
|
2
|
+
import type { IndexResult } from "./parser.js";
|
|
3
|
+
export declare function getGeminiTmpDir(): string;
|
|
4
|
+
/** Walk ~/.gemini/tmp and index every conversation log/checkpoint. Idempotent + incremental. */
|
|
5
|
+
export declare function indexGeminiSessions(db: DatabaseSync): IndexResult;
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* kit memory — Gemini CLI transcript parser (multi-harness).
|
|
3
|
+
*
|
|
4
|
+
* Gemini CLI persists conversation state under ~/.gemini/tmp/<projectHash>/ via a
|
|
5
|
+
* few mechanisms. Formats verified against the google-gemini/gemini-cli source:
|
|
6
|
+
* - logs.json — a JSON array of LogEntry records
|
|
7
|
+
* { sessionId, messageId, timestamp, type, message }
|
|
8
|
+
* - checkpoint files — either { history: Content[] } (modern) or a bare
|
|
9
|
+
* Content[] (legacy), where Content = { role: 'user'|'model', parts:[{text}] }
|
|
10
|
+
*
|
|
11
|
+
* We index user + model turns from whichever are present, tag harness="gemini",
|
|
12
|
+
* synthesize stable uuids (idempotent), and STRUCTURALLY skip non-conversation
|
|
13
|
+
* JSON (e.g. file-snapshot checkpoints whose shape isn't Content[]). RAW +
|
|
14
|
+
* deterministic; no model calls.
|
|
15
|
+
*
|
|
16
|
+
* Limitation: Gemini keys directories by a one-way projectHash, so the real repo
|
|
17
|
+
* path isn't recoverable — Gemini messages carry no cwd and surface in `--global`
|
|
18
|
+
* recall rather than project-scoped search.
|
|
19
|
+
*/
|
|
20
|
+
import { readFileSync, readdirSync, existsSync, statSync } from "node:fs";
|
|
21
|
+
import { homedir } from "node:os";
|
|
22
|
+
import { join, basename } from "node:path";
|
|
23
|
+
import { insertMessage, upsertSession, isFileIndexed, markFileIndexed } from "./db.js";
|
|
24
|
+
export function getGeminiTmpDir() {
|
|
25
|
+
const base = process.env.KIT_GEMINI_DIR ?? join(homedir(), ".gemini");
|
|
26
|
+
return join(base, "tmp");
|
|
27
|
+
}
|
|
28
|
+
function partsText(parts) {
|
|
29
|
+
if (!Array.isArray(parts))
|
|
30
|
+
return "";
|
|
31
|
+
return parts
|
|
32
|
+
.map((p) => p?.text ?? "")
|
|
33
|
+
.filter(Boolean)
|
|
34
|
+
.join("\n");
|
|
35
|
+
}
|
|
36
|
+
/** Coerce a parsed checkpoint to Content[], or null if it isn't a conversation. */
|
|
37
|
+
function asHistory(parsed) {
|
|
38
|
+
if (Array.isArray(parsed)) {
|
|
39
|
+
const looksLikeContent = parsed.every((x) => x !== null && typeof x === "object" && ("role" in x || "parts" in x));
|
|
40
|
+
return looksLikeContent ? parsed : null;
|
|
41
|
+
}
|
|
42
|
+
if (parsed !== null && typeof parsed === "object") {
|
|
43
|
+
const h = parsed.history;
|
|
44
|
+
if (Array.isArray(h))
|
|
45
|
+
return h;
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
/** Map a Gemini role/sender to the store's user|assistant. */
|
|
50
|
+
function roleOf(raw) {
|
|
51
|
+
return raw === "user" ? "user" : "assistant"; // 'model'/'gemini'/etc → assistant
|
|
52
|
+
}
|
|
53
|
+
function indexLogs(db, filepath) {
|
|
54
|
+
let parsed;
|
|
55
|
+
try {
|
|
56
|
+
parsed = JSON.parse(readFileSync(filepath, "utf8"));
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return { messages: 0 };
|
|
60
|
+
}
|
|
61
|
+
if (!Array.isArray(parsed))
|
|
62
|
+
return { messages: 0 };
|
|
63
|
+
let messages = 0;
|
|
64
|
+
let idx = 0;
|
|
65
|
+
for (const entry of parsed) {
|
|
66
|
+
const text = typeof entry?.message === "string" ? entry.message : "";
|
|
67
|
+
if (!text)
|
|
68
|
+
continue;
|
|
69
|
+
const sessionId = `gemini:${entry.sessionId ?? basename(filepath)}`;
|
|
70
|
+
upsertSession(db, { sessionId, harness: "gemini" });
|
|
71
|
+
const added = insertMessage(db, {
|
|
72
|
+
uuid: `gemini:log:${entry.sessionId ?? basename(filepath)}:${entry.messageId ?? idx}`,
|
|
73
|
+
sessionId,
|
|
74
|
+
type: roleOf(entry.type),
|
|
75
|
+
role: roleOf(entry.type),
|
|
76
|
+
content: text,
|
|
77
|
+
timestamp: entry.timestamp,
|
|
78
|
+
});
|
|
79
|
+
idx++;
|
|
80
|
+
if (added)
|
|
81
|
+
messages++;
|
|
82
|
+
}
|
|
83
|
+
return { messages };
|
|
84
|
+
}
|
|
85
|
+
function indexCheckpoint(db, filepath) {
|
|
86
|
+
let parsed;
|
|
87
|
+
try {
|
|
88
|
+
parsed = JSON.parse(readFileSync(filepath, "utf8"));
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return { messages: 0 };
|
|
92
|
+
}
|
|
93
|
+
const history = asHistory(parsed);
|
|
94
|
+
if (!history)
|
|
95
|
+
return { messages: 0 }; // not a conversation checkpoint — skip
|
|
96
|
+
const sessionId = `gemini-ckpt:${basename(filepath, ".json")}`;
|
|
97
|
+
upsertSession(db, { sessionId, harness: "gemini" });
|
|
98
|
+
let messages = 0;
|
|
99
|
+
history.forEach((c, idx) => {
|
|
100
|
+
if (c?.role !== "user" && c?.role !== "model")
|
|
101
|
+
return; // skip non-turn entries
|
|
102
|
+
const text = partsText(c.parts);
|
|
103
|
+
if (!text)
|
|
104
|
+
return;
|
|
105
|
+
const added = insertMessage(db, {
|
|
106
|
+
uuid: `gemini:ckpt:${basename(filepath)}:${idx}`,
|
|
107
|
+
sessionId,
|
|
108
|
+
type: roleOf(c.role),
|
|
109
|
+
role: roleOf(c.role),
|
|
110
|
+
content: text,
|
|
111
|
+
});
|
|
112
|
+
if (added)
|
|
113
|
+
messages++;
|
|
114
|
+
});
|
|
115
|
+
return { messages };
|
|
116
|
+
}
|
|
117
|
+
function* walkGeminiFiles(tmpDir) {
|
|
118
|
+
let hashes;
|
|
119
|
+
try {
|
|
120
|
+
hashes = readdirSync(tmpDir, { withFileTypes: true });
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
for (const h of hashes) {
|
|
126
|
+
if (!h.isDirectory())
|
|
127
|
+
continue;
|
|
128
|
+
const projDir = join(tmpDir, h.name);
|
|
129
|
+
const logs = join(projDir, "logs.json");
|
|
130
|
+
if (existsSync(logs))
|
|
131
|
+
yield { path: logs, kind: "logs" };
|
|
132
|
+
// checkpoint JSON lives at the project root and/or in a checkpoints/ subdir
|
|
133
|
+
for (const dir of [projDir, join(projDir, "checkpoints")]) {
|
|
134
|
+
let entries;
|
|
135
|
+
try {
|
|
136
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
for (const e of entries) {
|
|
142
|
+
if (e.isFile() && e.name.endsWith(".json") && e.name !== "logs.json") {
|
|
143
|
+
yield { path: join(dir, e.name), kind: "checkpoint" };
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/** Walk ~/.gemini/tmp and index every conversation log/checkpoint. Idempotent + incremental. */
|
|
150
|
+
export function indexGeminiSessions(db) {
|
|
151
|
+
const tmpDir = getGeminiTmpDir();
|
|
152
|
+
const result = { files: 0, sessions: 0, messages: 0, toolUses: 0, filesSkipped: 0 };
|
|
153
|
+
if (!existsSync(tmpDir))
|
|
154
|
+
return result;
|
|
155
|
+
for (const f of walkGeminiFiles(tmpDir)) {
|
|
156
|
+
let st;
|
|
157
|
+
try {
|
|
158
|
+
st = statSync(f.path);
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
const mtimeMs = Math.floor(st.mtimeMs);
|
|
164
|
+
if (isFileIndexed(db, f.path, mtimeMs, st.size)) {
|
|
165
|
+
result.filesSkipped++;
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
const counts = f.kind === "logs" ? indexLogs(db, f.path) : indexCheckpoint(db, f.path);
|
|
169
|
+
markFileIndexed(db, f.path, mtimeMs, st.size);
|
|
170
|
+
result.files++;
|
|
171
|
+
result.sessions++;
|
|
172
|
+
result.messages += counts.messages;
|
|
173
|
+
}
|
|
174
|
+
return result;
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=gemini.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gemini.js","sourceRoot":"","sources":["../../src/memory/gemini.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE3C,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAGvF,MAAM,UAAU,eAAe;IAC7B,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;IACtE,OAAO,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAC3B,CAAC;AAcD,SAAS,SAAS,CAAC,KAAsC;IACvD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACrC,OAAO,KAAK;SACT,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,IAAI,EAAE,CAAC;SACzB,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,mFAAmF;AACnF,SAAS,SAAS,CAAC,MAAe;IAChC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,MAAM,gBAAgB,GAAG,MAAM,CAAC,KAAK,CACnC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,OAAO,IAAI,CAAC,CAAC,CAC5E,CAAC;QACF,OAAO,gBAAgB,CAAC,CAAC,CAAE,MAA0B,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/D,CAAC;IACD,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAClD,MAAM,CAAC,GAAI,MAAkC,CAAC,OAAO,CAAC;QACtD,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;YAAE,OAAO,CAAoB,CAAC;IACpD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,8DAA8D;AAC9D,SAAS,MAAM,CAAC,GAAuB;IACrC,OAAO,GAAG,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,mCAAmC;AACnF,CAAC;AAED,SAAS,SAAS,CAAC,EAAgB,EAAE,QAAgB;IACnD,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IAEnD,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,GAAG,GAAG,CAAC,CAAC;IACZ,KAAK,MAAM,KAAK,IAAI,MAAoB,EAAE,CAAC;QACzC,MAAM,IAAI,GAAG,OAAO,KAAK,EAAE,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACrE,IAAI,CAAC,IAAI;YAAE,SAAS;QACpB,MAAM,SAAS,GAAG,UAAU,KAAK,CAAC,SAAS,IAAI,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACpE,aAAa,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;QACpD,MAAM,KAAK,GAAG,aAAa,CAAC,EAAE,EAAE;YAC9B,IAAI,EAAE,cAAc,KAAK,CAAC,SAAS,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,SAAS,IAAI,GAAG,EAAE;YACrF,SAAS;YACT,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;YACxB,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC;YACxB,OAAO,EAAE,IAAI;YACb,SAAS,EAAE,KAAK,CAAC,SAAS;SAC3B,CAAC,CAAC;QACH,GAAG,EAAE,CAAC;QACN,IAAI,KAAK;YAAE,QAAQ,EAAE,CAAC;IACxB,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,CAAC;AACtB,CAAC;AAED,SAAS,eAAe,CAAC,EAAgB,EAAE,QAAgB;IACzD,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;IACD,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IAClC,IAAI,CAAC,OAAO;QAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,uCAAuC;IAE7E,MAAM,SAAS,GAAG,eAAe,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,EAAE,CAAC;IAC/D,aAAa,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;IACpD,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE;QACzB,IAAI,CAAC,EAAE,IAAI,KAAK,MAAM,IAAI,CAAC,EAAE,IAAI,KAAK,OAAO;YAAE,OAAO,CAAC,wBAAwB;QAC/E,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,MAAM,KAAK,GAAG,aAAa,CAAC,EAAE,EAAE;YAC9B,IAAI,EAAE,eAAe,QAAQ,CAAC,QAAQ,CAAC,IAAI,GAAG,EAAE;YAChD,SAAS;YACT,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;YACpB,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;YACpB,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;QACH,IAAI,KAAK;YAAE,QAAQ,EAAE,CAAC;IACxB,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,QAAQ,EAAE,CAAC;AACtB,CAAC;AAOD,QAAQ,CAAC,CAAC,eAAe,CAAC,MAAc;IACtC,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,WAAW,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO;IACT,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,IAAI,CAAC,CAAC,CAAC,WAAW,EAAE;YAAE,SAAS;QAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QACxC,IAAI,UAAU,CAAC,IAAI,CAAC;YAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;QACzD,4EAA4E;QAC5E,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC,EAAE,CAAC;YAC1D,IAAI,OAAO,CAAC;YACZ,IAAI,CAAC;gBACH,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YACtD,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YACD,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;gBACxB,IAAI,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;oBACrE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;gBACxD,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,mBAAmB,CAAC,EAAgB;IAClD,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IACjC,MAAM,MAAM,GAAgB,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC;IACjG,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IAEvC,KAAK,MAAM,CAAC,IAAI,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC;QACxC,IAAI,EAAE,CAAC;QACP,IAAI,CAAC;YACH,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;QACvC,IAAI,aAAa,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAChD,MAAM,CAAC,YAAY,EAAE,CAAC;YACtB,SAAS;QACX,CAAC;QACD,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;QACvF,eAAe,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;QAC9C,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,QAAQ,EAAE,CAAC;QAClB,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC;IACrC,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Reminder injected before every prompt. Empty string on any error (fail-open). */
|
|
2
|
+
export declare function userPromptSubmitReminder(): string;
|
|
3
|
+
/** Index the just-ended session. Returns count of newly indexed messages (fail-open). */
|
|
4
|
+
export declare function runSessionEndIndex(): {
|
|
5
|
+
messages: number;
|
|
6
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* kit memory — Claude Code hook entry points (the "whole system is two hooks").
|
|
3
|
+
*
|
|
4
|
+
* - UserPromptSubmit → a short reminder that searchable memory exists. The agent
|
|
5
|
+
* pulls on demand (`kit memory search`) instead of pre-loading everything.
|
|
6
|
+
* - SessionEnd → index the just-ended session into the store (incremental sync).
|
|
7
|
+
*
|
|
8
|
+
* Both are FAIL-OPEN: any error yields an empty/no-op result so a hook can never
|
|
9
|
+
* block a prompt or break a session. Deterministic, zero model calls.
|
|
10
|
+
*/
|
|
11
|
+
import { basename } from "node:path";
|
|
12
|
+
import { openMemoryDb, getStats } from "./db.js";
|
|
13
|
+
import { indexClaudeTranscripts } from "./parser.js";
|
|
14
|
+
import { palList } from "./pal.js";
|
|
15
|
+
import { getCurrentProjectRoot } from "./project.js";
|
|
16
|
+
/** Reminder injected before every prompt. Empty string on any error (fail-open). */
|
|
17
|
+
export function userPromptSubmitReminder() {
|
|
18
|
+
try {
|
|
19
|
+
const db = openMemoryDb();
|
|
20
|
+
const s = getStats(db);
|
|
21
|
+
// Only surface THIS project's open items (plus globally-scoped) — no cross-project noise.
|
|
22
|
+
const openItems = palList(db, { scope: basename(getCurrentProjectRoot()) });
|
|
23
|
+
db.close();
|
|
24
|
+
let pending = "";
|
|
25
|
+
if (openItems.length > 0) {
|
|
26
|
+
const shown = openItems.slice(0, 3);
|
|
27
|
+
const titles = shown.map((p) => `${p.id} ${p.title}`).join("; ");
|
|
28
|
+
const more = openItems.length > shown.length ? " …" : "";
|
|
29
|
+
pending = ` ${openItems.length} open action item(s) blocked on you: ${titles}${more}.`;
|
|
30
|
+
}
|
|
31
|
+
return (`You have local conversation memory: ${s.messages} messages indexed. ` +
|
|
32
|
+
"Before answering anything project-specific, run `kit memory search <terms>` " +
|
|
33
|
+
`to retrieve what was actually said instead of reconstructing it.${pending}`);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return ""; // fail-open: never block a prompt
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** Index the just-ended session. Returns count of newly indexed messages (fail-open). */
|
|
40
|
+
export function runSessionEndIndex() {
|
|
41
|
+
try {
|
|
42
|
+
const db = openMemoryDb();
|
|
43
|
+
const res = indexClaudeTranscripts(db);
|
|
44
|
+
db.close();
|
|
45
|
+
return { messages: res.messages };
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return { messages: 0 }; // fail-open
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=hook%202.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook 2.js","sourceRoot":"","sources":["../../src/memory/hook 2.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACnC,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAErD,oFAAoF;AACpF,MAAM,UAAU,wBAAwB;IACtC,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,YAAY,EAAE,CAAC;QAC1B,MAAM,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;QACvB,0FAA0F;QAC1F,MAAM,SAAS,GAAG,OAAO,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,qBAAqB,EAAE,CAAC,EAAE,CAAC,CAAC;QAC5E,EAAE,CAAC,KAAK,EAAE,CAAC;QACX,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACpC,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjE,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YACzD,OAAO,GAAG,IAAI,SAAS,CAAC,MAAM,wCAAwC,MAAM,GAAG,IAAI,GAAG,CAAC;QACzF,CAAC;QACD,OAAO,CACL,uCAAuC,CAAC,CAAC,QAAQ,qBAAqB;YACtE,8EAA8E;YAC9E,mEAAmE,OAAO,EAAE,CAC7E,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC,CAAC,kCAAkC;IAC/C,CAAC;AACH,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,kBAAkB;IAChC,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,YAAY,EAAE,CAAC;QAC1B,MAAM,GAAG,GAAG,sBAAsB,CAAC,EAAE,CAAC,CAAC;QACvC,EAAE,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,YAAY;IACtC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Reminder injected before every prompt. Empty string on any error (fail-open). */
|
|
2
|
+
export declare function userPromptSubmitReminder(): string;
|
|
3
|
+
/**
|
|
4
|
+
* SessionStart recovery — re-inject "where you left off" for THIS project after a
|
|
5
|
+
* resume/compact, so the agent regains continuity instead of starting blank. Pulls
|
|
6
|
+
* the most recent messages + open action items from the store. FAIL-OPEN and
|
|
7
|
+
* deterministic: empty string on any error or when there's nothing to recover.
|
|
8
|
+
*/
|
|
9
|
+
export declare function sessionStartRecovery(opts?: {
|
|
10
|
+
limit?: number;
|
|
11
|
+
}): string;
|
|
12
|
+
/** Index the just-ended session. Returns count of newly indexed messages (fail-open). */
|
|
13
|
+
export declare function runSessionEndIndex(): {
|
|
14
|
+
messages: number;
|
|
15
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* kit memory — Claude Code hook entry points (the "whole system is two hooks").
|
|
3
|
+
*
|
|
4
|
+
* - UserPromptSubmit → a short reminder that searchable memory exists. The agent
|
|
5
|
+
* pulls on demand (`kit memory search`) instead of pre-loading everything.
|
|
6
|
+
* - SessionEnd → index the just-ended session into the store (incremental sync).
|
|
7
|
+
*
|
|
8
|
+
* Both are FAIL-OPEN: any error yields an empty/no-op result so a hook can never
|
|
9
|
+
* block a prompt or break a session. Deterministic, zero model calls.
|
|
10
|
+
*/
|
|
11
|
+
import { basename } from "node:path";
|
|
12
|
+
import { openMemoryDb, getStats, recentMessages } from "./db.js";
|
|
13
|
+
import { indexClaudeTranscripts } from "./parser.js";
|
|
14
|
+
import { palList } from "./pal.js";
|
|
15
|
+
import { getCurrentProjectRoot } from "./project.js";
|
|
16
|
+
/** Reminder injected before every prompt. Empty string on any error (fail-open). */
|
|
17
|
+
export function userPromptSubmitReminder() {
|
|
18
|
+
try {
|
|
19
|
+
const db = openMemoryDb();
|
|
20
|
+
const s = getStats(db);
|
|
21
|
+
// Only surface THIS project's open items (plus globally-scoped) — no cross-project noise.
|
|
22
|
+
const openItems = palList(db, { scope: basename(getCurrentProjectRoot()) });
|
|
23
|
+
db.close();
|
|
24
|
+
let pending = "";
|
|
25
|
+
if (openItems.length > 0) {
|
|
26
|
+
const shown = openItems.slice(0, 3);
|
|
27
|
+
const titles = shown.map((p) => `${p.id} ${p.title}`).join("; ");
|
|
28
|
+
const more = openItems.length > shown.length ? " …" : "";
|
|
29
|
+
pending = ` ${openItems.length} open action item(s) blocked on you: ${titles}${more}.`;
|
|
30
|
+
}
|
|
31
|
+
return (`You have local conversation memory: ${s.messages} messages indexed. ` +
|
|
32
|
+
"Before answering anything project-specific, run `kit memory search <terms>` " +
|
|
33
|
+
`to retrieve what was actually said instead of reconstructing it.${pending}`);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return ""; // fail-open: never block a prompt
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* SessionStart recovery — re-inject "where you left off" for THIS project after a
|
|
41
|
+
* resume/compact, so the agent regains continuity instead of starting blank. Pulls
|
|
42
|
+
* the most recent messages + open action items from the store. FAIL-OPEN and
|
|
43
|
+
* deterministic: empty string on any error or when there's nothing to recover.
|
|
44
|
+
*/
|
|
45
|
+
export function sessionStartRecovery(opts = {}) {
|
|
46
|
+
try {
|
|
47
|
+
const db = openMemoryDb();
|
|
48
|
+
const root = getCurrentProjectRoot();
|
|
49
|
+
const recent = recentMessages(db, { projectPath: root, limit: opts.limit ?? 6 });
|
|
50
|
+
const openItems = palList(db, { scope: basename(root) });
|
|
51
|
+
db.close();
|
|
52
|
+
if (recent.length === 0 && openItems.length === 0)
|
|
53
|
+
return "";
|
|
54
|
+
const lines = [`Picking up in ${basename(root)} — recent memory (newest first):`];
|
|
55
|
+
for (const m of recent) {
|
|
56
|
+
const who = m.role === "assistant" ? "assistant" : "you";
|
|
57
|
+
const text = (m.content ?? "").replace(/\s+/g, " ").trim().slice(0, 200);
|
|
58
|
+
if (text)
|
|
59
|
+
lines.push(` · ${who}: ${text}`);
|
|
60
|
+
}
|
|
61
|
+
if (openItems.length > 0) {
|
|
62
|
+
const titles = openItems.slice(0, 3).map((p) => `${p.id} ${p.title}`).join("; ");
|
|
63
|
+
lines.push(`Open action items blocked on you: ${titles}${openItems.length > 3 ? " …" : ""}.`);
|
|
64
|
+
}
|
|
65
|
+
lines.push("Run `kit memory search <terms>` to pull more of what was actually said.");
|
|
66
|
+
return lines.join("\n");
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return ""; // fail-open: never block a session start
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/** Index the just-ended session. Returns count of newly indexed messages (fail-open). */
|
|
73
|
+
export function runSessionEndIndex() {
|
|
74
|
+
try {
|
|
75
|
+
const db = openMemoryDb();
|
|
76
|
+
const res = indexClaudeTranscripts(db);
|
|
77
|
+
db.close();
|
|
78
|
+
return { messages: res.messages };
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return { messages: 0 }; // fail-open
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=hook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook.js","sourceRoot":"","sources":["../../src/memory/hook.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|