
























@@ -152,6 +152,11 @@ vi.mock("../runtime.js", () => ({
152152defaultRuntime: mocks.defaultRuntime,
153153}));
154154155+vi.mock("../utils.js", async (importOriginal) => ({
156+ ...(await importOriginal<typeof import("../utils.js")>()),
157+CONFIG_DIR: "/tmp/openclaw-config",
158+}));
159+155160vi.mock("../config/config.js", () => ({
156161getRuntimeConfig: () => mocks.loadConfigMock(),
157162loadConfig: () => mocks.loadConfigMock(),
@@ -353,6 +358,44 @@ describe("skills cli commands", () => {
353358);
354359});
355360361+it("installs a skill into the shared global skills directory", async () => {
362+installSkillFromClawHubMock.mockResolvedValue({
363+ok: true,
364+slug: "calendar",
365+version: "1.2.3",
366+targetDir: "/tmp/openclaw-config/skills/calendar",
367+});
368+369+await runCommand(["skills", "install", "calendar", "--global"]);
370+371+expect(resolveAgentIdByWorkspacePathMock).not.toHaveBeenCalled();
372+expect(resolveDefaultAgentIdMock).not.toHaveBeenCalled();
373+expect(resolveAgentWorkspaceDirMock).not.toHaveBeenCalled();
374+expect(installSkillFromClawHubMock).toHaveBeenCalledWith(
375+expect.objectContaining({
376+workspaceDir: "/tmp/openclaw-config",
377+}),
378+);
379+});
380+381+it("rejects using --global and --agent together for installs", async () => {
382+await expect(
383+runCommand(["skills", "install", "calendar", "--global", "--agent", "main"]),
384+).rejects.toThrow("__exit__:1");
385+386+expect(runtimeErrors).toContain("Use either --global or --agent, not both.");
387+expect(installSkillFromClawHubMock).not.toHaveBeenCalled();
388+});
389+390+it("rejects using parent --agent with install --global", async () => {
391+await expect(
392+runCommand(["skills", "--agent", "writer", "install", "calendar", "--global"]),
393+).rejects.toThrow("__exit__:1");
394+395+expect(runtimeErrors).toContain("Use either --global or --agent, not both.");
396+expect(installSkillFromClawHubMock).not.toHaveBeenCalled();
397+});
398+356399it("updates all tracked ClawHub skills", async () => {
357400readTrackedClawHubSkillSlugsMock.mockResolvedValue(["calendar"]);
358401updateSkillsFromClawHubMock.mockResolvedValue([
@@ -438,6 +481,78 @@ describe("skills cli commands", () => {
438481expectLogger(updateOverrideArgs.logger);
439482});
440483484+it("updates tracked ClawHub skills in the shared global skills directory", async () => {
485+readTrackedClawHubSkillSlugsMock.mockResolvedValue(["calendar"]);
486+updateSkillsFromClawHubMock.mockResolvedValue([
487+{
488+ok: true,
489+slug: "calendar",
490+previousVersion: "1.2.2",
491+version: "1.2.3",
492+changed: true,
493+targetDir: "/tmp/openclaw-config/skills/calendar",
494+},
495+]);
496+497+await runCommand(["skills", "update", "--all", "--global"]);
498+499+expect(resolveAgentIdByWorkspacePathMock).not.toHaveBeenCalled();
500+expect(resolveDefaultAgentIdMock).not.toHaveBeenCalled();
501+expect(resolveAgentWorkspaceDirMock).not.toHaveBeenCalled();
502+expect(readTrackedClawHubSkillSlugsMock).toHaveBeenCalledWith("/tmp/openclaw-config");
503+expect(updateSkillsFromClawHubMock).toHaveBeenCalledWith({
504+workspaceDir: "/tmp/openclaw-config",
505+slug: undefined,
506+logger: expect.any(Object),
507+});
508+});
509+510+it("updates a single tracked ClawHub skill in the shared global skills directory", async () => {
511+readTrackedClawHubSkillSlugsMock.mockResolvedValue(["calendar"]);
512+updateSkillsFromClawHubMock.mockResolvedValue([
513+{
514+ok: true,
515+slug: "calendar",
516+previousVersion: "1.2.2",
517+version: "1.2.3",
518+changed: true,
519+targetDir: "/tmp/openclaw-config/skills/calendar",
520+},
521+]);
522+523+await runCommand(["skills", "update", "calendar", "--global"]);
524+525+expect(resolveAgentIdByWorkspacePathMock).not.toHaveBeenCalled();
526+expect(resolveDefaultAgentIdMock).not.toHaveBeenCalled();
527+expect(resolveAgentWorkspaceDirMock).not.toHaveBeenCalled();
528+expect(readTrackedClawHubSkillSlugsMock).toHaveBeenCalledWith("/tmp/openclaw-config");
529+expect(updateSkillsFromClawHubMock).toHaveBeenCalledWith({
530+workspaceDir: "/tmp/openclaw-config",
531+slug: "calendar",
532+logger: expect.any(Object),
533+});
534+});
535+536+it("rejects using --global and --agent together for updates", async () => {
537+await expect(
538+runCommand(["skills", "update", "--all", "--global", "--agent", "main"]),
539+).rejects.toThrow("__exit__:1");
540+541+expect(runtimeErrors).toContain("Use either --global or --agent, not both.");
542+expect(readTrackedClawHubSkillSlugsMock).not.toHaveBeenCalled();
543+expect(updateSkillsFromClawHubMock).not.toHaveBeenCalled();
544+});
545+546+it("rejects using parent --agent with update --global", async () => {
547+await expect(
548+runCommand(["skills", "--agent", "writer", "update", "--all", "--global"]),
549+).rejects.toThrow("__exit__:1");
550+551+expect(runtimeErrors).toContain("Use either --global or --agent, not both.");
552+expect(readTrackedClawHubSkillSlugsMock).not.toHaveBeenCalled();
553+expect(updateSkillsFromClawHubMock).not.toHaveBeenCalled();
554+});
555+441556it.each([
442557{
443558label: "list",
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。