Merge d4dcd583d2cbbe327b3128c67a374fd56b636cb8 into 9fb78453e088cd7b553d7779faa0de5c83708e70

This commit is contained in:
TopangaLudwitt 2026-03-21 05:15:19 +00:00 committed by GitHub
commit a8a341481f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 50 additions and 6 deletions

View File

@ -51,4 +51,27 @@ describe("resolveWorkspaceTemplateDir", () => {
const resolved = await resolveWorkspaceTemplateDir({ cwd: distDir, moduleUrl });
expect(path.normalize(resolved)).toBe(path.resolve("docs", "reference", "templates"));
});
it("resolves via module-relative ../docs fallback when packageRoot is null and cwd lacks templates", async () => {
// Simulates the bundled dist/ layout where ../../ overshoots but ../ is correct.
// When resolveOpenClawPackageRoot returns null (no package.json in ancestors),
// the ../docs/reference/templates fallback relative to the module should work.
const root = await makeTempRoot();
// No package.json — packageRoot will be null
const distDir = path.join(root, "dist");
await fs.mkdir(distDir, { recursive: true });
// Create templates at ../docs (one level up from dist/) — the bundled layout
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 moduleUrl = pathToFileURL(path.join(distDir, "workspace-XXXX.mjs")).toString();
// Use a cwd that does NOT have docs/reference/templates
const fakeCwd = await makeTempRoot();
const resolved = await resolveWorkspaceTemplateDir({ cwd: fakeCwd, moduleUrl });
expect(resolved).toBe(templatesDir);
});
});

View File

@ -3,10 +3,25 @@ import { fileURLToPath } from "node:url";
import { resolveOpenClawPackageRoot } from "../infra/openclaw-root.js";
import { pathExists } from "../utils.js";
const FALLBACK_TEMPLATE_DIR = path.resolve(
path.dirname(fileURLToPath(import.meta.url)),
"../../docs/reference/templates",
);
/**
* Compute fallback template directory candidates relative to a module URL.
*
* In the source tree the module lives at `src/agents/workspace-templates.ts`,
* so `../../docs/reference/templates` resolves correctly to the repo root.
*
* After bundling, all files land in `dist/` (one level deep inside the
* package root), so `../../docs/reference/templates` overshoots by one
* directory (lands in node_modules/ instead of the package). We include
* both `../../` (source) and `../` (bundled dist) as fallback candidates
* to handle either layout.
*/
function computeFallbackTemplateDirs(moduleUrl: string): string[] {
const moduleDir = path.dirname(fileURLToPath(moduleUrl));
return [
path.resolve(moduleDir, "../../docs/reference/templates"), // source layout (src/agents/)
path.resolve(moduleDir, "../docs/reference/templates"), // bundled layout (dist/)
];
}
let cachedTemplateDir: string | undefined;
let resolvingTemplateDir: Promise<string> | undefined;
@ -29,10 +44,14 @@ export async function resolveWorkspaceTemplateDir(opts?: {
const cwd = opts?.cwd ?? process.cwd();
const packageRoot = await resolveOpenClawPackageRoot({ moduleUrl, argv1, cwd });
const fallbackDirs = computeFallbackTemplateDirs(moduleUrl);
const candidates = [
// Preferred: resolved package root (most reliable)
packageRoot ? path.join(packageRoot, "docs", "reference", "templates") : null,
// Fallback: relative to module file (handles both source and bundled layouts)
...fallbackDirs,
// Last resort: relative to cwd (only useful if running from repo checkout)
cwd ? path.resolve(cwd, "docs", "reference", "templates") : null,
FALLBACK_TEMPLATE_DIR,
].filter(Boolean) as string[];
for (const candidate of candidates) {
@ -42,7 +61,9 @@ export async function resolveWorkspaceTemplateDir(opts?: {
}
}
cachedTemplateDir = candidates[0] ?? FALLBACK_TEMPLATE_DIR;
// No candidate exists — return the package-root-based path (or first
// fallback) so the downstream error message shows a meaningful path.
cachedTemplateDir = candidates[0] ?? fallbackDirs[0];
return cachedTemplateDir;
})();