wealthbox-cli 2.0.0__tar.gz → 2.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/.github/workflows/ci.yml +15 -16
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/.github/workflows/docs.yml +5 -4
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/CHANGELOG.md +58 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/CONTRIBUTING.md +22 -14
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/PKG-INFO +1 -2
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/SECURITY.md +1 -1
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/docs/getting-started.md +1 -7
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/mkdocs.yml +1 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/pyproject.toml +1 -3
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/cli/_util.py +2 -10
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/cli/doctor.py +3 -11
- wealthbox_cli-2.2.0/src/wealthbox_tools/cli/me.py +68 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/cli/skills.py +1 -1
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/cli/users.py +1 -1
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/skills/wealthbox-crm/SKILL.md +1 -1
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/skills/wealthbox-crm/references/contacts.md +1 -1
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/skills/wealthbox-crm/references/lookups.md +29 -1
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/skills/wealthbox-crm/references/tasks.md +1 -1
- wealthbox_cli-2.2.0/uv.lock +635 -0
- wealthbox_cli-2.0.0/.env.example +0 -2
- wealthbox_cli-2.0.0/src/wealthbox_tools/cli/me.py +0 -25
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/.github/workflows/release-binaries.yml +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/.gitignore +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/LICENSE +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/README.md +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/docs/agents/domain.md +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/docs/agents/issue-tracker.md +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/docs/agents/triage-labels.md +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/docs/cli-reference.md +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/docs/index.md +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/docs/overrides/main.html +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/docs/promotion.md +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/__init__.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/cli/__init__.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/cli/_config.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/cli/_skill_bootstrap.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/cli/_skill_paths.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/cli/_skill_platforms.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/cli/activity.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/cli/categories.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/cli/config.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/cli/contacts.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/cli/events.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/cli/firm.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/cli/households.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/cli/internals.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/cli/main.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/cli/notes.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/cli/opportunities.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/cli/prefs.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/cli/projects.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/cli/self_cmd.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/cli/tasks.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/cli/workflows.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/client/__init__.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/client/activity.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/client/base.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/client/categories.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/client/comments.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/client/contacts.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/client/events.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/client/households.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/client/me.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/client/notes.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/client/opportunities.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/client/projects.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/client/tasks.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/client/users.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/client/workflows.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/firm/__init__.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/firm/archive.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/firm/diff.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/internals/__init__.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/internals/skill_ref_gen.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/models/__init__.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/models/activity.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/models/comments.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/models/common.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/models/contacts.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/models/custom_fields.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/models/enums.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/models/events.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/models/households.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/models/notes.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/models/opportunities.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/models/projects.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/models/tasks.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/models/workflows.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/py.typed +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/self_upgrade.py +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/skills/wealthbox-crm/bootstrap.md +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/contacts.md +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/events.md +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/notes.md +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/opportunities.md +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/projects.md +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/tasks.md +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/workflows.md +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/skills/wealthbox-crm/references/events.md +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/skills/wealthbox-crm/references/households.md +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/skills/wealthbox-crm/references/notes.md +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/skills/wealthbox-crm/references/opportunities.md +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/skills/wealthbox-crm/references/projects.md +0 -0
- {wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/skills/wealthbox-crm/references/workflows.md +0 -0
|
@@ -11,12 +11,12 @@ jobs:
|
|
|
11
11
|
lint:
|
|
12
12
|
runs-on: ubuntu-latest
|
|
13
13
|
steps:
|
|
14
|
-
- uses: actions/checkout@
|
|
15
|
-
- uses:
|
|
14
|
+
- uses: actions/checkout@v6
|
|
15
|
+
- uses: astral-sh/setup-uv@v8.1.0
|
|
16
16
|
with:
|
|
17
17
|
python-version: "3.12"
|
|
18
|
-
- run:
|
|
19
|
-
- run: ruff check src/ tests/
|
|
18
|
+
- run: uv sync --extra dev
|
|
19
|
+
- run: uv run ruff check src/ tests/
|
|
20
20
|
|
|
21
21
|
test:
|
|
22
22
|
runs-on: ubuntu-latest
|
|
@@ -24,23 +24,23 @@ jobs:
|
|
|
24
24
|
matrix:
|
|
25
25
|
python-version: ["3.11", "3.12", "3.13"]
|
|
26
26
|
steps:
|
|
27
|
-
- uses: actions/checkout@
|
|
28
|
-
- uses:
|
|
27
|
+
- uses: actions/checkout@v6
|
|
28
|
+
- uses: astral-sh/setup-uv@v8.1.0
|
|
29
29
|
with:
|
|
30
30
|
python-version: ${{ matrix.python-version }}
|
|
31
|
-
- run:
|
|
32
|
-
- run: pytest
|
|
31
|
+
- run: uv sync --extra dev
|
|
32
|
+
- run: uv run pytest
|
|
33
33
|
|
|
34
34
|
skill-ref-drift:
|
|
35
35
|
needs: [lint, test]
|
|
36
36
|
runs-on: ubuntu-latest
|
|
37
37
|
steps:
|
|
38
|
-
- uses: actions/checkout@
|
|
39
|
-
- uses:
|
|
38
|
+
- uses: actions/checkout@v6
|
|
39
|
+
- uses: astral-sh/setup-uv@v8.1.0
|
|
40
40
|
with:
|
|
41
41
|
python-version: "3.12"
|
|
42
|
-
- run:
|
|
43
|
-
- run: wbox internals regen-skill-refs
|
|
42
|
+
- run: uv sync --extra dev
|
|
43
|
+
- run: uv run wbox internals regen-skill-refs
|
|
44
44
|
- run: git diff --exit-code -- src/wealthbox_tools/skills/wealthbox-crm/references/
|
|
45
45
|
|
|
46
46
|
publish:
|
|
@@ -51,10 +51,9 @@ jobs:
|
|
|
51
51
|
id-token: write
|
|
52
52
|
environment: pypi
|
|
53
53
|
steps:
|
|
54
|
-
- uses: actions/checkout@
|
|
55
|
-
- uses:
|
|
54
|
+
- uses: actions/checkout@v6
|
|
55
|
+
- uses: astral-sh/setup-uv@v8.1.0
|
|
56
56
|
with:
|
|
57
57
|
python-version: "3.12"
|
|
58
|
-
- run:
|
|
59
|
-
- run: python -m build
|
|
58
|
+
- run: uv build
|
|
60
59
|
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -18,14 +18,15 @@ jobs:
|
|
|
18
18
|
build:
|
|
19
19
|
runs-on: ubuntu-latest
|
|
20
20
|
steps:
|
|
21
|
-
- uses: actions/checkout@
|
|
22
|
-
- uses: actions/setup-python@
|
|
21
|
+
- uses: actions/checkout@v6
|
|
22
|
+
- uses: actions/setup-python@v6
|
|
23
23
|
with:
|
|
24
24
|
python-version: "3.12"
|
|
25
25
|
- run: pip install mkdocs-material
|
|
26
26
|
- run: cp CONTRIBUTING.md docs/contributing.md
|
|
27
|
+
- run: cp CHANGELOG.md docs/changelog.md
|
|
27
28
|
- run: mkdocs build --strict
|
|
28
|
-
- uses: actions/upload-pages-artifact@
|
|
29
|
+
- uses: actions/upload-pages-artifact@v5
|
|
29
30
|
with:
|
|
30
31
|
path: site/
|
|
31
32
|
|
|
@@ -37,4 +38,4 @@ jobs:
|
|
|
37
38
|
url: ${{ steps.deployment.outputs.page_url }}
|
|
38
39
|
steps:
|
|
39
40
|
- id: deployment
|
|
40
|
-
uses: actions/deploy-pages@
|
|
41
|
+
uses: actions/deploy-pages@v5
|
|
@@ -4,6 +4,64 @@ All notable changes to `wealthbox-cli` are documented here. The format follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
|
|
5
5
|
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [2.2.0] - 2026-05-13
|
|
8
|
+
|
|
9
|
+
Small feature + correctness release. Disambiguates the two IDs returned by
|
|
10
|
+
`wbox me`, fixes a silent truncation in `wbox users list` on large firms, and
|
|
11
|
+
clears Node 20 deprecation warnings from CI ahead of GitHub's June 2026 cutoff.
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
- `wbox me user-id` — prints `current_user.id` (the workspace user ID accepted
|
|
15
|
+
by `--assigned-to`) as a bare integer, for composing with command
|
|
16
|
+
substitution: `wbox tasks list --assigned-to "$(wbox me user-id)"` (#90, #91).
|
|
17
|
+
- `wbox me --format table` now labels the two IDs as `login_id` and
|
|
18
|
+
`user_id (--assigned-to)` so they aren't confusable at a glance. The JSON
|
|
19
|
+
shape is unchanged — no breaking change for existing scripts (#91).
|
|
20
|
+
- Skill docs (`lookups.md`, `tasks.md`, `contacts.md`) flag the two-ID trap
|
|
21
|
+
inline near `--assigned-to`.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
- `wbox users list` now paginates across all pages. Previously, firms with
|
|
25
|
+
more than 25 users silently saw a truncated list — the CLI exposes no
|
|
26
|
+
`--page` flag, so there was no manual workaround.
|
|
27
|
+
- mkdocs docs deploy was failing on every main push because `docs/index.md`
|
|
28
|
+
linked to a missing `changelog.md`. `CHANGELOG.md` is now staged into
|
|
29
|
+
`docs/` at build time and listed in nav (#92).
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
- CI actions bumped to Node 24 runtimes ahead of GitHub's June 2 2026 cutoff:
|
|
33
|
+
`actions/checkout` v4→v6, `astral-sh/setup-uv` v6→v8.1.0 (pinned exact —
|
|
34
|
+
setup-uv v8+ no longer publishes rolling major tags as a supply-chain
|
|
35
|
+
mitigation), `actions/setup-python` v5→v6, `actions/deploy-pages` v4→v5,
|
|
36
|
+
`actions/upload-pages-artifact` v3→v5 (#92, #93).
|
|
37
|
+
|
|
38
|
+
## [2.1.0] - 2026-05-09
|
|
39
|
+
|
|
40
|
+
Repository simplification release. Drops a runtime dep, retires `.env` support,
|
|
41
|
+
and switches dev tooling to [uv](https://docs.astral.sh/uv/).
|
|
42
|
+
|
|
43
|
+
### Breaking
|
|
44
|
+
- **Removed `.env` file support.** Token resolution is now a 3-tier chain:
|
|
45
|
+
`--token` flag → `WEALTHBOX_TOKEN` env var → config file. Users relying on a
|
|
46
|
+
working-directory `.env` should migrate to `wbox config set-token` (preferred)
|
|
47
|
+
or export `WEALTHBOX_TOKEN` in their shell. The `python-dotenv` runtime
|
|
48
|
+
dependency was dropped.
|
|
49
|
+
|
|
50
|
+
### Changed
|
|
51
|
+
- Development tooling moved to [uv](https://docs.astral.sh/uv/). `uv sync
|
|
52
|
+
--extra dev` replaces the manual `python -m venv` + activate + `pip install
|
|
53
|
+
-e` dance, and `uv run wbox …` replaces direct `.venv/bin/wbox` invocation.
|
|
54
|
+
CI now uses `astral-sh/setup-uv@v6` and `uv build` for the publish job. Plain
|
|
55
|
+
`pip install -e ".[dev]"` continues to work — `pyproject.toml` is the source
|
|
56
|
+
of truth for both tools.
|
|
57
|
+
- `scripts/run-wbox.sh` and `scripts/smoke_test.sh` invoke via `uv run` and no
|
|
58
|
+
longer source a `.env` file.
|
|
59
|
+
|
|
60
|
+
### Removed
|
|
61
|
+
- `.env` and `.env.example` files at the repo root.
|
|
62
|
+
- `.python-version` file. `requires-python = ">=3.11"` in `pyproject.toml` is
|
|
63
|
+
the authoritative interpreter constraint; uv reads it directly.
|
|
64
|
+
|
|
7
65
|
## [2.0.0] - 2026-05-09
|
|
8
66
|
|
|
9
67
|
v2 retires the Claude marketplace plugin distribution and ships `wbox` as a
|
|
@@ -6,38 +6,46 @@ Thank you for your interest in contributing to **wealthbox-cli**!
|
|
|
6
6
|
|
|
7
7
|
## Development Setup
|
|
8
8
|
|
|
9
|
+
This project uses [uv](https://docs.astral.sh/uv/) for dependency management. Install it first if you don't have it:
|
|
10
|
+
|
|
9
11
|
```bash
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
# macOS / Linux
|
|
13
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
14
|
+
|
|
15
|
+
# Windows (PowerShell)
|
|
16
|
+
irm https://astral.sh/uv/install.ps1 | iex
|
|
13
17
|
```
|
|
14
18
|
|
|
15
|
-
|
|
19
|
+
Then clone and sync:
|
|
16
20
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
```bash
|
|
22
|
+
git clone https://github.com/massive-value/wealthbox-cli
|
|
23
|
+
cd wealthbox-cli
|
|
24
|
+
uv sync --extra dev
|
|
25
|
+
```
|
|
22
26
|
|
|
23
|
-
|
|
27
|
+
`uv sync` creates a project-local `.venv/` and installs the package in editable mode with dev dependencies. There is nothing to "activate" — prefix commands with `uv run`:
|
|
24
28
|
|
|
25
29
|
```bash
|
|
26
|
-
|
|
30
|
+
uv run wbox --version
|
|
31
|
+
uv run pytest
|
|
32
|
+
uv run ruff check src/ tests/
|
|
27
33
|
```
|
|
28
34
|
|
|
29
35
|
Configure your Wealthbox API token (optional — tests don't require a real token):
|
|
30
36
|
|
|
31
37
|
```bash
|
|
32
|
-
wbox config set-token
|
|
38
|
+
uv run wbox config set-token
|
|
33
39
|
```
|
|
34
40
|
|
|
41
|
+
> Prefer plain `pip`? `pip install -e ".[dev]"` still works — `pyproject.toml` is the source of truth for both tools.
|
|
42
|
+
|
|
35
43
|
---
|
|
36
44
|
|
|
37
45
|
## Running Tests
|
|
38
46
|
|
|
39
47
|
```bash
|
|
40
|
-
pytest
|
|
48
|
+
uv run pytest
|
|
41
49
|
```
|
|
42
50
|
|
|
43
51
|
Tests use [respx](https://lundberg.github.io/respx/) to mock HTTP at the transport layer — no real API calls are made.
|
|
@@ -45,7 +53,7 @@ Tests use [respx](https://lundberg.github.io/respx/) to mock HTTP at the transpo
|
|
|
45
53
|
## Code Style
|
|
46
54
|
|
|
47
55
|
```bash
|
|
48
|
-
ruff check src/ tests/
|
|
56
|
+
uv run ruff check src/ tests/
|
|
49
57
|
```
|
|
50
58
|
|
|
51
59
|
- **ruff** for linting (E, F, I rules; 120-char line length)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wealthbox-cli
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0
|
|
4
4
|
Summary: CLI and client library for the Wealthbox CRM API
|
|
5
5
|
Project-URL: Homepage, https://github.com/massive-value/wealthbox-cli
|
|
6
6
|
Project-URL: Documentation, https://massive-value.github.io/wealthbox-cli/
|
|
@@ -28,7 +28,6 @@ Classifier: Typing :: Typed
|
|
|
28
28
|
Requires-Python: >=3.11
|
|
29
29
|
Requires-Dist: httpx<1.0,>=0.27
|
|
30
30
|
Requires-Dist: pydantic<3.0,>=2.0
|
|
31
|
-
Requires-Dist: python-dotenv<2.0,>=1.0
|
|
32
31
|
Requires-Dist: tabulate<1.0,>=0.9
|
|
33
32
|
Requires-Dist: typer<1.0,>=0.12
|
|
34
33
|
Provides-Extra: dev
|
|
@@ -18,7 +18,7 @@ You will receive a response within 5 business days. If the issue is confirmed, a
|
|
|
18
18
|
|
|
19
19
|
Your Wealthbox API token grants access to your CRM data. Keep it safe:
|
|
20
20
|
|
|
21
|
-
- **Never commit your token to version control.** Use
|
|
21
|
+
- **Never commit your token to version control.** Use `wbox config set-token` to store it securely (written to your platform config dir, not the repo).
|
|
22
22
|
- **Never share your token** in issues, PRs, or chat.
|
|
23
23
|
- If a token is accidentally exposed, regenerate it immediately in your Wealthbox account settings under **Settings > API Access**.
|
|
24
24
|
|
|
@@ -89,19 +89,13 @@ For CI, scripting, or containers:
|
|
|
89
89
|
export WEALTHBOX_TOKEN="your_api_token_here"
|
|
90
90
|
```
|
|
91
91
|
|
|
92
|
-
=== ".env file"
|
|
93
|
-
|
|
94
|
-
```bash
|
|
95
|
-
echo 'WEALTHBOX_TOKEN=your_api_token_here' > .env
|
|
96
|
-
```
|
|
97
|
-
|
|
98
92
|
=== "Per-command flag"
|
|
99
93
|
|
|
100
94
|
```bash
|
|
101
95
|
wbox contacts list --token your_api_token_here
|
|
102
96
|
```
|
|
103
97
|
|
|
104
|
-
Token is resolved in this order: `--token` flag → `WEALTHBOX_TOKEN` env var → config file
|
|
98
|
+
Token is resolved in this order: `--token` flag → `WEALTHBOX_TOKEN` env var → config file.
|
|
105
99
|
|
|
106
100
|
---
|
|
107
101
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "wealthbox-cli"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.2.0"
|
|
8
8
|
description = "CLI and client library for the Wealthbox CRM API"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -44,7 +44,6 @@ dependencies = [
|
|
|
44
44
|
"pydantic>=2.0,<3.0",
|
|
45
45
|
"httpx>=0.27,<1.0",
|
|
46
46
|
"typer>=0.12,<1.0",
|
|
47
|
-
"python-dotenv>=1.0,<2.0",
|
|
48
47
|
"tabulate>=0.9,<1.0",
|
|
49
48
|
]
|
|
50
49
|
|
|
@@ -77,7 +76,6 @@ exclude = [
|
|
|
77
76
|
"resources/",
|
|
78
77
|
"scripts/",
|
|
79
78
|
"dev/",
|
|
80
|
-
".python-version",
|
|
81
79
|
"docs/superpowers/",
|
|
82
80
|
]
|
|
83
81
|
|
|
@@ -49,25 +49,17 @@ COMMENT_RESOURCE_TYPES: dict[str, str] = {
|
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
def get_client(token: str | None = None) -> WealthboxClient:
|
|
52
|
-
"""Create a WealthboxClient with token resolution: --token flag > env var > config file
|
|
52
|
+
"""Create a WealthboxClient with token resolution: --token flag > env var > config file."""
|
|
53
53
|
import os
|
|
54
54
|
if token is None:
|
|
55
55
|
token = os.environ.get("WEALTHBOX_TOKEN")
|
|
56
56
|
if token is None:
|
|
57
57
|
from ._config import get_stored_token
|
|
58
58
|
token = get_stored_token()
|
|
59
|
-
if token is None:
|
|
60
|
-
try:
|
|
61
|
-
from dotenv import load_dotenv
|
|
62
|
-
load_dotenv()
|
|
63
|
-
token = os.environ.get("WEALTHBOX_TOKEN")
|
|
64
|
-
except ImportError:
|
|
65
|
-
pass
|
|
66
59
|
if not token:
|
|
67
60
|
raise ValueError(
|
|
68
61
|
"Wealthbox token required. Provide one via any of: "
|
|
69
|
-
"--token flag, WEALTHBOX_TOKEN env var, "
|
|
70
|
-
"`wbox config set-token`, or a .env file in the working directory."
|
|
62
|
+
"--token flag, WEALTHBOX_TOKEN env var, or `wbox config set-token`."
|
|
71
63
|
)
|
|
72
64
|
return WealthboxClient(token=token)
|
|
73
65
|
|
|
@@ -28,7 +28,7 @@ from .self_cmd import _default_install_root
|
|
|
28
28
|
|
|
29
29
|
def _detect_token_source(token_arg: str | None) -> tuple[str | None, str]:
|
|
30
30
|
"""Return (token, source_label) matching get_client's resolution order:
|
|
31
|
-
--token flag > WEALTHBOX_TOKEN env > config file
|
|
31
|
+
--token flag > WEALTHBOX_TOKEN env > config file."""
|
|
32
32
|
if token_arg:
|
|
33
33
|
return token_arg, "--token flag"
|
|
34
34
|
env_token = os.environ.get("WEALTHBOX_TOKEN")
|
|
@@ -38,14 +38,6 @@ def _detect_token_source(token_arg: str | None) -> tuple[str | None, str]:
|
|
|
38
38
|
cfg_token = cfg.get("token")
|
|
39
39
|
if cfg_token:
|
|
40
40
|
return cfg_token, f"config file ({_config_path()})"
|
|
41
|
-
try:
|
|
42
|
-
from dotenv import load_dotenv
|
|
43
|
-
load_dotenv()
|
|
44
|
-
dotenv_token = os.environ.get("WEALTHBOX_TOKEN")
|
|
45
|
-
if dotenv_token:
|
|
46
|
-
return dotenv_token, ".env file in working directory"
|
|
47
|
-
except ImportError:
|
|
48
|
-
pass
|
|
49
41
|
return None, "not set"
|
|
50
42
|
|
|
51
43
|
|
|
@@ -257,7 +249,7 @@ def _ensure_firm_migrated():
|
|
|
257
249
|
def doctor_cmd(
|
|
258
250
|
token: str | None = typer.Option(
|
|
259
251
|
None, "--token",
|
|
260
|
-
help="Override the API token for the smoke test. Overrides env var
|
|
252
|
+
help="Override the API token for the smoke test. Overrides env var and config.",
|
|
261
253
|
),
|
|
262
254
|
) -> None:
|
|
263
255
|
"""Run the comprehensive doctor.
|
|
@@ -266,6 +258,6 @@ def doctor_cmd(
|
|
|
266
258
|
is informational, not a CI gate. (A future --strict flag could change
|
|
267
259
|
this for scripting.) Token is intentionally NOT bound to
|
|
268
260
|
`envvar=WEALTHBOX_TOKEN` so the doctor can report whether the token came
|
|
269
|
-
from the flag, env var,
|
|
261
|
+
from the flag, env var, or config file.
|
|
270
262
|
"""
|
|
271
263
|
run_doctor(token=token)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
import typer
|
|
6
|
+
|
|
7
|
+
from ._util import (
|
|
8
|
+
OutputFormat,
|
|
9
|
+
_flatten_record,
|
|
10
|
+
_render_kv_table,
|
|
11
|
+
handle_errors,
|
|
12
|
+
output_result,
|
|
13
|
+
run_client,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
app = typer.Typer(
|
|
17
|
+
context_settings={"help_option_names": ["-h", "--help"]},
|
|
18
|
+
help="Show info about the current authenticated user.",
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _relabel_for_table(data: dict[str, Any]) -> dict[str, Any]:
|
|
23
|
+
"""Rename top-level `id` to `login_id` and add `user_id (--assigned-to)`
|
|
24
|
+
so the two IDs aren't confusable in tabular output.
|
|
25
|
+
|
|
26
|
+
The top-level `id` is a login profile (not usable for `--assigned-to`);
|
|
27
|
+
`current_user.id` is the workspace user ID that filters accept.
|
|
28
|
+
"""
|
|
29
|
+
relabeled: dict[str, Any] = {}
|
|
30
|
+
for key, value in data.items():
|
|
31
|
+
relabeled["login_id" if key == "id" else key] = value
|
|
32
|
+
current_user = data.get("current_user")
|
|
33
|
+
if isinstance(current_user, dict) and "id" in current_user:
|
|
34
|
+
relabeled["user_id (--assigned-to)"] = current_user["id"]
|
|
35
|
+
return relabeled
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@app.callback(
|
|
39
|
+
invoke_without_command=True,
|
|
40
|
+
help="Show info about the current authenticated user. Use subcommands for more specific info.",
|
|
41
|
+
)
|
|
42
|
+
@handle_errors
|
|
43
|
+
def get_me(
|
|
44
|
+
ctx: typer.Context,
|
|
45
|
+
token: str | None = typer.Option(None, envvar="WEALTHBOX_TOKEN", hidden=True),
|
|
46
|
+
fmt: OutputFormat = typer.Option(OutputFormat.JSON, "--format"),
|
|
47
|
+
) -> None:
|
|
48
|
+
if ctx.invoked_subcommand is not None:
|
|
49
|
+
return
|
|
50
|
+
data = run_client(token, lambda c: c.get_me())
|
|
51
|
+
if fmt == OutputFormat.TABLE and isinstance(data, dict):
|
|
52
|
+
# Bypass output_result's collection-detection heuristic: once we drop
|
|
53
|
+
# the top-level `id` key, it would mistake `users[]` for a collection.
|
|
54
|
+
typer.echo(_render_kv_table(_flatten_record(_relabel_for_table(data))))
|
|
55
|
+
return
|
|
56
|
+
output_result(data, fmt)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@app.command("user-id", help="Print the workspace user ID (for --assigned-to) as a bare integer.")
|
|
60
|
+
@handle_errors
|
|
61
|
+
def user_id(
|
|
62
|
+
token: str | None = typer.Option(None, envvar="WEALTHBOX_TOKEN", hidden=True),
|
|
63
|
+
) -> None:
|
|
64
|
+
data = run_client(token, lambda c: c.get_me())
|
|
65
|
+
current_user = data.get("current_user") if isinstance(data, dict) else None
|
|
66
|
+
if not isinstance(current_user, dict) or "id" not in current_user:
|
|
67
|
+
raise ValueError("`current_user.id` missing from /me response; cannot determine user ID.")
|
|
68
|
+
typer.echo(current_user["id"])
|
|
@@ -295,7 +295,7 @@ def doctor_cmd(
|
|
|
295
295
|
# canonical top-level form. Both call the same function so the output
|
|
296
296
|
# never drifts. Token is intentionally not bound to envvar= so the
|
|
297
297
|
# doctor can report whether the token came from the flag, env var,
|
|
298
|
-
#
|
|
298
|
+
# or config file.
|
|
299
299
|
from .doctor import run_doctor
|
|
300
300
|
run_doctor(token=token)
|
|
301
301
|
|
|
@@ -21,4 +21,4 @@ def list_users(
|
|
|
21
21
|
token: str | None = typer.Option(None, envvar="WEALTHBOX_TOKEN", hidden=True),
|
|
22
22
|
fmt: OutputFormat = typer.Option(OutputFormat.JSON, "--format"),
|
|
23
23
|
) -> None:
|
|
24
|
-
output_result(run_client(token, lambda c: c.
|
|
24
|
+
output_result(run_client(token, lambda c: c.list_all_users()), fmt, fields=None if verbose else _DEFAULT_FIELDS)
|
{wealthbox_cli-2.0.0 → wealthbox_cli-2.2.0}/src/wealthbox_tools/skills/wealthbox-crm/SKILL.md
RENAMED
|
@@ -101,7 +101,7 @@ across every installed platform while preserving `firm/`.
|
|
|
101
101
|
# Windows (PowerShell)
|
|
102
102
|
irm https://raw.githubusercontent.com/massive-value/wealthbox-cli/main/scripts/install.ps1 | iex
|
|
103
103
|
```
|
|
104
|
-
- Token configured via one of: `wbox config set-token
|
|
104
|
+
- Token configured via one of: `wbox config set-token` or `WEALTHBOX_TOKEN` env var
|
|
105
105
|
|
|
106
106
|
Verify with: `wbox me`
|
|
107
107
|
|
|
@@ -20,7 +20,7 @@ wbox contacts list [OPTIONS]
|
|
|
20
20
|
| `--household-title` | STR | Filter by household title |
|
|
21
21
|
| `--tags` | STR | Comma-separated tag names |
|
|
22
22
|
| `--order` | asc\|desc | Sort order |
|
|
23
|
-
| `--assigned-to` | INT | User ID (fetches all pages, client-side filter) |
|
|
23
|
+
| `--assigned-to` | INT | User ID (fetches all pages, client-side filter). Get yours via `wbox me user-id`, **not** `wbox me \| jq .id` (that's the login profile, which silently returns zero results). |
|
|
24
24
|
| `--updated-since` | ISO datetime | Modified after this datetime |
|
|
25
25
|
| `--updated-before` | ISO datetime | Modified before this datetime |
|
|
26
26
|
| `--deleted-since` | ISO datetime | Deleted after this datetime |
|
|
@@ -6,10 +6,35 @@ Read-only resources: categories, users, activity feed, and current user info.
|
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
wbox me [--format json|table|csv|tsv]
|
|
9
|
+
wbox me user-id
|
|
9
10
|
```
|
|
10
11
|
|
|
11
12
|
Returns info about the authenticated user. Good for verifying token setup and getting your user ID.
|
|
12
13
|
|
|
14
|
+
### Two IDs — don't confuse them
|
|
15
|
+
|
|
16
|
+
`wbox me` returns two distinct ID fields, and they are NOT interchangeable:
|
|
17
|
+
|
|
18
|
+
| JSON field | What it is | Use for `--assigned-to`? |
|
|
19
|
+
|------------|------------|--------------------------|
|
|
20
|
+
| top-level `id` | Login profile ID (one per Wealthbox account, across workspaces) | **No** |
|
|
21
|
+
| `current_user.id` (also `users[].id` for the active workspace) | Workspace user ID | **Yes** |
|
|
22
|
+
|
|
23
|
+
Filters like `--assigned-to`, `--assigned-to-team`, and `--created-by` expect the workspace user ID. Passing the top-level `id` returns zero results silently — the API just ignores the filter.
|
|
24
|
+
|
|
25
|
+
The safe ways to get your workspace user ID:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
wbox me user-id # prints just the integer, ready for shell substitution
|
|
29
|
+
wbox me --format table # labels the rows `login_id` vs `user_id (--assigned-to)`
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Composing it:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
wbox tasks list --assigned-to "$(wbox me user-id)"
|
|
36
|
+
```
|
|
37
|
+
|
|
13
38
|
## Users
|
|
14
39
|
|
|
15
40
|
```bash
|
|
@@ -64,7 +89,10 @@ The contact-related types are also reachable as aliases under `wbox contacts cat
|
|
|
64
89
|
## Examples
|
|
65
90
|
|
|
66
91
|
```bash
|
|
67
|
-
# Get your user ID
|
|
92
|
+
# Get your workspace user ID (for --assigned-to)
|
|
93
|
+
wbox me user-id
|
|
94
|
+
|
|
95
|
+
# Or see both IDs side by side
|
|
68
96
|
wbox me --format table
|
|
69
97
|
|
|
70
98
|
# Find a user ID for assignment
|
|
@@ -13,7 +13,7 @@ wbox tasks list [OPTIONS]
|
|
|
13
13
|
| `--contact` | INT | Filter by linked contact ID |
|
|
14
14
|
| `--project` | INT | Filter by linked project ID |
|
|
15
15
|
| `--opportunity` | INT | Filter by linked opportunity ID |
|
|
16
|
-
| `--assigned-to` | INT | Filter by assigned user ID |
|
|
16
|
+
| `--assigned-to` | INT | Filter by assigned user ID — get yours via `wbox me user-id`, **not** `wbox me \| jq .id` (that's the login profile, which silently returns zero results). |
|
|
17
17
|
| `--assigned-to-team` | INT | Filter by assigned team ID |
|
|
18
18
|
| `--created-by` | INT | Filter by creator user ID |
|
|
19
19
|
| `--include-completed` | flag | Include completed tasks (default: outstanding only) |
|