Vendor OpenClaw source as Adolf fork baseline
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled
Some checks failed
ClawSweeper Dispatch / dispatch (push) Has been cancelled
CodeQL / Security High (actions) (push) Has been cancelled
CodeQL / Security High (channel-runtime-boundary) (push) Has been cancelled
CodeQL / Security High (core-auth-secrets) (push) Has been cancelled
CodeQL / Security High (mcp-process-tool-boundary) (push) Has been cancelled
CodeQL / Security High (network-ssrf-boundary) (push) Has been cancelled
CodeQL / Security High (plugin-trust-boundary) (push) Has been cancelled
CodeQL / Security High (process-exec-boundary) (push) Has been cancelled
Docs Sync Publish Repo / sync-publish-repo (push) Has been cancelled
Docs / docs (push) Has been cancelled
OpenClaw Stable Main Closeout / Resolve stable release closeout inputs (push) Has been cancelled
OpenClaw Stable Main Closeout / Verify stable main closeout (push) Has been cancelled
Workflow Sanity / no-tabs (push) Has been cancelled
Workflow Sanity / actionlint (push) Has been cancelled
Workflow Sanity / generated-doc-baselines (push) Has been cancelled
CI / runner-admission (push) Has been cancelled
CI / preflight (push) Has been cancelled
CI / security-fast (push) Has been cancelled
CI / pnpm-store-warmup (push) Has been cancelled
CI / build-artifacts (push) Has been cancelled
CI / native-i18n (push) Has been cancelled
CI / ${{ matrix.check_name }} (push) Has been cancelled
CI / ${{ matrix.checkName }} (push) Has been cancelled
CI / checks-node-compat-node22 (push) Has been cancelled
CI / check-bundled-channel-config-metadata (push) Has been cancelled
CI / check-dependencies (push) Has been cancelled
CI / check-guards (push) Has been cancelled
CI / check-lint (push) Has been cancelled
CI / check-prod-types (push) Has been cancelled
CI / check-shrinkwrap (push) Has been cancelled
CI / check-test-types (push) Has been cancelled
CI / check-additional-boundaries-a (push) Has been cancelled
CI / check-additional-boundaries-bcd (push) Has been cancelled
CI / check-additional-extension-bundled (push) Has been cancelled
CI / check-additional-extension-channels (push) Has been cancelled
CI / check-additional-extension-package-boundary (push) Has been cancelled
CI / check-additional-runtime-topology-architecture (push) Has been cancelled
CI / check-session-accessor-boundary (push) Has been cancelled
CI / check-session-transcript-reader-boundary (push) Has been cancelled
CI / check-docs (push) Has been cancelled
CI / skills-python (push) Has been cancelled
CI / macos-swift (push) Has been cancelled
CI / ios-build (push) Has been cancelled
CI / ci-timings-summary (push) Has been cancelled
Native App Locale Refresh / Refresh native fa (push) Has been cancelled
Native App Locale Refresh / Refresh native fr (push) Has been cancelled
Native App Locale Refresh / Refresh native hi (push) Has been cancelled
Native App Locale Refresh / Refresh native id (push) Has been cancelled
Native App Locale Refresh / Refresh native it (push) Has been cancelled
Native App Locale Refresh / Refresh native ja-JP (push) Has been cancelled
Control UI Locale Refresh / plan (push) Has been cancelled
Control UI Locale Refresh / Refresh ${{ matrix.locale }} (push) Has been cancelled
Control UI Locale Refresh / Commit control UI locale refresh (push) Has been cancelled
Live Media Runner Image / Build live media runner image (push) Has been cancelled
Native App Locale Refresh / Refresh native ar (push) Has been cancelled
Native App Locale Refresh / Refresh native de (push) Has been cancelled
Native App Locale Refresh / Refresh native es (push) Has been cancelled
Native App Locale Refresh / Refresh native ko (push) Has been cancelled
Native App Locale Refresh / Refresh native nl (push) Has been cancelled
Native App Locale Refresh / Refresh native pl (push) Has been cancelled
Native App Locale Refresh / Refresh native pt-BR (push) Has been cancelled
Native App Locale Refresh / Refresh native ru (push) Has been cancelled
Native App Locale Refresh / Refresh native sv (push) Has been cancelled
Native App Locale Refresh / Refresh native th (push) Has been cancelled
Native App Locale Refresh / Refresh native tr (push) Has been cancelled
Native App Locale Refresh / Refresh native uk (push) Has been cancelled
Native App Locale Refresh / Refresh native vi (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-CN (push) Has been cancelled
Native App Locale Refresh / Refresh native zh-TW (push) Has been cancelled
Native App Locale Refresh / Commit native locale refresh (push) Has been cancelled
Plugin Init Scaffold Validation / Validate provider scaffold (push) Has been cancelled
Plugin NPM Release / preview_plugins_npm (push) Has been cancelled
Plugin NPM Release / Validate release publish approval (push) Has been cancelled
Plugin NPM Release / preview_plugin_pack (push) Has been cancelled
Plugin NPM Release / publish_plugins_npm (push) Has been cancelled
Sandbox Common Smoke / sandbox-common-smoke (push) Has been cancelled
Website Installer Sync / static (push) Has been cancelled
Website Installer Sync / linux-docker (push) Has been cancelled
Website Installer Sync / macos-installer (push) Has been cancelled
Website Installer Sync / windows-installer (push) Has been cancelled
Website Installer Sync / sync-website (push) Has been cancelled
Adolf is a fork/vendored clone of github.com/openclaw/openclaw (v2026.6.11), free to diverge. Tree copied sans upstream .git; upstream remote added for future syncs. Node pinned to 24 (.nvmrc); engines already require >=22.19. Preserves docs/ARCHITECTURE.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LeqyaxJF2nbRXJtae2kNB2
This commit is contained in:
385
extensions/memory-wiki/src/apply.ts
Normal file
385
extensions/memory-wiki/src/apply.ts
Normal file
@@ -0,0 +1,385 @@
|
||||
// Memory Wiki plugin module implements apply behavior.
|
||||
import path from "node:path";
|
||||
import {
|
||||
replaceManagedMarkdownBlock,
|
||||
withTrailingNewline,
|
||||
} from "openclaw/plugin-sdk/memory-host-markdown";
|
||||
import { readFiniteNumberParam } from "openclaw/plugin-sdk/param-readers";
|
||||
import { FsSafeError, root as fsRoot } from "openclaw/plugin-sdk/security-runtime";
|
||||
import { normalizeStringEntries, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
|
||||
import { compileMemoryWikiVault, type CompileMemoryWikiResult } from "./compile.js";
|
||||
import type { ResolvedMemoryWikiConfig } from "./config.js";
|
||||
import {
|
||||
parseWikiMarkdown,
|
||||
renderWikiMarkdown,
|
||||
slugifyWikiPageStem,
|
||||
slugifyWikiSegment,
|
||||
normalizeSourceIds,
|
||||
normalizeWikiClaims,
|
||||
type WikiClaim,
|
||||
} from "./markdown.js";
|
||||
import {
|
||||
readQueryableWikiPages,
|
||||
resolveQueryableWikiPageByLookup,
|
||||
type QueryableWikiPage,
|
||||
} from "./query.js";
|
||||
import { initializeMemoryWikiVault } from "./vault.js";
|
||||
|
||||
const GENERATED_START = "<!-- openclaw:wiki:generated:start -->";
|
||||
const GENERATED_END = "<!-- openclaw:wiki:generated:end -->";
|
||||
const HUMAN_START = "<!-- openclaw:human:start -->";
|
||||
const HUMAN_END = "<!-- openclaw:human:end -->";
|
||||
|
||||
type CreateSynthesisMemoryWikiMutation = {
|
||||
op: "create_synthesis";
|
||||
title: string;
|
||||
body: string;
|
||||
sourceIds: string[];
|
||||
claims?: WikiClaim[];
|
||||
contradictions?: string[];
|
||||
questions?: string[];
|
||||
confidence?: number;
|
||||
status?: string;
|
||||
};
|
||||
|
||||
type UpdateMetadataMemoryWikiMutation = {
|
||||
op: "update_metadata";
|
||||
lookup: string;
|
||||
sourceIds?: string[];
|
||||
claims?: WikiClaim[];
|
||||
contradictions?: string[];
|
||||
questions?: string[];
|
||||
confidence?: number | null;
|
||||
status?: string;
|
||||
};
|
||||
|
||||
export type ApplyMemoryWikiMutation =
|
||||
| CreateSynthesisMemoryWikiMutation
|
||||
| UpdateMetadataMemoryWikiMutation;
|
||||
|
||||
type MemoryWikiMutationInputOp = ApplyMemoryWikiMutation["op"] | "synthesis" | "metadata";
|
||||
|
||||
type ApplyMemoryWikiMutationResult = {
|
||||
changed: boolean;
|
||||
operation: ApplyMemoryWikiMutation["op"];
|
||||
pagePath: string;
|
||||
pageId?: string;
|
||||
compile: CompileMemoryWikiResult;
|
||||
};
|
||||
|
||||
function normalizeMutationConfidence(
|
||||
params: Record<string, unknown>,
|
||||
options: { allowNull: false },
|
||||
): number | undefined;
|
||||
function normalizeMutationConfidence(
|
||||
params: Record<string, unknown>,
|
||||
options: { allowNull: true },
|
||||
): number | null | undefined;
|
||||
function normalizeMutationConfidence(
|
||||
params: Record<string, unknown>,
|
||||
options: { allowNull: boolean },
|
||||
): number | null | undefined {
|
||||
if (options.allowNull && params.confidence === null) {
|
||||
return null;
|
||||
}
|
||||
return readFiniteNumberParam(params, "confidence", {
|
||||
min: 0,
|
||||
max: 1,
|
||||
});
|
||||
}
|
||||
|
||||
function normalizeMemoryWikiMutationOp(
|
||||
op: MemoryWikiMutationInputOp,
|
||||
): ApplyMemoryWikiMutation["op"] {
|
||||
if (op === "synthesis") {
|
||||
return "create_synthesis";
|
||||
}
|
||||
if (op === "metadata") {
|
||||
return "update_metadata";
|
||||
}
|
||||
return op;
|
||||
}
|
||||
|
||||
export function normalizeMemoryWikiMutationInput(rawParams: unknown): ApplyMemoryWikiMutation {
|
||||
const params = rawParams as {
|
||||
op: MemoryWikiMutationInputOp;
|
||||
title?: string;
|
||||
body?: string;
|
||||
lookup?: string;
|
||||
sourceIds?: string[];
|
||||
claims?: WikiClaim[];
|
||||
contradictions?: string[];
|
||||
questions?: string[];
|
||||
confidence?: number | null;
|
||||
status?: string;
|
||||
};
|
||||
const op = normalizeMemoryWikiMutationOp(params.op);
|
||||
if (op === "create_synthesis") {
|
||||
if (!params.title?.trim()) {
|
||||
throw new Error("wiki mutation requires title for create_synthesis.");
|
||||
}
|
||||
if (!params.body?.trim()) {
|
||||
throw new Error("wiki mutation requires body for create_synthesis.");
|
||||
}
|
||||
if (!params.sourceIds || params.sourceIds.length === 0) {
|
||||
throw new Error("wiki mutation requires at least one sourceId for create_synthesis.");
|
||||
}
|
||||
const confidence = normalizeMutationConfidence(params as Record<string, unknown>, {
|
||||
allowNull: false,
|
||||
});
|
||||
return {
|
||||
op: "create_synthesis",
|
||||
title: params.title,
|
||||
body: params.body,
|
||||
sourceIds: params.sourceIds,
|
||||
...(Array.isArray(params.claims) ? { claims: normalizeWikiClaims(params.claims) } : {}),
|
||||
...(params.contradictions ? { contradictions: params.contradictions } : {}),
|
||||
...(params.questions ? { questions: params.questions } : {}),
|
||||
...(typeof confidence === "number" ? { confidence } : {}),
|
||||
...(params.status ? { status: params.status } : {}),
|
||||
};
|
||||
}
|
||||
if (!params.lookup?.trim()) {
|
||||
throw new Error("wiki mutation requires lookup for update_metadata.");
|
||||
}
|
||||
const confidence = normalizeMutationConfidence(params as Record<string, unknown>, {
|
||||
allowNull: true,
|
||||
});
|
||||
return {
|
||||
op: "update_metadata",
|
||||
lookup: params.lookup,
|
||||
...(params.sourceIds ? { sourceIds: params.sourceIds } : {}),
|
||||
...(Array.isArray(params.claims) ? { claims: normalizeWikiClaims(params.claims) } : {}),
|
||||
...(params.contradictions ? { contradictions: params.contradictions } : {}),
|
||||
...(params.questions ? { questions: params.questions } : {}),
|
||||
...(confidence !== undefined ? { confidence } : {}),
|
||||
...(params.status ? { status: params.status } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeUniqueStrings(values: string[] | undefined): string[] | undefined {
|
||||
if (!values) {
|
||||
return undefined;
|
||||
}
|
||||
return uniqueStrings(normalizeStringEntries(values));
|
||||
}
|
||||
|
||||
function ensureHumanNotesBlock(body: string): string {
|
||||
if (body.includes(HUMAN_START) && body.includes(HUMAN_END)) {
|
||||
return body;
|
||||
}
|
||||
const trimmed = body.trimEnd();
|
||||
const prefix = trimmed.length > 0 ? `${trimmed}\n\n` : "";
|
||||
return `${prefix}## Notes\n${HUMAN_START}\n${HUMAN_END}\n`;
|
||||
}
|
||||
|
||||
function buildSynthesisBody(params: {
|
||||
title: string;
|
||||
originalBody?: string;
|
||||
generatedBody: string;
|
||||
}): string {
|
||||
const base = params.originalBody?.trim().length
|
||||
? params.originalBody
|
||||
: `# ${params.title}\n\n## Notes\n${HUMAN_START}\n${HUMAN_END}\n`;
|
||||
const withGenerated = replaceManagedMarkdownBlock({
|
||||
original: base,
|
||||
heading: "## Summary",
|
||||
startMarker: GENERATED_START,
|
||||
endMarker: GENERATED_END,
|
||||
body: params.generatedBody,
|
||||
});
|
||||
return ensureHumanNotesBlock(withGenerated);
|
||||
}
|
||||
|
||||
type VaultRoot = Awaited<ReturnType<typeof fsRoot>>;
|
||||
|
||||
function isMissingWikiPageError(error: unknown): boolean {
|
||||
return error instanceof FsSafeError && error.code === "not-found";
|
||||
}
|
||||
|
||||
async function readExistingWikiPage(root: VaultRoot, pagePath: string): Promise<string> {
|
||||
try {
|
||||
return await root.readText(pagePath);
|
||||
} catch {
|
||||
try {
|
||||
return await root.readText(pagePath);
|
||||
} catch (retryError) {
|
||||
if (isMissingWikiPageError(retryError)) {
|
||||
return "";
|
||||
}
|
||||
throw retryError;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function writeWikiPage(params: {
|
||||
rootDir: string;
|
||||
relativePath: string;
|
||||
frontmatter: Record<string, unknown>;
|
||||
body: string;
|
||||
}): Promise<boolean> {
|
||||
const root = await fsRoot(params.rootDir);
|
||||
const rendered = withTrailingNewline(
|
||||
renderWikiMarkdown({
|
||||
frontmatter: params.frontmatter,
|
||||
body: params.body,
|
||||
}),
|
||||
);
|
||||
const existing = await readExistingWikiPage(root, params.relativePath);
|
||||
if (existing === rendered) {
|
||||
return false;
|
||||
}
|
||||
await root.write(params.relativePath, rendered);
|
||||
return true;
|
||||
}
|
||||
|
||||
async function resolveWritablePage(params: {
|
||||
config: ResolvedMemoryWikiConfig;
|
||||
lookup: string;
|
||||
}): Promise<QueryableWikiPage | null> {
|
||||
const pages = await readQueryableWikiPages(params.config.vault.path);
|
||||
return resolveQueryableWikiPageByLookup(pages, params.lookup);
|
||||
}
|
||||
|
||||
async function applyCreateSynthesisMutation(params: {
|
||||
config: ResolvedMemoryWikiConfig;
|
||||
mutation: CreateSynthesisMemoryWikiMutation;
|
||||
}): Promise<{ changed: boolean; pagePath: string; pageId: string }> {
|
||||
const slug = slugifyWikiSegment(params.mutation.title);
|
||||
const pageStem = slugifyWikiPageStem(params.mutation.title);
|
||||
const pagePath = path.join("syntheses", `${pageStem}.md`).replace(/\\/g, "/");
|
||||
const root = await fsRoot(params.config.vault.path);
|
||||
const existing = await readExistingWikiPage(root, pagePath);
|
||||
const parsed = parseWikiMarkdown(existing);
|
||||
const pageId =
|
||||
(typeof parsed.frontmatter.id === "string" && parsed.frontmatter.id.trim()) ||
|
||||
`synthesis.${slug}`;
|
||||
const changed = await writeWikiPage({
|
||||
rootDir: params.config.vault.path,
|
||||
relativePath: pagePath,
|
||||
frontmatter: {
|
||||
...parsed.frontmatter,
|
||||
pageType: "synthesis",
|
||||
id: pageId,
|
||||
title: params.mutation.title,
|
||||
sourceIds: normalizeSourceIds(params.mutation.sourceIds),
|
||||
...(params.mutation.claims ? { claims: normalizeWikiClaims(params.mutation.claims) } : {}),
|
||||
...(normalizeUniqueStrings(params.mutation.contradictions)
|
||||
? { contradictions: normalizeUniqueStrings(params.mutation.contradictions) }
|
||||
: {}),
|
||||
...(normalizeUniqueStrings(params.mutation.questions)
|
||||
? { questions: normalizeUniqueStrings(params.mutation.questions) }
|
||||
: {}),
|
||||
...(typeof params.mutation.confidence === "number"
|
||||
? { confidence: params.mutation.confidence }
|
||||
: {}),
|
||||
status: params.mutation.status?.trim() || "active",
|
||||
updatedAt: new Date().toISOString(),
|
||||
},
|
||||
body: buildSynthesisBody({
|
||||
title: params.mutation.title,
|
||||
originalBody: parsed.body,
|
||||
generatedBody: params.mutation.body.trim(),
|
||||
}),
|
||||
});
|
||||
return { changed, pagePath, pageId };
|
||||
}
|
||||
|
||||
function buildUpdatedFrontmatter(params: {
|
||||
original: Record<string, unknown>;
|
||||
mutation: UpdateMetadataMemoryWikiMutation;
|
||||
}): Record<string, unknown> {
|
||||
const frontmatter: Record<string, unknown> = {
|
||||
...params.original,
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
if (params.mutation.sourceIds) {
|
||||
frontmatter.sourceIds = normalizeSourceIds(params.mutation.sourceIds);
|
||||
}
|
||||
if (params.mutation.claims) {
|
||||
const claims = normalizeWikiClaims(params.mutation.claims);
|
||||
if (claims.length > 0) {
|
||||
frontmatter.claims = claims;
|
||||
} else {
|
||||
delete frontmatter.claims;
|
||||
}
|
||||
}
|
||||
if (params.mutation.contradictions) {
|
||||
const contradictions = normalizeUniqueStrings(params.mutation.contradictions) ?? [];
|
||||
if (contradictions.length > 0) {
|
||||
frontmatter.contradictions = contradictions;
|
||||
} else {
|
||||
delete frontmatter.contradictions;
|
||||
}
|
||||
}
|
||||
if (params.mutation.questions) {
|
||||
const questions = normalizeUniqueStrings(params.mutation.questions) ?? [];
|
||||
if (questions.length > 0) {
|
||||
frontmatter.questions = questions;
|
||||
} else {
|
||||
delete frontmatter.questions;
|
||||
}
|
||||
}
|
||||
if (params.mutation.confidence === null) {
|
||||
delete frontmatter.confidence;
|
||||
} else if (typeof params.mutation.confidence === "number") {
|
||||
frontmatter.confidence = params.mutation.confidence;
|
||||
}
|
||||
if (params.mutation.status?.trim()) {
|
||||
frontmatter.status = params.mutation.status.trim();
|
||||
}
|
||||
return frontmatter;
|
||||
}
|
||||
|
||||
async function applyUpdateMetadataMutation(params: {
|
||||
config: ResolvedMemoryWikiConfig;
|
||||
mutation: UpdateMetadataMemoryWikiMutation;
|
||||
}): Promise<{ changed: boolean; pagePath: string; pageId?: string }> {
|
||||
const page = await resolveWritablePage({
|
||||
config: params.config,
|
||||
lookup: params.mutation.lookup,
|
||||
});
|
||||
if (!page) {
|
||||
throw new Error(`Wiki page not found: ${params.mutation.lookup}`);
|
||||
}
|
||||
const parsed = parseWikiMarkdown(page.raw);
|
||||
const changed = await writeWikiPage({
|
||||
rootDir: params.config.vault.path,
|
||||
relativePath: page.relativePath,
|
||||
frontmatter: buildUpdatedFrontmatter({
|
||||
original: parsed.frontmatter,
|
||||
mutation: params.mutation,
|
||||
}),
|
||||
body: parsed.body,
|
||||
});
|
||||
return {
|
||||
changed,
|
||||
pagePath: page.relativePath,
|
||||
...(page.id ? { pageId: page.id } : {}),
|
||||
};
|
||||
}
|
||||
|
||||
export async function applyMemoryWikiMutation(params: {
|
||||
config: ResolvedMemoryWikiConfig;
|
||||
mutation: ApplyMemoryWikiMutation;
|
||||
}): Promise<ApplyMemoryWikiMutationResult> {
|
||||
await initializeMemoryWikiVault(params.config);
|
||||
const result =
|
||||
params.mutation.op === "create_synthesis"
|
||||
? await applyCreateSynthesisMutation({
|
||||
config: params.config,
|
||||
mutation: params.mutation,
|
||||
})
|
||||
: await applyUpdateMetadataMutation({
|
||||
config: params.config,
|
||||
mutation: params.mutation,
|
||||
});
|
||||
const compile = await compileMemoryWikiVault(params.config);
|
||||
return {
|
||||
changed: result.changed,
|
||||
operation: params.mutation.op,
|
||||
pagePath: result.pagePath,
|
||||
...(result.pageId ? { pageId: result.pageId } : {}),
|
||||
compile,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user