|
# retoor <retoor@molodetz.nl>
|
|
|
|
import sys
|
|
from devplacepy.database import db, get_table
|
|
from devplacepy.cli._shared import _audit_cli
|
|
|
|
|
|
def cmd_devii_reset_quota(args):
|
|
table_name = "devii_usage_ledger"
|
|
if table_name not in db.tables:
|
|
print(f"Table '{table_name}' does not exist, nothing to reset")
|
|
return
|
|
table = db[table_name]
|
|
if args.all:
|
|
count = table.count()
|
|
table.delete()
|
|
_audit_cli("cli.devii.quota.reset", "CLI reset AI quota (all)", metadata={"scope": "all", "rows_removed": count})
|
|
print(f"Reset all AI quotas ({count} ledger rows deleted)")
|
|
return
|
|
if args.guests:
|
|
count = table.count(owner_kind="guest")
|
|
table.delete(owner_kind="guest")
|
|
_audit_cli("cli.devii.quota.reset", "CLI reset AI quota (guests)", metadata={"scope": "guests", "rows_removed": count})
|
|
print(f"Reset all guest AI quotas ({count} ledger rows deleted)")
|
|
return
|
|
if not args.username:
|
|
print("Provide a username, or --guests, or --all")
|
|
sys.exit(1)
|
|
user = get_table("users").find_one(username=args.username)
|
|
if not user:
|
|
print(f"User '{args.username}' not found")
|
|
sys.exit(1)
|
|
count = table.count(owner_kind="user", owner_id=user["uid"])
|
|
table.delete(owner_kind="user", owner_id=user["uid"])
|
|
from devplacepy.services.audit import record as audit
|
|
|
|
_audit_cli(
|
|
"cli.devii.quota.reset",
|
|
f"CLI reset AI quota for {args.username}",
|
|
metadata={"scope": "user", "rows_removed": count},
|
|
target_type="user",
|
|
target_uid=user["uid"],
|
|
target_label=args.username,
|
|
links=[audit.target("user", user["uid"], args.username)],
|
|
)
|
|
print(f"Reset AI quota for '{args.username}' ({count} ledger rows deleted)")
|
|
|
|
|
|
def _active_count() -> int:
|
|
if "devii_lessons" not in db.tables:
|
|
return 0
|
|
return db["devii_lessons"].count(deleted_at=None)
|
|
|
|
|
|
def _soft_deleted_count() -> int:
|
|
if "devii_lessons" not in db.tables:
|
|
return 0
|
|
return db["devii_lessons"].count(deleted_at={"!=": None})
|
|
|
|
|
|
def cmd_devii_lessons_count(args):
|
|
active = _active_count()
|
|
deleted = _soft_deleted_count()
|
|
print(f"Lessons: {active} active, {deleted} soft-deleted ({active + deleted} total)")
|
|
|
|
|
|
def cmd_devii_lessons_clear(args):
|
|
from devplacepy.services.devii.agentic.lessons import TABLE
|
|
|
|
if TABLE not in db.tables:
|
|
print("No devii_lessons table exists")
|
|
return
|
|
active = _active_count()
|
|
deleted = _soft_deleted_count()
|
|
total = active + deleted
|
|
if not args.force:
|
|
print(f"Will delete {total} lesson(s) ({active} active, {deleted} soft-deleted). Pass --force to confirm.")
|
|
return
|
|
db[TABLE].delete()
|
|
_audit_cli("cli.devii.lessons.clear", "CLI cleared all devii_lessons", metadata={"active": active, "soft_deleted": deleted})
|
|
print(f"Deleted {total} lesson(s)")
|
|
|
|
|
|
def cmd_devii_lessons_prune(args):
|
|
from devplacepy.services.devii.agentic.lessons import LessonStore, _read_retention_settings
|
|
|
|
if "devii_lessons" not in db.tables:
|
|
print("No devii_lessons table exists")
|
|
return
|
|
active_before = _active_count()
|
|
if args.all_owners:
|
|
_, max_age = _read_retention_settings(db)
|
|
store = LessonStore(db, "_global", "_global")
|
|
pruned = store.prune_all_owners(max_age)
|
|
elif args.username:
|
|
user = get_table("users").find_one(username=args.username)
|
|
if not user:
|
|
print(f"User '{args.username}' not found")
|
|
sys.exit(1)
|
|
_, max_age = _read_retention_settings(db)
|
|
store = LessonStore(db, "user", user["uid"])
|
|
pruned = store.prune(max_age)
|
|
else:
|
|
print("Provide --all-owners, or --username USER")
|
|
sys.exit(1)
|
|
_audit_cli("cli.devii.lessons.prune", "CLI pruned devii_lessons", metadata={"pruned": pruned, "active_before": active_before})
|
|
print(f"Pruned {pruned} lesson(s) (active before: {active_before}, now: {_active_count()})")
|
|
|
|
|
|
def register_devii(subparsers):
|
|
devii = subparsers.add_parser("devii", help="Devii assistant management")
|
|
devii_sub = devii.add_subparsers(title="action", dest="action")
|
|
devii_reset = devii_sub.add_parser(
|
|
"reset-quota", help="Reset the rolling 24h AI spend quota"
|
|
)
|
|
devii_reset.add_argument(
|
|
"username", nargs="?", help="Reset the quota for a single user"
|
|
)
|
|
devii_reset.add_argument(
|
|
"--guests", action="store_true", help="Reset every guest quota"
|
|
)
|
|
devii_reset.add_argument(
|
|
"--all", action="store_true", help="Reset every quota (users and guests)"
|
|
)
|
|
devii_reset.set_defaults(func=cmd_devii_reset_quota)
|
|
|
|
devii_lessons = devii_sub.add_parser("lessons", help="Manage persisted Devii lesson data")
|
|
lessons_sub = devii_lessons.add_subparsers(title="sub-action", dest="sub_action")
|
|
|
|
lessons_count = lessons_sub.add_parser("count", help="Count active and soft-deleted lessons")
|
|
lessons_count.set_defaults(func=cmd_devii_lessons_count)
|
|
|
|
lessons_prune = lessons_sub.add_parser("prune", help="Soft-delete lessons older than the configured max age")
|
|
lessons_prune.add_argument("--all-owners", action="store_true", help="Prune across every owner")
|
|
lessons_prune.add_argument("--username", help="Prune for a specific user")
|
|
lessons_prune.set_defaults(func=cmd_devii_lessons_prune)
|
|
|
|
lessons_clear = lessons_sub.add_parser("clear", help="Hard-delete every devii_lessons row")
|
|
lessons_clear.add_argument("--force", action="store_true", help="Required to confirm hard deletion")
|
|
lessons_clear.set_defaults(func=cmd_devii_lessons_clear)
|