mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-23 21:31:12 +00:00
* feat(control-ui): import coding assistant memory * test(migrate): clean memory import temp dirs * chore: move memory import note to PR body * build: refresh memory import generated artifacts * fix(control-ui): complete memory import checks * build(control-ui): localize memory recovery labels * fix(control-ui): harden memory import recovery * refactor(migrate): keep memory import surfaces bounded * fix(control-ui): use canonical agent row type * fix(codex): drop dead migration type exports * fix(migrate): restrict imported memory permissions * fix(control-ui): preserve memory import recovery state * fix(control-ui): retain memory import results * build(control-ui): preserve translation memory history * fix(control-ui): bind memory import state to agent * fix(control-ui): unlock memory import after refresh * test(gateway): preserve memory method suffix * fix(migrate): bind reviewed memory imports * fix(migrate): make memory imports retry-safe * perf(ui): keep memory import lazy * build: refresh generated artifacts after rebase * chore: keep migration runtime within LOC guard * build: refresh Swift protocol model
76 lines
2.5 KiB
TypeScript
76 lines
2.5 KiB
TypeScript
// Codex memory plans validate source/destination separation before exposing copy items.
|
|
import fs from "node:fs/promises";
|
|
import path from "node:path";
|
|
import { createMigrationItem, MIGRATION_REASON_TARGET_EXISTS } from "openclaw/plugin-sdk/migration";
|
|
import type { MigrationItem } from "openclaw/plugin-sdk/plugin-entry";
|
|
import {
|
|
canonicalPathFromExistingAncestor,
|
|
isPathInside,
|
|
} from "openclaw/plugin-sdk/security-runtime";
|
|
import { exists } from "./helpers.js";
|
|
import type { CodexMemorySource } from "./source-files.js";
|
|
|
|
async function assertSafeMemoryDestination(params: {
|
|
source: string;
|
|
workspaceDir: string;
|
|
target: string;
|
|
}): Promise<void> {
|
|
const [canonicalSource, canonicalWorkspace, canonicalTarget] = await Promise.all([
|
|
fs.realpath(path.dirname(params.source)),
|
|
canonicalPathFromExistingAncestor(params.workspaceDir),
|
|
canonicalPathFromExistingAncestor(params.target),
|
|
]);
|
|
if (!isPathInside(canonicalWorkspace, canonicalTarget)) {
|
|
throw new Error("Codex memory import destination must stay in the selected workspace.");
|
|
}
|
|
if (
|
|
isPathInside(canonicalSource, canonicalTarget) ||
|
|
isPathInside(canonicalTarget, canonicalSource)
|
|
) {
|
|
throw new Error("Codex memory source and OpenClaw import destination must be separate paths.");
|
|
}
|
|
}
|
|
|
|
export async function buildCodexMemoryItems(params: {
|
|
memoryFiles: readonly CodexMemorySource[];
|
|
workspaceDir: string;
|
|
overwrite?: boolean;
|
|
}): Promise<MigrationItem[]> {
|
|
const items: MigrationItem[] = [];
|
|
for (const memory of params.memoryFiles) {
|
|
const target = path.join(
|
|
params.workspaceDir,
|
|
"memory",
|
|
"imports",
|
|
"codex",
|
|
path.basename(memory.path),
|
|
);
|
|
await assertSafeMemoryDestination({
|
|
source: memory.path,
|
|
workspaceDir: params.workspaceDir,
|
|
target,
|
|
});
|
|
const targetExists = await exists(target);
|
|
items.push(
|
|
createMigrationItem({
|
|
id: memory.id,
|
|
kind: "memory",
|
|
action: "copy",
|
|
source: memory.path,
|
|
target,
|
|
status: targetExists && !params.overwrite ? "conflict" : "planned",
|
|
reason: targetExists && !params.overwrite ? MIGRATION_REASON_TARGET_EXISTS : undefined,
|
|
message: "Copy consolidated Codex memory into the OpenClaw memory index.",
|
|
details: {
|
|
sourceType: "codex-memory",
|
|
sourceLabel: memory.label,
|
|
collectionId: "codex",
|
|
collectionLabel: "Codex",
|
|
relativePath: path.basename(memory.path),
|
|
},
|
|
}),
|
|
);
|
|
}
|
|
return items;
|
|
}
|