fix: workspace template resolution fails in bundled dist/ layout
After bundling, all source files land in dist/ (one level deep). The FALLBACK_TEMPLATE_DIR used '../../docs/reference/templates' relative to the module file, which correctly resolves from the source layout (src/agents/) but overshoots in the bundled layout (dist/) — landing in node_modules/ instead of the package root. When resolveOpenClawPackageRoot returns null (e.g. in isolated cron sessions or worker processes where the module context differs), the resolution falls through to cwd-based lookup, which for the gateway daemon is the home directory. This causes: Error: Missing workspace template: AGENTS.md (/home/user/docs/reference/templates/AGENTS.md) Fix: Add both '../' and '../../' relative paths as fallback candidates (covering bundled and source layouts). Also reorder candidates to prefer module-relative paths over cwd-based paths, since cwd is unreliable for daemon processes. Closes: gateway crash when TUI input triggers session creation in isolated cron contexts.
This commit is contained in:
parent
128e5bc317
commit
21cb241f02
@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
@ -3,10 +3,23 @@ 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 directories relative to the current module.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
const MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
|
||||
const FALLBACK_TEMPLATE_DIRS = [
|
||||
path.resolve(MODULE_DIR, "../../docs/reference/templates"), // source layout (src/agents/)
|
||||
path.resolve(MODULE_DIR, "../docs/reference/templates"), // bundled layout (dist/)
|
||||
];
|
||||
|
||||
let cachedTemplateDir: string | undefined;
|
||||
let resolvingTemplateDir: Promise<string> | undefined;
|
||||
@ -30,9 +43,12 @@ export async function resolveWorkspaceTemplateDir(opts?: {
|
||||
|
||||
const packageRoot = await resolveOpenClawPackageRoot({ moduleUrl, argv1, cwd });
|
||||
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)
|
||||
...FALLBACK_TEMPLATE_DIRS,
|
||||
// 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 +58,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] ?? FALLBACK_TEMPLATE_DIRS[0];
|
||||
return cachedTemplateDir;
|
||||
})();
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user