diff --git a/docs/us-cpa.md b/docs/us-cpa.md index 1a6cdcb..7eb7a0e 100644 --- a/docs/us-cpa.md +++ b/docs/us-cpa.md @@ -17,6 +17,35 @@ Without installing, the repo-local wrapper works directly: skills/us-cpa/scripts/us-cpa --help ``` +## OpenClaw installation + +To install the skill for OpenClaw itself, copy the repo skill into the workspace skill directory and install its Python dependencies there. + +1. Sync the repo copy into the workspace: + +```bash +rsync -a --delete \ + /Users/stefano/.openclaw/workspace/projects/stef-openclaw-skills/skills/us-cpa/ \ + /Users/stefano/.openclaw/workspace/skills/us-cpa/ +``` + +2. Create a workspace-local virtualenv and install the package: + +```bash +cd /Users/stefano/.openclaw/workspace/skills/us-cpa +python3 -m venv .venv +. .venv/bin/activate +pip install -e .[dev] +``` + +3. Verify the installed workspace wrapper: + +```bash +~/.openclaw/workspace/skills/us-cpa/scripts/us-cpa --help +``` + +The wrapper prefers `.venv/bin/python` inside the skill directory when present, so OpenClaw can run the workspace copy without relying on global Python packages. + ## Current Milestone Current implementation now includes: diff --git a/skills/us-cpa/README.md b/skills/us-cpa/README.md index 54a3140..d9512a6 100644 --- a/skills/us-cpa/README.md +++ b/skills/us-cpa/README.md @@ -10,6 +10,35 @@ From `skills/us-cpa/`: pip install -e .[dev] ``` +## OpenClaw installation + +Install the skill into the OpenClaw workspace copy, not only in the repo checkout. + +1. Sync the skill into the workspace: + +```bash +rsync -a --delete \ + /Users/stefano/.openclaw/workspace/projects/stef-openclaw-skills/skills/us-cpa/ \ + /Users/stefano/.openclaw/workspace/skills/us-cpa/ +``` + +2. Create a skill-local virtualenv in the workspace copy: + +```bash +cd /Users/stefano/.openclaw/workspace/skills/us-cpa +python3 -m venv .venv +. .venv/bin/activate +pip install -e .[dev] +``` + +3. Run the workspace wrapper: + +```bash +~/.openclaw/workspace/skills/us-cpa/scripts/us-cpa --help +``` + +The wrapper now prefers `~/.openclaw/workspace/skills/us-cpa/.venv/bin/python` when present and falls back to `python3` otherwise. + ## Run Installed entry point: @@ -24,6 +53,12 @@ Repo-local wrapper without installation: scripts/us-cpa --help ``` +OpenClaw workspace wrapper: + +```bash +~/.openclaw/workspace/skills/us-cpa/scripts/us-cpa --help +``` + Module execution: ```bash diff --git a/skills/us-cpa/SKILL.md b/skills/us-cpa/SKILL.md index 010a6e4..8feccd7 100644 --- a/skills/us-cpa/SKILL.md +++ b/skills/us-cpa/SKILL.md @@ -40,6 +40,12 @@ skills/us-cpa/scripts/us-cpa review --tax-year 2025 --case-dir ~/tax-cases/2025- skills/us-cpa/scripts/us-cpa extract-docs --tax-year 2025 --case-dir ~/tax-cases/2025-jane-doe --create-case --case-label "Jane Doe" --facts-json ./facts.json ``` +When OpenClaw is using the installed workspace copy, the entrypoint is: + +```bash +~/.openclaw/workspace/skills/us-cpa/scripts/us-cpa --help +``` + ## Rules - federal individual returns only in v1 diff --git a/skills/us-cpa/scripts/us-cpa b/skills/us-cpa/scripts/us-cpa index fbcef77..01fb0bd 100755 --- a/skills/us-cpa/scripts/us-cpa +++ b/skills/us-cpa/scripts/us-cpa @@ -3,6 +3,11 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SKILL_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" +PYTHON_BIN="${SKILL_DIR}/.venv/bin/python" export PYTHONPATH="${SKILL_DIR}/src${PYTHONPATH:+:${PYTHONPATH}}" -exec python3 -m us_cpa.cli "$@" +if [[ ! -x "${PYTHON_BIN}" ]]; then + PYTHON_BIN="python3" +fi + +exec "${PYTHON_BIN}" -m us_cpa.cli "$@" diff --git a/skills/us-cpa/tests/test_cli.py b/skills/us-cpa/tests/test_cli.py index da341f0..4a2416d 100644 --- a/skills/us-cpa/tests/test_cli.py +++ b/skills/us-cpa/tests/test_cli.py @@ -40,6 +40,23 @@ class UsCpaCliSmokeTests(unittest.TestCase): self.assertIn("scripts/us-cpa", readme) self.assertIn("python -m unittest", readme) + def test_docs_explain_openclaw_installation_flow(self) -> None: + readme = (SKILL_DIR / "README.md").read_text() + operator_doc = (SKILL_DIR.parent.parent / "docs" / "us-cpa.md").read_text() + skill_doc = (SKILL_DIR / "SKILL.md").read_text() + + self.assertIn("OpenClaw installation", readme) + self.assertIn("~/.openclaw/workspace/skills/us-cpa", readme) + self.assertIn(".venv/bin/python", readme) + self.assertIn("OpenClaw installation", operator_doc) + self.assertIn("rsync -a --delete", operator_doc) + self.assertIn("~/.openclaw/workspace/skills/us-cpa/scripts/us-cpa", skill_doc) + + def test_wrapper_prefers_local_virtualenv_python(self) -> None: + wrapper = (SKILL_DIR / "scripts" / "us-cpa").read_text() + self.assertIn('.venv/bin/python', wrapper) + self.assertIn('PYTHON_BIN', wrapper) + def test_fixture_directories_exist(self) -> None: fixtures_dir = SKILL_DIR / "tests" / "fixtures" for name in ("irs", "facts", "documents", "returns"):