wealthbox-cli 1.3.0__tar.gz → 1.4.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.3.0 → wealthbox_cli-1.4.0}/.claude-plugin/marketplace.json +1 -1
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/.codex-plugin/plugin.json +1 -1
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/PKG-INFO +1 -1
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/plugins/wealthbox-crm/.claude-plugin/plugin.json +1 -1
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/pyproject.toml +1 -1
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/cli/_skill_platforms.py +68 -13
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/cli/_util.py +26 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/cli/doctor.py +5 -1
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/cli/skills.py +4 -2
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/cli/tasks.py +28 -7
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/skills/wealthbox-crm/references/tasks.md +4 -1
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/.env.example +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/.github/workflows/ci.yml +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/.github/workflows/docs.yml +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/.gitignore +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/CONTRIBUTING.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/LICENSE +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/README.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/SECURITY.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/SKILL.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/bootstrap.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/firm-examples/contacts.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/firm-examples/events.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/firm-examples/notes.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/firm-examples/opportunities.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/firm-examples/projects.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/firm-examples/tasks.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/firm-examples/workflows.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/references/contacts.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/references/events.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/references/households.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/references/lookups.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/references/notes.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/references/opportunities.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/references/projects.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/references/tasks.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/references/workflows.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/docs/changelog.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/docs/cli-reference.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/docs/getting-started.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/docs/index.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/docs/overrides/main.html +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/docs/promotion.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/mkdocs.yml +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/plugins/wealthbox-crm/skills/wealthbox-crm/SKILL.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/plugins/wealthbox-crm/skills/wealthbox-crm/bootstrap.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/plugins/wealthbox-crm/skills/wealthbox-crm/firm-examples/contacts.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/plugins/wealthbox-crm/skills/wealthbox-crm/firm-examples/events.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/plugins/wealthbox-crm/skills/wealthbox-crm/firm-examples/notes.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/plugins/wealthbox-crm/skills/wealthbox-crm/firm-examples/opportunities.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/plugins/wealthbox-crm/skills/wealthbox-crm/firm-examples/projects.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/plugins/wealthbox-crm/skills/wealthbox-crm/firm-examples/tasks.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/plugins/wealthbox-crm/skills/wealthbox-crm/firm-examples/workflows.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/plugins/wealthbox-crm/skills/wealthbox-crm/references/contacts.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/plugins/wealthbox-crm/skills/wealthbox-crm/references/events.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/plugins/wealthbox-crm/skills/wealthbox-crm/references/households.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/plugins/wealthbox-crm/skills/wealthbox-crm/references/lookups.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/plugins/wealthbox-crm/skills/wealthbox-crm/references/notes.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/plugins/wealthbox-crm/skills/wealthbox-crm/references/opportunities.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/plugins/wealthbox-crm/skills/wealthbox-crm/references/projects.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/plugins/wealthbox-crm/skills/wealthbox-crm/references/tasks.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/plugins/wealthbox-crm/skills/wealthbox-crm/references/workflows.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/__init__.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/cli/__init__.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/cli/_config.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/cli/_skill_bootstrap.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/cli/_skill_paths.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/cli/activity.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/cli/categories.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/cli/config.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/cli/contacts.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/cli/events.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/cli/households.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/cli/main.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/cli/me.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/cli/notes.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/cli/opportunities.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/cli/projects.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/cli/users.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/cli/workflows.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/client/__init__.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/client/activity.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/client/base.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/client/categories.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/client/comments.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/client/contacts.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/client/events.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/client/households.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/client/me.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/client/notes.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/client/opportunities.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/client/projects.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/client/tasks.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/client/users.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/client/workflows.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/models/__init__.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/models/activity.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/models/comments.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/models/common.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/models/contacts.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/models/custom_fields.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/models/enums.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/models/events.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/models/households.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/models/notes.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/models/opportunities.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/models/projects.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/models/tasks.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/models/workflows.py +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/py.typed +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/skills/wealthbox-crm/SKILL.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/skills/wealthbox-crm/bootstrap.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/contacts.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/events.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/notes.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/opportunities.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/projects.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/tasks.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/skills/wealthbox-crm/firm-examples/workflows.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/skills/wealthbox-crm/references/contacts.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/skills/wealthbox-crm/references/events.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/skills/wealthbox-crm/references/households.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/skills/wealthbox-crm/references/lookups.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/skills/wealthbox-crm/references/notes.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/skills/wealthbox-crm/references/opportunities.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/skills/wealthbox-crm/references/projects.md +0 -0
- {wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/skills/wealthbox-crm/references/workflows.md +0 -0
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"name": "wealthbox-crm",
|
|
11
11
|
"source": "./plugins/wealthbox-crm",
|
|
12
12
|
"description": "Wealthbox CRM agent skill — natural-language CRM automation backed by the `wbox` CLI.",
|
|
13
|
-
"version": "1.
|
|
13
|
+
"version": "1.3.0",
|
|
14
14
|
"category": "productivity",
|
|
15
15
|
"tags": [
|
|
16
16
|
"wealthbox",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wealthbox-crm",
|
|
3
3
|
"description": "Wealthbox CRM agent skill — drive contacts, tasks, notes, events, and households via natural language. Bundles SKILL.md, references, and firm-bootstrap workflow. Requires the `wbox` CLI (auto-install instructions in SKILL.md).",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.4.0",
|
|
5
5
|
"author": "Kadin Bullock",
|
|
6
6
|
"homepage": "https://github.com/massive-value/wealthbox-cli",
|
|
7
7
|
"repository": "https://github.com/massive-value/wealthbox-cli",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wealthbox-cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.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/
|
{wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/plugins/wealthbox-crm/.claude-plugin/plugin.json
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wealthbox-crm",
|
|
3
3
|
"description": "Wealthbox CRM agent skill — drive contacts, tasks, notes, events, and households via natural language. Bundles SKILL.md, references, and firm-bootstrap workflow. Requires the `wbox` CLI (auto-install instructions in SKILL.md).",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.4.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Kadin Bullock"
|
|
7
7
|
},
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import json
|
|
3
4
|
import shutil
|
|
4
5
|
from dataclasses import dataclass
|
|
5
6
|
from pathlib import Path
|
|
@@ -23,18 +24,59 @@ class PluginInstall:
|
|
|
23
24
|
These are managed by the host CLI (`claude plugin install ...` or the
|
|
24
25
|
Codex equivalent) — `wbox skills install` does not write here, and
|
|
25
26
|
`wbox skills uninstall` does not touch them.
|
|
27
|
+
|
|
28
|
+
`active` is True when the host's `installed_plugins.json` has a record
|
|
29
|
+
pointing at this version's installPath. Old/cached versions kept around
|
|
30
|
+
by the host for rollback report active=False. If the host has no
|
|
31
|
+
`installed_plugins.json` (e.g., older Claude Code, or a Codex setup that
|
|
32
|
+
hasn't shipped one yet), `active` defaults to True since we can't tell.
|
|
26
33
|
"""
|
|
27
34
|
host: str # 'claude-code-user' | 'claude-code-project' | 'codex'
|
|
28
35
|
marketplace: str
|
|
29
36
|
version: str
|
|
30
37
|
skill_dir: Path
|
|
38
|
+
active: bool = True
|
|
31
39
|
|
|
32
40
|
|
|
33
41
|
def _home() -> Path:
|
|
34
42
|
return Path.home()
|
|
35
43
|
|
|
36
44
|
|
|
37
|
-
def
|
|
45
|
+
def _read_active_install_paths(plugins_root: Path) -> set[Path] | None:
|
|
46
|
+
"""Read <plugins_root>/installed_plugins.json and return the set of
|
|
47
|
+
install-path roots the host considers active across every scope.
|
|
48
|
+
|
|
49
|
+
Returns None when no state file exists — caller should treat every
|
|
50
|
+
discovered plugin as active in that case (we don't have enough info
|
|
51
|
+
to differentiate cached vs active).
|
|
52
|
+
"""
|
|
53
|
+
state_file = plugins_root / "installed_plugins.json"
|
|
54
|
+
if not state_file.is_file():
|
|
55
|
+
return None
|
|
56
|
+
try:
|
|
57
|
+
data = json.loads(state_file.read_text(encoding="utf-8"))
|
|
58
|
+
except (json.JSONDecodeError, OSError):
|
|
59
|
+
return None
|
|
60
|
+
active: set[Path] = set()
|
|
61
|
+
for entries in (data.get("plugins") or {}).values():
|
|
62
|
+
if not isinstance(entries, list):
|
|
63
|
+
continue
|
|
64
|
+
for entry in entries:
|
|
65
|
+
install_path = entry.get("installPath")
|
|
66
|
+
if not install_path:
|
|
67
|
+
continue
|
|
68
|
+
try:
|
|
69
|
+
active.add(Path(install_path).resolve())
|
|
70
|
+
except OSError:
|
|
71
|
+
active.add(Path(install_path))
|
|
72
|
+
return active
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _scan_plugin_cache(
|
|
76
|
+
cache_root: Path,
|
|
77
|
+
host: str,
|
|
78
|
+
active_paths: set[Path] | None,
|
|
79
|
+
) -> list[PluginInstall]:
|
|
38
80
|
"""Find any `<marketplace>/<plugin-name>/<version>/skills/wealthbox-crm/`
|
|
39
81
|
matches under a Claude Code- or Codex-style plugin cache root."""
|
|
40
82
|
if not cache_root.is_dir():
|
|
@@ -50,13 +92,23 @@ def _scan_plugin_cache(cache_root: Path, host: str) -> list[PluginInstall]:
|
|
|
50
92
|
if not version_dir.is_dir():
|
|
51
93
|
continue
|
|
52
94
|
skill_dir = version_dir / "skills" / SKILL_NAME
|
|
53
|
-
if (skill_dir / "SKILL.md").is_file():
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
95
|
+
if not (skill_dir / "SKILL.md").is_file():
|
|
96
|
+
continue
|
|
97
|
+
try:
|
|
98
|
+
version_dir_resolved = version_dir.resolve()
|
|
99
|
+
except OSError:
|
|
100
|
+
version_dir_resolved = version_dir
|
|
101
|
+
if active_paths is None:
|
|
102
|
+
is_active = True
|
|
103
|
+
else:
|
|
104
|
+
is_active = version_dir_resolved in active_paths
|
|
105
|
+
out.append(PluginInstall(
|
|
106
|
+
host=host,
|
|
107
|
+
marketplace=marketplace_dir.name,
|
|
108
|
+
version=version_dir.name,
|
|
109
|
+
skill_dir=skill_dir,
|
|
110
|
+
active=is_active,
|
|
111
|
+
))
|
|
60
112
|
return out
|
|
61
113
|
|
|
62
114
|
|
|
@@ -72,14 +124,17 @@ def detect_plugin_installs() -> list[PluginInstall]:
|
|
|
72
124
|
home = _home()
|
|
73
125
|
cwd = Path.cwd()
|
|
74
126
|
candidates = [
|
|
75
|
-
(home / ".claude" / "plugins"
|
|
76
|
-
(cwd / ".claude" / "plugins"
|
|
77
|
-
(home / ".codex" / "plugins"
|
|
127
|
+
(home / ".claude" / "plugins", "claude-code-user"),
|
|
128
|
+
(cwd / ".claude" / "plugins", "claude-code-project"),
|
|
129
|
+
(home / ".codex" / "plugins", "codex"),
|
|
78
130
|
]
|
|
79
131
|
installs: list[PluginInstall] = []
|
|
80
132
|
seen: set[Path] = set()
|
|
81
|
-
for
|
|
82
|
-
|
|
133
|
+
for plugins_root, host in candidates:
|
|
134
|
+
active_paths = _read_active_install_paths(plugins_root)
|
|
135
|
+
for pi in _scan_plugin_cache(
|
|
136
|
+
plugins_root / "cache", host=host, active_paths=active_paths,
|
|
137
|
+
):
|
|
83
138
|
try:
|
|
84
139
|
key = pi.skill_dir.resolve()
|
|
85
140
|
except OSError:
|
|
@@ -416,6 +416,32 @@ def build_resource_filter(
|
|
|
416
416
|
return result
|
|
417
417
|
|
|
418
418
|
|
|
419
|
+
async def resolve_category_id(
|
|
420
|
+
client: WealthboxClient, category_type: CategoryType, value: str
|
|
421
|
+
) -> int:
|
|
422
|
+
"""Resolve a category name or numeric string to an integer ID.
|
|
423
|
+
|
|
424
|
+
If `value` is purely digits, returns int(value) without an API call.
|
|
425
|
+
Otherwise fetches all categories of the given type and case-insensitively
|
|
426
|
+
matches `name`. Raises typer.BadParameter on miss with available names.
|
|
427
|
+
"""
|
|
428
|
+
if value.isdigit():
|
|
429
|
+
return int(value)
|
|
430
|
+
data = await client.list_all_categories(category_type)
|
|
431
|
+
items = data.get(category_type.value, [])
|
|
432
|
+
target = value.strip().casefold()
|
|
433
|
+
for item in items:
|
|
434
|
+
if str(item.get("name", "")).casefold() == target:
|
|
435
|
+
return int(item["id"])
|
|
436
|
+
available = sorted(str(i["name"]) for i in items if i.get("name"))
|
|
437
|
+
label = category_type.value.replace("_", " ")
|
|
438
|
+
if available:
|
|
439
|
+
raise typer.BadParameter(
|
|
440
|
+
f"Unknown {label} value '{value}'. Available: {', '.join(available)}"
|
|
441
|
+
)
|
|
442
|
+
raise typer.BadParameter(f"No {label} configured in this workspace.")
|
|
443
|
+
|
|
444
|
+
|
|
419
445
|
def parse_more_fields(more_fields: str, reserved: set[str]) -> dict[str, Any]:
|
|
420
446
|
"""Parse --more-fields JSON and validate against reserved keys.
|
|
421
447
|
|
|
@@ -122,10 +122,14 @@ def run_doctor(token: str | None = None) -> int:
|
|
|
122
122
|
if not plugin_installs:
|
|
123
123
|
typer.echo(" (none detected)")
|
|
124
124
|
else:
|
|
125
|
+
# Active first, then cached (descending version) so the live
|
|
126
|
+
# install is the first thing the eye lands on.
|
|
127
|
+
plugin_installs.sort(key=lambda p: (not p.active, p.version), reverse=False)
|
|
125
128
|
for pi in plugin_installs:
|
|
129
|
+
status_label = "active" if pi.active else "cached"
|
|
126
130
|
typer.echo(
|
|
127
131
|
f" {pi.host:<22} plugin@{pi.marketplace:<18} "
|
|
128
|
-
f"version={pi.version:<
|
|
132
|
+
f"version={pi.version:<8} {status_label:<7} {pi.skill_dir}"
|
|
129
133
|
)
|
|
130
134
|
|
|
131
135
|
# --- Firm data --------------------------------------------------------
|
|
@@ -70,11 +70,13 @@ def list_platforms() -> None:
|
|
|
70
70
|
"installed" if installed else "not installed",
|
|
71
71
|
template_version,
|
|
72
72
|
))
|
|
73
|
-
|
|
73
|
+
plugin_installs = detect_plugin_installs()
|
|
74
|
+
plugin_installs.sort(key=lambda p: (not p.active, p.version))
|
|
75
|
+
for pi in plugin_installs:
|
|
74
76
|
rows.append((
|
|
75
77
|
f"plugin:{pi.host}",
|
|
76
78
|
str(pi.skill_dir),
|
|
77
|
-
f"plugin@{pi.marketplace}",
|
|
79
|
+
f"plugin@{pi.marketplace} ({'active' if pi.active else 'cached'})",
|
|
78
80
|
pi.version,
|
|
79
81
|
))
|
|
80
82
|
|
|
@@ -25,6 +25,7 @@ from ._util import (
|
|
|
25
25
|
make_resource_app,
|
|
26
26
|
output_result,
|
|
27
27
|
parse_more_fields,
|
|
28
|
+
resolve_category_id,
|
|
28
29
|
run_client,
|
|
29
30
|
run_client_with_comments,
|
|
30
31
|
slim_comments,
|
|
@@ -47,7 +48,9 @@ _GET_JSON_FIELDS = [
|
|
|
47
48
|
"category", "linked_to", "comments",
|
|
48
49
|
]
|
|
49
50
|
|
|
50
|
-
_TASK_CREATE_RESERVED = {
|
|
51
|
+
_TASK_CREATE_RESERVED = {
|
|
52
|
+
"name", "due_date", "frame", "priority", "assigned_to", "linked_to", "category", "description",
|
|
53
|
+
}
|
|
51
54
|
|
|
52
55
|
|
|
53
56
|
@app.command(
|
|
@@ -130,13 +133,18 @@ def add_task(
|
|
|
130
133
|
),
|
|
131
134
|
frame: TaskFrame | None = typer.Option(None, "--frame", help="Friendly due timeframe"),
|
|
132
135
|
priority: TaskPriority | None = typer.Option(None, "--priority", help="Low, Medium, or High"),
|
|
136
|
+
category: str | None = typer.Option(
|
|
137
|
+
None, "--category",
|
|
138
|
+
help="Task category by name or ID — see: wbox categories task-categories",
|
|
139
|
+
),
|
|
140
|
+
description: str | None = typer.Option(None, "--description", help="Task description"),
|
|
133
141
|
assigned_to: int | None = typer.Option(None, "--assigned-to", help="Assign to a user by ID"),
|
|
134
142
|
contact: int | None = typer.Option(None, "--contact", help="Link to a Contact by ID"),
|
|
135
143
|
project: int | None = typer.Option(None, "--project", help="Link to a Project by ID"),
|
|
136
144
|
opportunity: int | None = typer.Option(None, "--opportunity", help="Link to an Opportunity by ID"),
|
|
137
145
|
more_fields: str | None = typer.Option(
|
|
138
146
|
None, "--more-fields",
|
|
139
|
-
help='JSON: {"
|
|
147
|
+
help='JSON: {"complete": false, "assigned_to_team": 456}',
|
|
140
148
|
),
|
|
141
149
|
token: str | None = typer.Option(None, envvar="WEALTHBOX_TOKEN", hidden=True),
|
|
142
150
|
fmt: OutputFormat = typer.Option(OutputFormat.JSON, "--format"),
|
|
@@ -150,6 +158,7 @@ def add_task(
|
|
|
150
158
|
"due_date": due_date,
|
|
151
159
|
"frame": frame,
|
|
152
160
|
"priority": priority,
|
|
161
|
+
"description": description,
|
|
153
162
|
"assigned_to": assigned_to,
|
|
154
163
|
"linked_to": build_linked_to(contact, project, opportunity),
|
|
155
164
|
}
|
|
@@ -157,10 +166,14 @@ def add_task(
|
|
|
157
166
|
if more_fields:
|
|
158
167
|
payload.update(parse_more_fields(more_fields, _TASK_CREATE_RESERVED))
|
|
159
168
|
|
|
160
|
-
|
|
161
|
-
|
|
169
|
+
async def _create(client): # type: ignore[no-untyped-def]
|
|
170
|
+
if category is not None:
|
|
171
|
+
payload["category"] = await resolve_category_id(client, CategoryType.TASK_CATEGORIES, category)
|
|
172
|
+
# Strip None before model construction (due_date XOR frame validator needs clean input)
|
|
173
|
+
clean = {k: v for k, v in payload.items() if v is not None}
|
|
174
|
+
return await client.create_task(TaskCreateInput(**clean))
|
|
162
175
|
|
|
163
|
-
output_result(run_client(token,
|
|
176
|
+
output_result(run_client(token, _create), fmt)
|
|
164
177
|
|
|
165
178
|
|
|
166
179
|
@app.command("update", help="Update an existing task. Pass only the fields you want to change.")
|
|
@@ -171,6 +184,10 @@ def update_task(
|
|
|
171
184
|
due_date: str | None = typer.Option(None, "--due-date", help="ISO 8601 datetime, e.g. '2026-04-01T09:00:00-07:00'"),
|
|
172
185
|
frame: TaskFrame | None = typer.Option(None, "--frame", help="Friendly due timeframe"),
|
|
173
186
|
priority: TaskPriority | None = typer.Option(None, "--priority", help="Low, Medium, or High"),
|
|
187
|
+
category: str | None = typer.Option(
|
|
188
|
+
None, "--category",
|
|
189
|
+
help="Task category by name or ID — see: wbox categories task-categories",
|
|
190
|
+
),
|
|
174
191
|
assigned_to: int | None = typer.Option(None, "--assigned-to", help="Reassign to a user by ID"),
|
|
175
192
|
complete: bool | None = typer.Option(None, "--complete/--no-complete", help="Mark as complete or incomplete"),
|
|
176
193
|
description: str | None = typer.Option(None, "--description"),
|
|
@@ -193,9 +210,13 @@ def update_task(
|
|
|
193
210
|
linked = build_linked_to(contact, project, opportunity)
|
|
194
211
|
if linked is not None:
|
|
195
212
|
payload["linked_to"] = linked
|
|
196
|
-
input_model = TaskUpdateInput(**payload)
|
|
197
213
|
|
|
198
|
-
|
|
214
|
+
async def _update(client): # type: ignore[no-untyped-def]
|
|
215
|
+
if category is not None:
|
|
216
|
+
payload["category"] = await resolve_category_id(client, CategoryType.TASK_CATEGORIES, category)
|
|
217
|
+
return await client.update_task(task_id, TaskUpdateInput(**payload))
|
|
218
|
+
|
|
219
|
+
output_result(run_client(token, _update), fmt)
|
|
199
220
|
|
|
200
221
|
|
|
201
222
|
@app.command("delete", help="Delete a task by ID.")
|
|
@@ -46,11 +46,13 @@ wbox tasks add <NAME> [OPTIONS]
|
|
|
46
46
|
| `--due-date` | STR | Due date (XOR with --frame) |
|
|
47
47
|
| `--frame` | today\|tomorrow\|this-week\|next-week\|this-month\|next-month\|... | Relative due date (XOR with --due-date) |
|
|
48
48
|
| `--priority` | Low\|Medium\|High | Priority level |
|
|
49
|
+
| `--category` | STR | Task category by name or ID (e.g. "Follow-up"). See `wbox categories task-categories`. |
|
|
50
|
+
| `--description` | STR | Task description |
|
|
49
51
|
| `--assigned-to` | INT | Assign to user ID |
|
|
50
52
|
| `--contact` | INT | Link to contact |
|
|
51
53
|
| `--project` | INT | Link to project |
|
|
52
54
|
| `--opportunity` | INT | Link to opportunity |
|
|
53
|
-
| `--more-fields` | JSON | e.g. `{"
|
|
55
|
+
| `--more-fields` | JSON | e.g. `{"complete": false, "assigned_to_team": 456}` |
|
|
54
56
|
| `--format` | json\|table\|csv\|tsv | Output format |
|
|
55
57
|
|
|
56
58
|
**Note:** `--due-date` and `--frame` are mutually exclusive. Use `--frame` for relative dates.
|
|
@@ -67,6 +69,7 @@ wbox tasks update <ID> [OPTIONS]
|
|
|
67
69
|
| `--due-date` | STR | Change due date |
|
|
68
70
|
| `--frame` | STR | Change relative due date |
|
|
69
71
|
| `--priority` | Low\|Medium\|High | Change priority |
|
|
72
|
+
| `--category` | STR | Task category by name or ID. See `wbox categories task-categories`. |
|
|
70
73
|
| `--assigned-to` | INT | Reassign |
|
|
71
74
|
| `--complete` / `--no-complete` | flag | Mark complete/incomplete |
|
|
72
75
|
| `--description` | STR | Update description |
|
|
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.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/firm-examples/contacts.md
RENAMED
|
File without changes
|
{wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/firm-examples/events.md
RENAMED
|
File without changes
|
{wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/firm-examples/notes.md
RENAMED
|
File without changes
|
{wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/firm-examples/opportunities.md
RENAMED
|
File without changes
|
{wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/firm-examples/projects.md
RENAMED
|
File without changes
|
{wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/firm-examples/tasks.md
RENAMED
|
File without changes
|
{wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/firm-examples/workflows.md
RENAMED
|
File without changes
|
{wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/references/contacts.md
RENAMED
|
File without changes
|
|
File without changes
|
{wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/references/households.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/references/opportunities.md
RENAMED
|
File without changes
|
{wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/codex-skill/wealthbox-crm/references/projects.md
RENAMED
|
File without changes
|
|
File without changes
|
{wealthbox_cli-1.3.0 → wealthbox_cli-1.4.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
|
|
File without changes
|
{wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/plugins/wealthbox-crm/skills/wealthbox-crm/SKILL.md
RENAMED
|
File without changes
|
{wealthbox_cli-1.3.0 → wealthbox_cli-1.4.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
|
{wealthbox_cli-1.3.0 → wealthbox_cli-1.4.0}/src/wealthbox_tools/skills/wealthbox-crm/SKILL.md
RENAMED
|
File without changes
|
{wealthbox_cli-1.3.0 → wealthbox_cli-1.4.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
|