This repository has been archived on 2026-06-08. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
workflow/packages/cli-workflow/src/__tests__/thread-step-count.test.ts
T
xiaoju 7b50969307 refactor(cli): reorganize CLI commands into four-layer model (#463)
Implement comprehensive CLI refactoring to clarify the four-layer model:
workflow → thread → step → turn

## Breaking Changes

### Renamed Commands
- `uwf workflow put` → `uwf workflow add`
- `uwf thread step` → `uwf thread exec`

### Removed Commands
- `uwf thread running` (merged into `thread list --status running`)
- `uwf thread kill` (split into `thread stop` and `thread cancel`)

### Moved Commands
- `uwf thread steps` → `uwf step list`
- `uwf thread step-details` → `uwf step show`
- `uwf thread fork` → `uwf step fork`

## New Commands

### Thread Commands
- `uwf thread list --status <idle|running|completed>` - Filter threads by status
- `uwf thread stop <thread-id>` - Stop background execution (keep thread active)
- `uwf thread cancel <thread-id>` - Cancel thread (stop + archive to history)

### Step Command Group (New)
- `uwf step list <thread-id>` - List all steps in a thread
- `uwf step show <step-hash>` - Show step details
- `uwf step read <step-hash> [--before N]` - Read step output as markdown
- `uwf step fork <step-hash>` - Fork thread from a step

## Implementation Details

### Files Modified
- `packages/cli-workflow/src/commands/workflow.ts` - Renamed cmdWorkflowPut → cmdWorkflowAdd
- `packages/cli-workflow/src/commands/thread.ts`:
  - Renamed cmdThreadStep → cmdThreadExec
  - Added cmdThreadStop and cmdThreadCancel (split from cmdThreadKill)
  - Updated cmdThreadList to support --status filter with idle/running/completed
  - Removed cmdThreadSteps, cmdThreadStepDetails, cmdThreadFork
- `packages/cli-workflow/src/commands/step.ts` - New module with:
  - cmdStepList (moved from cmdThreadSteps)
  - cmdStepShow (moved from cmdThreadStepDetails)
  - cmdStepFork (moved from cmdThreadFork)
  - cmdStepRead (new, stub implementation pending #462)
- `packages/cli-workflow/src/cli.ts` - Updated all CLI command registrations

### Tests Updated
- `packages/cli-workflow/src/__tests__/thread-step-count.test.ts` - Updated references from "thread step" to "thread exec"
- `packages/cli-workflow/src/__tests__/thread.test.ts` - Updated imports to use cmdStepShow from step.ts

## Test Results
All 124 tests pass in cli-workflow package.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-05-24 10:40:32 +00:00

72 lines
2.7 KiB
TypeScript

import { execFileSync } from "node:child_process";
import { join } from "node:path";
import { describe, expect, test } from "vitest";
const CLI_PATH = join(import.meta.dirname, "..", "cli.js");
function runCli(args: string[]): { stdout: string; stderr: string; exitCode: number } {
try {
const stdout = execFileSync("bun", ["run", CLI_PATH, ...args], {
encoding: "utf8",
env: { ...process.env, WORKFLOW_STORAGE_ROOT: "/tmp/uwf-test-nonexistent" },
stdio: ["ignore", "pipe", "pipe"],
});
return { stdout, stderr: "", exitCode: 0 };
} catch (e: unknown) {
const err = e as NodeJS.ErrnoException & { stdout?: string; stderr?: string; status?: number };
return {
stdout: err.stdout ?? "",
stderr: err.stderr ?? "",
exitCode: err.status ?? 1,
};
}
}
describe("thread exec --count CLI parsing", () => {
test("--help shows -c/--count option", () => {
const result = runCli(["thread", "exec", "--help"]);
expect(result.stdout).toContain("--count");
expect(result.stdout).toContain("-c");
});
test("description says 'one or more steps'", () => {
const result = runCli(["thread", "exec", "--help"]);
expect(result.stdout).toContain("one or more steps");
});
});
describe("cmdThreadExec count logic", () => {
test("count=0 fails with validation error", () => {
const result = runCli(["thread", "exec", "FAKE_THREAD_ID", "-c", "0"]);
expect(result.exitCode).not.toBe(0);
expect(result.stderr).toContain("positive integer");
});
test("negative count fails with validation error", () => {
const result = runCli(["thread", "exec", "FAKE_THREAD_ID", "-c", "-1"]);
expect(result.exitCode).not.toBe(0);
expect(result.stderr).toContain("positive integer");
});
test("non-integer count fails with validation error", () => {
const result = runCli(["thread", "exec", "FAKE_THREAD_ID", "-c", "1.5"]);
expect(result.exitCode).not.toBe(0);
expect(result.stderr).toContain("positive integer");
});
test("count=1 is the default (no -c flag)", () => {
// Without -c, it should attempt to run 1 step (failing on missing thread, not on count validation)
const result = runCli(["thread", "exec", "FAKE_THREAD_ID"]);
expect(result.exitCode).not.toBe(0);
// Should NOT contain "positive integer" error — should fail on thread lookup instead
expect(result.stderr).not.toContain("positive integer");
});
test("count=3 passes validation (fails on thread lookup)", () => {
const result = runCli(["thread", "exec", "FAKE_THREAD_ID", "-c", "3"]);
expect(result.exitCode).not.toBe(0);
// Should NOT contain "positive integer" error — should fail on thread/storage lookup
expect(result.stderr).not.toContain("positive integer");
});
});