wealthbox-cli 2.1.0__tar.gz → 2.2.1__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.
Files changed (103) hide show
  1. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/.github/workflows/ci.yml +8 -8
  2. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/.github/workflows/docs.yml +5 -4
  3. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/CHANGELOG.md +47 -0
  4. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/PKG-INFO +1 -1
  5. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/mkdocs.yml +1 -0
  6. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/pyproject.toml +1 -1
  7. wealthbox_cli-2.2.1/src/wealthbox_tools/cli/me.py +68 -0
  8. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/cli/self_cmd.py +21 -0
  9. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/self_upgrade.py +30 -0
  10. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/skills/wealthbox-crm/references/contacts.md +1 -1
  11. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/skills/wealthbox-crm/references/lookups.md +29 -1
  12. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/skills/wealthbox-crm/references/tasks.md +1 -1
  13. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/uv.lock +1 -1
  14. wealthbox_cli-2.1.0/src/wealthbox_tools/cli/me.py +0 -25
  15. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/.github/workflows/release-binaries.yml +0 -0
  16. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/.gitignore +0 -0
  17. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/CONTRIBUTING.md +0 -0
  18. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/LICENSE +0 -0
  19. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/README.md +0 -0
  20. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/SECURITY.md +0 -0
  21. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/docs/agents/domain.md +0 -0
  22. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/docs/agents/issue-tracker.md +0 -0
  23. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/docs/agents/triage-labels.md +0 -0
  24. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/docs/cli-reference.md +0 -0
  25. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/docs/getting-started.md +0 -0
  26. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/docs/index.md +0 -0
  27. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/docs/overrides/main.html +0 -0
  28. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/docs/promotion.md +0 -0
  29. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/__init__.py +0 -0
  30. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/cli/__init__.py +0 -0
  31. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/cli/_config.py +0 -0
  32. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/cli/_skill_bootstrap.py +0 -0
  33. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/cli/_skill_paths.py +0 -0
  34. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/cli/_skill_platforms.py +0 -0
  35. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/cli/_util.py +0 -0
  36. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/cli/activity.py +0 -0
  37. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/cli/categories.py +0 -0
  38. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/cli/config.py +0 -0
  39. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/cli/contacts.py +0 -0
  40. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/cli/doctor.py +0 -0
  41. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/cli/events.py +0 -0
  42. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/cli/firm.py +0 -0
  43. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/cli/households.py +0 -0
  44. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/cli/internals.py +0 -0
  45. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/cli/main.py +0 -0
  46. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/cli/notes.py +0 -0
  47. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/cli/opportunities.py +0 -0
  48. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/cli/prefs.py +0 -0
  49. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/cli/projects.py +0 -0
  50. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/cli/skills.py +0 -0
  51. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/cli/tasks.py +0 -0
  52. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/cli/users.py +0 -0
  53. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/cli/workflows.py +0 -0
  54. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/client/__init__.py +0 -0
  55. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/client/activity.py +0 -0
  56. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/client/base.py +0 -0
  57. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/client/categories.py +0 -0
  58. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/client/comments.py +0 -0
  59. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/client/contacts.py +0 -0
  60. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/client/events.py +0 -0
  61. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/client/households.py +0 -0
  62. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/client/me.py +0 -0
  63. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/client/notes.py +0 -0
  64. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/client/opportunities.py +0 -0
  65. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/client/projects.py +0 -0
  66. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/client/tasks.py +0 -0
  67. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/client/users.py +0 -0
  68. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/client/workflows.py +0 -0
  69. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/firm/__init__.py +0 -0
  70. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/firm/archive.py +0 -0
  71. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/firm/diff.py +0 -0
  72. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/internals/__init__.py +0 -0
  73. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/internals/skill_ref_gen.py +0 -0
  74. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/models/__init__.py +0 -0
  75. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/models/activity.py +0 -0
  76. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/models/comments.py +0 -0
  77. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/models/common.py +0 -0
  78. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/models/contacts.py +0 -0
  79. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/models/custom_fields.py +0 -0
  80. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/models/enums.py +0 -0
  81. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/models/events.py +0 -0
  82. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/models/households.py +0 -0
  83. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/models/notes.py +0 -0
  84. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/models/opportunities.py +0 -0
  85. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/models/projects.py +0 -0
  86. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/models/tasks.py +0 -0
  87. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/models/workflows.py +0 -0
  88. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/py.typed +0 -0
  89. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/skills/wealthbox-crm/SKILL.md +0 -0
  90. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/skills/wealthbox-crm/bootstrap.md +0 -0
  91. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/contacts.md +0 -0
  92. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/events.md +0 -0
  93. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/notes.md +0 -0
  94. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/opportunities.md +0 -0
  95. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/projects.md +0 -0
  96. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/tasks.md +0 -0
  97. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/workflows.md +0 -0
  98. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/skills/wealthbox-crm/references/events.md +0 -0
  99. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/skills/wealthbox-crm/references/households.md +0 -0
  100. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/skills/wealthbox-crm/references/notes.md +0 -0
  101. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/skills/wealthbox-crm/references/opportunities.md +0 -0
  102. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/skills/wealthbox-crm/references/projects.md +0 -0
  103. {wealthbox_cli-2.1.0 → wealthbox_cli-2.2.1}/src/wealthbox_tools/skills/wealthbox-crm/references/workflows.md +0 -0
@@ -11,8 +11,8 @@ jobs:
11
11
  lint:
12
12
  runs-on: ubuntu-latest
13
13
  steps:
14
- - uses: actions/checkout@v4
15
- - uses: astral-sh/setup-uv@v6
14
+ - uses: actions/checkout@v6
15
+ - uses: astral-sh/setup-uv@v8.1.0
16
16
  with:
17
17
  python-version: "3.12"
18
18
  - run: uv sync --extra dev
@@ -24,8 +24,8 @@ jobs:
24
24
  matrix:
25
25
  python-version: ["3.11", "3.12", "3.13"]
26
26
  steps:
27
- - uses: actions/checkout@v4
28
- - uses: astral-sh/setup-uv@v6
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
31
  - run: uv sync --extra dev
@@ -35,8 +35,8 @@ jobs:
35
35
  needs: [lint, test]
36
36
  runs-on: ubuntu-latest
37
37
  steps:
38
- - uses: actions/checkout@v4
39
- - uses: astral-sh/setup-uv@v6
38
+ - uses: actions/checkout@v6
39
+ - uses: astral-sh/setup-uv@v8.1.0
40
40
  with:
41
41
  python-version: "3.12"
42
42
  - run: uv sync --extra dev
@@ -51,8 +51,8 @@ jobs:
51
51
  id-token: write
52
52
  environment: pypi
53
53
  steps:
54
- - uses: actions/checkout@v4
55
- - uses: astral-sh/setup-uv@v6
54
+ - uses: actions/checkout@v6
55
+ - uses: astral-sh/setup-uv@v8.1.0
56
56
  with:
57
57
  python-version: "3.12"
58
58
  - run: uv build
@@ -18,14 +18,15 @@ jobs:
18
18
  build:
19
19
  runs-on: ubuntu-latest
20
20
  steps:
21
- - uses: actions/checkout@v4
22
- - uses: actions/setup-python@v5
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@v3
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@v4
41
+ uses: actions/deploy-pages@v5
@@ -4,6 +4,53 @@ 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.1] - 2026-05-13
8
+
9
+ Bug-fix release. `wbox self upgrade` was silently no-op'ing for users who
10
+ installed `wbox` via `uv tool install` or `pipx`: it computed the install root
11
+ from `sys.executable` (the venv's `python.exe`) and tried to swap the
12
+ console-script shim there, but `~/.local/bin/wbox.exe` (or pipx's equivalent)
13
+ is a separate copy uv/pipx made — replacing the venv-side shim never changed
14
+ what `PATH` resolved.
15
+
16
+ ### Fixed
17
+ - `wbox self upgrade` now detects the install kind (`bundle` / `uv-tool` /
18
+ `pipx` / `pip`) up front. Non-bundle installs exit `1` with the correct
19
+ follow-up command (`uv tool upgrade wealthbox-cli`, `pipx upgrade
20
+ wealthbox-cli`, or `pip install --upgrade wealthbox-cli`) instead of
21
+ scheduling a swap that would never take effect on `PATH`.
22
+
23
+ ## [2.2.0] - 2026-05-13
24
+
25
+ Small feature + correctness release. Disambiguates the two IDs returned by
26
+ `wbox me`, fixes a silent truncation in `wbox users list` on large firms, and
27
+ clears Node 20 deprecation warnings from CI ahead of GitHub's June 2026 cutoff.
28
+
29
+ ### Added
30
+ - `wbox me user-id` — prints `current_user.id` (the workspace user ID accepted
31
+ by `--assigned-to`) as a bare integer, for composing with command
32
+ substitution: `wbox tasks list --assigned-to "$(wbox me user-id)"` (#90, #91).
33
+ - `wbox me --format table` now labels the two IDs as `login_id` and
34
+ `user_id (--assigned-to)` so they aren't confusable at a glance. The JSON
35
+ shape is unchanged — no breaking change for existing scripts (#91).
36
+ - Skill docs (`lookups.md`, `tasks.md`, `contacts.md`) flag the two-ID trap
37
+ inline near `--assigned-to`.
38
+
39
+ ### Fixed
40
+ - `wbox users list` now paginates across all pages. Previously, firms with
41
+ more than 25 users silently saw a truncated list — the CLI exposes no
42
+ `--page` flag, so there was no manual workaround.
43
+ - mkdocs docs deploy was failing on every main push because `docs/index.md`
44
+ linked to a missing `changelog.md`. `CHANGELOG.md` is now staged into
45
+ `docs/` at build time and listed in nav (#92).
46
+
47
+ ### Changed
48
+ - CI actions bumped to Node 24 runtimes ahead of GitHub's June 2 2026 cutoff:
49
+ `actions/checkout` v4→v6, `astral-sh/setup-uv` v6→v8.1.0 (pinned exact —
50
+ setup-uv v8+ no longer publishes rolling major tags as a supply-chain
51
+ mitigation), `actions/setup-python` v5→v6, `actions/deploy-pages` v4→v5,
52
+ `actions/upload-pages-artifact` v3→v5 (#92, #93).
53
+
7
54
  ## [2.1.0] - 2026-05-09
8
55
 
9
56
  Repository simplification release. Drops a runtime dep, retires `.env` support,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wealthbox-cli
3
- Version: 2.1.0
3
+ Version: 2.2.1
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/
@@ -59,6 +59,7 @@ nav:
59
59
  - Getting Started: getting-started.md
60
60
  - CLI Reference: cli-reference.md
61
61
  - Contributing: contributing.md
62
+ - Changelog: changelog.md
62
63
 
63
64
  extra:
64
65
  social:
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "wealthbox-cli"
7
- version = "2.1.0"
7
+ version = "2.2.1"
8
8
  description = "CLI and client library for the Wealthbox CRM API"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -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"])
@@ -37,8 +37,29 @@ def _default_install_root() -> Path:
37
37
  return Path(sys.executable).resolve().parent
38
38
 
39
39
 
40
+ _NON_BUNDLE_UPGRADE_HINTS = {
41
+ "uv-tool": "uv tool upgrade wealthbox-cli",
42
+ "pipx": "pipx upgrade wealthbox-cli",
43
+ "pip": "pip install --upgrade wealthbox-cli",
44
+ }
45
+
46
+
40
47
  @app.command("upgrade", help="Upgrade the `wbox` CLI to the latest GitHub release.")
41
48
  def upgrade_cmd() -> None:
49
+ kind = self_upgrade._install_kind()
50
+ if kind != "bundle":
51
+ # The frozen-bundle swap would either silently no-op (uv copies the
52
+ # shim to ~/.local/bin so replacing the venv-side shim doesn't change
53
+ # what PATH resolves) or wedge the venv. Refuse before downloading.
54
+ hint = _NON_BUNDLE_UPGRADE_HINTS.get(kind, _NON_BUNDLE_UPGRADE_HINTS["pip"])
55
+ typer.echo(
56
+ "wbox self upgrade only swaps the standalone binary from "
57
+ "install.ps1.",
58
+ err=True,
59
+ )
60
+ typer.echo(f"This wbox was installed via {kind} — run: {hint}", err=True)
61
+ raise typer.Exit(code=1)
62
+
42
63
  candidate = self_upgrade.check()
43
64
  if candidate is None:
44
65
  typer.echo("Already on the latest version.")
@@ -51,6 +51,7 @@ __all__ = [
51
51
  "check_release_staleness",
52
52
  "apply",
53
53
  "_cleanup_stale_backups",
54
+ "_install_kind",
54
55
  ]
55
56
 
56
57
  _RELEASES_LATEST_URL = (
@@ -139,6 +140,35 @@ def _running_version() -> str:
139
140
  return __version__
140
141
 
141
142
 
143
+ def _install_kind() -> str:
144
+ """Classify how the running ``wbox`` was installed.
145
+
146
+ The :func:`apply` swap is only correct for the standalone PyInstaller
147
+ bundle that ``install.ps1`` ships. Under uv / pipx / pip the install is
148
+ a tiny console-script shim around a venv; replacing it with a frozen
149
+ binary would either silently no-op (PATH points at a copy uv made
150
+ elsewhere, e.g. ``~/.local/bin/wbox.exe``) or wedge the venv on the
151
+ next ``uv tool sync``. The gate in :mod:`cli.self_cmd` consults this
152
+ classifier to refuse with a clear "use <installer> instead" message.
153
+
154
+ Returns one of:
155
+
156
+ - ``"bundle"`` — frozen PyInstaller EXE (``sys.frozen`` is set).
157
+ - ``"uv-tool"`` — ``sys.executable`` lives under a ``uv/tools/`` venv.
158
+ - ``"pipx"`` — ``sys.executable`` lives under a ``pipx/`` venv.
159
+ - ``"pip"`` — anything else (ordinary pip/venv install).
160
+ """
161
+ if getattr(sys, "frozen", False):
162
+ return "bundle"
163
+ parts = [p.lower() for p in Path(sys.executable).resolve().parts]
164
+ for i in range(len(parts) - 1):
165
+ if parts[i] == "uv" and parts[i + 1] == "tools":
166
+ return "uv-tool"
167
+ if "pipx" in parts:
168
+ return "pipx"
169
+ return "pip"
170
+
171
+
142
172
  # ---------------------------------------------------------------------------
143
173
  # Internal helpers
144
174
  # ---------------------------------------------------------------------------
@@ -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) |
@@ -602,7 +602,7 @@ wheels = [
602
602
 
603
603
  [[package]]
604
604
  name = "wealthbox-cli"
605
- version = "2.1.0"
605
+ version = "2.2.0"
606
606
  source = { editable = "." }
607
607
  dependencies = [
608
608
  { name = "httpx" },
@@ -1,25 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import typer
4
-
5
- from ._util import OutputFormat, handle_errors, output_result, run_client
6
-
7
- app = typer.Typer(
8
- context_settings={"help_option_names": ["-h", "--help"]},
9
- help="Show info about the current authenticated user.",
10
- )
11
-
12
-
13
- @app.callback(
14
- invoke_without_command=True,
15
- help="Show info about the current authenticated user. Use subcommands for more specific info.",
16
- )
17
- @handle_errors
18
- def get_me(
19
- ctx: typer.Context,
20
- token: str | None = typer.Option(None, envvar="WEALTHBOX_TOKEN", hidden=True),
21
- fmt: OutputFormat = typer.Option(OutputFormat.JSON, "--format"),
22
- ) -> None:
23
- if ctx.invoked_subcommand is not None:
24
- return
25
- output_result(run_client(token, lambda c: c.get_me()), fmt)
File without changes
File without changes
File without changes
File without changes