wealthbox-cli 2.4.0__tar.gz → 2.5.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.
Files changed (112) hide show
  1. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/.github/workflows/ci.yml +27 -6
  2. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/.github/workflows/release-binaries.yml +221 -220
  3. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/CHANGELOG.md +97 -0
  4. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/CONTRIBUTING.md +2 -1
  5. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/PKG-INFO +3 -3
  6. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/README.md +1 -1
  7. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/pyproject.toml +1 -1
  8. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/_client.py +13 -0
  9. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/_factory.py +7 -2
  10. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/_resolve.py +69 -1
  11. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/_util.py +4 -0
  12. wealthbox_cli-2.5.0/src/wealthbox_tools/cli/comments.py +126 -0
  13. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/events.py +39 -14
  14. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/main.py +4 -0
  15. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/opportunities.py +6 -2
  16. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/tasks.py +43 -5
  17. wealthbox_cli-2.5.0/src/wealthbox_tools/cli/teams.py +37 -0
  18. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/users.py +19 -0
  19. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/workflows.py +66 -9
  20. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/client/__init__.py +2 -0
  21. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/client/base.py +54 -0
  22. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/client/tasks.py +23 -1
  23. wealthbox_cli-2.5.0/src/wealthbox_tools/client/teams.py +24 -0
  24. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/client/workflows.py +22 -1
  25. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/internals/skill_ref_gen.py +1 -0
  26. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/models/__init__.py +4 -0
  27. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/models/enums.py +29 -1
  28. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/models/events.py +3 -2
  29. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/models/tasks.py +3 -2
  30. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/skills/wealthbox-crm/SKILL.md +10 -0
  31. wealthbox_cli-2.5.0/src/wealthbox_tools/skills/wealthbox-crm/references/comments.md +129 -0
  32. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/skills/wealthbox-crm/references/events.md +17 -0
  33. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/skills/wealthbox-crm/references/lookups.md +26 -1
  34. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/skills/wealthbox-crm/references/opportunities.md +9 -2
  35. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/skills/wealthbox-crm/references/tasks.md +58 -4
  36. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/skills/wealthbox-crm/references/workflows.md +44 -7
  37. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/uv.lock +1 -1
  38. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/.github/dependabot.yml +0 -0
  39. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/.github/workflows/docs.yml +0 -0
  40. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/.gitignore +0 -0
  41. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/.pre-commit-config.yaml +0 -0
  42. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/LICENSE +0 -0
  43. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/SECURITY.md +0 -0
  44. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/docs/agents/domain.md +0 -0
  45. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/docs/agents/issue-tracker.md +0 -0
  46. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/docs/agents/triage-labels.md +0 -0
  47. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/docs/cli-reference.md +0 -0
  48. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/docs/getting-started.md +0 -0
  49. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/docs/index.md +0 -0
  50. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/docs/overrides/main.html +0 -0
  51. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/docs/promotion.md +0 -0
  52. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/mkdocs.yml +0 -0
  53. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/__init__.py +0 -0
  54. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/__init__.py +0 -0
  55. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/_config.py +0 -0
  56. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/_format.py +0 -0
  57. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/_skill_bootstrap.py +0 -0
  58. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/_skill_paths.py +0 -0
  59. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/_skill_platforms.py +0 -0
  60. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/activity.py +0 -0
  61. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/categories.py +0 -0
  62. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/config.py +0 -0
  63. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/contacts.py +0 -0
  64. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/doctor.py +0 -0
  65. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/firm.py +0 -0
  66. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/households.py +0 -0
  67. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/internals.py +0 -0
  68. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/me.py +0 -0
  69. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/notes.py +0 -0
  70. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/prefs.py +0 -0
  71. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/projects.py +0 -0
  72. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/self_cmd.py +0 -0
  73. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/cli/skills.py +0 -0
  74. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/client/activity.py +0 -0
  75. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/client/categories.py +0 -0
  76. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/client/comments.py +0 -0
  77. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/client/contacts.py +0 -0
  78. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/client/events.py +0 -0
  79. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/client/households.py +0 -0
  80. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/client/me.py +0 -0
  81. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/client/notes.py +0 -0
  82. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/client/opportunities.py +0 -0
  83. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/client/projects.py +0 -0
  84. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/client/users.py +0 -0
  85. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/firm/__init__.py +0 -0
  86. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/firm/archive.py +0 -0
  87. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/firm/diff.py +0 -0
  88. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/internals/__init__.py +0 -0
  89. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/models/activity.py +0 -0
  90. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/models/comments.py +0 -0
  91. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/models/common.py +0 -0
  92. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/models/contacts.py +0 -0
  93. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/models/custom_fields.py +0 -0
  94. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/models/households.py +0 -0
  95. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/models/notes.py +0 -0
  96. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/models/opportunities.py +0 -0
  97. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/models/projects.py +0 -0
  98. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/models/workflows.py +0 -0
  99. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/py.typed +0 -0
  100. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/self_upgrade.py +0 -0
  101. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/skills/wealthbox-crm/bootstrap.md +0 -0
  102. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/contacts.md +0 -0
  103. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/events.md +0 -0
  104. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/notes.md +0 -0
  105. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/opportunities.md +0 -0
  106. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/projects.md +0 -0
  107. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/tasks.md +0 -0
  108. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/workflows.md +0 -0
  109. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/skills/wealthbox-crm/references/contacts.md +0 -0
  110. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/skills/wealthbox-crm/references/households.md +0 -0
  111. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/skills/wealthbox-crm/references/notes.md +0 -0
  112. {wealthbox_cli-2.4.0 → wealthbox_cli-2.5.0}/src/wealthbox_tools/skills/wealthbox-crm/references/projects.md +0 -0
@@ -12,7 +12,7 @@ jobs:
12
12
  runs-on: ubuntu-latest
13
13
  steps:
14
14
  - uses: actions/checkout@v6
15
- - uses: astral-sh/setup-uv@v8.1.0
15
+ - uses: astral-sh/setup-uv@v8.2.0
16
16
  with:
17
17
  python-version: "3.12"
18
18
  - run: uv sync --extra dev
@@ -29,7 +29,7 @@ jobs:
29
29
  python-version: "3.12"
30
30
  steps:
31
31
  - uses: actions/checkout@v6
32
- - uses: astral-sh/setup-uv@v8.1.0
32
+ - uses: astral-sh/setup-uv@v8.2.0
33
33
  with:
34
34
  python-version: ${{ matrix.python-version }}
35
35
  - run: uv sync --extra dev
@@ -44,18 +44,39 @@ jobs:
44
44
  runs-on: ubuntu-latest
45
45
  steps:
46
46
  - uses: actions/checkout@v6
47
- - uses: astral-sh/setup-uv@v8.1.0
47
+ - uses: astral-sh/setup-uv@v8.2.0
48
48
  with:
49
49
  python-version: "3.12"
50
50
  - run: uv sync --extra dev
51
51
  - run: uv run mypy src/
52
52
 
53
+ smoke:
54
+ # Install the built wheel in isolation WITHOUT dev dependencies and run the
55
+ # entrypoint, so a missing runtime dependency (e.g. a module-level import of
56
+ # a package typer no longer pulls in) is caught before publish. The normal
57
+ # test job always has dev deps present and cannot catch this.
58
+ runs-on: ${{ matrix.os }}
59
+ strategy:
60
+ matrix:
61
+ os: [ubuntu-latest, windows-latest]
62
+ steps:
63
+ - uses: actions/checkout@v6
64
+ - uses: astral-sh/setup-uv@v8.2.0
65
+ with:
66
+ python-version: "3.12"
67
+ - name: Build and smoke-test clean install
68
+ shell: bash
69
+ run: |
70
+ uv build
71
+ uv run --isolated --no-project --with "$(ls dist/*.whl)" wbox --version
72
+ uv run --isolated --no-project --with "$(ls dist/*.whl)" wbox notes --help
73
+
53
74
  skill-ref-drift:
54
75
  needs: [lint, test]
55
76
  runs-on: ubuntu-latest
56
77
  steps:
57
78
  - uses: actions/checkout@v6
58
- - uses: astral-sh/setup-uv@v8.1.0
79
+ - uses: astral-sh/setup-uv@v8.2.0
59
80
  with:
60
81
  python-version: "3.12"
61
82
  - run: uv sync --extra dev
@@ -63,7 +84,7 @@ jobs:
63
84
  - run: git diff --exit-code -- src/wealthbox_tools/skills/wealthbox-crm/references/
64
85
 
65
86
  publish:
66
- needs: [lint, test, typecheck, skill-ref-drift]
87
+ needs: [lint, test, typecheck, smoke, skill-ref-drift]
67
88
  if: startsWith(github.ref, 'refs/tags/v')
68
89
  runs-on: ubuntu-latest
69
90
  permissions:
@@ -71,7 +92,7 @@ jobs:
71
92
  environment: pypi
72
93
  steps:
73
94
  - uses: actions/checkout@v6
74
- - uses: astral-sh/setup-uv@v8.1.0
95
+ - uses: astral-sh/setup-uv@v8.2.0
75
96
  with:
76
97
  python-version: "3.12"
77
98
  - name: Check changelog matches version
@@ -1,220 +1,221 @@
1
- # Per-platform PyInstaller build + GitHub Release upload.
2
- #
3
- # Triggered on v* tags (and manually via workflow_dispatch for fork
4
- # validation). Builds a single-file ``wbox`` binary for each of the four
5
- # supported targets, computes its SHA-256, and uploads the binaries plus
6
- # a combined manifest as assets on the GitHub Release for the tag.
7
- #
8
- # The PyPI publish job lives in ci.yml and is intentionally not touched
9
- # here — both workflows fire on ``v*`` tags but operate independently.
10
- #
11
- # ----------------------------------------------------------------------
12
- # Manifest contract (LOCKED — downstream consumers: issue #42 install.sh
13
- # rewrite, issue #43 install.ps1 parity)
14
- # ----------------------------------------------------------------------
15
- # Manifest filename: SHA256SUMS.txt
16
- # Format: standard sha256sum-compatible. One record per line:
17
- # <hex-sha256><two-spaces><filename>
18
- # Sort order: ASCII-sorted by filename (stable across runs)
19
- # Binary filenames:
20
- # wbox-linux-x64
21
- # wbox-macos-arm64
22
- # wbox-macos-x64
23
- # wbox-windows-x64.exe
24
- # Manifest assets are attached to the same GitHub Release as the four
25
- # binaries. Install scripts can fetch SHA256SUMS.txt and a single binary
26
- # from the same release URL prefix and verify the binary against the
27
- # matching line.
28
- # ----------------------------------------------------------------------
29
-
30
- name: Release Binaries
31
-
32
- on:
33
- push:
34
- tags: ["v*"]
35
- workflow_dispatch: {}
36
-
37
- permissions:
38
- contents: read
39
-
40
- jobs:
41
- build:
42
- name: Build ${{ matrix.target }}
43
- runs-on: ${{ matrix.os }}
44
- strategy:
45
- fail-fast: false
46
- matrix:
47
- include:
48
- - os: ubuntu-latest
49
- target: linux-x64
50
- binary: wbox-linux-x64
51
- - os: macos-15-intel # Intel runner (x86_64) — macos-13 was retired Dec 2025
52
- target: macos-x64
53
- binary: wbox-macos-x64
54
- - os: macos-14 # Apple Silicon runner (arm64)
55
- target: macos-arm64
56
- binary: wbox-macos-arm64
57
- - os: windows-latest
58
- target: windows-x64
59
- binary: wbox-windows-x64.exe
60
- steps:
61
- - name: Checkout
62
- uses: actions/checkout@v6
63
-
64
- - name: Set up Python
65
- uses: actions/setup-python@v6
66
- with:
67
- python-version: "3.12"
68
-
69
- - name: Install runtime + build deps
70
- run: |
71
- python -m pip install --upgrade pip
72
- pip install .
73
- pip install pyinstaller
74
-
75
- - name: Build single-file binary (Unix)
76
- if: runner.os != 'Windows'
77
- shell: bash
78
- run: |
79
- pyinstaller \
80
- --onefile \
81
- --name "${{ matrix.binary }}" \
82
- --noconfirm \
83
- --collect-data wealthbox_tools \
84
- --copy-metadata wealthbox-cli \
85
- scripts/wbox_entry.py
86
- test -f "dist/${{ matrix.binary }}"
87
- chmod +x "dist/${{ matrix.binary }}"
88
-
89
- - name: Build single-file binary (Windows)
90
- if: runner.os == 'Windows'
91
- shell: pwsh
92
- run: |
93
- pyinstaller `
94
- --onefile `
95
- --name "${{ matrix.binary }}" `
96
- --noconfirm `
97
- --collect-data wealthbox_tools `
98
- --copy-metadata wealthbox-cli `
99
- scripts/wbox_entry.py
100
- if (-not (Test-Path "dist/${{ matrix.binary }}")) {
101
- throw "expected dist/${{ matrix.binary }} to exist"
102
- }
103
-
104
- - name: Smoke-test binary
105
- # `--version` only proves the entry point runs. `skills install`
106
- # exercises bundled package data — it reads
107
- # wealthbox_tools/skills/wealthbox-crm via importlib.resources — so
108
- # this fails loudly if --collect-data wealthbox_tools didn't bundle
109
- # the skill template. Runs against the fresh runner HOME with
110
- # --no-bootstrap to skip the post-install confirm prompt.
111
- run: |
112
- ./dist/${{ matrix.binary }} --version
113
- ./dist/${{ matrix.binary }} skills install --platform claude-code-user --no-bootstrap
114
-
115
- - name: Compute SHA-256 (Unix)
116
- if: runner.os != 'Windows'
117
- shell: bash
118
- working-directory: dist
119
- run: |
120
- if command -v sha256sum >/dev/null 2>&1; then
121
- sha256sum "${{ matrix.binary }}" > "${{ matrix.binary }}.sha256"
122
- else
123
- # macOS: shasum -a 256 emits sha256sum-compatible "<hash> <name>"
124
- shasum -a 256 "${{ matrix.binary }}" > "${{ matrix.binary }}.sha256"
125
- fi
126
- cat "${{ matrix.binary }}.sha256"
127
-
128
- - name: Compute SHA-256 (Windows)
129
- if: runner.os == 'Windows'
130
- shell: pwsh
131
- working-directory: dist
132
- run: |
133
- $hash = (Get-FileHash -Algorithm SHA256 "${{ matrix.binary }}").Hash.ToLower()
134
- # sha256sum format: "<hex> <filename>" (two spaces, LF line ending)
135
- $line = "$hash ${{ matrix.binary }}`n"
136
- [System.IO.File]::WriteAllText(
137
- (Join-Path $PWD "${{ matrix.binary }}.sha256"),
138
- $line
139
- )
140
- Get-Content "${{ matrix.binary }}.sha256"
141
-
142
- - name: Upload build artifact
143
- uses: actions/upload-artifact@v4
144
- with:
145
- name: wbox-${{ matrix.target }}
146
- path: |
147
- dist/${{ matrix.binary }}
148
- dist/${{ matrix.binary }}.sha256
149
- if-no-files-found: error
150
- retention-days: 7
151
-
152
- manifest-and-release:
153
- name: Combine manifest and upload to release
154
- needs: [build]
155
- runs-on: ubuntu-latest
156
- permissions:
157
- contents: write
158
- steps:
159
- - name: Download all build artifacts
160
- uses: actions/download-artifact@v4
161
- with:
162
- path: artifacts
163
-
164
- - name: Stage release files
165
- shell: bash
166
- run: |
167
- mkdir -p release
168
- # Each artifact directory contains one binary + one .sha256 file.
169
- find artifacts -type f \( -name 'wbox-*' -a ! -name '*.sha256' \) -exec cp -v {} release/ \;
170
- find artifacts -type f -name '*.sha256' -exec cp -v {} release/ \;
171
- ls -la release
172
-
173
- - name: Build combined SHA256SUMS.txt
174
- shell: bash
175
- working-directory: release
176
- run: |
177
- # Concatenate per-binary sums into a single sha256sum-compatible
178
- # manifest, ASCII-sorted by filename for stability.
179
- # Each .sha256 file is already in "<hex> <filename>" form.
180
- cat *.sha256 | LC_ALL=C sort -k 2 > SHA256SUMS.txt
181
- echo "----- SHA256SUMS.txt -----"
182
- cat SHA256SUMS.txt
183
- echo "--------------------------"
184
- # Verify the manifest against the staged binaries as a sanity check.
185
- sha256sum -c SHA256SUMS.txt
186
-
187
- - name: Upload combined manifest artifact
188
- uses: actions/upload-artifact@v4
189
- with:
190
- name: SHA256SUMS
191
- path: release/SHA256SUMS.txt
192
- if-no-files-found: error
193
-
194
- - name: Upload assets to GitHub Release
195
- if: startsWith(github.ref, 'refs/tags/')
196
- env:
197
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
198
- TAG: ${{ github.ref_name }}
199
- GH_REPO: ${{ github.repository }}
200
- shell: bash
201
- working-directory: release
202
- run: |
203
- # Ensure a release exists for the tag. If the PyPI publish job in
204
- # ci.yml or a manual release-create created it first, --clobber on
205
- # upload handles re-runs cleanly.
206
- if ! gh release view "$TAG" >/dev/null 2>&1; then
207
- gh release create "$TAG" \
208
- --title "$TAG" \
209
- --notes "Automated release for $TAG. Binaries built by release-binaries.yml; PyPI wheel published by ci.yml."
210
- fi
211
- # Upload all four binaries + the combined manifest. Per-platform
212
- # .sha256 sidecars are intentionally not uploaded SHA256SUMS.txt
213
- # is the single source of truth for installers.
214
- gh release upload "$TAG" \
215
- wbox-linux-x64 \
216
- wbox-macos-arm64 \
217
- wbox-macos-x64 \
218
- wbox-windows-x64.exe \
219
- SHA256SUMS.txt \
220
- --clobber
1
+ # Per-platform PyInstaller build + GitHub Release upload.
2
+ #
3
+ # Triggered on v* tags (and manually via workflow_dispatch for fork
4
+ # validation). Builds a single-file ``wbox`` binary for each of the four
5
+ # supported targets, computes its SHA-256, and uploads the binaries plus
6
+ # a combined manifest as assets on the GitHub Release for the tag.
7
+ #
8
+ # The PyPI publish job lives in ci.yml and is intentionally not touched
9
+ # here — both workflows fire on ``v*`` tags but operate independently.
10
+ #
11
+ # ----------------------------------------------------------------------
12
+ # Manifest contract (LOCKED — downstream consumers: issue #42 install.sh
13
+ # rewrite, issue #43 install.ps1 parity)
14
+ # ----------------------------------------------------------------------
15
+ # Manifest filename: SHA256SUMS.txt
16
+ # Format: standard sha256sum-compatible. One record per line:
17
+ # <hex-sha256><two-spaces><filename>
18
+ # Sort order: ASCII-sorted by filename (stable across runs)
19
+ # Binary filenames:
20
+ # wbox-linux-x64
21
+ # wbox-macos-arm64
22
+ # wbox-macos-x64
23
+ # wbox-windows-x64.exe
24
+ # Manifest assets are attached to the same GitHub Release as the four
25
+ # binaries. Install scripts can fetch SHA256SUMS.txt and a single binary
26
+ # from the same release URL prefix and verify the binary against the
27
+ # matching line.
28
+ # ----------------------------------------------------------------------
29
+
30
+ name: Release Binaries
31
+
32
+ on:
33
+ push:
34
+ tags: ["v*"]
35
+ workflow_dispatch: {}
36
+
37
+ permissions:
38
+ contents: read
39
+
40
+ jobs:
41
+ build:
42
+ name: Build ${{ matrix.target }}
43
+ runs-on: ${{ matrix.os }}
44
+ strategy:
45
+ fail-fast: false
46
+ matrix:
47
+ include:
48
+ - os: ubuntu-latest
49
+ target: linux-x64
50
+ binary: wbox-linux-x64
51
+ - os: macos-15-intel # Intel runner (x86_64) — macos-13 was retired Dec 2025
52
+ target: macos-x64
53
+ binary: wbox-macos-x64
54
+ - os: macos-14 # Apple Silicon runner (arm64)
55
+ target: macos-arm64
56
+ binary: wbox-macos-arm64
57
+ - os: windows-latest
58
+ target: windows-x64
59
+ binary: wbox-windows-x64.exe
60
+ steps:
61
+ - name: Checkout
62
+ uses: actions/checkout@v6
63
+
64
+ - name: Set up Python
65
+ uses: actions/setup-python@v6
66
+ with:
67
+ python-version: "3.12"
68
+
69
+ - name: Install runtime + build deps
70
+ run: |
71
+ python -m pip install --upgrade pip
72
+ pip install .
73
+ pip install pyinstaller
74
+
75
+ - name: Build single-file binary (Unix)
76
+ if: runner.os != 'Windows'
77
+ shell: bash
78
+ run: |
79
+ pyinstaller \
80
+ --onefile \
81
+ --name "${{ matrix.binary }}" \
82
+ --noconfirm \
83
+ --collect-data wealthbox_tools \
84
+ --copy-metadata wealthbox-cli \
85
+ scripts/wbox_entry.py
86
+ test -f "dist/${{ matrix.binary }}"
87
+ chmod +x "dist/${{ matrix.binary }}"
88
+
89
+ - name: Build single-file binary (Windows)
90
+ if: runner.os == 'Windows'
91
+ shell: pwsh
92
+ run: |
93
+ pyinstaller `
94
+ --onefile `
95
+ --name "${{ matrix.binary }}" `
96
+ --noconfirm `
97
+ --collect-data wealthbox_tools `
98
+ --copy-metadata wealthbox-cli `
99
+ scripts/wbox_entry.py
100
+ if (-not (Test-Path "dist/${{ matrix.binary }}")) {
101
+ throw "expected dist/${{ matrix.binary }} to exist"
102
+ }
103
+
104
+ - name: Smoke-test binary
105
+ # `--version` only proves the entry point runs. `skills install`
106
+ # exercises bundled package data — it reads
107
+ # wealthbox_tools/skills/wealthbox-crm via importlib.resources — so
108
+ # this fails loudly if --collect-data wealthbox_tools didn't bundle
109
+ # the skill template. Runs against the fresh runner HOME with
110
+ # --no-bootstrap to skip the post-install confirm prompt.
111
+ run: |
112
+ ./dist/${{ matrix.binary }} --version
113
+ ./dist/${{ matrix.binary }} skills install --platform claude-code-user --no-bootstrap
114
+
115
+ - name: Compute SHA-256 (Unix)
116
+ if: runner.os != 'Windows'
117
+ shell: bash
118
+ working-directory: dist
119
+ run: |
120
+ if command -v sha256sum >/dev/null 2>&1; then
121
+ sha256sum "${{ matrix.binary }}" > "${{ matrix.binary }}.sha256"
122
+ else
123
+ # macOS: shasum -a 256 emits sha256sum-compatible "<hash> <name>"
124
+ shasum -a 256 "${{ matrix.binary }}" > "${{ matrix.binary }}.sha256"
125
+ fi
126
+ cat "${{ matrix.binary }}.sha256"
127
+
128
+ - name: Compute SHA-256 (Windows)
129
+ if: runner.os == 'Windows'
130
+ shell: pwsh
131
+ working-directory: dist
132
+ run: |
133
+ $hash = (Get-FileHash -Algorithm SHA256 "${{ matrix.binary }}").Hash.ToLower()
134
+ # sha256sum format: "<hex> <filename>" (two spaces, LF line ending)
135
+ $line = "$hash ${{ matrix.binary }}`n"
136
+ [System.IO.File]::WriteAllText(
137
+ (Join-Path $PWD "${{ matrix.binary }}.sha256"),
138
+ $line
139
+ )
140
+ Get-Content "${{ matrix.binary }}.sha256"
141
+
142
+ - name: Upload build artifact
143
+ uses: actions/upload-artifact@v7
144
+ with:
145
+ name: wbox-${{ matrix.target }}
146
+ path: |
147
+ dist/${{ matrix.binary }}
148
+ dist/${{ matrix.binary }}.sha256
149
+ if-no-files-found: error
150
+ retention-days: 1
151
+
152
+ manifest-and-release:
153
+ name: Combine manifest and upload to release
154
+ needs: [build]
155
+ runs-on: ubuntu-latest
156
+ permissions:
157
+ contents: write
158
+ steps:
159
+ - name: Download all build artifacts
160
+ uses: actions/download-artifact@v8
161
+ with:
162
+ path: artifacts
163
+
164
+ - name: Stage release files
165
+ shell: bash
166
+ run: |
167
+ mkdir -p release
168
+ # Each artifact directory contains one binary + one .sha256 file.
169
+ find artifacts -type f \( -name 'wbox-*' -a ! -name '*.sha256' \) -exec cp -v {} release/ \;
170
+ find artifacts -type f -name '*.sha256' -exec cp -v {} release/ \;
171
+ ls -la release
172
+
173
+ - name: Build combined SHA256SUMS.txt
174
+ shell: bash
175
+ working-directory: release
176
+ run: |
177
+ # Concatenate per-binary sums into a single sha256sum-compatible
178
+ # manifest, ASCII-sorted by filename for stability.
179
+ # Each .sha256 file is already in "<hex> <filename>" form.
180
+ cat *.sha256 | LC_ALL=C sort -k 2 > SHA256SUMS.txt
181
+ echo "----- SHA256SUMS.txt -----"
182
+ cat SHA256SUMS.txt
183
+ echo "--------------------------"
184
+ # Verify the manifest against the staged binaries as a sanity check.
185
+ sha256sum -c SHA256SUMS.txt
186
+
187
+ - name: Upload combined manifest artifact
188
+ uses: actions/upload-artifact@v7
189
+ with:
190
+ name: SHA256SUMS
191
+ path: release/SHA256SUMS.txt
192
+ if-no-files-found: error
193
+ retention-days: 1
194
+
195
+ - name: Upload assets to GitHub Release
196
+ if: startsWith(github.ref, 'refs/tags/')
197
+ env:
198
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
199
+ TAG: ${{ github.ref_name }}
200
+ GH_REPO: ${{ github.repository }}
201
+ shell: bash
202
+ working-directory: release
203
+ run: |
204
+ # Ensure a release exists for the tag. If the PyPI publish job in
205
+ # ci.yml or a manual release-create created it first, --clobber on
206
+ # upload handles re-runs cleanly.
207
+ if ! gh release view "$TAG" >/dev/null 2>&1; then
208
+ gh release create "$TAG" \
209
+ --title "$TAG" \
210
+ --notes "Automated release for $TAG. Binaries built by release-binaries.yml; PyPI wheel published by ci.yml."
211
+ fi
212
+ # Upload all four binaries + the combined manifest. Per-platform
213
+ # .sha256 sidecars are intentionally not uploaded SHA256SUMS.txt
214
+ # is the single source of truth for installers.
215
+ gh release upload "$TAG" \
216
+ wbox-linux-x64 \
217
+ wbox-macos-arm64 \
218
+ wbox-macos-x64 \
219
+ wbox-windows-x64.exe \
220
+ SHA256SUMS.txt \
221
+ --clobber
@@ -4,6 +4,103 @@ 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.5.0] - 2026-09-20
8
+
9
+ Fills in the work-record commands an AI agent needs, and corrects two list
10
+ defaults that were quietly returning a slice of the data.
11
+
12
+ ### Fixed
13
+
14
+ - **`wbox tasks list --include-completed` returned completed tasks *only*.**
15
+ Wealthbox's `completed` parameter is a two-way switch, not an "include":
16
+ omitted or `false` means open only, `true` means completed only. The flag
17
+ mapped to `completed=true`, so it did the opposite of its name. It is now a
18
+ hidden alias for `--status all` and keeps working in existing prompts.
19
+ - **A bad `--category`, `--advisor-role`, or `--custom-field` value printed
20
+ "Unexpected error".** These resolvers raise `BadParameter` from inside the
21
+ command body, after Click's own parsing is finished, so the generic handler
22
+ caught them. `handle_errors` now renders them as the user errors they are.
23
+ The exit code was already 1 and has not changed.
24
+
25
+ ### Added
26
+
27
+ - **`wbox tasks list --status open|completed|all`** (default `open`). `all`
28
+ issues both calls in sequence and merges by `id`, keeping the copy with the
29
+ later `updated_at`. In a firm with 5,174 tasks, 4,994 of them complete, the
30
+ default was showing 3% of the record set without saying so.
31
+ - **`wbox workflows list --status all`**, alongside the existing `active`,
32
+ `completed`, and `scheduled`. The default is now an explicit `active`, which
33
+ is what the API did all along when given no status. `all` runs three
34
+ sequential calls and merges by `id`.
35
+ - **`wbox teams list`** and **`wbox users groups`**. Team IDs are what
36
+ `--assigned-to-team` expects and there was no way to look one up; group IDs
37
+ are what `visible_to` accepts. Both render `id`, `name`, and `member_count`,
38
+ with the full member list under `--verbose`.
39
+ - **`wbox comments list`**, filtered by `--task`, `--event`, `--note`,
40
+ `--opportunity`, `--project`, or `--workflow`, or by an
41
+ `--updated-since`/`--updated-before` window. An unfiltered call exits 1 with
42
+ a one-line reason: `GET /comments` costs about 8.5 seconds per page of 100
43
+ unfiltered, against about 1.5 seconds inside a one-month window.
44
+ - **`wbox workflows next` now lists the active step's outcomes** (`id`, `name`,
45
+ `action`, `go_to_step_id`) in JSON and on stderr, so they stay readable in
46
+ every `--format`. `complete-step --outcome-id` is the only way to branch such
47
+ a step and the IDs appeared nowhere else in the CLI. `complete-step`'s own
48
+ advance hint lists them too.
49
+ - **`--custom-field NAME=VALUE` on `tasks add|update` and `events add|update`**
50
+ (repeatable, accepts a name or a numeric ID). Names are resolved against
51
+ `wbox categories custom-fields --document-type Task|Event` and an unknown
52
+ name is a hard error listing the valid ones. That check is load-bearing:
53
+ Wealthbox accepts a custom-field payload keyed by name with a 200 and then
54
+ silently discards it.
55
+
56
+ ### Changed
57
+
58
+ - Help text on `wbox opportunities list` and `--include-closed` now says that
59
+ closed opportunities are dropped by default (117 records in the firm, 73
60
+ returned). No behavior change.
61
+ - New `references/comments.md`; the tasks, workflows, opportunities, events,
62
+ and lookups references document the defaults, the new flags, and the
63
+ teams/user-group lookups.
64
+
65
+ ### Not built
66
+
67
+ - **`wbox comments add`.** The token-authenticated v1 REST API cannot write a
68
+ comment: `POST /v1/comments` returns a response byte-identical to a
69
+ nonexistent path, as does `POST /v1/tasks/{id}/comments`. The write route
70
+ lives on Wealthbox's session-authenticated web surface (`POST /comments`
71
+ without the `/v1` prefix answers 302 to `/users/login`), which the official
72
+ Wealthbox MCP reaches over OAuth via its `CreateComment` tool. Supporting it
73
+ from `wbox` would mean driving a logged-in web session with CSRF tokens, a
74
+ different auth model than the rest of the CLI. `references/comments.md`
75
+ documents the MCP-writes / `wbox`-reads split; a comment created through the
76
+ MCP is immediately readable by `wbox comments list`.
77
+ - **`tasks add --parent`.** The API takes subtasks only as inline objects in a
78
+ parent task's create payload, never as a `parent` reference on a child. The
79
+ read side's `parent {id, type}` object has no write counterpart. Use
80
+ `--more-fields '{"subtasks": [...]}'`.
81
+
82
+ ## [2.4.1] - 2026-06-12
83
+
84
+ Patch release fixing a startup crash in 2.4.0. The `cli/_factory.py` module
85
+ (introduced in the 2.4.0 refactor) imported `click` at module level to
86
+ annotate a `TyperGroup` subclass, but `click` is only referenced in type
87
+ annotations. On installs where `typer` (>=0.26) does not pull in `click` as a
88
+ transitive dependency, `wbox` crashed on launch with
89
+ `ModuleNotFoundError: No module named 'click'` — the same failure class fixed
90
+ for `skill_ref_gen` in 2.3.1. This was not caught by CI because the test
91
+ environment always has `click` present via the dev dependencies.
92
+
93
+ ### Fixed
94
+ - `wbox` startup crash (`ModuleNotFoundError: click`) on clean installs that
95
+ lack `click`. The `import click` in `cli/_factory.py` is now guarded by
96
+ `TYPE_CHECKING` (it is only used in annotations, which are not evaluated at
97
+ runtime under `from __future__ import annotations`).
98
+
99
+ ### Internal
100
+ - CI gains a `smoke` job that installs the built wheel in isolation **without
101
+ dev dependencies** and runs `wbox --version`, so a missing-runtime-dependency
102
+ startup crash can no longer reach PyPI. The `publish` job now depends on it.
103
+
7
104
  ## [2.4.0] - 2026-06-12
8
105
 
9
106
  The notable user-facing change in this release is **differentiated CLI exit
@@ -167,9 +167,10 @@ Pull requests and pushes to `main` run GitHub Actions CI:
167
167
  - **Lint:** `ruff check src/ tests/`
168
168
  - **Test:** `pytest` across Python 3.11, 3.12, 3.13 (ubuntu) + 3.12 (windows); coverage gate `--cov-fail-under=91` on ubuntu
169
169
  - **Typecheck:** `mypy src/` (strict)
170
+ - **Smoke:** installs the built wheel in isolation (no dev deps) and runs `wbox --version` / `wbox notes --help`, catching missing-runtime-dependency startup crashes
170
171
  - **Skill-ref drift:** regenerates refs and asserts no git diff
171
172
 
172
- All four jobs must pass before merging.
173
+ All jobs must pass before merging; `publish` (on `v*` tags) additionally gates on lint, test, typecheck, and smoke.
173
174
 
174
175
  ---
175
176
 
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: wealthbox-cli
3
- Version: 2.4.0
3
+ Version: 2.5.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/
@@ -95,7 +95,7 @@ If you're new to Claude Code itself, [download it here](https://claude.ai/downlo
95
95
 
96
96
  ## What it covers
97
97
 
98
- Full read/write access for **contacts** (people, households, organizations, trusts), **tasks**, **events**, **notes**, **opportunities**, **projects**, and **workflows**. Read access for users, activity, and your firm's category lookups.
98
+ Full read/write access for **contacts** (people, households, organizations, trusts), **tasks**, **events**, **notes**, **opportunities**, **projects**, and **workflows**. Read access for users, teams, user groups, comments, activity, and your firm's category lookups.
99
99
 
100
100
  Anything you can do in Wealthbox manually, the agent can do for you — usually in one sentence.
101
101