Repository navigation
Description
Scope / evidence
Audit of the framework's own examples/audiobook-curator at 72a8857ebe968636ac44dfc7ce4eba30664a8445. This is not ScriptedAlchemy/audiobook-curator, the separate Python plugin. Source review only; no local test run.
The framework already implements CLI surface projections (#596/#616), but its flagship example still teaches a second executable route for an identical operation.
Concrete pair
- src/cli/audible-search.tsx owns another input schema, renames duration/regions, invokes
audibleOperations.audibleSearch.handler, and rendersAgent.Result,audibleSearchHeadlineandSearchRanking. - src/mcp/curator/tools/search_audible.tsx invokes the same operation and produces the same rendered receipt.
Sharing a domain handler is good, but it does not justify duplicating the input/execution/render boundary the framework can already project.
Existing replacement
Use an adjacent search_audible.cli.ts with CliProjectionConfig, explicit command/flag aliases, projection defaults, exitCode and mapInput where needed. The actual projection contract already supports these declarations; a projection is not another route.
Work / deletion requirements
- Inventory the example's
src/cli/*againstsrc/mcp/curator/tools/*. Classify exact operation aliases separately from genuinely independent/aggregate CLI workflows. - Convert equivalent pairs to canonical tool projections, starting with the verified Audible search pair. Delete the replaced standalone route, duplicate canonical fields and render body in the same change.
- Preserve existing CLI names, argument spellings, CSV/array input behavior, defaults, required fields, exit codes and confirmation policy through explicit projection metadata/mapping.
- Keep
audibleOperations, identity resolution, media auditing and conversion logic as ordinary domain functions. Do not create a second operation registry to replace the old CLI files. - If an existing CLI grammar genuinely cannot be expressed without semantic change, capture the smallest framework limitation with a failing fixture; do not silently drop the flag or claim all CLI routes must be MCP tools.
- Update example docs, route-count/identity expectations and Workbench links to operation + CLI surface instead of duplicated
cli:*identity.
Acceptance
Exercise the same domain input through invokeCli/installed generated bin and invokeMcpTool/packed stdio. Verify one domain invocation, equivalent structured result and intended rendered text, correct progress/cancellation, and no duplicate side effects. Cover --duration, region-list mapping, represented failure/exitCode, defaulted/omitted input, unknown options, and confirmation for any migrated mutation command.
Use deterministic local domain fixtures for the projection parity test; a live Audible outage must not prevent testing the compiler contract. Keep separate labelled external-service acceptance. Run the example from a relocated/source-free built artifact as well as the route harness.
Boundaries
This is example adoption, not a request to reimplement #616, manufacture an MCP endpoint for every CLI task, collapse application-specific render components, or remove useful domain helpers. Preserve the existing public-export-only rule for user-facing examples.
Activity
refactor(audiobook-curator): ship the CLI as <tool>.cli.ts projection…
refactor(audiobook-curator): ship the CLI as <tool>.cli.ts projection…
docs(audiobook-curator): inventory --report and convert --receipt are…