fix(coding-agent): rebind relative extension roots
This commit is contained in:
@@ -36,6 +36,8 @@ export interface OmpExtensionRoot {
|
||||
|
||||
interface InjectedRoot {
|
||||
path: string;
|
||||
/** Relative CLI spelling, rebound against the active project on discovery. */
|
||||
relativePath?: string;
|
||||
level: "user" | "project";
|
||||
}
|
||||
|
||||
@@ -73,13 +75,16 @@ export function injectOmpExtensionCliRoots(
|
||||
if (paths.length === 0) return;
|
||||
const expanded = paths.map(raw => {
|
||||
const tilde = expandTilde(raw, home);
|
||||
return path.isAbsolute(tilde) ? tilde : path.resolve(cwd, tilde);
|
||||
return {
|
||||
path: path.isAbsolute(tilde) ? tilde : path.resolve(cwd, tilde),
|
||||
relativePath: path.isAbsolute(tilde) ? undefined : tilde,
|
||||
};
|
||||
});
|
||||
const merged = new Map<string, InjectedRoot>();
|
||||
for (const root of injectedCliRoots) merged.set(root.path, root);
|
||||
for (const resolved of expanded) {
|
||||
for (const { path: resolved, relativePath } of expanded) {
|
||||
// CLI scope mirrors how `--extension` is treated elsewhere — user-level overrides win.
|
||||
if (!merged.has(resolved)) merged.set(resolved, { path: resolved, level: "user" });
|
||||
if (!merged.has(resolved)) merged.set(resolved, { path: resolved, relativePath, level: "user" });
|
||||
}
|
||||
injectedCliRoots = [...merged.values()];
|
||||
}
|
||||
@@ -154,7 +159,9 @@ async function isDirectory(p: string): Promise<boolean> {
|
||||
* other sources still surface.
|
||||
*/
|
||||
export async function listOmpExtensionRoots(ctx: LoadContext): Promise<OmpExtensionRoot[]> {
|
||||
let candidates: InjectedRoot[] = [...injectedCliRoots];
|
||||
let candidates: InjectedRoot[] = injectedCliRoots.map(root =>
|
||||
root.relativePath ? { ...root, path: path.resolve(ctx.cwd, root.relativePath) } : root,
|
||||
);
|
||||
if (injectedCliRootMode === "merge") {
|
||||
const { project, user } = scopeDirs(ctx);
|
||||
const [projectExtensions, userExtensions, installedPlugins] = await Promise.all([
|
||||
|
||||
@@ -158,6 +158,24 @@ test("`--extension` CLI injection is wired through the same provider", async ()
|
||||
expect(tools.map(t => t.name)).toEqual(expect.arrayContaining(["wcount", "deep-tool"]));
|
||||
});
|
||||
|
||||
test("relative CLI roots rebind when resume switches projects", async () => {
|
||||
const relativeRoot = "relative-extension";
|
||||
const launchRoot = path.join(project, relativeRoot);
|
||||
const destination = path.join(tempDir, "destination");
|
||||
const destinationRoot = path.join(destination, relativeRoot);
|
||||
buildExtensionPackage(launchRoot, "launch-skill");
|
||||
buildExtensionPackage(destinationRoot, "destination-skill");
|
||||
|
||||
injectOmpExtensionCliRoots([`./${relativeRoot}`], home, project);
|
||||
|
||||
const destinationContext = { cwd: destination, home, repoRoot: destination };
|
||||
const roots = await listOmpExtensionRoots(destinationContext);
|
||||
const skills = await loadFromPlugin<{ name: string }>(skillCapability.id, destinationContext);
|
||||
expect(roots.map(root => root.path)).toEqual([destinationRoot]);
|
||||
expect(skills.map(skill => skill.name)).toContain("destination-skill");
|
||||
expect(skills.map(skill => skill.name)).not.toContain("launch-skill");
|
||||
});
|
||||
|
||||
test("explicit-only CLI roots replace stale state and exclude every ambient package source", async () => {
|
||||
const stale = path.join(tempDir, "stale-extension");
|
||||
const projectExt = path.join(tempDir, "project-extension");
|
||||
|
||||
Reference in New Issue
Block a user