Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions __tests__/run-command.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
"use strict";

/**
* Coverage for cli/run.js — the `supercli run <plugin> <resource> <action>`
* one-shot discover+install+execute command (issue #335).
*
* These tests cover the usage-validation paths, which return before any
* network/catalog/install calls. cli/executor is mocked with an explicit
* factory (rather than left to load for real) since it pulls in the vm2
* native sandbox, which these tests have no need to exercise.
*/

jest.mock("../cli/executor", () => ({ execute: jest.fn() }));

const { handleRunCommand } = require("../cli/run");

describe("handleRunCommand — usage validation", () => {
test("missing plugin name reports invalid_argument with usage message", async () => {
const outputError = jest.fn();
const output = jest.fn();

await handleRunCommand({
positional: ["run"],
flags: {},
humanMode: false,
output,
outputError,
});

expect(output).not.toHaveBeenCalled();
expect(outputError).toHaveBeenCalledWith(
expect.objectContaining({
code: 85,
type: "invalid_argument",
message: expect.stringContaining("Usage: supercli run"),
recoverable: false,
})
);
});

test("missing resource/action reports invalid_argument scoped to the plugin", async () => {
const outputError = jest.fn();
const output = jest.fn();

await handleRunCommand({
positional: ["run", "claude-session-optimizer"],
flags: {},
humanMode: false,
output,
outputError,
});

expect(output).not.toHaveBeenCalled();
expect(outputError).toHaveBeenCalledWith(
expect.objectContaining({
code: 85,
type: "invalid_argument",
message: "Usage: supercli run claude-session-optimizer <resource> <action> [--args]",
recoverable: false,
})
);
});

test("missing action alone also reports invalid_argument", async () => {
const outputError = jest.fn();
const output = jest.fn();

await handleRunCommand({
positional: ["run", "claude-session-optimizer", "self"],
flags: {},
humanMode: false,
output,
outputError,
});

expect(output).not.toHaveBeenCalled();
expect(outputError).toHaveBeenCalledWith(
expect.objectContaining({ code: 85, type: "invalid_argument" })
);
});
});
58 changes: 58 additions & 0 deletions __tests__/skills-mcp.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"use strict";

const { buildMcpServersUsageSkillMarkdown } = require("../cli/skills-mcp");

function fakeRenderYamlObject(obj) {
return JSON.stringify(obj);
}

describe("buildMcpServersUsageSkillMarkdown", () => {
test("wraps rendered frontmatter in --- fences followed by the instruction body", () => {
const md = buildMcpServersUsageSkillMarkdown({ renderYamlObject: fakeRenderYamlObject });

expect(md.startsWith("---\n")).toBe(true);
expect(md).toContain("\n---\n\n# Instruction");
expect(md).toContain("supercli mcp list --json");
});

test("omits the dag field by default", () => {
let capturedFrontmatter;
buildMcpServersUsageSkillMarkdown({
renderYamlObject: (obj) => {
capturedFrontmatter = obj;
return "";
},
});

expect(capturedFrontmatter.dag).toBeUndefined();
expect(capturedFrontmatter.command).toBe("skills get mcp.servers.usage");
});

test("includes the reasoning DAG when showDag is true", () => {
let capturedFrontmatter;
buildMcpServersUsageSkillMarkdown({
showDag: true,
renderYamlObject: (obj) => {
capturedFrontmatter = obj;
return "";
},
});

expect(Array.isArray(capturedFrontmatter.dag)).toBe(true);
expect(capturedFrontmatter.dag).toHaveLength(4);
expect(capturedFrontmatter.dag[0]).toMatchObject({ id: 1, type: "list_or_register_mcp_server" });
});

test("honors a custom skillId in both the command and dag-less frontmatter", () => {
let capturedFrontmatter;
buildMcpServersUsageSkillMarkdown({
skillId: "mcp.custom.usage",
renderYamlObject: (obj) => {
capturedFrontmatter = obj;
return "";
},
});

expect(capturedFrontmatter.command).toBe("skills get mcp.custom.usage");
});
});
Loading