From eb263596124dea587630d25ea287a084b44f2191 Mon Sep 17 00:00:00 2001 From: tully-8888 <60903950+tully-8888@users.noreply.github.com> Date: Tue, 9 Jun 2026 18:35:49 +0000 Subject: [PATCH] fix: dispatch ulw-loop component subcommands --- plugins/omo/components/ulw-loop/src/cli.ts | 18 +++++++++- .../ulw-loop/test/cli-entrypoint.test.ts | 36 +++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 plugins/omo/components/ulw-loop/test/cli-entrypoint.test.ts diff --git a/plugins/omo/components/ulw-loop/src/cli.ts b/plugins/omo/components/ulw-loop/src/cli.ts index ed9d5fd..4e65d63 100644 --- a/plugins/omo/components/ulw-loop/src/cli.ts +++ b/plugins/omo/components/ulw-loop/src/cli.ts @@ -5,14 +5,30 @@ import { runPreToolUseGoalBudgetGuardCli, runUlwLoopHookCli } from "./codex-hook const TOP_LEVEL_HELP = "Usage:\n omo ulw-loop [args]\n omo hook user-prompt-submit (Codex UserPromptSubmit hook)\n omo help | --help | -h (this message)\n\nRun `omo ulw-loop help` for ulw-loop subcommands.\n"; +const ULW_LOOP_DIRECT_COMMANDS = new Set([ + "help", + "--help", + "-h", + "create-goals", + "status", + "complete-goals", + "checkpoint", + "steer", + "add-goal", + "criteria", + "record-evidence", + "record-review-blockers", +]); + async function main(): Promise { const argv = process.argv.slice(2); const command = argv[0]; - if (command === undefined || command === "help" || command === "--help" || command === "-h") { + if (command === undefined) { process.stdout.write(TOP_LEVEL_HELP); return 0; } if (command === "ulw-loop") return ulwLoopCommand(argv.slice(1)); + if (ULW_LOOP_DIRECT_COMMANDS.has(command)) return ulwLoopCommand(argv); if (command === "hook") { const sub = argv[1]; if (sub === "user-prompt-submit") { diff --git a/plugins/omo/components/ulw-loop/test/cli-entrypoint.test.ts b/plugins/omo/components/ulw-loop/test/cli-entrypoint.test.ts new file mode 100644 index 0000000..2bdaef8 --- /dev/null +++ b/plugins/omo/components/ulw-loop/test/cli-entrypoint.test.ts @@ -0,0 +1,36 @@ +import { execFile } from "node:child_process"; +import { mkdtemp, rm } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join, resolve } from "node:path"; +import { promisify } from "node:util"; +import { afterAll, beforeAll, describe, expect, it } from "vitest"; + +const execFileAsync = promisify(execFile); +const repoRoot = resolve(import.meta.dirname, ".."); +let qaRoot = ""; + +beforeAll(async () => { + await execFileAsync("npm", ["run", "build"], { cwd: repoRoot }); + qaRoot = await mkdtemp(join(tmpdir(), "omo-ulw-loop-cli-entrypoint-")); +}); + +afterAll(async () => { + if (qaRoot) await rm(qaRoot, { recursive: true, force: true }); +}); + +describe("dist/cli.js component entrypoint", () => { + it("dispatches direct subcommands when invoked as omo-ulw-loop", async () => { + const cliPath = join(repoRoot, "dist", "cli.js"); + const result = await execFileAsync(process.execPath, [cliPath, "status", "--json"], { cwd: qaRoot }).catch( + (error: unknown) => { + if (error instanceof Error && "stderr" in error && "stdout" in error) { + return error as Error & { readonly stdout: string; readonly stderr: string }; + } + throw error; + }, + ); + + expect(result.stderr).toContain("[ulw-loop] No ulw-loop plan found"); + expect(result.stderr).not.toContain("[omo] unknown command: status"); + }); +});