tetra-cli 0.2.0__py3-none-any.whl
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.
- tetra_cli/__init__.py +6 -0
- tetra_cli/api_client/__init__.py +10 -0
- tetra_cli/api_client/client.py +173 -0
- tetra_cli/api_client/config.py +125 -0
- tetra_cli/api_client/operations/__init__.py +9 -0
- tetra_cli/api_client/operations/accounts.py +303 -0
- tetra_cli/api_client/operations/ai.py +278 -0
- tetra_cli/api_client/operations/analysis.py +190 -0
- tetra_cli/api_client/operations/api_keys.py +145 -0
- tetra_cli/api_client/operations/archive.py +114 -0
- tetra_cli/api_client/operations/awards.py +123 -0
- tetra_cli/api_client/operations/capacity.py +84 -0
- tetra_cli/api_client/operations/conversations.py +447 -0
- tetra_cli/api_client/operations/conversations_2.py +262 -0
- tetra_cli/api_client/operations/cosmetics.py +148 -0
- tetra_cli/api_client/operations/dashboard.py +282 -0
- tetra_cli/api_client/operations/data.py +250 -0
- tetra_cli/api_client/operations/events.py +734 -0
- tetra_cli/api_client/operations/gamification.py +470 -0
- tetra_cli/api_client/operations/goals.py +1144 -0
- tetra_cli/api_client/operations/groups.py +647 -0
- tetra_cli/api_client/operations/issues.py +198 -0
- tetra_cli/api_client/operations/offset.py +61 -0
- tetra_cli/api_client/operations/onboarding.py +284 -0
- tetra_cli/api_client/operations/outcome_schemas.py +292 -0
- tetra_cli/api_client/operations/peer_connections.py +243 -0
- tetra_cli/api_client/operations/plaid.py +329 -0
- tetra_cli/api_client/operations/reminders.py +273 -0
- tetra_cli/api_client/operations/scratches.py +280 -0
- tetra_cli/api_client/operations/skill_trees.py +160 -0
- tetra_cli/api_client/operations/social_2.py +560 -0
- tetra_cli/api_client/operations/social_3.py +618 -0
- tetra_cli/api_client/operations/social_4.py +527 -0
- tetra_cli/api_client/operations/strava.py +215 -0
- tetra_cli/api_client/operations/stripe.py +113 -0
- tetra_cli/api_client/operations/tags.py +488 -0
- tetra_cli/api_client/operations/values.py +867 -0
- tetra_cli/api_client/operations/values_2.py +584 -0
- tetra_cli/api_client/operations/watch.py +105 -0
- tetra_cli/api_client/operations/webhooks.py +50 -0
- tetra_cli/api_client/operations/xp.py +27 -0
- tetra_cli/cli/__init__.py +5 -0
- tetra_cli/cli/__main__.py +5 -0
- tetra_cli/cli/app.py +86 -0
- tetra_cli/cli/commands/__init__.py +1 -0
- tetra_cli/cli/commands/auth.py +201 -0
- tetra_cli/cli/commands/guide.py +8 -0
- tetra_cli/cli/commands/messages.py +161 -0
- tetra_cli/cli/commands/skill.py +71 -0
- tetra_cli/cli/context.py +13 -0
- tetra_cli/cli/generate.py +282 -0
- tetra_cli/cli/output.py +58 -0
- tetra_cli/mcp_gen.py +137 -0
- tetra_cli/ontology.py +70 -0
- tetra_cli/registry.py +118 -0
- tetra_cli/skill/SKILL.md +69 -0
- tetra_cli/skill/__init__.py +1 -0
- tetra_cli-0.2.0.dist-info/METADATA +140 -0
- tetra_cli-0.2.0.dist-info/RECORD +62 -0
- tetra_cli-0.2.0.dist-info/WHEEL +5 -0
- tetra_cli-0.2.0.dist-info/entry_points.txt +2 -0
- tetra_cli-0.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"""Pure async operations for the archive API.
|
|
2
|
+
|
|
3
|
+
The archive surface lets an agent inspect and recover entities (values,
|
|
4
|
+
goals, events) that were soft-deleted. Listing and inspecting are reads;
|
|
5
|
+
restore recreates the entity from its archived snapshot, while permanent
|
|
6
|
+
delete removes the archived row for good (irreversible).
|
|
7
|
+
"""
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from tetra_cli.api_client import TetraClient
|
|
11
|
+
from tetra_cli.registry import arg, operation, opt
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@operation(
|
|
15
|
+
cli="archive list",
|
|
16
|
+
summary="List archived (soft-deleted) entities, newest first.",
|
|
17
|
+
covers=[("GET", "/api/v1/archive/")],
|
|
18
|
+
params={
|
|
19
|
+
"entity_type": opt(
|
|
20
|
+
"--entity-type",
|
|
21
|
+
choices=["value", "goal", "event"],
|
|
22
|
+
help="Filter by entity type (value | goal | event).",
|
|
23
|
+
),
|
|
24
|
+
},
|
|
25
|
+
)
|
|
26
|
+
async def list_archived(
|
|
27
|
+
client: TetraClient,
|
|
28
|
+
*,
|
|
29
|
+
entity_type: str | None = None,
|
|
30
|
+
) -> list[dict[str, Any]]:
|
|
31
|
+
"""List all archived entities for the current user.
|
|
32
|
+
|
|
33
|
+
Optionally filter by entity type. Results come back sorted by deletion
|
|
34
|
+
date, most recent first.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
client: Authenticated TetraClient
|
|
38
|
+
entity_type: Optional filter — one of 'value', 'goal', or 'event'.
|
|
39
|
+
When None, all archived entities are returned.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
List of archived-entity dicts (uid, original_uid, entity_type,
|
|
43
|
+
entity_name, deleted_at, deleted_reason, cascade_from_uid).
|
|
44
|
+
"""
|
|
45
|
+
params: dict[str, Any] = {}
|
|
46
|
+
if entity_type is not None:
|
|
47
|
+
params["entity_type"] = entity_type
|
|
48
|
+
return await client.get("/api/v1/archive/", params=params or None)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
@operation(
|
|
52
|
+
cli="archive get",
|
|
53
|
+
summary="Get a single archived entity by its archive UID.",
|
|
54
|
+
covers=[("GET", "/api/v1/archive/{uid}")],
|
|
55
|
+
params={"uid": arg(help="Archive entry UID")},
|
|
56
|
+
)
|
|
57
|
+
async def get_archived(client: TetraClient, uid: str) -> dict[str, Any]:
|
|
58
|
+
"""Get a single archived entity by UID.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
client: Authenticated TetraClient
|
|
62
|
+
uid: The archive entry's UID (not the original entity UID).
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Archived-entity dict.
|
|
66
|
+
"""
|
|
67
|
+
return await client.get(f"/api/v1/archive/{uid}")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@operation(
|
|
71
|
+
cli="archive restore",
|
|
72
|
+
summary="Restore an archived entity, recreating it with its original data.",
|
|
73
|
+
covers=[("POST", "/api/v1/archive/{uid}/restore")],
|
|
74
|
+
params={"uid": arg(help="Archive entry UID to restore")},
|
|
75
|
+
)
|
|
76
|
+
async def restore_archived(client: TetraClient, uid: str) -> dict[str, Any]:
|
|
77
|
+
"""Restore an archived entity.
|
|
78
|
+
|
|
79
|
+
The entity is recreated from its archived snapshot. Restoration fails
|
|
80
|
+
(the API returns an error) if an active entity with the same name
|
|
81
|
+
already exists, or if restoring a goal/value would exceed the account's
|
|
82
|
+
active-entity capacity.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
client: Authenticated TetraClient
|
|
86
|
+
uid: The archive entry's UID to restore.
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
Restore result dict with 'restored' (bool) and the recreated
|
|
90
|
+
entity 'uid' on success.
|
|
91
|
+
"""
|
|
92
|
+
return await client.post(f"/api/v1/archive/{uid}/restore")
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@operation(
|
|
96
|
+
cli="archive delete",
|
|
97
|
+
summary="Permanently delete an archived entity (irreversible).",
|
|
98
|
+
covers=[("DELETE", "/api/v1/archive/{uid}")],
|
|
99
|
+
params={"uid": arg(help="Archive entry UID to permanently delete")},
|
|
100
|
+
)
|
|
101
|
+
async def delete_archived(client: TetraClient, uid: str) -> dict[str, Any]:
|
|
102
|
+
"""Permanently delete an archived entity.
|
|
103
|
+
|
|
104
|
+
This action cannot be undone — the archived row is removed entirely and
|
|
105
|
+
the entity can no longer be restored.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
client: Authenticated TetraClient
|
|
109
|
+
uid: The archive entry's UID to permanently delete.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
Deletion confirmation dict ({'deleted': True} on 204).
|
|
113
|
+
"""
|
|
114
|
+
return await client.delete(f"/api/v1/archive/{uid}")
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""Pure async operations for the awards API.
|
|
2
|
+
|
|
3
|
+
Awards are the gamification catalog: definitions describe possible
|
|
4
|
+
achievements, progress tracks a user toward each one, evaluation scans data to
|
|
5
|
+
grant missing awards, and seeding installs the predefined definitions. These
|
|
6
|
+
ops mirror the backend ``/api/v1/awards`` routes one-to-one.
|
|
7
|
+
"""
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from tetra_cli.api_client import TetraClient
|
|
11
|
+
from tetra_cli.registry import arg, operation, opt
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@operation(
|
|
15
|
+
cli="awards definitions",
|
|
16
|
+
summary="List all award definitions in the catalog.",
|
|
17
|
+
covers=[("GET", "/api/v1/awards/definitions")],
|
|
18
|
+
)
|
|
19
|
+
async def list_award_definitions(client: TetraClient) -> dict[str, Any]:
|
|
20
|
+
"""List the catalog of all possible awards with criteria and rewards.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
client: Authenticated TetraClient
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
Dict with a 'definitions' list.
|
|
27
|
+
"""
|
|
28
|
+
return await client.get("/api/v1/awards/definitions")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@operation(
|
|
32
|
+
cli="awards progress",
|
|
33
|
+
summary="Show progress toward all awards.",
|
|
34
|
+
covers=[("GET", "/api/v1/awards/progress")],
|
|
35
|
+
)
|
|
36
|
+
async def get_award_progress(client: TetraClient) -> dict[str, Any]:
|
|
37
|
+
"""Get progress (level, triggers, credits) toward every award.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
client: Authenticated TetraClient
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
Dict with an 'awards' list and a 'summary'.
|
|
44
|
+
"""
|
|
45
|
+
return await client.get("/api/v1/awards/progress")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@operation(
|
|
49
|
+
cli="awards progress-for",
|
|
50
|
+
summary="Show progress toward a single award.",
|
|
51
|
+
covers=[("GET", "/api/v1/awards/progress/{award_id}")],
|
|
52
|
+
params={"award_id": arg(help="Award definition id")},
|
|
53
|
+
)
|
|
54
|
+
async def get_award_progress_for(
|
|
55
|
+
client: TetraClient, award_id: str
|
|
56
|
+
) -> dict[str, Any]:
|
|
57
|
+
"""Get progress toward one specific award.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
client: Authenticated TetraClient
|
|
61
|
+
award_id: The award definition id to look up.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
Award progress dict for the given award.
|
|
65
|
+
"""
|
|
66
|
+
return await client.get(f"/api/v1/awards/progress/{award_id}")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@operation(
|
|
70
|
+
cli="awards evaluate",
|
|
71
|
+
summary="Scan data and grant any missing awards.",
|
|
72
|
+
covers=[("POST", "/api/v1/awards/evaluate")],
|
|
73
|
+
params={
|
|
74
|
+
"start_date": opt("--start-date", help="Only consider data from this date (YYYY-MM-DD)"),
|
|
75
|
+
"end_date": opt("--end-date", help="Only consider data until this date (YYYY-MM-DD)"),
|
|
76
|
+
},
|
|
77
|
+
)
|
|
78
|
+
async def evaluate_awards(
|
|
79
|
+
client: TetraClient,
|
|
80
|
+
*,
|
|
81
|
+
dry_run: bool = False,
|
|
82
|
+
start_date: str | None = None,
|
|
83
|
+
end_date: str | None = None,
|
|
84
|
+
as_regular: bool = False,
|
|
85
|
+
) -> dict[str, Any]:
|
|
86
|
+
"""Evaluate all data and grant awards that should have been earned.
|
|
87
|
+
|
|
88
|
+
Useful after a data import. ``dry_run`` calculates without granting.
|
|
89
|
+
``as_regular`` is superuser-only and grants full (non-retroactive) credits.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
client: Authenticated TetraClient
|
|
93
|
+
dry_run: If True, calculate but do not grant awards.
|
|
94
|
+
start_date: Optional lower bound date filter (YYYY-MM-DD).
|
|
95
|
+
end_date: Optional upper bound date filter (YYYY-MM-DD).
|
|
96
|
+
as_regular: Superuser only — grant as regular awards with full credits.
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
Dict with 'results', 'total_credits', 'total_xp', and 'dry_run'.
|
|
100
|
+
"""
|
|
101
|
+
body: dict[str, Any] = {"dry_run": dry_run, "as_regular": as_regular}
|
|
102
|
+
if start_date is not None:
|
|
103
|
+
body["start_date"] = start_date
|
|
104
|
+
if end_date is not None:
|
|
105
|
+
body["end_date"] = end_date
|
|
106
|
+
return await client.post("/api/v1/awards/evaluate", json=body)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@operation(
|
|
110
|
+
cli="awards seed",
|
|
111
|
+
summary="Seed predefined award definitions into the database.",
|
|
112
|
+
covers=[("POST", "/api/v1/awards/seed")],
|
|
113
|
+
)
|
|
114
|
+
async def seed_award_definitions(client: TetraClient) -> dict[str, Any]:
|
|
115
|
+
"""Create any predefined award definitions that don't already exist.
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
client: Authenticated TetraClient
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
Dict with 'created' count and a 'message'.
|
|
122
|
+
"""
|
|
123
|
+
return await client.post("/api/v1/awards/seed")
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""Pure async operations for the capacity API.
|
|
2
|
+
|
|
3
|
+
Capacity tracks how many *active* entities the caller (or a group) may hold.
|
|
4
|
+
Personal scope exposes the effective cap, current usage, credit-purchased
|
|
5
|
+
slots, and the escalating cost of the next slot; group scope exposes the
|
|
6
|
+
shared-pool cap. Slots are bought with credits via ``purchase-slot``.
|
|
7
|
+
|
|
8
|
+
These ops are the single source of truth for both the CLI and MCP surfaces —
|
|
9
|
+
each is a thin async wrapper over :class:`TetraClient`.
|
|
10
|
+
"""
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
from tetra_cli.api_client import TetraClient
|
|
14
|
+
from tetra_cli.registry import arg, operation
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@operation(
|
|
18
|
+
cli="capacity status",
|
|
19
|
+
summary="Show the caller's active/archive capacity usage and next-slot cost.",
|
|
20
|
+
covers=[("GET", "/api/v1/capacity/")],
|
|
21
|
+
)
|
|
22
|
+
async def get_capacity(client: TetraClient) -> dict[str, Any]:
|
|
23
|
+
"""Show active-entity capacity status for the caller's personal scope.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
client: Authenticated TetraClient
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
Dict with ``effective_cap`` (null == unlimited for Pro),
|
|
30
|
+
``active_count``, ``archive_cap``, ``archive_count``, ``is_pro``,
|
|
31
|
+
``at_capacity``, ``purchased_slots`` (credit-bought cap slots), and
|
|
32
|
+
``next_slot_cost`` (credit price of the next slot; null for Pro/comp).
|
|
33
|
+
"""
|
|
34
|
+
return await client.get("/api/v1/capacity/")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@operation(
|
|
38
|
+
cli="capacity group",
|
|
39
|
+
summary="Show shared-pool capacity for a group the caller can see.",
|
|
40
|
+
covers=[("GET", "/api/v1/capacity/group/{group_uid}")],
|
|
41
|
+
params={"group_uid": arg(help="Group UID")},
|
|
42
|
+
)
|
|
43
|
+
async def get_group_capacity(
|
|
44
|
+
client: TetraClient, group_uid: str,
|
|
45
|
+
) -> dict[str, Any]:
|
|
46
|
+
"""Show shared-pool capacity for a group the caller can see.
|
|
47
|
+
|
|
48
|
+
Non-members of a private group get a 404 (surfaced as a ``Not found``
|
|
49
|
+
error) so the endpoint never discloses the group's existence.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
client: Authenticated TetraClient
|
|
53
|
+
group_uid: Group UID
|
|
54
|
+
|
|
55
|
+
Returns:
|
|
56
|
+
Dict with the group's ``effective_cap`` (null == unlimited),
|
|
57
|
+
``active_count``, ``is_unlimited``, and ``at_capacity``.
|
|
58
|
+
"""
|
|
59
|
+
return await client.get(f"/api/v1/capacity/group/{group_uid}")
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@operation(
|
|
63
|
+
cli="capacity purchase-slot",
|
|
64
|
+
summary="Buy the next credit-purchased active capacity slot.",
|
|
65
|
+
covers=[("POST", "/api/v1/capacity/purchase-slot")],
|
|
66
|
+
)
|
|
67
|
+
async def purchase_capacity_slot(client: TetraClient) -> dict[str, Any]:
|
|
68
|
+
"""Buy the next credit-purchased active slot (escalating credit cost).
|
|
69
|
+
|
|
70
|
+
The endpoint takes no body — the next slot's cost and the caller's
|
|
71
|
+
eligibility are derived server-side from the account state.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
client: Authenticated TetraClient
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
Updated capacity dict reflecting the new ``purchased_slots`` and
|
|
78
|
+
``next_slot_cost``.
|
|
79
|
+
|
|
80
|
+
Raises:
|
|
81
|
+
TetraClientError: 400 ``insufficient_credits`` if the balance is too
|
|
82
|
+
low; 400 ``unlimited_capacity`` for Pro/comped accounts.
|
|
83
|
+
"""
|
|
84
|
+
return await client.post("/api/v1/capacity/purchase-slot")
|