Add-package helpers for repo-scaffold add-package.
Three layers, split across this package:
- :mod:
repo_scaffold.add_package.config — ProjectType enum,
AddPackageConfig dataclass, and detect_project_type for
auto-detecting the workspace type from manifest files.
- :mod:
repo_scaffold.add_package.workspace — add_rust_package and
add_uv_package implement the per-type skeleton creation, cog.toml
update, and workspace verification.
- this module —
add_package orchestrates detection and delegation.
AddPackageConfig
dataclass
AddPackageConfig(
project_path: Path, name: str, project_type: ProjectType
)
Resolved configuration for one add-package invocation.
ProjectType
Bases: Enum
Supported workspace project types.
add_package
add_package(project_path: Path, name: str) -> None
Detect the project type and delegate to the appropriate add-package logic.
| PARAMETER |
DESCRIPTION |
project_path
|
Root directory of the workspace project.
TYPE:
Path
|
name
|
Name of the new package/crate to add.
TYPE:
str
|
| RAISES |
DESCRIPTION |
ClickException
|
When no workspace is detected or the package
directory already exists.
|
Source code in repo_scaffold/add_package/__init__.py
| def add_package(project_path: Path, name: str) -> None:
"""Detect the project type and delegate to the appropriate add-package logic.
Args:
project_path: Root directory of the workspace project.
name: Name of the new package/crate to add.
Raises:
click.ClickException: When no workspace is detected or the package
directory already exists.
"""
project_type = detect_project_type(project_path)
config = AddPackageConfig(
project_path=project_path,
name=name,
project_type=project_type,
)
if project_type == ProjectType.RUST_WORKSPACE:
add_rust_package(config)
elif project_type == ProjectType.PNPM_WORKSPACE:
add_pnpm_package(config)
else:
add_uv_package(config)
|
add_pnpm_package
add_pnpm_package(config: AddPackageConfig) -> None
Add a new package to a pnpm workspace.
Steps
- Validate
packages/<name> does not already exist.
- Create
packages/<name>/package.json, vite.config.ts,
tsconfig.json, and src/index.ts.
- Append a
[packages.<name>] section to cog.toml.
- Run
pnpm install to update the lockfile.
Source code in repo_scaffold/add_package/workspace.py
| def add_pnpm_package(config: AddPackageConfig) -> None:
"""Add a new package to a pnpm workspace.
Steps:
1. Validate ``packages/<name>`` does not already exist.
2. Create ``packages/<name>/package.json``, ``vite.config.ts``,
``tsconfig.json``, and ``src/index.ts``.
3. Append a ``[packages.<name>]`` section to ``cog.toml``.
4. Run ``pnpm install`` to update the lockfile.
"""
name = config.name
project_path = config.project_path
pkg_dir = project_path / "packages" / name
if pkg_dir.exists():
raise click.ClickException(f"❌ {pkg_dir.relative_to(project_path)} already exists")
# 1. Create package skeleton
click.echo(f"Creating package '{name}' …")
pkg_dir.mkdir(parents=True, exist_ok=True)
src_dir = pkg_dir / "src"
src_dir.mkdir(exist_ok=True)
(pkg_dir / "package.json").write_text(_PNPM_PACKAGE_JSON_TEMPLATE.format(name=name), encoding="utf-8")
(pkg_dir / "vite.config.ts").write_text(_PNPM_VITE_CONFIG_TEMPLATE.format(name=name), encoding="utf-8")
(pkg_dir / "tsconfig.json").write_text(_PNPM_TSCONFIG_TEMPLATE.format(), encoding="utf-8")
(src_dir / "index.ts").write_text(_PNPM_INDEX_TS_TEMPLATE.format(name=name), encoding="utf-8")
# 2. Append cog.toml section
_append_cog_section(project_path, name, _PNPM_COG_SECTION_TEMPLATE)
# 3. Sync workspace
click.echo("Syncing workspace …")
subprocess.check_call(
["pnpm", "install"],
cwd=str(project_path),
)
click.echo(f"✅ Package '{name}' added.")
|
add_rust_package
add_rust_package(config: AddPackageConfig) -> None
Add a new crate to a cargo workspace.
Steps
- Validate
packages/<name> does not already exist.
- Create
packages/<name>/Cargo.toml and src/lib.rs.
- Append a
[packages.<name>] section to cog.toml.
- Run
cargo check to verify the workspace compiles.
Source code in repo_scaffold/add_package/workspace.py
| def add_rust_package(config: AddPackageConfig) -> None:
"""Add a new crate to a cargo workspace.
Steps:
1. Validate ``packages/<name>`` does not already exist.
2. Create ``packages/<name>/Cargo.toml`` and ``src/lib.rs``.
3. Append a ``[packages.<name>]`` section to ``cog.toml``.
4. Run ``cargo check`` to verify the workspace compiles.
"""
name = config.name
project_path = config.project_path
pkg_dir = project_path / "packages" / name
if pkg_dir.exists():
raise click.ClickException(f"❌ {pkg_dir.relative_to(project_path)} already exists")
# 1. Create package skeleton
click.echo(f"Creating crate '{name}' …")
pkg_dir.mkdir(parents=True, exist_ok=True)
src_dir = pkg_dir / "src"
src_dir.mkdir(exist_ok=True)
# Write Cargo.toml
cargo_toml = pkg_dir / "Cargo.toml"
cargo_toml.write_text(_CARGO_TOML_TEMPLATE.format(name=name), encoding="utf-8")
# Write src/lib.rs
lib_rs = src_dir / "lib.rs"
lib_rs.write_text(_LIB_RS_TEMPLATE.format(name=name), encoding="utf-8")
# 2. Append cog.toml section
_append_cog_section(project_path, name, _RUST_COG_SECTION_TEMPLATE)
# 3. Verify workspace compiles
click.echo("Checking workspace …")
result = subprocess.run(
["cargo", "check"],
cwd=str(project_path),
capture_output=True,
text=True,
)
if result.returncode != 0:
click.echo(f"⚠️ cargo check failed:\n{result.stderr}")
else:
click.echo(f"✅ Crate '{name}' added.")
click.echo("\nNext steps:")
click.echo(f" 1. Add dependencies to packages/{name}/Cargo.toml")
click.echo(f" 2. Implement your domain in packages/{name}/src/")
click.echo(" 3. Register routes in packages/api-server/src/app.rs")
|
add_uv_package
add_uv_package(config: AddPackageConfig) -> None
Add a new package to a uv workspace.
Steps
- Validate
packages/<name> does not already exist.
- Run
uv init --lib to create the package skeleton.
- Append a
[packages.<name>] section to cog.toml.
- Run
uv sync --all-packages --all-groups to update the lockfile.
Source code in repo_scaffold/add_package/workspace.py
| def add_uv_package(config: AddPackageConfig) -> None:
"""Add a new package to a uv workspace.
Steps:
1. Validate ``packages/<name>`` does not already exist.
2. Run ``uv init --lib`` to create the package skeleton.
3. Append a ``[packages.<name>]`` section to ``cog.toml``.
4. Run ``uv sync --all-packages --all-groups`` to update the lockfile.
"""
name = config.name
project_path = config.project_path
pkg_dir = project_path / "packages" / name
if pkg_dir.exists():
raise click.ClickException(f"❌ {pkg_dir.relative_to(project_path)} already exists")
# 1. Create package skeleton via uv
click.echo(f"Creating package '{name}' …")
subprocess.check_call(
["uv", "init", "--lib", "--name", name, str(pkg_dir)],
cwd=str(project_path),
)
# 2. Append cog.toml section
_append_cog_section(project_path, name, _UV_COG_SECTION_TEMPLATE)
# 3. Sync workspace
click.echo("Syncing workspace …")
subprocess.check_call(
["uv", "sync", "--all-packages", "--all-groups"],
cwd=str(project_path),
)
module = name.replace("-", "_")
click.echo(f"✅ Package '{name}' added. Module import name: {module}")
|
detect_project_type
detect_project_type(project_path: Path) -> ProjectType
Detect the workspace type from manifest files.
Resolution order
Cargo.toml with a [workspace] section → RUST_WORKSPACE
pyproject.toml with a [tool.uv.workspace] section → UV_WORKSPACE
pnpm-workspace.yaml → PNPM_WORKSPACE
- None of the above → raise
click.ClickException
| PARAMETER |
DESCRIPTION |
project_path
|
Root directory of the workspace project.
TYPE:
Path
|
| RETURNS |
DESCRIPTION |
ProjectType
|
The detected ProjectType.
|
| RAISES |
DESCRIPTION |
ClickException
|
When no recognised workspace manifest is found.
|
Source code in repo_scaffold/add_package/config.py
| def detect_project_type(project_path: Path) -> ProjectType:
"""Detect the workspace type from manifest files.
Resolution order:
1. ``Cargo.toml`` with a ``[workspace]`` section → ``RUST_WORKSPACE``
2. ``pyproject.toml`` with a ``[tool.uv.workspace]`` section → ``UV_WORKSPACE``
3. ``pnpm-workspace.yaml`` → ``PNPM_WORKSPACE``
4. None of the above → raise ``click.ClickException``
Args:
project_path: Root directory of the workspace project.
Returns:
The detected ``ProjectType``.
Raises:
click.ClickException: When no recognised workspace manifest is found.
"""
project_path = project_path.resolve()
cargo_toml = project_path / "Cargo.toml"
if cargo_toml.is_file():
with cargo_toml.open("rb") as f:
data = tomllib.load(f)
if "workspace" in data:
return ProjectType.RUST_WORKSPACE
pyproject_toml = project_path / "pyproject.toml"
if pyproject_toml.is_file():
with pyproject_toml.open("rb") as f:
data = tomllib.load(f)
if "uv" in data.get("tool", {}) and "workspace" in data["tool"]["uv"]:
return ProjectType.UV_WORKSPACE
pnpm_workspace = project_path / "pnpm-workspace.yaml"
if pnpm_workspace.is_file():
return ProjectType.PNPM_WORKSPACE
raise click.ClickException(
"No workspace detected. Expected a Cargo.toml with [workspace], "
"a pyproject.toml with [tool.uv.workspace], or a pnpm-workspace.yaml."
)
|