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,35 @@
|
|
|
1
|
+
import { describe, it, before, after } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { openMemoryDb, upsertSession, insertMessage } from "./db.js";
|
|
7
|
+
import { userPromptSubmitReminder } from "./hook.js";
|
|
8
|
+
describe("memory hook — UserPromptSubmit reminder", () => {
|
|
9
|
+
let tmp;
|
|
10
|
+
const prev = process.env.KIT_MEMORY_DB;
|
|
11
|
+
before(() => {
|
|
12
|
+
tmp = mkdtempSync(join(tmpdir(), "kit-hook-"));
|
|
13
|
+
process.env.KIT_MEMORY_DB = join(tmp, "memory.db");
|
|
14
|
+
const db = openMemoryDb();
|
|
15
|
+
upsertSession(db, { sessionId: "s1", harness: "claude-code" });
|
|
16
|
+
insertMessage(db, { uuid: "u1", sessionId: "s1", type: "user", content: "hi" });
|
|
17
|
+
db.close();
|
|
18
|
+
});
|
|
19
|
+
after(() => {
|
|
20
|
+
if (prev === undefined)
|
|
21
|
+
delete process.env.KIT_MEMORY_DB;
|
|
22
|
+
else
|
|
23
|
+
process.env.KIT_MEMORY_DB = prev;
|
|
24
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
25
|
+
});
|
|
26
|
+
it("nudges the agent to search and reports the message count", () => {
|
|
27
|
+
const text = userPromptSubmitReminder();
|
|
28
|
+
assert.match(text, /kit memory search/);
|
|
29
|
+
assert.match(text, /1 messages/);
|
|
30
|
+
});
|
|
31
|
+
it("never throws (fail-open)", () => {
|
|
32
|
+
assert.doesNotThrow(() => userPromptSubmitReminder());
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
//# sourceMappingURL=hook.test%202.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook.test 2.js","sourceRoot":"","sources":["../../src/memory/hook.test 2.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AACxD,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACrE,OAAO,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAC;AAErD,QAAQ,CAAC,yCAAyC,EAAE,GAAG,EAAE;IACvD,IAAI,GAAW,CAAC;IAChB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IAEvC,MAAM,CAAC,GAAG,EAAE;QACV,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC;QAC/C,OAAO,CAAC,GAAG,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QACnD,MAAM,EAAE,GAAG,YAAY,EAAE,CAAC;QAC1B,aAAa,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,CAAC;QAC/D,aAAa,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAChF,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC,CAAC,CAAC;IAEH,KAAK,CAAC,GAAG,EAAE;QACT,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;;YACpD,OAAO,CAAC,GAAG,CAAC,aAAa,GAAG,IAAI,CAAC;QACtC,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,MAAM,IAAI,GAAG,wBAAwB,EAAE,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,mBAAmB,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAClC,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC,wBAAwB,EAAE,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* kit memory — install/remove the two Claude Code hooks in ~/.claude/settings.json.
|
|
3
|
+
*
|
|
4
|
+
* Idempotent and non-destructive: merges our hook entries into the existing
|
|
5
|
+
* settings without touching the user's other hooks. Re-running adds nothing.
|
|
6
|
+
* Honors KIT_CLAUDE_SETTINGS for tests.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
9
|
+
import { homedir } from "node:os";
|
|
10
|
+
import { join, dirname } from "node:path";
|
|
11
|
+
const MEMORY_HOOKS = [
|
|
12
|
+
{ event: "UserPromptSubmit", command: "kit memory hook user-prompt-submit" },
|
|
13
|
+
{ event: "SessionEnd", command: "kit memory hook session-end" },
|
|
14
|
+
];
|
|
15
|
+
export function getClaudeSettingsPath() {
|
|
16
|
+
return process.env.KIT_CLAUDE_SETTINGS ?? join(homedir(), ".claude", "settings.json");
|
|
17
|
+
}
|
|
18
|
+
function readSettings(path) {
|
|
19
|
+
if (!existsSync(path))
|
|
20
|
+
return {};
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return {}; // corrupt/unreadable → start fresh rather than crash
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function writeSettings(path, s) {
|
|
29
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
30
|
+
writeFileSync(path, JSON.stringify(s, null, 2) + "\n");
|
|
31
|
+
}
|
|
32
|
+
function groupsHaveCommand(groups, command) {
|
|
33
|
+
return groups.some((g) => g.hooks?.some((h) => h.command === command));
|
|
34
|
+
}
|
|
35
|
+
export function installMemoryHooks(path = getClaudeSettingsPath()) {
|
|
36
|
+
const s = readSettings(path);
|
|
37
|
+
const hooks = (s.hooks ??= {});
|
|
38
|
+
const added = [];
|
|
39
|
+
const alreadyPresent = [];
|
|
40
|
+
for (const { event, command } of MEMORY_HOOKS) {
|
|
41
|
+
const groups = (hooks[event] ??= []);
|
|
42
|
+
if (groupsHaveCommand(groups, command)) {
|
|
43
|
+
alreadyPresent.push(event);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
groups.push({ hooks: [{ type: "command", command }] });
|
|
47
|
+
added.push(event);
|
|
48
|
+
}
|
|
49
|
+
if (added.length)
|
|
50
|
+
writeSettings(path, s);
|
|
51
|
+
return { added, alreadyPresent };
|
|
52
|
+
}
|
|
53
|
+
export function uninstallMemoryHooks(path = getClaudeSettingsPath()) {
|
|
54
|
+
const s = readSettings(path);
|
|
55
|
+
if (!s.hooks)
|
|
56
|
+
return { removed: [] };
|
|
57
|
+
const removed = [];
|
|
58
|
+
for (const { event, command } of MEMORY_HOOKS) {
|
|
59
|
+
const groups = s.hooks[event];
|
|
60
|
+
if (!Array.isArray(groups))
|
|
61
|
+
continue;
|
|
62
|
+
const filtered = groups.filter((g) => !g.hooks?.some((h) => h.command === command));
|
|
63
|
+
if (filtered.length !== groups.length) {
|
|
64
|
+
s.hooks[event] = filtered;
|
|
65
|
+
removed.push(event);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (removed.length)
|
|
69
|
+
writeSettings(path, s);
|
|
70
|
+
return { removed };
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=install%202.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install 2.js","sourceRoot":"","sources":["../../src/memory/install 2.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* kit memory — install/remove the two Claude Code hooks in ~/.claude/settings.json.
|
|
3
|
+
*
|
|
4
|
+
* Idempotent and non-destructive: merges our hook entries into the existing
|
|
5
|
+
* settings without touching the user's other hooks. Re-running adds nothing.
|
|
6
|
+
* Honors KIT_CLAUDE_SETTINGS for tests.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
9
|
+
import { homedir } from "node:os";
|
|
10
|
+
import { join, dirname } from "node:path";
|
|
11
|
+
const MEMORY_HOOKS = [
|
|
12
|
+
{ event: "UserPromptSubmit", command: "kit memory hook user-prompt-submit" },
|
|
13
|
+
{ event: "SessionEnd", command: "kit memory hook session-end" },
|
|
14
|
+
{ event: "SessionStart", command: "kit memory hook session-start" },
|
|
15
|
+
];
|
|
16
|
+
export function getClaudeSettingsPath() {
|
|
17
|
+
return process.env.KIT_CLAUDE_SETTINGS ?? join(homedir(), ".claude", "settings.json");
|
|
18
|
+
}
|
|
19
|
+
function readSettings(path) {
|
|
20
|
+
if (!existsSync(path))
|
|
21
|
+
return {};
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return {}; // corrupt/unreadable → start fresh rather than crash
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function writeSettings(path, s) {
|
|
30
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
31
|
+
writeFileSync(path, JSON.stringify(s, null, 2) + "\n");
|
|
32
|
+
}
|
|
33
|
+
function groupsHaveCommand(groups, command) {
|
|
34
|
+
return groups.some((g) => g.hooks?.some((h) => h.command === command));
|
|
35
|
+
}
|
|
36
|
+
export function installMemoryHooks(path = getClaudeSettingsPath()) {
|
|
37
|
+
const s = readSettings(path);
|
|
38
|
+
const hooks = (s.hooks ??= {});
|
|
39
|
+
const added = [];
|
|
40
|
+
const alreadyPresent = [];
|
|
41
|
+
for (const { event, command } of MEMORY_HOOKS) {
|
|
42
|
+
const groups = (hooks[event] ??= []);
|
|
43
|
+
if (groupsHaveCommand(groups, command)) {
|
|
44
|
+
alreadyPresent.push(event);
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
groups.push({ hooks: [{ type: "command", command }] });
|
|
48
|
+
added.push(event);
|
|
49
|
+
}
|
|
50
|
+
if (added.length)
|
|
51
|
+
writeSettings(path, s);
|
|
52
|
+
return { added, alreadyPresent };
|
|
53
|
+
}
|
|
54
|
+
export function uninstallMemoryHooks(path = getClaudeSettingsPath()) {
|
|
55
|
+
const s = readSettings(path);
|
|
56
|
+
if (!s.hooks)
|
|
57
|
+
return { removed: [] };
|
|
58
|
+
const removed = [];
|
|
59
|
+
for (const { event, command } of MEMORY_HOOKS) {
|
|
60
|
+
const groups = s.hooks[event];
|
|
61
|
+
if (!Array.isArray(groups))
|
|
62
|
+
continue;
|
|
63
|
+
const filtered = groups.filter((g) => !g.hooks?.some((h) => h.command === command));
|
|
64
|
+
if (filtered.length !== groups.length) {
|
|
65
|
+
s.hooks[event] = filtered;
|
|
66
|
+
removed.push(event);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (removed.length)
|
|
70
|
+
writeSettings(path, s);
|
|
71
|
+
return { removed };
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/memory/install.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { describe, it, before, after, beforeEach } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import { mkdtempSync, rmSync, writeFileSync, readFileSync } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { installMemoryHooks, uninstallMemoryHooks } from "./install.js";
|
|
7
|
+
describe("memory hook installer", () => {
|
|
8
|
+
let tmp;
|
|
9
|
+
let settingsPath;
|
|
10
|
+
const prev = process.env.KIT_CLAUDE_SETTINGS;
|
|
11
|
+
before(() => {
|
|
12
|
+
tmp = mkdtempSync(join(tmpdir(), "kit-install-"));
|
|
13
|
+
settingsPath = join(tmp, "settings.json");
|
|
14
|
+
process.env.KIT_CLAUDE_SETTINGS = settingsPath;
|
|
15
|
+
});
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
// Start each test from a settings file with an unrelated, pre-existing hook.
|
|
18
|
+
writeFileSync(settingsPath, JSON.stringify({
|
|
19
|
+
hooks: {
|
|
20
|
+
UserPromptSubmit: [{ hooks: [{ type: "command", command: "some-other-tool" }] }],
|
|
21
|
+
},
|
|
22
|
+
}));
|
|
23
|
+
});
|
|
24
|
+
after(() => {
|
|
25
|
+
if (prev === undefined)
|
|
26
|
+
delete process.env.KIT_CLAUDE_SETTINGS;
|
|
27
|
+
else
|
|
28
|
+
process.env.KIT_CLAUDE_SETTINGS = prev;
|
|
29
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
30
|
+
});
|
|
31
|
+
it("installs both hooks without clobbering existing ones", () => {
|
|
32
|
+
const res = installMemoryHooks();
|
|
33
|
+
assert.deepEqual(res.added.sort(), ["SessionEnd", "UserPromptSubmit"]);
|
|
34
|
+
const s = JSON.parse(readFileSync(settingsPath, "utf8"));
|
|
35
|
+
const ups = s.hooks.UserPromptSubmit.flatMap((g) => g.hooks.map((h) => h.command));
|
|
36
|
+
assert.ok(ups.includes("some-other-tool"), "preserves the pre-existing hook");
|
|
37
|
+
assert.ok(ups.includes("kit memory hook user-prompt-submit"));
|
|
38
|
+
assert.ok(s.hooks.SessionEnd.some((g) => g.hooks.some((h) => h.command === "kit memory hook session-end")));
|
|
39
|
+
});
|
|
40
|
+
it("is idempotent — re-install adds nothing and creates no duplicates", () => {
|
|
41
|
+
installMemoryHooks();
|
|
42
|
+
const res2 = installMemoryHooks();
|
|
43
|
+
assert.deepEqual(res2.added, []);
|
|
44
|
+
assert.deepEqual(res2.alreadyPresent.sort(), ["SessionEnd", "UserPromptSubmit"]);
|
|
45
|
+
const s = JSON.parse(readFileSync(settingsPath, "utf8"));
|
|
46
|
+
const ours = s.hooks.UserPromptSubmit.filter((g) => g.hooks.some((h) => h.command === "kit memory hook user-prompt-submit"));
|
|
47
|
+
assert.equal(ours.length, 1);
|
|
48
|
+
});
|
|
49
|
+
it("uninstall removes only our hooks, leaving others intact", () => {
|
|
50
|
+
installMemoryHooks();
|
|
51
|
+
const res = uninstallMemoryHooks();
|
|
52
|
+
assert.deepEqual(res.removed.sort(), ["SessionEnd", "UserPromptSubmit"]);
|
|
53
|
+
const s = JSON.parse(readFileSync(settingsPath, "utf8"));
|
|
54
|
+
const ups = s.hooks.UserPromptSubmit.flatMap((g) => g.hooks.map((h) => h.command));
|
|
55
|
+
assert.ok(ups.includes("some-other-tool"), "unrelated hook survives uninstall");
|
|
56
|
+
assert.ok(!ups.includes("kit memory hook user-prompt-submit"));
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
//# sourceMappingURL=install.test%202.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.test 2.js","sourceRoot":"","sources":["../../src/memory/install.test 2.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* kit memory — merge another store into this one.
|
|
3
|
+
*
|
|
4
|
+
* Consolidate memory across machines (a server, an old laptop) into one brain.
|
|
5
|
+
* Idempotent: messages dedupe by uuid, sessions/pending/threads by their keys, and
|
|
6
|
+
* a message's tool_uses are copied only when the message itself is newly added, so
|
|
7
|
+
* re-merging the same source adds nothing. `file_index` is NOT merged (it tracks
|
|
8
|
+
* machine-local file paths). Deterministic; no model calls.
|
|
9
|
+
*/
|
|
10
|
+
import { DatabaseSync } from "node:sqlite";
|
|
11
|
+
export interface MergeResult {
|
|
12
|
+
sessions: number;
|
|
13
|
+
messages: number;
|
|
14
|
+
toolUses: number;
|
|
15
|
+
pending: number;
|
|
16
|
+
threads: number;
|
|
17
|
+
}
|
|
18
|
+
export declare function mergeDb(target: DatabaseSync, sourcePath: string): MergeResult;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* kit memory — merge another store into this one.
|
|
3
|
+
*
|
|
4
|
+
* Consolidate memory across machines (a server, an old laptop) into one brain.
|
|
5
|
+
* Idempotent: messages dedupe by uuid, sessions/pending/threads by their keys, and
|
|
6
|
+
* a message's tool_uses are copied only when the message itself is newly added, so
|
|
7
|
+
* re-merging the same source adds nothing. `file_index` is NOT merged (it tracks
|
|
8
|
+
* machine-local file paths). Deterministic; no model calls.
|
|
9
|
+
*/
|
|
10
|
+
import { DatabaseSync } from "node:sqlite";
|
|
11
|
+
import { existsSync } from "node:fs";
|
|
12
|
+
import { insertMessage, insertToolUse, upsertSession } from "./db.js";
|
|
13
|
+
const str = (v) => (typeof v === "string" && v ? v : undefined);
|
|
14
|
+
const num = (v) => (typeof v === "number" ? v : undefined);
|
|
15
|
+
export function mergeDb(target, sourcePath) {
|
|
16
|
+
if (!existsSync(sourcePath))
|
|
17
|
+
throw new Error(`source memory db not found: ${sourcePath}`);
|
|
18
|
+
const src = new DatabaseSync(sourcePath, { readOnly: true });
|
|
19
|
+
const out = { sessions: 0, messages: 0, toolUses: 0, pending: 0, threads: 0 };
|
|
20
|
+
try {
|
|
21
|
+
// Sessions
|
|
22
|
+
for (const s of src.prepare("SELECT * FROM sessions").all()) {
|
|
23
|
+
const sessionId = str(s.session_id);
|
|
24
|
+
if (!sessionId)
|
|
25
|
+
continue;
|
|
26
|
+
upsertSession(target, {
|
|
27
|
+
sessionId,
|
|
28
|
+
harness: str(s.harness) ?? "claude-code",
|
|
29
|
+
project: str(s.project),
|
|
30
|
+
firstMessageAt: str(s.first_message_at),
|
|
31
|
+
lastMessageAt: str(s.last_message_at),
|
|
32
|
+
isAgentSidechain: !!s.is_agent_sidechain,
|
|
33
|
+
});
|
|
34
|
+
out.sessions++;
|
|
35
|
+
}
|
|
36
|
+
// tool_uses grouped by message uuid (copied only for newly-added messages)
|
|
37
|
+
const toolsByUuid = new Map();
|
|
38
|
+
for (const t of src.prepare("SELECT * FROM tool_uses").all()) {
|
|
39
|
+
const uuid = str(t.message_uuid);
|
|
40
|
+
if (!uuid)
|
|
41
|
+
continue;
|
|
42
|
+
(toolsByUuid.get(uuid) ?? toolsByUuid.set(uuid, []).get(uuid)).push(t);
|
|
43
|
+
}
|
|
44
|
+
// Messages (dedupe by uuid) + their tool_uses
|
|
45
|
+
for (const m of src.prepare("SELECT * FROM messages").all()) {
|
|
46
|
+
const uuid = str(m.uuid);
|
|
47
|
+
const sessionId = str(m.session_id);
|
|
48
|
+
const type = str(m.type);
|
|
49
|
+
if (!uuid || !sessionId || !type)
|
|
50
|
+
continue; // need a stable id to dedupe
|
|
51
|
+
const added = insertMessage(target, {
|
|
52
|
+
uuid,
|
|
53
|
+
sessionId,
|
|
54
|
+
parentUuid: str(m.parent_uuid),
|
|
55
|
+
type,
|
|
56
|
+
role: str(m.role),
|
|
57
|
+
content: str(m.content),
|
|
58
|
+
model: str(m.model),
|
|
59
|
+
inputTokens: num(m.input_tokens),
|
|
60
|
+
outputTokens: num(m.output_tokens),
|
|
61
|
+
timestamp: str(m.timestamp),
|
|
62
|
+
cwd: str(m.cwd),
|
|
63
|
+
gitBranch: str(m.git_branch),
|
|
64
|
+
version: str(m.version),
|
|
65
|
+
});
|
|
66
|
+
if (!added)
|
|
67
|
+
continue;
|
|
68
|
+
out.messages++;
|
|
69
|
+
for (const t of toolsByUuid.get(uuid) ?? []) {
|
|
70
|
+
insertToolUse(target, {
|
|
71
|
+
messageUuid: uuid,
|
|
72
|
+
sessionId: str(t.session_id),
|
|
73
|
+
toolName: str(t.tool_name) ?? "unknown",
|
|
74
|
+
toolInput: str(t.tool_input),
|
|
75
|
+
timestamp: str(t.timestamp),
|
|
76
|
+
});
|
|
77
|
+
out.toolUses++;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Pending actions (dedupe by id)
|
|
81
|
+
const insPending = target.prepare(`INSERT OR IGNORE INTO pending_actions
|
|
82
|
+
(id, status, title, detail, scope, kind, verify_cmd, created_at, next_check, snooze_until, closed_at, verify_passes)
|
|
83
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
84
|
+
for (const p of src.prepare("SELECT * FROM pending_actions").all()) {
|
|
85
|
+
if (!str(p.id) || !str(p.title))
|
|
86
|
+
continue;
|
|
87
|
+
const r = insPending.run(p.id, str(p.status) ?? "open", p.title, (str(p.detail) ?? null), (str(p.scope) ?? null), str(p.kind) ?? "manual", (str(p.verify_cmd) ?? null), (str(p.created_at) ?? null), (str(p.next_check) ?? null), (str(p.snooze_until) ?? null), (str(p.closed_at) ?? null), num(p.verify_passes) ?? 0);
|
|
88
|
+
if (Number(r.changes) > 0)
|
|
89
|
+
out.pending++;
|
|
90
|
+
}
|
|
91
|
+
// Saved threads (dedupe by name)
|
|
92
|
+
const insThread = target.prepare(`INSERT OR IGNORE INTO saved_threads (name, session_id, summary, project_path, saved_at)
|
|
93
|
+
VALUES (?, ?, ?, ?, ?)`);
|
|
94
|
+
for (const t of src.prepare("SELECT * FROM saved_threads").all()) {
|
|
95
|
+
const name = str(t.name);
|
|
96
|
+
const sid = str(t.session_id);
|
|
97
|
+
if (!name || !sid)
|
|
98
|
+
continue;
|
|
99
|
+
const r = insThread.run(name, sid, (str(t.summary) ?? null), (str(t.project_path) ?? null), (str(t.saved_at) ?? null));
|
|
100
|
+
if (Number(r.changes) > 0)
|
|
101
|
+
out.threads++;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
src.close();
|
|
106
|
+
}
|
|
107
|
+
return out;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=merge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge.js","sourceRoot":"","sources":["../../src/memory/merge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { DatabaseSync } from "node:sqlite";
|
|
2
|
+
export interface PendingAction {
|
|
3
|
+
id: string;
|
|
4
|
+
status: string;
|
|
5
|
+
title: string;
|
|
6
|
+
detail: string | null;
|
|
7
|
+
scope: string | null;
|
|
8
|
+
kind: string;
|
|
9
|
+
verify_cmd: string | null;
|
|
10
|
+
created_at: string | null;
|
|
11
|
+
next_check: string | null;
|
|
12
|
+
snooze_until: string | null;
|
|
13
|
+
closed_at: string | null;
|
|
14
|
+
verify_passes: number;
|
|
15
|
+
}
|
|
16
|
+
export interface PalAddInput {
|
|
17
|
+
title: string;
|
|
18
|
+
detail?: string;
|
|
19
|
+
scope?: string;
|
|
20
|
+
kind?: "manual" | "auto";
|
|
21
|
+
verifyCmd?: string;
|
|
22
|
+
}
|
|
23
|
+
export declare function palAdd(db: DatabaseSync, input: PalAddInput): string;
|
|
24
|
+
export interface PalListOptions {
|
|
25
|
+
status?: string;
|
|
26
|
+
/** Restrict to this scope plus globally-scoped (NULL) items. Omit = every scope. */
|
|
27
|
+
scope?: string;
|
|
28
|
+
}
|
|
29
|
+
export declare function palList(db: DatabaseSync, opts?: PalListOptions): PendingAction[];
|
|
30
|
+
export declare function palDone(db: DatabaseSync, id: string): boolean;
|
|
31
|
+
export declare function palSnooze(db: DatabaseSync, id: string, days: number): boolean;
|
|
32
|
+
export interface AutoVerifyResult {
|
|
33
|
+
checked: number;
|
|
34
|
+
closed: string[];
|
|
35
|
+
reopened: string[];
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Auto-verify `auto` items. An OPEN item that passes `confirmPasses` consecutive
|
|
39
|
+
* times is closed (a pass increments the streak, a fail resets it). A CLOSED item
|
|
40
|
+
* whose verify now FAILS is reopened (reopen-on-regress). No-info leaves it alone.
|
|
41
|
+
*/
|
|
42
|
+
export declare function palAutoVerify(db: DatabaseSync, confirmPasses?: number): AutoVerifyResult;
|
|
43
|
+
export declare function getLegacyLedgerPath(): string;
|
|
44
|
+
/** Import the old `~/.claude/pal/ledger.jsonl` into pending_actions. Idempotent (by id). */
|
|
45
|
+
export declare function importLegacyLedger(db: DatabaseSync, path?: string): {
|
|
46
|
+
imported: number;
|
|
47
|
+
};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* kit memory — PAL (Pending Action Ledger), folded into the memory store.
|
|
3
|
+
*
|
|
4
|
+
* PAL is the STRUCTURED, actionable layer on top of raw conversation memory:
|
|
5
|
+
* "blocked-on-you" items that survive sessions and auto-close when their verify
|
|
6
|
+
* command starts passing. It lives in the `pending_actions` table of the same
|
|
7
|
+
* SQLite store. Deterministic; the only side effect is running operator-defined
|
|
8
|
+
* verify commands (local shell, with a timeout). Fail-open / no-info aware.
|
|
9
|
+
*/
|
|
10
|
+
import { randomBytes } from "node:crypto";
|
|
11
|
+
import { execSync } from "node:child_process";
|
|
12
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
13
|
+
import { homedir } from "node:os";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
function newId(db) {
|
|
16
|
+
for (let i = 0; i < 100; i++) {
|
|
17
|
+
const id = randomBytes(2).toString("hex"); // 4 hex chars, e.g. "ec95"
|
|
18
|
+
if (!db.prepare("SELECT 1 FROM pending_actions WHERE id = ?").get(id))
|
|
19
|
+
return id;
|
|
20
|
+
}
|
|
21
|
+
throw new Error("could not allocate a unique pending-action id");
|
|
22
|
+
}
|
|
23
|
+
export function palAdd(db, input) {
|
|
24
|
+
const id = newId(db);
|
|
25
|
+
const kind = input.kind ?? (input.verifyCmd ? "auto" : "manual");
|
|
26
|
+
db.prepare(`INSERT INTO pending_actions (id, status, title, detail, scope, kind, verify_cmd)
|
|
27
|
+
VALUES (?, 'open', ?, ?, ?, ?, ?)`).run(id, input.title, input.detail ?? null, input.scope ?? null, kind, input.verifyCmd ?? null);
|
|
28
|
+
return id;
|
|
29
|
+
}
|
|
30
|
+
export function palList(db, opts = {}) {
|
|
31
|
+
const status = opts.status ?? "open";
|
|
32
|
+
if (opts.scope !== undefined) {
|
|
33
|
+
return db
|
|
34
|
+
.prepare("SELECT * FROM pending_actions WHERE status = ? AND (scope = ? OR scope IS NULL) ORDER BY created_at, id")
|
|
35
|
+
.all(status, opts.scope);
|
|
36
|
+
}
|
|
37
|
+
return db
|
|
38
|
+
.prepare("SELECT * FROM pending_actions WHERE status = ? ORDER BY created_at, id")
|
|
39
|
+
.all(status);
|
|
40
|
+
}
|
|
41
|
+
export function palDone(db, id) {
|
|
42
|
+
const res = db
|
|
43
|
+
.prepare("UPDATE pending_actions SET status='closed', closed_at=datetime('now') WHERE id=? AND status!='closed'")
|
|
44
|
+
.run(id);
|
|
45
|
+
return Number(res.changes) > 0;
|
|
46
|
+
}
|
|
47
|
+
export function palSnooze(db, id, days) {
|
|
48
|
+
const d = Math.max(1, Math.floor(days));
|
|
49
|
+
const res = db
|
|
50
|
+
.prepare("UPDATE pending_actions SET status='snoozed', snooze_until=datetime('now', ?) WHERE id=?")
|
|
51
|
+
.run(`+${d} days`, id);
|
|
52
|
+
return Number(res.changes) > 0;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Run a verify command. true = pass (exit 0), false = ran but failed, null = no-info.
|
|
56
|
+
*
|
|
57
|
+
* SECURITY: this runs `cmd` through a shell on purpose — verify commands routinely
|
|
58
|
+
* need pipes / `&&` (e.g. `curl -fsS … | grep 200`). The trust boundary: `verify_cmd`
|
|
59
|
+
* is OPERATOR-AUTHORED and lives only in the PERSONAL store (~/.kit/memory.db); running
|
|
60
|
+
* it is equivalent to the operator running their own command — no untrusted data is
|
|
61
|
+
* interpolated, so this is not a command-injection sink. INVARIANT for Track D (shared
|
|
62
|
+
* memory): shared/synced items must NEVER carry an executable `verify_cmd` that runs
|
|
63
|
+
* unreviewed — only manual items or review-gated verifies cross the sharing boundary.
|
|
64
|
+
*/
|
|
65
|
+
function runVerify(cmd) {
|
|
66
|
+
try {
|
|
67
|
+
execSync(cmd, { stdio: "ignore", timeout: 15_000 });
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
const status = err.status;
|
|
72
|
+
if (typeof status === "number")
|
|
73
|
+
return false; // ran, non-zero exit
|
|
74
|
+
return null; // spawn error / timeout → no-info, leave state unchanged
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Auto-verify `auto` items. An OPEN item that passes `confirmPasses` consecutive
|
|
79
|
+
* times is closed (a pass increments the streak, a fail resets it). A CLOSED item
|
|
80
|
+
* whose verify now FAILS is reopened (reopen-on-regress). No-info leaves it alone.
|
|
81
|
+
*/
|
|
82
|
+
export function palAutoVerify(db, confirmPasses = 2) {
|
|
83
|
+
const out = { checked: 0, closed: [], reopened: [] };
|
|
84
|
+
const rows = db
|
|
85
|
+
.prepare("SELECT * FROM pending_actions WHERE kind='auto' AND verify_cmd IS NOT NULL AND status IN ('open','closed')")
|
|
86
|
+
.all();
|
|
87
|
+
for (const r of rows) {
|
|
88
|
+
const result = runVerify(r.verify_cmd);
|
|
89
|
+
if (result === null)
|
|
90
|
+
continue; // no-info
|
|
91
|
+
out.checked++;
|
|
92
|
+
if (r.status === "open") {
|
|
93
|
+
if (result) {
|
|
94
|
+
const passes = r.verify_passes + 1;
|
|
95
|
+
if (passes >= confirmPasses) {
|
|
96
|
+
db.prepare("UPDATE pending_actions SET status='closed', closed_at=datetime('now'), verify_passes=? WHERE id=?").run(passes, r.id);
|
|
97
|
+
out.closed.push(r.id);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
db.prepare("UPDATE pending_actions SET verify_passes=? WHERE id=?").run(passes, r.id);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else if (r.verify_passes !== 0) {
|
|
104
|
+
db.prepare("UPDATE pending_actions SET verify_passes=0 WHERE id=?").run(r.id);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else if (r.status === "closed" && !result) {
|
|
108
|
+
db.prepare("UPDATE pending_actions SET status='open', verify_passes=0, closed_at=NULL WHERE id=?").run(r.id);
|
|
109
|
+
out.reopened.push(r.id);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return out;
|
|
113
|
+
}
|
|
114
|
+
// ── Migration from the legacy python PAL ledger ───────────────────────────────
|
|
115
|
+
export function getLegacyLedgerPath() {
|
|
116
|
+
return process.env.KIT_PAL_LEDGER ?? join(homedir(), ".claude", "pal", "ledger.jsonl");
|
|
117
|
+
}
|
|
118
|
+
/** Import the old `~/.claude/pal/ledger.jsonl` into pending_actions. Idempotent (by id). */
|
|
119
|
+
export function importLegacyLedger(db, path = getLegacyLedgerPath()) {
|
|
120
|
+
if (!existsSync(path))
|
|
121
|
+
return { imported: 0 };
|
|
122
|
+
let raw;
|
|
123
|
+
try {
|
|
124
|
+
raw = readFileSync(path, "utf8");
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return { imported: 0 };
|
|
128
|
+
}
|
|
129
|
+
const insert = db.prepare(`INSERT OR IGNORE INTO pending_actions
|
|
130
|
+
(id, status, title, detail, scope, kind, verify_cmd, created_at, next_check, verify_passes)
|
|
131
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
132
|
+
let imported = 0;
|
|
133
|
+
for (const line of raw.split("\n")) {
|
|
134
|
+
const t = line.trim();
|
|
135
|
+
if (!t)
|
|
136
|
+
continue;
|
|
137
|
+
let e;
|
|
138
|
+
try {
|
|
139
|
+
e = JSON.parse(t);
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (!e.id || !e.title)
|
|
145
|
+
continue;
|
|
146
|
+
const status = e.status === "done" ? "closed" : (e.status ?? "open");
|
|
147
|
+
const kind = e.verify ? "auto" : "manual";
|
|
148
|
+
const res = insert.run(e.id, status, e.title, e.why ?? null, e.repo ?? null, kind, e.verify ?? null, e.ts ?? null, e.next_check ?? null, e.pass_streak ?? 0);
|
|
149
|
+
if (Number(res.changes) > 0)
|
|
150
|
+
imported++;
|
|
151
|
+
}
|
|
152
|
+
return { imported };
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=pal%202.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pal 2.js","sourceRoot":"","sources":["../../src/memory/pal 2.ts"],"names":[],"mappings":"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"}
|