wealthbox-cli 1.2.0__tar.gz → 1.3.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-1.2.0 → wealthbox_cli-1.3.0}/PKG-INFO +1 -1
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/docs/changelog.md +16 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/pyproject.toml +1 -1
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/cli/_skill_platforms.py +73 -0
- wealthbox_cli-1.3.0/src/wealthbox_tools/cli/doctor.py +199 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/cli/main.py +7 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/cli/skills.py +26 -54
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/.claude-plugin/marketplace.json +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/.codex-plugin/plugin.json +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/.env.example +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/.github/workflows/ci.yml +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/.github/workflows/docs.yml +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/.gitignore +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/CONTRIBUTING.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/LICENSE +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/README.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/SECURITY.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/SKILL.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/bootstrap.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/firm-examples/contacts.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/firm-examples/events.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/firm-examples/notes.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/firm-examples/opportunities.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/firm-examples/projects.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/firm-examples/tasks.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/firm-examples/workflows.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/references/contacts.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/references/events.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/references/households.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/references/lookups.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/references/notes.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/references/opportunities.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/references/projects.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/references/tasks.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/references/workflows.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/docs/cli-reference.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/docs/getting-started.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/docs/index.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/docs/overrides/main.html +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/docs/promotion.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/mkdocs.yml +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/plugins/wealthbox-crm/.claude-plugin/plugin.json +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/plugins/wealthbox-crm/skills/wealthbox-crm/SKILL.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/plugins/wealthbox-crm/skills/wealthbox-crm/bootstrap.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/plugins/wealthbox-crm/skills/wealthbox-crm/firm-examples/contacts.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/plugins/wealthbox-crm/skills/wealthbox-crm/firm-examples/events.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/plugins/wealthbox-crm/skills/wealthbox-crm/firm-examples/notes.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/plugins/wealthbox-crm/skills/wealthbox-crm/firm-examples/opportunities.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/plugins/wealthbox-crm/skills/wealthbox-crm/firm-examples/projects.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/plugins/wealthbox-crm/skills/wealthbox-crm/firm-examples/tasks.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/plugins/wealthbox-crm/skills/wealthbox-crm/firm-examples/workflows.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/plugins/wealthbox-crm/skills/wealthbox-crm/references/contacts.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/plugins/wealthbox-crm/skills/wealthbox-crm/references/events.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/plugins/wealthbox-crm/skills/wealthbox-crm/references/households.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/plugins/wealthbox-crm/skills/wealthbox-crm/references/lookups.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/plugins/wealthbox-crm/skills/wealthbox-crm/references/notes.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/plugins/wealthbox-crm/skills/wealthbox-crm/references/opportunities.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/plugins/wealthbox-crm/skills/wealthbox-crm/references/projects.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/plugins/wealthbox-crm/skills/wealthbox-crm/references/tasks.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/plugins/wealthbox-crm/skills/wealthbox-crm/references/workflows.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/__init__.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/cli/__init__.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/cli/_config.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/cli/_skill_bootstrap.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/cli/_skill_paths.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/cli/_util.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/cli/activity.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/cli/categories.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/cli/config.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/cli/contacts.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/cli/events.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/cli/households.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/cli/me.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/cli/notes.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/cli/opportunities.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/cli/projects.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/cli/tasks.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/cli/users.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/cli/workflows.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/client/__init__.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/client/activity.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/client/base.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/client/categories.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/client/comments.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/client/contacts.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/client/events.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/client/households.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/client/me.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/client/notes.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/client/opportunities.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/client/projects.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/client/tasks.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/client/users.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/client/workflows.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/models/__init__.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/models/activity.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/models/comments.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/models/common.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/models/contacts.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/models/custom_fields.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/models/enums.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/models/events.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/models/households.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/models/notes.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/models/opportunities.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/models/projects.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/models/tasks.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/models/workflows.py +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/py.typed +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/skills/wealthbox-crm/SKILL.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/skills/wealthbox-crm/bootstrap.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/contacts.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/events.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/notes.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/opportunities.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/projects.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/tasks.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/workflows.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/skills/wealthbox-crm/references/contacts.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/skills/wealthbox-crm/references/events.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/skills/wealthbox-crm/references/households.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/skills/wealthbox-crm/references/lookups.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/skills/wealthbox-crm/references/notes.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/skills/wealthbox-crm/references/opportunities.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/skills/wealthbox-crm/references/projects.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/skills/wealthbox-crm/references/tasks.md +0 -0
- {wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/skills/wealthbox-crm/references/workflows.md +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wealthbox-cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.3.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/
|
|
@@ -6,6 +6,22 @@ This project uses [Semantic Versioning](https://semver.org/).
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
+
## [1.3.0](https://github.com/massive-value/wealthbox-cli/releases/tag/v1.3.0) — 2026-05-03
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **`wbox doctor`** — comprehensive top-level health check at the CLI root. Reports the wbox CLI version + Python version + binary location; authentication source detection (flag / env var / config file / `.env`) plus a smoke test against `/me`; agent CLI presence (`claude` / `codex` on PATH); legacy skill installs; plugin installs (managed via `claude plugin install` / `codex plugin install`); firm data state with file count, generated-vs-hand-edited split, and oldest-generated-file timestamp; and a Summary section listing actionable issues. `wbox skills doctor` keeps working as an alias of the new top-level command — both call the same function so output never drifts.
|
|
14
|
+
- `wbox skills list` and `wbox skills doctor` now detect plugin-installed copies of `wealthbox-crm` under `~/.claude/plugins/cache/.../skills/wealthbox-crm/` and `~/.codex/plugins/cache/.../skills/wealthbox-crm/`. Previously a user who installed via the marketplace plugin path saw "not installed" everywhere even though the plugin was actively serving the skill.
|
|
15
|
+
- Bootstrap installer (`scripts/install.sh` / `scripts/install.ps1`) now prefers the Claude Code plugin marketplace path when `claude` is on PATH — runs `claude plugin marketplace add` + `claude plugin install` directly, then offers a separate Codex install. Falls back to the legacy `wbox skills install` picker when no `claude` CLI is detected.
|
|
16
|
+
- Bootstrap installer pre-flight checks Windows PowerShell `ExecutionPolicy` and offers to set `RemoteSigned` for the current user if needed (no admin required), instead of bombing partway through with Astral's terse error.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- Bootstrap `install.sh` no longer hangs at startup. The previous version did `exec </dev/tty` at the top, which cut off bash's source of piped script content (`curl … | bash`) and waited forever for the rest of the script to arrive on the user's keyboard. The whole body is now wrapped in a `main()` function so bash reads it fully before executing.
|
|
21
|
+
- Bootstrap `install.ps1` no longer auto-closes its window on error. Wrapped in try/catch/finally with explicit step headers and a "Press Enter to close" pause so a transient PowerShell host stays open long enough to show the actual error.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
9
25
|
## [1.2.0](https://github.com/massive-value/wealthbox-cli/releases/tag/v1.2.0) — 2026-05-02
|
|
10
26
|
|
|
11
27
|
### Changed
|
|
@@ -4,6 +4,8 @@ import shutil
|
|
|
4
4
|
from dataclasses import dataclass
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
|
|
7
|
+
SKILL_NAME = "wealthbox-crm"
|
|
8
|
+
|
|
7
9
|
|
|
8
10
|
@dataclass(frozen=True)
|
|
9
11
|
class Platform:
|
|
@@ -14,10 +16,81 @@ class Platform:
|
|
|
14
16
|
requires_project_cwd: bool
|
|
15
17
|
|
|
16
18
|
|
|
19
|
+
@dataclass(frozen=True)
|
|
20
|
+
class PluginInstall:
|
|
21
|
+
"""A copy of `wealthbox-crm` discovered inside an agent host's plugin cache.
|
|
22
|
+
|
|
23
|
+
These are managed by the host CLI (`claude plugin install ...` or the
|
|
24
|
+
Codex equivalent) — `wbox skills install` does not write here, and
|
|
25
|
+
`wbox skills uninstall` does not touch them.
|
|
26
|
+
"""
|
|
27
|
+
host: str # 'claude-code-user' | 'claude-code-project' | 'codex'
|
|
28
|
+
marketplace: str
|
|
29
|
+
version: str
|
|
30
|
+
skill_dir: Path
|
|
31
|
+
|
|
32
|
+
|
|
17
33
|
def _home() -> Path:
|
|
18
34
|
return Path.home()
|
|
19
35
|
|
|
20
36
|
|
|
37
|
+
def _scan_plugin_cache(cache_root: Path, host: str) -> list[PluginInstall]:
|
|
38
|
+
"""Find any `<marketplace>/<plugin-name>/<version>/skills/wealthbox-crm/`
|
|
39
|
+
matches under a Claude Code- or Codex-style plugin cache root."""
|
|
40
|
+
if not cache_root.is_dir():
|
|
41
|
+
return []
|
|
42
|
+
out: list[PluginInstall] = []
|
|
43
|
+
for marketplace_dir in cache_root.iterdir():
|
|
44
|
+
if not marketplace_dir.is_dir():
|
|
45
|
+
continue
|
|
46
|
+
plugin_dir = marketplace_dir / SKILL_NAME
|
|
47
|
+
if not plugin_dir.is_dir():
|
|
48
|
+
continue
|
|
49
|
+
for version_dir in plugin_dir.iterdir():
|
|
50
|
+
if not version_dir.is_dir():
|
|
51
|
+
continue
|
|
52
|
+
skill_dir = version_dir / "skills" / SKILL_NAME
|
|
53
|
+
if (skill_dir / "SKILL.md").is_file():
|
|
54
|
+
out.append(PluginInstall(
|
|
55
|
+
host=host,
|
|
56
|
+
marketplace=marketplace_dir.name,
|
|
57
|
+
version=version_dir.name,
|
|
58
|
+
skill_dir=skill_dir,
|
|
59
|
+
))
|
|
60
|
+
return out
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def detect_plugin_installs() -> list[PluginInstall]:
|
|
64
|
+
"""Discover every host-managed plugin copy of wealthbox-crm on this
|
|
65
|
+
machine. Includes Claude Code user scope, Claude Code project scope
|
|
66
|
+
(cwd-relative), and Codex.
|
|
67
|
+
|
|
68
|
+
Deduped by resolved skill_dir path so a single install isn't reported
|
|
69
|
+
twice when home and cwd point at the same directory (rare in real use,
|
|
70
|
+
common in tests).
|
|
71
|
+
"""
|
|
72
|
+
home = _home()
|
|
73
|
+
cwd = Path.cwd()
|
|
74
|
+
candidates = [
|
|
75
|
+
(home / ".claude" / "plugins" / "cache", "claude-code-user"),
|
|
76
|
+
(cwd / ".claude" / "plugins" / "cache", "claude-code-project"),
|
|
77
|
+
(home / ".codex" / "plugins" / "cache", "codex"),
|
|
78
|
+
]
|
|
79
|
+
installs: list[PluginInstall] = []
|
|
80
|
+
seen: set[Path] = set()
|
|
81
|
+
for cache_root, host in candidates:
|
|
82
|
+
for pi in _scan_plugin_cache(cache_root, host=host):
|
|
83
|
+
try:
|
|
84
|
+
key = pi.skill_dir.resolve()
|
|
85
|
+
except OSError:
|
|
86
|
+
key = pi.skill_dir
|
|
87
|
+
if key in seen:
|
|
88
|
+
continue
|
|
89
|
+
seen.add(key)
|
|
90
|
+
installs.append(pi)
|
|
91
|
+
return installs
|
|
92
|
+
|
|
93
|
+
|
|
21
94
|
def detect_platforms() -> list[Platform]:
|
|
22
95
|
home = _home()
|
|
23
96
|
cwd = Path.cwd()
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"""Comprehensive health check across the wbox install.
|
|
2
|
+
|
|
3
|
+
`wbox doctor` and `wbox skills doctor` both call into `run_doctor()` so
|
|
4
|
+
the legacy `skills doctor` command keeps working as an alias.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import os
|
|
9
|
+
import platform as _platform_module
|
|
10
|
+
import shutil
|
|
11
|
+
import sys
|
|
12
|
+
from datetime import datetime
|
|
13
|
+
from importlib.metadata import version as _pkg_version
|
|
14
|
+
|
|
15
|
+
import typer
|
|
16
|
+
|
|
17
|
+
from ._config import _config_path, load_config
|
|
18
|
+
from ._skill_bootstrap import migrate_legacy_firm, read_firm_meta, read_meta
|
|
19
|
+
from ._skill_paths import firm_dir, firm_meta_path
|
|
20
|
+
from ._skill_platforms import (
|
|
21
|
+
detect_platforms,
|
|
22
|
+
detect_plugin_installs,
|
|
23
|
+
is_installed,
|
|
24
|
+
skill_dir,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _detect_token_source(token_arg: str | None) -> tuple[str | None, str]:
|
|
29
|
+
"""Return (token, source_label) matching get_client's resolution order:
|
|
30
|
+
--token flag > WEALTHBOX_TOKEN env > config file > .env (loaded as env)."""
|
|
31
|
+
if token_arg:
|
|
32
|
+
return token_arg, "--token flag"
|
|
33
|
+
env_token = os.environ.get("WEALTHBOX_TOKEN")
|
|
34
|
+
if env_token:
|
|
35
|
+
return env_token, "env var (WEALTHBOX_TOKEN or .env)"
|
|
36
|
+
cfg = load_config()
|
|
37
|
+
cfg_token = cfg.get("token")
|
|
38
|
+
if cfg_token:
|
|
39
|
+
return cfg_token, f"config file ({_config_path()})"
|
|
40
|
+
return None, "not set"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def run_doctor(token: str | None = None) -> int:
|
|
44
|
+
"""Run all health checks. Returns exit code (0 = healthy, 1 = issues found)."""
|
|
45
|
+
issues: list[str] = []
|
|
46
|
+
|
|
47
|
+
migrated_from = _ensure_firm_migrated()
|
|
48
|
+
if migrated_from is not None:
|
|
49
|
+
typer.echo(f"! migrated legacy firm/ data from {migrated_from} to {firm_dir()}")
|
|
50
|
+
typer.echo("")
|
|
51
|
+
|
|
52
|
+
# --- wbox CLI ---------------------------------------------------------
|
|
53
|
+
typer.echo("# wbox CLI")
|
|
54
|
+
cli_version = _pkg_version("wealthbox-cli")
|
|
55
|
+
py_version = ".".join(str(v) for v in sys.version_info[:3])
|
|
56
|
+
binary = shutil.which("wbox") or "(not on PATH -running via python -m)"
|
|
57
|
+
typer.echo(f" version: {cli_version}")
|
|
58
|
+
typer.echo(f" python: {py_version} ({_platform_module.system()})")
|
|
59
|
+
typer.echo(f" binary: {binary}")
|
|
60
|
+
|
|
61
|
+
# --- Authentication ---------------------------------------------------
|
|
62
|
+
typer.echo("\n# Authentication")
|
|
63
|
+
config_path = _config_path()
|
|
64
|
+
if config_path.exists():
|
|
65
|
+
cfg = load_config()
|
|
66
|
+
cfg_token = cfg.get("token", "")
|
|
67
|
+
masked = f"...{cfg_token[-4:]}" if len(cfg_token) > 4 else "****"
|
|
68
|
+
typer.echo(f" config: {config_path} (present, masked: {masked})")
|
|
69
|
+
else:
|
|
70
|
+
typer.echo(f" config: {config_path} (not present)")
|
|
71
|
+
resolved_token, source = _detect_token_source(token)
|
|
72
|
+
typer.echo(f" source: {source}")
|
|
73
|
+
if not resolved_token:
|
|
74
|
+
typer.echo(" smoke: skipped (no token)")
|
|
75
|
+
issues.append("token not configured - run 'wbox config set-token'")
|
|
76
|
+
else:
|
|
77
|
+
from wealthbox_tools.client import WealthboxAPIError
|
|
78
|
+
|
|
79
|
+
from ._util import run_client
|
|
80
|
+
try:
|
|
81
|
+
me = run_client(token, lambda c: c.get_me())
|
|
82
|
+
accounts = me.get("accounts") or []
|
|
83
|
+
firm_name = accounts[0].get("name") if accounts else "(no firm)"
|
|
84
|
+
typer.echo(
|
|
85
|
+
f" smoke: OK /me returned {me.get('name')} "
|
|
86
|
+
f"({firm_name}, user {me.get('id')})"
|
|
87
|
+
)
|
|
88
|
+
except WealthboxAPIError as e:
|
|
89
|
+
typer.echo(f" smoke: FAILED token rejected by /me: {e}")
|
|
90
|
+
issues.append("token rejected by /me - check it's still valid")
|
|
91
|
+
except Exception as e:
|
|
92
|
+
typer.echo(f" smoke: FAILED network/config error: {e}")
|
|
93
|
+
issues.append(f"smoke test failed: {e}")
|
|
94
|
+
|
|
95
|
+
# --- Agent CLIs -------------------------------------------------------
|
|
96
|
+
typer.echo("\n# Agent CLIs on PATH")
|
|
97
|
+
claude_path = shutil.which("claude") or shutil.which("claude.exe")
|
|
98
|
+
codex_path = shutil.which("codex") or shutil.which("codex.exe")
|
|
99
|
+
typer.echo(f" claude: {claude_path or 'not detected'}")
|
|
100
|
+
typer.echo(f" codex: {codex_path or 'not detected'}")
|
|
101
|
+
|
|
102
|
+
# --- Legacy skill installs --------------------------------------------
|
|
103
|
+
typer.echo("\n# Skill installs (legacy template-copy)")
|
|
104
|
+
for p in detect_platforms():
|
|
105
|
+
status = "installed" if is_installed(p) else "not installed"
|
|
106
|
+
meta = read_meta(skill_dir(p)) if is_installed(p) else {}
|
|
107
|
+
template_v = (meta.get("template") or {}).get("cli_version", "-")
|
|
108
|
+
upgrade_hint = ""
|
|
109
|
+
if template_v not in ("-", cli_version):
|
|
110
|
+
upgrade_hint = f" [upgrade: {template_v} -> {cli_version}]"
|
|
111
|
+
issues.append(
|
|
112
|
+
f"{p.id} skill template is {template_v}, latest is {cli_version} "
|
|
113
|
+
f"- run 'wbox skills upgrade'"
|
|
114
|
+
)
|
|
115
|
+
typer.echo(
|
|
116
|
+
f" {p.id:<22} {status:<16} template={template_v:<10} {skill_dir(p)}{upgrade_hint}"
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# --- Plugin installs --------------------------------------------------
|
|
120
|
+
plugin_installs = detect_plugin_installs()
|
|
121
|
+
typer.echo("\n# Plugin installs (managed by host CLI: claude/codex plugin)")
|
|
122
|
+
if not plugin_installs:
|
|
123
|
+
typer.echo(" (none detected)")
|
|
124
|
+
else:
|
|
125
|
+
for pi in plugin_installs:
|
|
126
|
+
typer.echo(
|
|
127
|
+
f" {pi.host:<22} plugin@{pi.marketplace:<18} "
|
|
128
|
+
f"version={pi.version:<10} {pi.skill_dir}"
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# --- Firm data --------------------------------------------------------
|
|
132
|
+
typer.echo("\n# Firm data (canonical)")
|
|
133
|
+
typer.echo(f" path: {firm_dir()}")
|
|
134
|
+
typer.echo(f" meta: {firm_meta_path()}")
|
|
135
|
+
firm_meta = read_firm_meta()
|
|
136
|
+
if not firm_meta:
|
|
137
|
+
typer.echo(" state: not bootstrapped")
|
|
138
|
+
issues.append("firm data not bootstrapped - run 'wbox skills bootstrap'")
|
|
139
|
+
else:
|
|
140
|
+
identity = firm_meta.get("identity") or {}
|
|
141
|
+
if firm_meta.get("onboarded_at"):
|
|
142
|
+
firm_state = "onboarded"
|
|
143
|
+
else:
|
|
144
|
+
firm_state = "bootstrapped (qualitative pending)"
|
|
145
|
+
issues.append(
|
|
146
|
+
"firm onboarding incomplete - open the skill in your agent to "
|
|
147
|
+
"walk through bootstrap.md (it'll call 'wbox skills mark-onboarded')"
|
|
148
|
+
)
|
|
149
|
+
typer.echo(f" state: {firm_state}")
|
|
150
|
+
typer.echo(f" firm: {identity.get('name', '-')}")
|
|
151
|
+
typer.echo(f" user: {identity.get('user_name', '-')}")
|
|
152
|
+
if firm_dir().exists():
|
|
153
|
+
md_files = sorted(p.name for p in firm_dir().glob("*.md"))
|
|
154
|
+
generated_set = set((firm_meta.get("files") or {}).keys())
|
|
155
|
+
handed = [f for f in md_files if f not in generated_set and not f.startswith("_")]
|
|
156
|
+
typer.echo(
|
|
157
|
+
f" files: {len(md_files)} markdown ({len(generated_set)} generated, "
|
|
158
|
+
f"{len(handed)} hand-edited)"
|
|
159
|
+
)
|
|
160
|
+
file_ts = list((firm_meta.get("files") or {}).values())
|
|
161
|
+
if file_ts:
|
|
162
|
+
try:
|
|
163
|
+
oldest = min(datetime.fromisoformat(t).date() for t in file_ts)
|
|
164
|
+
typer.echo(f" oldest: {oldest}")
|
|
165
|
+
except (ValueError, TypeError):
|
|
166
|
+
pass
|
|
167
|
+
|
|
168
|
+
# --- Summary ----------------------------------------------------------
|
|
169
|
+
typer.echo("\n# Summary")
|
|
170
|
+
if not issues:
|
|
171
|
+
typer.echo(" All checks passed.")
|
|
172
|
+
return 0
|
|
173
|
+
typer.echo(f" {len(issues)} issue(s) found:")
|
|
174
|
+
for i in issues:
|
|
175
|
+
typer.echo(f" ! {i}")
|
|
176
|
+
return 1
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _ensure_firm_migrated():
|
|
180
|
+
"""Migrate legacy firm/ data on first read (idempotent)."""
|
|
181
|
+
installed = [skill_dir(p) for p in detect_platforms() if is_installed(p)]
|
|
182
|
+
return migrate_legacy_firm(installed)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def doctor_cmd(
|
|
186
|
+
token: str | None = typer.Option(
|
|
187
|
+
None, "--token",
|
|
188
|
+
help="Override the API token for the smoke test. Overrides env var, config, .env.",
|
|
189
|
+
),
|
|
190
|
+
) -> None:
|
|
191
|
+
"""Run the comprehensive doctor.
|
|
192
|
+
|
|
193
|
+
Always exits 0 — issues are surfaced in the Summary section. The doctor
|
|
194
|
+
is informational, not a CI gate. (A future --strict flag could change
|
|
195
|
+
this for scripting.) Token is intentionally NOT bound to
|
|
196
|
+
`envvar=WEALTHBOX_TOKEN` so the doctor can report whether the token came
|
|
197
|
+
from the flag, env var, config file, or .env file.
|
|
198
|
+
"""
|
|
199
|
+
run_doctor(token=token)
|
|
@@ -8,6 +8,7 @@ from .activity import app as activity_app
|
|
|
8
8
|
from .categories import app as categories_app
|
|
9
9
|
from .config import app as config_app
|
|
10
10
|
from .contacts import app as contacts_app
|
|
11
|
+
from .doctor import doctor_cmd as _doctor_cmd
|
|
11
12
|
from .events import app as events_app
|
|
12
13
|
from .households import app as households_app
|
|
13
14
|
from .me import app as me_app
|
|
@@ -35,6 +36,12 @@ def _main(
|
|
|
35
36
|
raise typer.Exit()
|
|
36
37
|
|
|
37
38
|
|
|
39
|
+
app.command(
|
|
40
|
+
"doctor",
|
|
41
|
+
help="Comprehensive health check: CLI version, auth, agent CLIs, skills, plugins, firm.",
|
|
42
|
+
)(_doctor_cmd)
|
|
43
|
+
|
|
44
|
+
|
|
38
45
|
app.add_typer(activity_app, name="activity")
|
|
39
46
|
app.add_typer(categories_app, name="categories")
|
|
40
47
|
app.add_typer(config_app, name="config")
|
|
@@ -14,11 +14,12 @@ from ._skill_bootstrap import (
|
|
|
14
14
|
read_meta,
|
|
15
15
|
update_template_meta,
|
|
16
16
|
)
|
|
17
|
-
from ._skill_paths import firm_dir
|
|
17
|
+
from ._skill_paths import firm_dir
|
|
18
18
|
from ._skill_platforms import (
|
|
19
19
|
Platform,
|
|
20
20
|
SkillInstallError,
|
|
21
21
|
detect_platforms,
|
|
22
|
+
detect_plugin_installs,
|
|
22
23
|
install_skill,
|
|
23
24
|
is_installed,
|
|
24
25
|
skill_dir,
|
|
@@ -43,7 +44,7 @@ def _ensure_firm_migrated() -> Path | None:
|
|
|
43
44
|
return migrate_legacy_firm(installed)
|
|
44
45
|
|
|
45
46
|
|
|
46
|
-
@app.command("list", help="Show
|
|
47
|
+
@app.command("list", help="Show every skill copy on this machine: legacy installs and plugin-managed.")
|
|
47
48
|
def list_platforms() -> None:
|
|
48
49
|
_ensure_firm_migrated()
|
|
49
50
|
firm_meta = read_firm_meta()
|
|
@@ -55,7 +56,7 @@ def list_platforms() -> None:
|
|
|
55
56
|
last_bootstrap = max(files_map.values())
|
|
56
57
|
onboarded = firm_meta.get("onboarded_at") or "no"
|
|
57
58
|
|
|
58
|
-
header = ("
|
|
59
|
+
header = ("source", "path", "status", "version")
|
|
59
60
|
rows: list[tuple[str, str, str, str]] = []
|
|
60
61
|
for p in detect_platforms():
|
|
61
62
|
dest = skill_dir(p)
|
|
@@ -69,6 +70,13 @@ def list_platforms() -> None:
|
|
|
69
70
|
"installed" if installed else "not installed",
|
|
70
71
|
template_version,
|
|
71
72
|
))
|
|
73
|
+
for pi in detect_plugin_installs():
|
|
74
|
+
rows.append((
|
|
75
|
+
f"plugin:{pi.host}",
|
|
76
|
+
str(pi.skill_dir),
|
|
77
|
+
f"plugin@{pi.marketplace}",
|
|
78
|
+
pi.version,
|
|
79
|
+
))
|
|
72
80
|
|
|
73
81
|
widths = [
|
|
74
82
|
max(len(r[i]) for r in ([header] + rows))
|
|
@@ -278,59 +286,23 @@ def upgrade_cmd(
|
|
|
278
286
|
typer.echo(f"OK upgraded {t.id}: {existing} -> {current}")
|
|
279
287
|
|
|
280
288
|
|
|
281
|
-
@app.command(
|
|
289
|
+
@app.command(
|
|
290
|
+
"doctor",
|
|
291
|
+
help="Diagnose install state, auth, and firm data. Alias of `wbox doctor`.",
|
|
292
|
+
)
|
|
282
293
|
def doctor_cmd(
|
|
283
|
-
token: str | None = typer.Option(
|
|
294
|
+
token: str | None = typer.Option(
|
|
295
|
+
None, "--token",
|
|
296
|
+
help="Override the API token for the smoke test.",
|
|
297
|
+
),
|
|
284
298
|
) -> None:
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
current = _pkg_version("wealthbox-cli")
|
|
294
|
-
typer.echo("# Skill install state")
|
|
295
|
-
for p in detect_platforms():
|
|
296
|
-
status = "installed" if is_installed(p) else "not installed"
|
|
297
|
-
meta = read_meta(skill_dir(p)) if is_installed(p) else {}
|
|
298
|
-
template_v = (meta.get("template") or {}).get("cli_version", "-")
|
|
299
|
-
upgrade_hint = ""
|
|
300
|
-
if template_v not in ("-", current):
|
|
301
|
-
upgrade_hint = f" [upgrade available: {template_v} -> {current}]"
|
|
302
|
-
typer.echo(
|
|
303
|
-
f" {p.id:<22} {status:<16} template={template_v:<10} {skill_dir(p)}{upgrade_hint}"
|
|
304
|
-
)
|
|
305
|
-
|
|
306
|
-
typer.echo("\n# Firm data (canonical)")
|
|
307
|
-
firm_meta = read_firm_meta()
|
|
308
|
-
if not firm_meta:
|
|
309
|
-
firm_state = "not bootstrapped"
|
|
310
|
-
elif firm_meta.get("onboarded_at"):
|
|
311
|
-
firm_state = "onboarded"
|
|
312
|
-
else:
|
|
313
|
-
firm_state = "bootstrapped (qualitative pending)"
|
|
314
|
-
identity = firm_meta.get("identity") or {}
|
|
315
|
-
typer.echo(f" state: {firm_state}")
|
|
316
|
-
typer.echo(f" firm: {identity.get('name', '-')}")
|
|
317
|
-
typer.echo(f" user: {identity.get('user_name', '-')}")
|
|
318
|
-
typer.echo(f" path: {firm_dir()}")
|
|
319
|
-
typer.echo(f" meta: {firm_meta_path()}")
|
|
320
|
-
|
|
321
|
-
typer.echo("\n# Token")
|
|
322
|
-
try:
|
|
323
|
-
me = run_client(token, lambda c: c.get_me())
|
|
324
|
-
accounts = me.get("accounts") or []
|
|
325
|
-
firm_name = accounts[0].get("name") if accounts else "(no firm)"
|
|
326
|
-
typer.echo(
|
|
327
|
-
f" token ok - authenticated as {me.get('name')} "
|
|
328
|
-
f"(firm: {firm_name}, user id={me.get('id')})"
|
|
329
|
-
)
|
|
330
|
-
except WealthboxAPIError as e:
|
|
331
|
-
typer.echo(f" token failed: {e}")
|
|
332
|
-
except Exception as e: # network, config, etc.
|
|
333
|
-
typer.echo(f" token check failed: {e}")
|
|
299
|
+
# `wbox skills doctor` is the older entry point; `wbox doctor` is the
|
|
300
|
+
# canonical top-level form. Both call the same function so the output
|
|
301
|
+
# never drifts. Token is intentionally not bound to envvar= so the
|
|
302
|
+
# doctor can report whether the token came from the flag, env var,
|
|
303
|
+
# config file, or .env file.
|
|
304
|
+
from .doctor import run_doctor
|
|
305
|
+
run_doctor(token=token)
|
|
334
306
|
|
|
335
307
|
|
|
336
308
|
@app.command(
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/firm-examples/contacts.md
RENAMED
|
File without changes
|
{wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/firm-examples/events.md
RENAMED
|
File without changes
|
{wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/firm-examples/notes.md
RENAMED
|
File without changes
|
{wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/firm-examples/opportunities.md
RENAMED
|
File without changes
|
{wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/firm-examples/projects.md
RENAMED
|
File without changes
|
{wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/firm-examples/tasks.md
RENAMED
|
File without changes
|
{wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/firm-examples/workflows.md
RENAMED
|
File without changes
|
{wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/references/contacts.md
RENAMED
|
File without changes
|
|
File without changes
|
{wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/references/households.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/references/opportunities.md
RENAMED
|
File without changes
|
{wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/references/projects.md
RENAMED
|
File without changes
|
|
File without changes
|
{wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/codex-skill/wealthbox-crm/references/workflows.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/plugins/wealthbox-crm/.claude-plugin/plugin.json
RENAMED
|
File without changes
|
{wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/plugins/wealthbox-crm/skills/wealthbox-crm/SKILL.md
RENAMED
|
File without changes
|
{wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/plugins/wealthbox-crm/skills/wealthbox-crm/bootstrap.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/skills/wealthbox-crm/SKILL.md
RENAMED
|
File without changes
|
{wealthbox_cli-1.2.0 → wealthbox_cli-1.3.0}/src/wealthbox_tools/skills/wealthbox-crm/bootstrap.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|