feat: add uwf skill cli command and Prepare section in role prompt

- Add 'uwf skill cli' command that prints markdown CLI reference
- buildRolePrompt now generates ## Prepare section:
  - Always prompts agent to run 'uwf skill cli' (explicit skill)
  - Renders capabilities as keyword hints for implicit skill loading

Fixes #369
This commit is contained in:
2026-05-22 03:20:04 +00:00
parent 8efc5050cb
commit 866154ad73
4 changed files with 114 additions and 4 deletions
@@ -18,13 +18,16 @@ describe("buildRolePrompt", () => {
expect(result).toContain("## Capabilities");
expect(result).toContain("- cursor-agent");
expect(result).toContain("- file-edit");
expect(result).toContain("## Prepare");
expect(result).toContain("uwf skill cli");
expect(result).toContain("cursor-agent, file-edit");
expect(result).toContain("## Procedure");
expect(result).toContain("Implement the feature.");
expect(result).toContain("## Output");
expect(result).toContain("Summarize changes.");
});
test("empty fields are omitted", () => {
test("empty fields are omitted but Prepare is always present", () => {
const role: RoleDefinition = {
description: "A reviewer",
goal: "You are a code reviewer.",
@@ -35,12 +38,14 @@ describe("buildRolePrompt", () => {
};
const result = buildRolePrompt(role);
expect(result).toContain("## Goal");
expect(result).toContain("## Prepare");
expect(result).toContain("uwf skill cli");
expect(result).toContain("## Procedure");
expect(result).not.toContain("## Capabilities");
expect(result).not.toContain("## Output");
});
test("all empty returns empty string", () => {
test("all empty still includes Prepare section", () => {
const role: RoleDefinition = {
description: "Minimal",
goal: "",
@@ -50,7 +55,12 @@ describe("buildRolePrompt", () => {
meta: "placeholder00000" as string,
};
const result = buildRolePrompt(role);
expect(result).toBe("");
expect(result).toContain("## Prepare");
expect(result).toContain("uwf skill cli");
expect(result).not.toContain("## Goal");
expect(result).not.toContain("## Capabilities");
expect(result).not.toContain("## Procedure");
expect(result).not.toContain("## Output");
});
test("capabilities rendered as bullet list", () => {
@@ -3,8 +3,12 @@ import type { RoleDefinition } from "@uncaged/workflow-protocol";
/**
* Build the role prompt from a RoleDefinition.
*
* Assembles structured sections: Goal, Capabilities, Procedure, Output.
* Assembles structured sections: Goal, Capabilities, Prepare, Procedure, Output.
* Empty strings and empty arrays are omitted from the output.
*
* The Prepare section always instructs the agent to run `uwf skill cli` to load
* workflow knowledge, plus renders the capabilities array as keyword hints for
* implicit skill loading.
*/
export function buildRolePrompt(role: RoleDefinition): string {
const sections: string[] = [];
@@ -18,6 +22,22 @@ export function buildRolePrompt(role: RoleDefinition): string {
sections.push(`## Capabilities\n\n${list}`);
}
const prepareLines: string[] = [
"Run the following command to load workflow CLI knowledge before starting work:",
"",
"```",
"uwf skill cli",
"```",
];
if (role.capabilities.length > 0) {
const keywords = role.capabilities.join(", ");
prepareLines.push(
"",
`You have the following capabilities: ${keywords}. Load relevant skills matching these keywords before starting work.`,
);
}
sections.push(`## Prepare\n\n${prepareLines.join("\n")}`);
if (role.procedure !== "") {
sections.push(`## Procedure\n\n${role.procedure}`);
}