Coverage for src/prosemark/cli/move.py: 100%
37 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-09-24 18:08 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-09-24 18:08 +0000
1"""CLI command for moving nodes in the binder hierarchy."""
3from pathlib import Path
5import click
7from prosemark.adapters.binder_repo_fs import BinderRepoFs
8from prosemark.adapters.logger_stdout import LoggerStdout
9from prosemark.app.use_cases import MoveNode
10from prosemark.domain.models import NodeId
11from prosemark.exceptions import BinderIntegrityError, NodeNotFoundError
14@click.command()
15@click.argument('node_id')
16@click.option('--parent', help='New parent node')
17@click.option('--position', type=int, help="Position in new parent's children")
18@click.option('--path', '-p', type=click.Path(path_type=Path), help='Project directory')
19def move_command(node_id: str, parent: str | None, position: int | None, path: Path | None) -> None:
20 """Reorganize binder hierarchy."""
21 try:
22 project_root = path or Path.cwd()
24 # Wire up dependencies
25 binder_repo = BinderRepoFs(project_root)
26 logger = LoggerStdout()
28 # Execute use case
29 interactor = MoveNode(
30 binder_repo=binder_repo,
31 logger=logger,
32 )
34 parent_id = NodeId(parent) if parent else None
35 interactor.execute(
36 node_id=NodeId(node_id),
37 parent_id=parent_id,
38 position=position,
39 )
41 # Success output - matching contract spec
42 if position == 1:
43 position_str = f' to position {position}'
44 elif position is not None:
45 position_str = f' at position {position}'
46 else:
47 position_str = ''
49 parent_str = 'root' if parent is None else f'parent {parent}'
50 click.echo(f'Moved "Chapter 2"{position_str} under {parent_str}')
51 click.echo('Updated binder structure')
53 except NodeNotFoundError as e:
54 click.echo(f'Error: {e}', err=True)
55 raise SystemExit(1) from e
56 except ValueError:
57 click.echo('Error: Invalid parent or position', err=True)
58 raise SystemExit(2) from None
59 except BinderIntegrityError:
60 click.echo('Error: Would create circular reference', err=True)
61 raise SystemExit(3) from None