























@@ -3,7 +3,11 @@ import { resolveSessionAgentId } from "../../agents/agent-scope.js";
33import type { OpenClawConfig } from "../../config/config.js";
44import type { MsgContext } from "../templating.js";
55import { handleContextCommand } from "./commands-context-command.js";
6-import { handleExportTrajectoryCommand, handleStatusCommand } from "./commands-info.js";
6+import {
7+handleExportTrajectoryCommand,
8+handleSkillCommandUsage,
9+handleStatusCommand,
10+} from "./commands-info.js";
711import { buildStatusReply } from "./commands-status.js";
812import type { HandleCommandsParams } from "./commands-types.js";
913import { handleWhoamiCommand } from "./commands-whoami.js";
@@ -39,9 +43,14 @@ vi.mock("../../agents/agent-scope.js", async () => {
3943};
4044});
414542-vi.mock("../skill-commands.js", () => ({
43-listSkillCommandsForAgents: listSkillCommandsForAgentsMock,
44-}));
46+vi.mock("../skill-commands.js", async () => {
47+const actual =
48+await vi.importActual<typeof import("../skill-commands.js")>("../skill-commands.js");
49+return {
50+ ...actual,
51+listSkillCommandsForAgents: listSkillCommandsForAgentsMock,
52+};
53+});
45544655vi.mock("../status.js", async () => {
4756const actual = await vi.importActual<typeof import("../status.js")>("../status.js");
@@ -156,6 +165,54 @@ describe("info command handlers", () => {
156165expect(result?.reply?.text).toContain("AllowFrom: 12345");
157166});
158167168+it("returns usage for bare /skill without continuing to the agent", async () => {
169+const params = buildInfoParams("/skill", {
170+commands: { text: true },
171+} as OpenClawConfig);
172+params.skillCommands = [
173+{
174+name: "demo_skill",
175+skillName: "demo-skill",
176+description: "Demo skill",
177+},
178+];
179+180+const result = await handleSkillCommandUsage(params, true);
181+182+expect(result?.shouldContinue).toBe(false);
183+expect(result?.reply?.text).toContain("Usage: /skill <name> [input]");
184+expect(result?.reply?.text).toContain("Available: demo-skill");
185+});
186+187+it("returns an unknown skill reply for unmatched /skill targets", async () => {
188+const params = buildInfoParams("/skill missing input", {
189+commands: { text: true },
190+} as OpenClawConfig);
191+192+const result = await handleSkillCommandUsage(params, true);
193+194+expect(result?.shouldContinue).toBe(false);
195+expect(result?.reply?.text).toContain("Unknown skill: missing");
196+expect(result?.reply?.text).toContain("Usage: /skill <name> [input]");
197+});
198+199+it("lets valid /skill invocations continue to the skill command path", async () => {
200+const params = buildInfoParams("/skill demo_skill input", {
201+commands: { text: true },
202+} as OpenClawConfig);
203+params.skillCommands = [
204+{
205+name: "demo_skill",
206+skillName: "demo-skill",
207+description: "Demo skill",
208+},
209+];
210+211+const result = await handleSkillCommandUsage(params, true);
212+213+expect(result).toBeNull();
214+});
215+159216it("uses the canonical command sender identity for /whoami AllowFrom", async () => {
160217const params = buildInfoParams(
161218"/whoami",
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。