feat(cli): help --skill command for agent-consumable docs (#69)
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { runCli } from "../src/cli-dispatch.js";
|
||||
import { formatSkillDoc } from "../src/cmd-help.js";
|
||||
|
||||
const STORAGE_ROOT = "/tmp/help-test-storage";
|
||||
|
||||
describe("help command", () => {
|
||||
test("help returns 0", async () => {
|
||||
const code = await runCli(STORAGE_ROOT, ["help"]);
|
||||
expect(code).toBe(0);
|
||||
});
|
||||
|
||||
test("help --skill returns 0", async () => {
|
||||
const code = await runCli(STORAGE_ROOT, ["help", "--skill"]);
|
||||
expect(code).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("formatSkillDoc", () => {
|
||||
const doc = formatSkillDoc();
|
||||
|
||||
test("contains title", () => {
|
||||
expect(doc).toContain("# uncaged-workflow CLI Reference");
|
||||
});
|
||||
|
||||
test("contains all command group headers", () => {
|
||||
expect(doc).toContain("### workflow");
|
||||
expect(doc).toContain("### thread");
|
||||
expect(doc).toContain("### cas");
|
||||
expect(doc).toContain("### init");
|
||||
expect(doc).toContain("### Top-level shortcuts");
|
||||
});
|
||||
|
||||
test("contains core concepts", () => {
|
||||
expect(doc).toContain("## Core Concepts");
|
||||
expect(doc).toContain("Workflow");
|
||||
expect(doc).toContain("Bundle");
|
||||
expect(doc).toContain("Thread");
|
||||
expect(doc).toContain("CAS");
|
||||
expect(doc).toContain("Registry");
|
||||
});
|
||||
|
||||
test("mentions all workflow subcommands", () => {
|
||||
for (const sub of ["add", "list", "show", "rm", "history", "rollback"]) {
|
||||
expect(doc).toContain(`workflow ${sub}`);
|
||||
}
|
||||
});
|
||||
|
||||
test("mentions all thread subcommands", () => {
|
||||
for (const sub of [
|
||||
"run",
|
||||
"list",
|
||||
"show",
|
||||
"rm",
|
||||
"fork",
|
||||
"ps",
|
||||
"kill",
|
||||
"live",
|
||||
"pause",
|
||||
"resume",
|
||||
]) {
|
||||
expect(doc).toContain(`thread ${sub}`);
|
||||
}
|
||||
});
|
||||
|
||||
test("mentions all cas subcommands", () => {
|
||||
for (const sub of ["get", "put", "list", "rm", "gc"]) {
|
||||
expect(doc).toContain(`cas ${sub}`);
|
||||
}
|
||||
});
|
||||
|
||||
test("contains exit codes section", () => {
|
||||
expect(doc).toContain("## Exit Codes");
|
||||
});
|
||||
|
||||
test("contains environment variables section", () => {
|
||||
expect(doc).toContain("## Environment Variables");
|
||||
expect(doc).toContain("UNCAGED_WORKFLOW_STORAGE_ROOT");
|
||||
});
|
||||
|
||||
test("contains typical workflow section", () => {
|
||||
expect(doc).toContain("## Typical Workflow");
|
||||
});
|
||||
});
|
||||
@@ -3,6 +3,7 @@ import { cmdAdd, formatAddSuccess, parseAddArgv } from "./cmd-add.js";
|
||||
import { cmdCasGet, cmdCasList, cmdCasPut, cmdCasRm } from "./cmd-cas.js";
|
||||
import { cmdFork, parseForkArgv } from "./cmd-fork.js";
|
||||
import { cmdGc } from "./cmd-gc.js";
|
||||
import { formatSkillDoc } from "./cmd-help.js";
|
||||
import { cmdHistory } from "./cmd-history.js";
|
||||
import { cmdInitTemplate, cmdInitWorkspace } from "./cmd-init.js";
|
||||
import { cmdKill } from "./cmd-kill.js";
|
||||
@@ -501,6 +502,17 @@ async function dispatchThread(storageRoot: string, argv: string[]): Promise<numb
|
||||
return handler(storageRoot, argv.slice(1));
|
||||
}
|
||||
|
||||
// ── Help ────────────────────────────────────────────────────────────────
|
||||
|
||||
async function dispatchHelp(_storageRoot: string, argv: string[]): Promise<number> {
|
||||
if (argv.includes("--skill")) {
|
||||
printCliLine(formatSkillDoc());
|
||||
} else {
|
||||
printCliLine(formatCliUsage());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ── Top-level command table (Phase 3) ──────────────────────────────────
|
||||
|
||||
const COMMAND_TABLE: Record<string, DispatchFn> = {
|
||||
@@ -509,6 +521,7 @@ const COMMAND_TABLE: Record<string, DispatchFn> = {
|
||||
thread: dispatchThread,
|
||||
cas: dispatchCas,
|
||||
init: dispatchInit,
|
||||
help: dispatchHelp,
|
||||
|
||||
// Top-level shortcuts (no deprecation)
|
||||
run: dispatchRun,
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
export function formatSkillDoc(): string {
|
||||
return `# uncaged-workflow CLI Reference
|
||||
|
||||
## Core Concepts
|
||||
|
||||
| Concept | Description |
|
||||
|---------|-------------|
|
||||
| **Workflow** | A single-file ESM bundle (\`.esm.js\`) that exports \`run\` and \`descriptor\`. Identified by name and XXH64 hash. |
|
||||
| **Bundle** | The physical \`.esm.js\` file stored in the bundles directory. Immutable once written. |
|
||||
| **Thread** | A single execution of a workflow, identified by a ULID. Persists state as JSONL files. |
|
||||
| **CAS** | Content-Addressable Storage. Per-thread key-value store keyed by content hash. |
|
||||
| **Registry** | \`workflow.yaml\` — maps workflow names to their current and historical bundle hashes. |
|
||||
|
||||
## Commands
|
||||
|
||||
### workflow
|
||||
|
||||
| Command | Args | Description |
|
||||
|---------|------|-------------|
|
||||
| \`workflow add\` | \`<name> <file.esm.js> [--types <path>]\` | Register a workflow bundle in the registry |
|
||||
| \`workflow list\` | (none) | List all registered workflows |
|
||||
| \`workflow show\` | \`<name>\` | Show details of a registered workflow |
|
||||
| \`workflow rm\` | \`<name>\` | Remove a workflow from the registry |
|
||||
| \`workflow history\` | \`<name>\` | Show version history of a workflow |
|
||||
| \`workflow rollback\` | \`<name> [hash]\` | Rollback a workflow to a previous version |
|
||||
|
||||
### thread
|
||||
|
||||
| Command | Args | Description |
|
||||
|---------|------|-------------|
|
||||
| \`thread run\` | \`<name> [--prompt <text>] [--max-rounds N]\` | Start a new thread executing a workflow |
|
||||
| \`thread list\` | \`[name]\` | List threads, optionally filtered by workflow name |
|
||||
| \`thread show\` | \`<id>\` | Show thread details and state |
|
||||
| \`thread rm\` | \`<id>\` | Remove a thread |
|
||||
| \`thread fork\` | \`<thread-id> [--from-role <role>]\` | Fork a thread, optionally from a specific role |
|
||||
| \`thread ps\` | (none) | List running threads |
|
||||
| \`thread kill\` | \`<thread-id>\` | Kill a running thread |
|
||||
| \`thread live\` | \`<thread-id> [--debug] [--role <name>]\` or \`--latest [--debug] [--role <name>]\` | Attach to a thread and stream output live |
|
||||
| \`thread pause\` | \`<thread-id>\` | Pause a running thread |
|
||||
| \`thread resume\` | \`<thread-id>\` | Resume a paused thread |
|
||||
|
||||
### cas
|
||||
|
||||
| Command | Args | Description |
|
||||
|---------|------|-------------|
|
||||
| \`cas get\` | \`<thread-id> <hash>\` | Retrieve content by hash from a thread's CAS |
|
||||
| \`cas put\` | \`<thread-id> <content>\` | Store content in a thread's CAS, returns hash |
|
||||
| \`cas list\` | \`<thread-id>\` | List all CAS entries for a thread |
|
||||
| \`cas rm\` | \`<thread-id> <hash>\` | Remove a CAS entry |
|
||||
| \`cas gc\` | (none) | Garbage-collect unreferenced CAS entries |
|
||||
|
||||
### init
|
||||
|
||||
| Command | Args | Description |
|
||||
|---------|------|-------------|
|
||||
| \`init workspace\` | \`<name>\` | Initialize a new workflow workspace |
|
||||
| \`init template\` | \`<name>\` | Initialize a new workflow template |
|
||||
|
||||
### Top-level shortcuts
|
||||
|
||||
| Command | Equivalent | Description |
|
||||
|---------|------------|-------------|
|
||||
| \`run\` | \`thread run\` | Shortcut to start a thread |
|
||||
| \`live\` | \`thread live\` | Shortcut to attach to a thread |
|
||||
|
||||
## Typical Workflow
|
||||
|
||||
1. \`uncaged-workflow workflow add my-wf ./my-wf.esm.js\` — register a workflow
|
||||
2. \`uncaged-workflow run my-wf --prompt "do the thing"\` — start a thread
|
||||
3. \`uncaged-workflow live --latest\` — attach and watch output
|
||||
4. \`uncaged-workflow thread show <thread-id>\` — inspect completed thread
|
||||
|
||||
## Exit Codes
|
||||
|
||||
| Code | Meaning |
|
||||
|------|---------|
|
||||
| 0 | Success |
|
||||
| 1 | Error |
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| \`UNCAGED_WORKFLOW_STORAGE_ROOT\` | Override the default storage directory for all workflow data |
|
||||
`;
|
||||
}
|
||||
Reference in New Issue
Block a user