chapterhouse 0.8.2 → 0.9.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/dist/api/korg.js +2 -19
- package/dist/api/route-coverage.test.js +224 -0
- package/dist/api/server.js +238 -14
- package/dist/api/server.test.js +88 -2
- package/dist/shared/api-schemas.js +615 -0
- package/dist/store/db.js +1 -0
- package/dist/wiki/index-manager.js +1 -1
- package/package.json +1 -1
- package/web/dist/assets/{index-BbX9RKf3.js → index-iQrv3lQN.js} +155 -94
- package/web/dist/assets/index-iQrv3lQN.js.map +1 -0
- package/web/dist/index.html +1 -1
- package/dist/api/korg.test.js +0 -42
- package/web/dist/assets/index-BbX9RKf3.js.map +0 -1
package/dist/api/server.test.js
CHANGED
|
@@ -756,6 +756,24 @@ tags: [ops]
|
|
|
756
756
|
assert.deepEqual(await missingResponse.json(), { error: "Page not found" });
|
|
757
757
|
});
|
|
758
758
|
});
|
|
759
|
+
test("POST /api/wiki/page/pin rejects path traversal slugs", async () => {
|
|
760
|
+
await withStartedServer(async ({ baseUrl, authHeader }) => {
|
|
761
|
+
const response = await fetch(`${baseUrl}/api/wiki/page/pin`, {
|
|
762
|
+
method: "POST",
|
|
763
|
+
headers: {
|
|
764
|
+
authorization: authHeader,
|
|
765
|
+
"content-type": "application/json",
|
|
766
|
+
},
|
|
767
|
+
body: JSON.stringify({
|
|
768
|
+
slug: "../../etc/passwd",
|
|
769
|
+
pinned: true,
|
|
770
|
+
}),
|
|
771
|
+
});
|
|
772
|
+
assert.equal(response.status, 400);
|
|
773
|
+
const body = await response.json();
|
|
774
|
+
assert.match(body.error ?? "", /unsafe wiki path/i);
|
|
775
|
+
});
|
|
776
|
+
});
|
|
759
777
|
test("server worker detail returns the stored dispatched prompt", async () => {
|
|
760
778
|
await withStartedServer(async ({ baseUrl, authHeader, testRoot }) => {
|
|
761
779
|
const db = new Database(join(testRoot, ".chapterhouse", "chapterhouse.db"));
|
|
@@ -891,6 +909,74 @@ test("server wiki route still returns 404 for other missing wiki pages", async (
|
|
|
891
909
|
assert.deepEqual(await response.json(), { error: "Page not found" });
|
|
892
910
|
});
|
|
893
911
|
});
|
|
912
|
+
test("GET /api/wiki/browser-pages maps wiki_pages rows to the browser contract and filters them", async () => {
|
|
913
|
+
await withStartedServer(async ({ baseUrl, authHeader, testRoot }) => {
|
|
914
|
+
const db = new Database(getProjectDbPath(testRoot));
|
|
915
|
+
try {
|
|
916
|
+
db.prepare(`
|
|
917
|
+
INSERT INTO wiki_pages (path, title, entity_type, tags, summary, last_updated, pinned)
|
|
918
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
919
|
+
`).run("pages/topics/rust/index.md", "Rust", "topics", "[]", "Systems programming language", "2026-05-15T12:00:00.000Z", 1);
|
|
920
|
+
db.prepare(`
|
|
921
|
+
INSERT INTO wiki_pages (path, title, entity_type, tags, summary, last_updated, pinned)
|
|
922
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
923
|
+
`).run("pages/projects/chapterhouse/index.md", "Chapterhouse", "projects", "[]", "Team AI assistant", "2026-05-14T12:00:00.000Z", 0);
|
|
924
|
+
}
|
|
925
|
+
finally {
|
|
926
|
+
db.close();
|
|
927
|
+
}
|
|
928
|
+
const response = await fetch(`${baseUrl}/api/wiki/browser-pages?type=topics&q=systems`, {
|
|
929
|
+
headers: { authorization: authHeader },
|
|
930
|
+
});
|
|
931
|
+
assert.equal(response.status, 200);
|
|
932
|
+
assert.deepEqual(await response.json(), {
|
|
933
|
+
pages: [
|
|
934
|
+
{
|
|
935
|
+
slug: "topics/rust/index",
|
|
936
|
+
title: "Rust",
|
|
937
|
+
summary: "Systems programming language",
|
|
938
|
+
type: "topics",
|
|
939
|
+
last_updated: "2026-05-15T12:00:00.000Z",
|
|
940
|
+
pinned: true,
|
|
941
|
+
},
|
|
942
|
+
],
|
|
943
|
+
});
|
|
944
|
+
});
|
|
945
|
+
});
|
|
946
|
+
test("GET /api/wiki/browser-pages falls back to indexed and orphan wiki pages when wiki_pages is empty", async () => {
|
|
947
|
+
await withStartedServer(async ({ baseUrl, authHeader, testRoot }) => {
|
|
948
|
+
const indexedDir = join(testRoot, ".chapterhouse", "wiki", "pages", "topics", "fallback");
|
|
949
|
+
mkdirSync(indexedDir, { recursive: true });
|
|
950
|
+
writeFileSync(join(indexedDir, "index.md"), "# Fallback\n", "utf-8");
|
|
951
|
+
const orphanDir = join(testRoot, ".chapterhouse", "wiki", "pages", "projects", "orphan-browser");
|
|
952
|
+
mkdirSync(orphanDir, { recursive: true });
|
|
953
|
+
writeFileSync(join(orphanDir, "index.md"), "# Orphan Browser\n", "utf-8");
|
|
954
|
+
const db = new Database(getProjectDbPath(testRoot));
|
|
955
|
+
try {
|
|
956
|
+
db.prepare("DELETE FROM wiki_pages").run();
|
|
957
|
+
}
|
|
958
|
+
finally {
|
|
959
|
+
db.close();
|
|
960
|
+
}
|
|
961
|
+
const response = await fetch(`${baseUrl}/api/wiki/browser-pages?type=Unindexed&q=orphan`, {
|
|
962
|
+
headers: { authorization: authHeader },
|
|
963
|
+
});
|
|
964
|
+
assert.equal(response.status, 200);
|
|
965
|
+
const body = await response.json();
|
|
966
|
+
assert.deepEqual(body.pages.map((page) => ({
|
|
967
|
+
slug: page.slug,
|
|
968
|
+
title: page.title,
|
|
969
|
+
type: page.type,
|
|
970
|
+
})), [
|
|
971
|
+
{
|
|
972
|
+
slug: "projects/orphan-browser/index",
|
|
973
|
+
title: "pages/projects/orphan-browser/index.md",
|
|
974
|
+
type: "Unindexed",
|
|
975
|
+
},
|
|
976
|
+
]);
|
|
977
|
+
assert.notEqual(body.pages[0]?.last_updated, "");
|
|
978
|
+
});
|
|
979
|
+
});
|
|
894
980
|
test("GET /api/wiki/pages coerces empty updated fields to page mtimes", async () => {
|
|
895
981
|
await withStartedServer(async ({ baseUrl, authHeader, testRoot }) => {
|
|
896
982
|
const indexedPath = join(testRoot, ".chapterhouse", "wiki", "pages", "topics", "coerced-updated", "index.md");
|
|
@@ -1541,8 +1627,8 @@ test("GET /api/wiki/korg/sessions returns grouped active research sessions", asy
|
|
|
1541
1627
|
id: "compiler-research",
|
|
1542
1628
|
name: "Compiler research",
|
|
1543
1629
|
source_count: 2,
|
|
1544
|
-
|
|
1545
|
-
|
|
1630
|
+
open_questions_count: 0,
|
|
1631
|
+
last_activity_at: "2026-05-14T22:00:00.000Z",
|
|
1546
1632
|
},
|
|
1547
1633
|
],
|
|
1548
1634
|
});
|