chapterhouse 0.7.0 → 0.8.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/agents/korg.agent.md +65 -0
- package/dist/api/korg.js +34 -0
- package/dist/api/korg.test.js +42 -0
- package/dist/api/server.js +238 -2
- package/dist/api/server.test.js +199 -0
- package/dist/config.js +28 -0
- package/dist/config.test.js +20 -0
- package/dist/copilot/agents.js +3 -4
- package/dist/copilot/agents.test.js +12 -1
- package/dist/copilot/orchestrator.js +12 -1
- package/dist/copilot/orchestrator.test.js +3 -7
- package/dist/copilot/system-message.js +12 -10
- package/dist/copilot/system-message.test.js +6 -1
- package/dist/copilot/tools.js +193 -375
- package/dist/copilot/tools.memory.test.js +32 -0
- package/dist/copilot/tools.wiki.test.js +80 -59
- package/dist/copilot/turn-event-log-env.test.js +11 -15
- package/dist/daemon.js +19 -0
- package/dist/memory/decisions.js +6 -5
- package/dist/memory/entities.js +20 -9
- package/dist/memory/eot.js +30 -8
- package/dist/memory/eot.test.js +220 -6
- package/dist/memory/hooks.js +151 -0
- package/dist/memory/hooks.test.js +325 -0
- package/dist/memory/hot-tier.js +37 -0
- package/dist/memory/hot-tier.test.js +30 -0
- package/dist/memory/housekeeping-scheduler.js +35 -0
- package/dist/memory/housekeeping-scheduler.test.js +50 -0
- package/dist/memory/inbox.js +10 -0
- package/dist/memory/index.js +3 -1
- package/dist/memory/migration.js +244 -0
- package/dist/memory/migration.test.js +108 -0
- package/dist/memory/reflect.js +273 -0
- package/dist/memory/reflect.test.js +254 -0
- package/dist/paths.js +31 -11
- package/dist/store/db.js +187 -4
- package/dist/store/db.test.js +66 -2
- package/dist/test/helpers/reset-singletons.js +8 -0
- package/dist/test/helpers/reset-singletons.test.js +37 -0
- package/dist/test/setup-env.js +9 -1
- package/dist/wiki/consolidation.js +641 -0
- package/dist/wiki/consolidation.test.js +143 -0
- package/dist/wiki/frontmatter.js +48 -0
- package/dist/wiki/frontmatter.test.js +42 -0
- package/dist/wiki/fs.js +22 -13
- package/dist/wiki/index-manager.js +305 -330
- package/dist/wiki/index-manager.test.js +265 -144
- package/dist/wiki/ingest.js +347 -0
- package/dist/wiki/ingest.test.js +111 -0
- package/dist/wiki/links.js +151 -0
- package/dist/wiki/links.test.js +176 -0
- package/dist/wiki/log-manager.js +8 -5
- package/dist/wiki/log-manager.test.js +4 -0
- package/dist/wiki/migrate-topics.test.js +16 -6
- package/dist/wiki/scheduler.js +118 -0
- package/dist/wiki/scheduler.test.js +64 -0
- package/dist/wiki/timeline.js +51 -0
- package/dist/wiki/timeline.test.js +65 -0
- package/dist/wiki/topic-structure.js +1 -1
- package/package.json +1 -1
- package/skills/pkb-ideas/SKILL.md +78 -0
- package/skills/pkb-ideas/_meta.json +4 -0
- package/skills/pkb-org/SKILL.md +82 -0
- package/skills/pkb-org/_meta.json +4 -0
- package/skills/pkb-people/SKILL.md +74 -0
- package/skills/pkb-people/_meta.json +4 -0
- package/skills/pkb-research/SKILL.md +83 -0
- package/skills/pkb-research/_meta.json +4 -0
- package/skills/pkb-source/SKILL.md +38 -0
- package/skills/pkb-source/_meta.json +4 -0
- package/skills/wiki-conventions/SKILL.md +5 -5
- package/web/dist/assets/{index-DuKYxMIR.css → index-5kz9aRU9.css} +1 -1
- package/web/dist/assets/{index-DytB69KC.js → index-BbX9RKf3.js} +91 -89
- package/web/dist/assets/index-BbX9RKf3.js.map +1 -0
- package/web/dist/index.html +2 -2
- package/dist/wiki/context.js +0 -138
- package/dist/wiki/fix.js +0 -335
- package/dist/wiki/fix.test.js +0 -350
- package/dist/wiki/lint.js +0 -451
- package/dist/wiki/lint.test.js +0 -329
- package/web/dist/assets/index-DytB69KC.js.map +0 -1
package/dist/store/db.test.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import assert from "node:assert/strict";
|
|
2
|
-
import { mkdirSync, rmSync } from "node:fs";
|
|
2
|
+
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import test from "node:test";
|
|
5
5
|
import Database from "better-sqlite3";
|
|
6
|
+
import { resetSingletons } from "../test/helpers/reset-singletons.js";
|
|
6
7
|
const repoRoot = process.cwd();
|
|
7
8
|
const sandboxRoot = join(repoRoot, ".test-work", `store-db-${process.pid}`);
|
|
8
9
|
const chapterhouseHome = join(sandboxRoot, ".chapterhouse");
|
|
@@ -17,11 +18,56 @@ function resetSandbox() {
|
|
|
17
18
|
mkdirSync(chapterhouseHome, { recursive: true });
|
|
18
19
|
}
|
|
19
20
|
test.beforeEach(() => {
|
|
21
|
+
process.env.CHAPTERHOUSE_HOME = sandboxRoot;
|
|
20
22
|
resetSandbox();
|
|
23
|
+
resetSingletons();
|
|
21
24
|
});
|
|
22
25
|
test.after(() => {
|
|
26
|
+
resetSingletons();
|
|
23
27
|
rmSync(sandboxRoot, { recursive: true, force: true });
|
|
24
28
|
});
|
|
29
|
+
test("getDb startup reindex populates wiki_pages when pages exist on disk", async () => {
|
|
30
|
+
mkdirSync(join(chapterhouseHome, "wiki", "pages", "topics", "rust"), { recursive: true });
|
|
31
|
+
writeFileSync(join(chapterhouseHome, "wiki", "pages", "topics", "rust", "index.md"), "---\ntitle: Rust\nsummary: Systems language\nupdated: 2026-05-15\n---\n\n# Rust\n\nFearless concurrency.\n", "utf-8");
|
|
32
|
+
const dbModule = await loadDbModule();
|
|
33
|
+
try {
|
|
34
|
+
const db = dbModule.getDb();
|
|
35
|
+
const count = db.prepare(`SELECT COUNT(*) AS count FROM wiki_pages`).get().count;
|
|
36
|
+
assert.equal(count, 1);
|
|
37
|
+
}
|
|
38
|
+
finally {
|
|
39
|
+
dbModule.closeDb();
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
test("getDb startup reindex is idempotent across repeated startups", async () => {
|
|
43
|
+
mkdirSync(join(chapterhouseHome, "wiki", "pages", "topics", "rust"), { recursive: true });
|
|
44
|
+
writeFileSync(join(chapterhouseHome, "wiki", "pages", "topics", "rust", "index.md"), "---\ntitle: Rust\nsummary: Systems language\nupdated: 2026-05-15\n---\n\n# Rust\n\nFearless concurrency.\n", "utf-8");
|
|
45
|
+
const dbModule = await loadDbModule();
|
|
46
|
+
try {
|
|
47
|
+
dbModule.getDb();
|
|
48
|
+
dbModule.closeDb();
|
|
49
|
+
dbModule.getDb();
|
|
50
|
+
const reopened = new Database(dbPath, { readonly: true });
|
|
51
|
+
const count = reopened.prepare(`SELECT COUNT(*) AS count FROM wiki_pages WHERE path = 'pages/topics/rust/index.md'`).get().count;
|
|
52
|
+
reopened.close();
|
|
53
|
+
assert.equal(count, 1);
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
dbModule.closeDb();
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
test("getDb startup reindex creates the wiki log directory when it is missing", async () => {
|
|
60
|
+
mkdirSync(join(chapterhouseHome, "wiki", "pages", "topics", "rust"), { recursive: true });
|
|
61
|
+
writeFileSync(join(chapterhouseHome, "wiki", "pages", "topics", "rust", "index.md"), "---\ntitle: Rust\nsummary: Systems language\nupdated: 2026-05-15\n---\n\n# Rust\n\nFearless concurrency.\n", "utf-8");
|
|
62
|
+
const dbModule = await loadDbModule();
|
|
63
|
+
try {
|
|
64
|
+
dbModule.getDb();
|
|
65
|
+
assert.equal(existsSync(join(chapterhouseHome, "wiki", "pages", "_meta", "log.md")), true);
|
|
66
|
+
}
|
|
67
|
+
finally {
|
|
68
|
+
dbModule.closeDb();
|
|
69
|
+
}
|
|
70
|
+
});
|
|
25
71
|
test("getDb initializes schema, state helpers, and conversation formatting", async () => {
|
|
26
72
|
const dbModule = await loadDbModule();
|
|
27
73
|
try {
|
|
@@ -58,7 +104,7 @@ test("getDb initializes schema, state helpers, and conversation formatting", asy
|
|
|
58
104
|
dbModule.closeDb();
|
|
59
105
|
}
|
|
60
106
|
});
|
|
61
|
-
test("getDb initializes action-item memory schema and FTS shadow", async () => {
|
|
107
|
+
test("getDb initializes action-item memory schema, reflect patterns schema, and FTS shadow", async () => {
|
|
62
108
|
const dbModule = await loadDbModule();
|
|
63
109
|
try {
|
|
64
110
|
const db = dbModule.getDb();
|
|
@@ -66,6 +112,7 @@ test("getDb initializes action-item memory schema and FTS shadow", async () => {
|
|
|
66
112
|
const tableNames = new Set(tables.map((row) => row.name));
|
|
67
113
|
assert.equal(tableNames.has("mem_action_items"), true, "expected mem_action_items table");
|
|
68
114
|
assert.equal(tableNames.has("mem_action_items_fts"), true, "expected mem_action_items_fts virtual table");
|
|
115
|
+
assert.equal(tableNames.has("mem_patterns"), true, "expected mem_patterns table");
|
|
69
116
|
const columns = db.prepare(`PRAGMA table_info(mem_action_items)`).all();
|
|
70
117
|
const columnNames = new Set(columns.map((column) => column.name));
|
|
71
118
|
for (const name of [
|
|
@@ -89,6 +136,23 @@ test("getDb initializes action-item memory schema and FTS shadow", async () => {
|
|
|
89
136
|
]) {
|
|
90
137
|
assert.equal(columnNames.has(name), true, `expected mem_action_items.${name}`);
|
|
91
138
|
}
|
|
139
|
+
const patternColumns = db.prepare(`PRAGMA table_info(mem_patterns)`).all();
|
|
140
|
+
const patternColumnNames = new Set(patternColumns.map((column) => column.name));
|
|
141
|
+
for (const name of [
|
|
142
|
+
"id",
|
|
143
|
+
"scope_id",
|
|
144
|
+
"title",
|
|
145
|
+
"summary",
|
|
146
|
+
"source_observation_ids",
|
|
147
|
+
"confidence",
|
|
148
|
+
"tier",
|
|
149
|
+
"created_at",
|
|
150
|
+
"last_updated",
|
|
151
|
+
]) {
|
|
152
|
+
assert.equal(patternColumnNames.has(name), true, `expected mem_patterns.${name}`);
|
|
153
|
+
}
|
|
154
|
+
const patternIndexes = db.prepare(`PRAGMA index_list(mem_patterns)`).all();
|
|
155
|
+
assert.equal(patternIndexes.some((index) => index.name === "mem_patterns_scope_tier_idx"), true, "expected mem_patterns scope/tier index");
|
|
92
156
|
const scope = db.prepare(`SELECT id FROM mem_scopes WHERE slug = 'chapterhouse'`).get();
|
|
93
157
|
const inserted = db.prepare(`
|
|
94
158
|
INSERT INTO mem_action_items (scope_id, title, detail, source)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { resetPathsForTests } from "../../paths.js";
|
|
2
|
+
import { resetDbForTests } from "../../store/db.js";
|
|
3
|
+
export function resetSingletons() {
|
|
4
|
+
resetDbForTests();
|
|
5
|
+
resetPathsForTests();
|
|
6
|
+
}
|
|
7
|
+
export const resetModuleCache = resetSingletons;
|
|
8
|
+
//# sourceMappingURL=reset-singletons.js.map
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { existsSync, mkdirSync, rmSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import test from "node:test";
|
|
5
|
+
const repoRoot = process.cwd();
|
|
6
|
+
const sandboxRoot = join(repoRoot, ".test-work", `reset-singletons-${process.pid}`);
|
|
7
|
+
function sandboxPath(name) {
|
|
8
|
+
return join(sandboxRoot, name);
|
|
9
|
+
}
|
|
10
|
+
test.before(() => {
|
|
11
|
+
mkdirSync(sandboxRoot, { recursive: true });
|
|
12
|
+
});
|
|
13
|
+
test.after(() => {
|
|
14
|
+
rmSync(sandboxRoot, { recursive: true, force: true });
|
|
15
|
+
});
|
|
16
|
+
test("resetSingletons refreshes cached db and path singletons after CHAPTERHOUSE_HOME changes", async () => {
|
|
17
|
+
const helper = await import("./reset-singletons.js");
|
|
18
|
+
const paths = await import("../../paths.js");
|
|
19
|
+
const dbModule = await import("../../store/db.js");
|
|
20
|
+
const firstHome = sandboxPath("first-home");
|
|
21
|
+
const secondHome = sandboxPath("second-home");
|
|
22
|
+
mkdirSync(firstHome, { recursive: true });
|
|
23
|
+
process.env.CHAPTERHOUSE_HOME = firstHome;
|
|
24
|
+
await helper.resetSingletons();
|
|
25
|
+
dbModule.getDb().prepare("SELECT 1").get();
|
|
26
|
+
assert.equal(paths.CHAPTERHOUSE_HOME, join(firstHome, ".chapterhouse"));
|
|
27
|
+
assert.equal(paths.DB_PATH, join(firstHome, ".chapterhouse", "chapterhouse.db"));
|
|
28
|
+
assert.equal(existsSync(join(firstHome, ".chapterhouse", "chapterhouse.db")), true);
|
|
29
|
+
mkdirSync(secondHome, { recursive: true });
|
|
30
|
+
process.env.CHAPTERHOUSE_HOME = secondHome;
|
|
31
|
+
await helper.resetSingletons();
|
|
32
|
+
dbModule.getDb().prepare("SELECT 1").get();
|
|
33
|
+
assert.equal(paths.CHAPTERHOUSE_HOME, join(secondHome, ".chapterhouse"));
|
|
34
|
+
assert.equal(paths.DB_PATH, join(secondHome, ".chapterhouse", "chapterhouse.db"));
|
|
35
|
+
assert.equal(existsSync(join(secondHome, ".chapterhouse", "chapterhouse.db")), true);
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=reset-singletons.test.js.map
|
package/dist/test/setup-env.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import { resetSingletons } from "./helpers/reset-singletons.js";
|
|
1
3
|
const RUNTIME_OVERRIDE_ENV_VARS = [
|
|
2
4
|
"CHAPTERHOUSE_MODE",
|
|
3
5
|
"CHAPTERHOUSE_SELF_EDIT",
|
|
@@ -12,6 +14,7 @@ const RUNTIME_OVERRIDE_ENV_VARS = [
|
|
|
12
14
|
"CHAPTERHOUSE_MEMORY_INJECT",
|
|
13
15
|
"CHAPTERHOUSE_MEMORY_AUTO_ACCEPT",
|
|
14
16
|
"CHAPTERHOUSE_MEMORY_EOT_HOOK_ENABLED",
|
|
17
|
+
"CHAPTERHOUSE_MEMORY_HOOKS_ENABLED",
|
|
15
18
|
"CHAPTERHOUSE_MEMORY_HOUSEKEEPING_ENABLED",
|
|
16
19
|
"CHAPTERHOUSE_MEMORY_HOUSEKEEPING_TURNS",
|
|
17
20
|
"CHAPTERHOUSE_MEMORY_DECAY_DAYS",
|
|
@@ -25,5 +28,10 @@ for (const name of [...RUNTIME_OVERRIDE_ENV_VARS, ...AUTH_ENV_VARS]) {
|
|
|
25
28
|
delete process.env[name];
|
|
26
29
|
}
|
|
27
30
|
process.env.CHAPTERHOUSE_DISABLE_DOTENV = "1";
|
|
28
|
-
|
|
31
|
+
test.beforeEach(() => {
|
|
32
|
+
resetSingletons();
|
|
33
|
+
});
|
|
34
|
+
test.afterEach(() => {
|
|
35
|
+
resetSingletons();
|
|
36
|
+
});
|
|
29
37
|
//# sourceMappingURL=setup-env.js.map
|