From f4db93176e9e339258aef4d518e0e4d8cc0494e4 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 16 Mar 2026 14:58:12 +0000 Subject: [PATCH] fix: skills list should prefer cwd-matched workspace over default agent When running 'openclaw skills list' from a directory that belongs to a configured agent's workspace, the CLI now correctly infers the agent from the current working directory instead of always using the default agent's workspace. Changes: - loadSkillsStatusReport() now calls resolveAgentIdByWorkspacePath() with process.cwd() before falling back to resolveDefaultAgentId() - Added regression test for cwd-based agent inference Fixes #48266 --- src/cli/skills-cli.commands.test.ts | 18 ++++++++++++++++++ src/cli/skills-cli.ts | 10 ++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/cli/skills-cli.commands.test.ts b/src/cli/skills-cli.commands.test.ts index 48b4164903d..02345a99502 100644 --- a/src/cli/skills-cli.commands.test.ts +++ b/src/cli/skills-cli.commands.test.ts @@ -2,6 +2,7 @@ import { Command } from "commander"; import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; const loadConfigMock = vi.fn(); +const resolveAgentIdByWorkspacePathMock = vi.fn(); const resolveAgentWorkspaceDirMock = vi.fn(); const resolveDefaultAgentIdMock = vi.fn(); const buildWorkspaceSkillStatusMock = vi.fn(); @@ -20,6 +21,7 @@ vi.mock("../config/config.js", () => ({ })); vi.mock("../agents/agent-scope.js", () => ({ + resolveAgentIdByWorkspacePath: resolveAgentIdByWorkspacePathMock, resolveAgentWorkspaceDir: resolveAgentWorkspaceDirMock, resolveDefaultAgentId: resolveDefaultAgentIdMock, })); @@ -60,6 +62,7 @@ describe("registerSkillsCli", () => { beforeEach(() => { vi.clearAllMocks(); loadConfigMock.mockReturnValue({ gateway: {} }); + resolveAgentIdByWorkspacePathMock.mockReturnValue(undefined); resolveDefaultAgentIdMock.mockReturnValue("main"); resolveAgentWorkspaceDirMock.mockReturnValue("/tmp/workspace"); buildWorkspaceSkillStatusMock.mockReturnValue(report); @@ -71,6 +74,8 @@ describe("registerSkillsCli", () => { it("runs list command with resolved report and formatter options", async () => { await runCli(["skills", "list", "--eligible", "--verbose", "--json"]); + expect(resolveAgentIdByWorkspacePathMock).toHaveBeenCalledWith({ gateway: {} }, process.cwd()); + expect(resolveAgentWorkspaceDirMock).toHaveBeenCalledWith({ gateway: {} }, "main"); expect(buildWorkspaceSkillStatusMock).toHaveBeenCalledWith("/tmp/workspace", { config: { gateway: {} }, }); @@ -85,6 +90,19 @@ describe("registerSkillsCli", () => { expect(runtime.log).toHaveBeenCalledWith("skills-list-output"); }); + it("prefers the agent inferred from cwd over the default agent", async () => { + resolveAgentIdByWorkspacePathMock.mockReturnValue("ops"); + resolveAgentWorkspaceDirMock.mockReturnValue("/tmp/ops-workspace"); + + await runCli(["skills", "list"]); + + expect(resolveAgentWorkspaceDirMock).toHaveBeenCalledWith({ gateway: {} }, "ops"); + expect(resolveDefaultAgentIdMock).not.toHaveBeenCalled(); + expect(buildWorkspaceSkillStatusMock).toHaveBeenCalledWith("/tmp/ops-workspace", { + config: { gateway: {} }, + }); + }); + it("runs info command and forwards skill name", async () => { await runCli(["skills", "info", "peekaboo", "--json"]); diff --git a/src/cli/skills-cli.ts b/src/cli/skills-cli.ts index 49f288f36c0..4d553d2e5d3 100644 --- a/src/cli/skills-cli.ts +++ b/src/cli/skills-cli.ts @@ -1,5 +1,9 @@ import type { Command } from "commander"; -import { resolveAgentWorkspaceDir, resolveDefaultAgentId } from "../agents/agent-scope.js"; +import { + resolveAgentIdByWorkspacePath, + resolveAgentWorkspaceDir, + resolveDefaultAgentId, +} from "../agents/agent-scope.js"; import { loadConfig } from "../config/config.js"; import { defaultRuntime } from "../runtime.js"; import { formatDocsLink } from "../terminal/links.js"; @@ -19,7 +23,9 @@ type SkillStatusReport = Awaited< async function loadSkillsStatusReport(): Promise { const config = loadConfig(); - const workspaceDir = resolveAgentWorkspaceDir(config, resolveDefaultAgentId(config)); + const agentId = + resolveAgentIdByWorkspacePath(config, process.cwd()) ?? resolveDefaultAgentId(config); + const workspaceDir = resolveAgentWorkspaceDir(config, agentId); const { buildWorkspaceSkillStatus } = await import("../agents/skills-status.js"); return buildWorkspaceSkillStatus(workspaceDir, { config }); }