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.
Files changed (81) hide show
  1. package/agents/korg.agent.md +65 -0
  2. package/dist/api/korg.js +34 -0
  3. package/dist/api/korg.test.js +42 -0
  4. package/dist/api/server.js +238 -2
  5. package/dist/api/server.test.js +199 -0
  6. package/dist/config.js +28 -0
  7. package/dist/config.test.js +20 -0
  8. package/dist/copilot/agents.js +3 -4
  9. package/dist/copilot/agents.test.js +12 -1
  10. package/dist/copilot/orchestrator.js +12 -1
  11. package/dist/copilot/orchestrator.test.js +3 -7
  12. package/dist/copilot/system-message.js +12 -10
  13. package/dist/copilot/system-message.test.js +6 -1
  14. package/dist/copilot/tools.js +193 -375
  15. package/dist/copilot/tools.memory.test.js +32 -0
  16. package/dist/copilot/tools.wiki.test.js +80 -59
  17. package/dist/copilot/turn-event-log-env.test.js +11 -15
  18. package/dist/daemon.js +19 -0
  19. package/dist/memory/decisions.js +6 -5
  20. package/dist/memory/entities.js +20 -9
  21. package/dist/memory/eot.js +30 -8
  22. package/dist/memory/eot.test.js +220 -6
  23. package/dist/memory/hooks.js +151 -0
  24. package/dist/memory/hooks.test.js +325 -0
  25. package/dist/memory/hot-tier.js +37 -0
  26. package/dist/memory/hot-tier.test.js +30 -0
  27. package/dist/memory/housekeeping-scheduler.js +35 -0
  28. package/dist/memory/housekeeping-scheduler.test.js +50 -0
  29. package/dist/memory/inbox.js +10 -0
  30. package/dist/memory/index.js +3 -1
  31. package/dist/memory/migration.js +244 -0
  32. package/dist/memory/migration.test.js +108 -0
  33. package/dist/memory/reflect.js +273 -0
  34. package/dist/memory/reflect.test.js +254 -0
  35. package/dist/paths.js +31 -11
  36. package/dist/store/db.js +187 -4
  37. package/dist/store/db.test.js +66 -2
  38. package/dist/test/helpers/reset-singletons.js +8 -0
  39. package/dist/test/helpers/reset-singletons.test.js +37 -0
  40. package/dist/test/setup-env.js +9 -1
  41. package/dist/wiki/consolidation.js +641 -0
  42. package/dist/wiki/consolidation.test.js +143 -0
  43. package/dist/wiki/frontmatter.js +48 -0
  44. package/dist/wiki/frontmatter.test.js +42 -0
  45. package/dist/wiki/fs.js +22 -13
  46. package/dist/wiki/index-manager.js +305 -330
  47. package/dist/wiki/index-manager.test.js +265 -144
  48. package/dist/wiki/ingest.js +347 -0
  49. package/dist/wiki/ingest.test.js +111 -0
  50. package/dist/wiki/links.js +151 -0
  51. package/dist/wiki/links.test.js +176 -0
  52. package/dist/wiki/log-manager.js +8 -5
  53. package/dist/wiki/log-manager.test.js +4 -0
  54. package/dist/wiki/migrate-topics.test.js +16 -6
  55. package/dist/wiki/scheduler.js +118 -0
  56. package/dist/wiki/scheduler.test.js +64 -0
  57. package/dist/wiki/timeline.js +51 -0
  58. package/dist/wiki/timeline.test.js +65 -0
  59. package/dist/wiki/topic-structure.js +1 -1
  60. package/package.json +1 -1
  61. package/skills/pkb-ideas/SKILL.md +78 -0
  62. package/skills/pkb-ideas/_meta.json +4 -0
  63. package/skills/pkb-org/SKILL.md +82 -0
  64. package/skills/pkb-org/_meta.json +4 -0
  65. package/skills/pkb-people/SKILL.md +74 -0
  66. package/skills/pkb-people/_meta.json +4 -0
  67. package/skills/pkb-research/SKILL.md +83 -0
  68. package/skills/pkb-research/_meta.json +4 -0
  69. package/skills/pkb-source/SKILL.md +38 -0
  70. package/skills/pkb-source/_meta.json +4 -0
  71. package/skills/wiki-conventions/SKILL.md +5 -5
  72. package/web/dist/assets/{index-DuKYxMIR.css → index-5kz9aRU9.css} +1 -1
  73. package/web/dist/assets/{index-DytB69KC.js → index-BbX9RKf3.js} +91 -89
  74. package/web/dist/assets/index-BbX9RKf3.js.map +1 -0
  75. package/web/dist/index.html +2 -2
  76. package/dist/wiki/context.js +0 -138
  77. package/dist/wiki/fix.js +0 -335
  78. package/dist/wiki/fix.test.js +0 -350
  79. package/dist/wiki/lint.js +0 -451
  80. package/dist/wiki/lint.test.js +0 -329
  81. package/web/dist/assets/index-DytB69KC.js.map +0 -1
@@ -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
@@ -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
- export {};
31
+ test.beforeEach(() => {
32
+ resetSingletons();
33
+ });
34
+ test.afterEach(() => {
35
+ resetSingletons();
36
+ });
29
37
  //# sourceMappingURL=setup-env.js.map