fix(work): dispatch CLI handoff broke after import-side-effect guard

cli.mjs's `dispatch` branch called `import("./dispatch.mjs")` and
relied on dispatch.mjs's top-level CLI block running as a side
effect of the import. The earlier guard added to dispatch.mjs (to
stop the CLI firing when sibling work scripts import
`resolveClaudeAuth`) also stopped this legit handoff — so
`pnpm work dispatch` silently exited with no output.

Fix: explicit CLI entry function, called by name. Same pattern
already in use for prd-ship + decompose.

dispatch.mjs:
  - Wraps the args parsing + print/execute branch in `export async
    function runCli(args)`
  - The invokedDirectly guard now wraps `runCli(process.argv.slice(2))`
    so direct-invocation (`node scripts/work/dispatch.mjs ...`) still
    works

cli.mjs:
  - Imports runCli as runDispatch
  - The `cmd === "dispatch"` branch calls runDispatch(args) directly
    with a .catch attached (instead of import("./dispatch.mjs"))

Verified: `pnpm work dispatch` now correctly prints the dispatch
plan for the first ready task (`binder-wrap-helper /
01-wire-use-case-helper`'s first bullet); decompose tests stay 9/9.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-13 18:17:47 +02:00
parent 6f18075593
commit bb643b8635
2 changed files with 17 additions and 9 deletions

View File

@@ -13,6 +13,7 @@ import { fileURLToPath } from "node:url";
import { buildState } from "./state-builder.mjs";
import { runCli as runPrdShip } from "./prd-ship.mjs";
import { runCli as runDecompose } from "./decompose.mjs";
import { runCli as runDispatch } from "./dispatch.mjs";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const REPO_ROOT = path.resolve(__dirname, "..", "..");
@@ -138,8 +139,8 @@ else if (cmd === "next") printNext();
else if (cmd === "ready") printReady();
else if (cmd === "blocked") printBlocked();
else if (cmd === "dispatch") {
// Re-dispatch to the dispatch script so it can handle its own --execute flag
import("./dispatch.mjs").catch((e) => {
// dispatch.mjs handles its own --execute flag
runDispatch(process.argv.slice(3)).catch((e) => {
console.error(e);
process.exit(1);
});

View File

@@ -295,15 +295,22 @@ async function executeDispatch() {
console.log("(Automatic state mutation by the orchestrator is v2.)");
}
// Only run the CLI when this module is invoked directly. Without this guard,
// importing any export (e.g. `resolveClaudeAuth` from sibling work scripts)
// triggers the CLI as a side effect.
const invokedDirectly = import.meta.url === `file://${process.argv[1]}`;
if (invokedDirectly) {
const args = process.argv.slice(2);
/**
* Explicit CLI entry. Exported so cli.mjs can dispatch into this module
* without relying on a top-level side effect (which would also fire when
* sibling work scripts import `resolveClaudeAuth`, etc.).
*/
export async function runCli(args) {
if (args.includes("--execute")) {
executeDispatch();
await executeDispatch();
} else {
printPlan();
}
}
// When invoked directly (`node scripts/work/dispatch.mjs ...`), run the CLI.
// When imported by cli.mjs or any sibling, do nothing — the caller decides.
const invokedDirectly = import.meta.url === `file://${process.argv[1]}`;
if (invokedDirectly) {
runCli(process.argv.slice(2));
}