mirror of
https://github.com/Patiun/com.gregkilmer.www.git
synced 2026-11-07 19:58:24 +00:00
3f646048a2
services/content watches the vault's Site folder, runs every change through fixed rules, keeps the last accepted version of each note with its history, and serves one write API. The HTTP API, the MCP server for agents, and the admin page and editing tools to come all write through it. - SQLite store with history, review queue, redirects, links and full-text search - Rules: invalid, misplaced, duplicate name or slug, text loss, secrets, agent contact details, agent edits, agent publishing, agent batches - Watcher with debounce and a periodic full scan - HTTP API with reader, agent, editor and admin tokens - MCP tools: search, get_note, get_schema, list_held, set_status, add_library_item, update_fields, draft_post - Tests, including taking in all 545 migrated notes with nothing held Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012aSbo2D1qP8cMFQCykf7kx
79 lines
2.1 KiB
TypeScript
79 lines
2.1 KiB
TypeScript
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { dirname, join } from "node:path";
|
|
import { notePath, writeNote } from "@gk/schema";
|
|
import { ContentService } from "../src/service.ts";
|
|
import { Store } from "../src/store.ts";
|
|
import { Vault } from "../src/vault.ts";
|
|
|
|
export interface Rig {
|
|
dir: string;
|
|
site: string;
|
|
store: Store;
|
|
vault: Vault;
|
|
service: ContentService;
|
|
clock: { t: number; advance(minutes: number): void };
|
|
/** Write a note into the vault the way Obsidian would, returning its path. */
|
|
put(data: Record<string, unknown>, body?: string): string;
|
|
putText(path: string, text: string): void;
|
|
done(): void;
|
|
}
|
|
|
|
export function rig(): Rig {
|
|
const dir = mkdtempSync(join(tmpdir(), "gk-content-"));
|
|
const site = join(dir, "Site");
|
|
mkdirSync(site);
|
|
const store = new Store(join(dir, "content.db"));
|
|
const vault = new Vault(site);
|
|
const clock = {
|
|
t: Date.parse("2026-10-11T12:00:00Z"),
|
|
advance(minutes: number) {
|
|
this.t += minutes * 60_000;
|
|
},
|
|
};
|
|
const service = new ContentService({ store, vault, now: () => new Date(clock.t) });
|
|
const putText = (path: string, text: string) => {
|
|
mkdirSync(dirname(join(site, path)), { recursive: true });
|
|
writeFileSync(join(site, path), text);
|
|
};
|
|
return {
|
|
dir,
|
|
site,
|
|
store,
|
|
vault,
|
|
service,
|
|
clock,
|
|
put(data, body = "") {
|
|
const path = notePath(data);
|
|
putText(path, writeNote(data, body));
|
|
return path;
|
|
},
|
|
putText,
|
|
done() {
|
|
store.close();
|
|
rmSync(dir, { recursive: true, force: true });
|
|
},
|
|
};
|
|
}
|
|
|
|
export const book = (title: string, extra: Record<string, unknown> = {}) => ({
|
|
type: "library-item",
|
|
title,
|
|
medium: "book",
|
|
state: "finished",
|
|
publish: true,
|
|
...extra,
|
|
});
|
|
|
|
export const post = (title: string, extra: Record<string, unknown> = {}) => ({
|
|
type: "post",
|
|
title,
|
|
date: "2026-10-01",
|
|
topic: "Making",
|
|
summary: "A summary.",
|
|
publish: true,
|
|
...extra,
|
|
});
|
|
|
|
export const long = (n = 600) => "Paragraph of real writing. ".repeat(Math.ceil(n / 27)).slice(0, n);
|