mirror of
https://github.com/openclaw/openclaw.git
synced 2026-02-19 18:39:20 -05:00
fix: resolve workspace templates from package root
This commit is contained in:
34
src/agents/workspace-templates.test.ts
Normal file
34
src/agents/workspace-templates.test.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
resetWorkspaceTemplateDirCache,
|
||||
resolveWorkspaceTemplateDir,
|
||||
} from "./workspace-templates.js";
|
||||
|
||||
async function makeTempRoot(): Promise<string> {
|
||||
return await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-templates-"));
|
||||
}
|
||||
|
||||
describe("resolveWorkspaceTemplateDir", () => {
|
||||
it("resolves templates from package root when module url is dist-rooted", async () => {
|
||||
resetWorkspaceTemplateDirCache();
|
||||
const root = await makeTempRoot();
|
||||
await fs.writeFile(path.join(root, "package.json"), JSON.stringify({ name: "openclaw" }));
|
||||
|
||||
const templatesDir = path.join(root, "docs", "reference", "templates");
|
||||
await fs.mkdir(templatesDir, { recursive: true });
|
||||
await fs.writeFile(path.join(templatesDir, "AGENTS.md"), "# ok\n");
|
||||
|
||||
const distDir = path.join(root, "dist");
|
||||
await fs.mkdir(distDir, { recursive: true });
|
||||
const moduleUrl = pathToFileURL(path.join(distDir, "model-selection.mjs")).toString();
|
||||
|
||||
const resolved = await resolveWorkspaceTemplateDir({ cwd: distDir, moduleUrl });
|
||||
expect(resolved).toBe(templatesDir);
|
||||
});
|
||||
});
|
||||
69
src/agents/workspace-templates.ts
Normal file
69
src/agents/workspace-templates.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
import { resolveOpenClawPackageRoot } from "../infra/openclaw-root.js";
|
||||
|
||||
const FALLBACK_TEMPLATE_DIR = path.resolve(
|
||||
path.dirname(fileURLToPath(import.meta.url)),
|
||||
"../../docs/reference/templates",
|
||||
);
|
||||
|
||||
let cachedTemplateDir: string | undefined;
|
||||
let resolvingTemplateDir: Promise<string> | undefined;
|
||||
|
||||
async function pathExists(candidate: string): Promise<boolean> {
|
||||
try {
|
||||
await fs.access(candidate);
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export async function resolveWorkspaceTemplateDir(opts?: {
|
||||
cwd?: string;
|
||||
argv1?: string;
|
||||
moduleUrl?: string;
|
||||
}): Promise<string> {
|
||||
if (cachedTemplateDir) {
|
||||
return cachedTemplateDir;
|
||||
}
|
||||
if (resolvingTemplateDir) {
|
||||
return resolvingTemplateDir;
|
||||
}
|
||||
|
||||
resolvingTemplateDir = (async () => {
|
||||
const moduleUrl = opts?.moduleUrl ?? import.meta.url;
|
||||
const argv1 = opts?.argv1 ?? process.argv[1];
|
||||
const cwd = opts?.cwd ?? process.cwd();
|
||||
|
||||
const packageRoot = await resolveOpenClawPackageRoot({ moduleUrl, argv1, cwd });
|
||||
const candidates = [
|
||||
packageRoot ? path.join(packageRoot, "docs", "reference", "templates") : null,
|
||||
cwd ? path.resolve(cwd, "docs", "reference", "templates") : null,
|
||||
FALLBACK_TEMPLATE_DIR,
|
||||
].filter(Boolean) as string[];
|
||||
|
||||
for (const candidate of candidates) {
|
||||
if (await pathExists(candidate)) {
|
||||
cachedTemplateDir = candidate;
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
cachedTemplateDir = candidates[0] ?? FALLBACK_TEMPLATE_DIR;
|
||||
return cachedTemplateDir;
|
||||
})();
|
||||
|
||||
try {
|
||||
return await resolvingTemplateDir;
|
||||
} finally {
|
||||
resolvingTemplateDir = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export function resetWorkspaceTemplateDirCache() {
|
||||
cachedTemplateDir = undefined;
|
||||
resolvingTemplateDir = undefined;
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
import { isSubagentSessionKey } from "../routing/session-key.js";
|
||||
import { runCommandWithTimeout } from "../process/exec.js";
|
||||
import { resolveUserPath } from "../utils.js";
|
||||
import { resolveWorkspaceTemplateDir } from "./workspace-templates.js";
|
||||
|
||||
export function resolveDefaultAgentWorkspaceDir(
|
||||
env: NodeJS.ProcessEnv = process.env,
|
||||
@@ -29,11 +28,6 @@ export const DEFAULT_BOOTSTRAP_FILENAME = "BOOTSTRAP.md";
|
||||
export const DEFAULT_MEMORY_FILENAME = "MEMORY.md";
|
||||
export const DEFAULT_MEMORY_ALT_FILENAME = "memory.md";
|
||||
|
||||
const TEMPLATE_DIR = path.resolve(
|
||||
path.dirname(fileURLToPath(import.meta.url)),
|
||||
"../../docs/reference/templates",
|
||||
);
|
||||
|
||||
function stripFrontMatter(content: string): string {
|
||||
if (!content.startsWith("---")) {
|
||||
return content;
|
||||
@@ -49,7 +43,8 @@ function stripFrontMatter(content: string): string {
|
||||
}
|
||||
|
||||
async function loadTemplate(name: string): Promise<string> {
|
||||
const templatePath = path.join(TEMPLATE_DIR, name);
|
||||
const templateDir = await resolveWorkspaceTemplateDir();
|
||||
const templatePath = path.join(templateDir, name);
|
||||
try {
|
||||
const content = await fs.readFile(templatePath, "utf-8");
|
||||
return stripFrontMatter(content);
|
||||
|
||||
@@ -3,6 +3,7 @@ import os from "node:os";
|
||||
import path from "node:path";
|
||||
|
||||
import { resolveDefaultAgentWorkspaceDir } from "../../agents/workspace.js";
|
||||
import { resolveWorkspaceTemplateDir } from "../../agents/workspace-templates.js";
|
||||
import { handleReset } from "../../commands/onboard-helpers.js";
|
||||
import { createConfigIO, writeConfigFile } from "../../config/config.js";
|
||||
import { defaultRuntime } from "../../runtime.js";
|
||||
@@ -13,14 +14,10 @@ const DEV_IDENTITY_THEME = "protocol droid";
|
||||
const DEV_IDENTITY_EMOJI = "🤖";
|
||||
const DEV_AGENT_WORKSPACE_SUFFIX = "dev";
|
||||
|
||||
const DEV_TEMPLATE_DIR = path.resolve(
|
||||
path.dirname(new URL(import.meta.url).pathname),
|
||||
"../../../docs/reference/templates",
|
||||
);
|
||||
|
||||
async function loadDevTemplate(name: string, fallback: string): Promise<string> {
|
||||
try {
|
||||
const raw = await fs.promises.readFile(path.join(DEV_TEMPLATE_DIR, name), "utf-8");
|
||||
const templateDir = await resolveWorkspaceTemplateDir();
|
||||
const raw = await fs.promises.readFile(path.join(templateDir, name), "utf-8");
|
||||
if (!raw.startsWith("---")) {
|
||||
return raw;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user