feat: add ISSLOP AI usage analysis CLI commands, game router, and politics topic

- Add `cmd_isslop_prune`, `cmd_isslop_clear`, `cmd_isslop_analyze` CLI commands for AI usage analysis job management
- Register `/game` router with `index` and `farm` endpoints for Code Farm idle game
- Add `politics` to allowed TOPICS constant replacing `signals`
- Introduce `ISSLOP_DIR`, `ISSLOP_WORKSPACES_DIR`, `ISSLOP_RUNS_DIR`, `ISSLOP_MEDIA_DIR` config paths
- Add `clear_user_stars` and `clear_user_projects_cache` calls on vote and project create/delete
- Update `make prod` to use `nproc` workers via `DEVPLACE_WEB_WORKERS` env var
- Convert `database.py` and `utils.py` to packages for modular structure
- Add `devplace apikey` and `devplace token` CLI subcommands for API key and access token management
This commit is contained in:
2026-07-06 03:57:47 +00:00
parent f1bdefd834
commit 9a8046ab2a
110 changed files with 1466 additions and 374 deletions
+6
View File
@@ -21,6 +21,9 @@ from devplacepy.cli.jobs import (
cmd_forks_clear,
cmd_seo_prune,
cmd_seo_clear,
cmd_isslop_prune,
cmd_isslop_clear,
cmd_isslop_analyze,
cmd_seo_meta_prune,
cmd_seo_meta_clear,
cmd_deepsearch_prune,
@@ -65,6 +68,9 @@ __all__ = [
"cmd_forks_clear",
"cmd_seo_prune",
"cmd_seo_clear",
"cmd_isslop_prune",
"cmd_isslop_clear",
"cmd_isslop_analyze",
"cmd_seo_meta_prune",
"cmd_seo_meta_clear",
"cmd_deepsearch_prune",
+116
View File
@@ -210,6 +210,104 @@ def cmd_deepsearch_clear(args):
print(f"Cleared {len(jobs)} DeepSearch job(s) and their collections")
def cmd_isslop_prune(args):
from datetime import datetime, timezone
from devplacepy.services.jobs import queue
now = datetime.now(timezone.utc)
removed = 0
for job in queue.list_jobs(kind="isslop", status=queue.DONE):
expires_at = job.get("expires_at")
if not expires_at:
continue
try:
expiry = datetime.fromisoformat(expires_at)
except (ValueError, TypeError):
continue
if expiry < now:
get_table("jobs").delete(uid=job["uid"])
removed += 1
_audit_cli("cli.isslop.prune", f"CLI pruned {removed} expired AI usage analysis jobs", metadata={"count": removed})
print(f"Pruned {removed} expired AI usage analysis job(s) (reports persist)")
def cmd_isslop_clear(args):
from devplacepy.services.jobs import queue
from devplacepy.services.jobs.isslop import store
jobs = queue.list_jobs(kind="isslop")
for job in jobs:
get_table("jobs").delete(uid=job["uid"])
analyses = list(get_table(store.TABLE_ANALYSES).find())
for analysis in analyses:
store.purge_analysis(analysis["uid"])
_audit_cli(
"cli.isslop.clear",
f"CLI cleared {len(analyses)} AI usage analyses and {len(jobs)} job rows",
metadata={"analyses": len(analyses), "jobs": len(jobs)},
)
print(f"Cleared {len(analyses)} AI usage analysis(es), their reports and {len(jobs)} job row(s)")
def cmd_isslop_analyze(args):
import asyncio
import json
from devplacepy.config import ISSLOP_WORKSPACES_DIR, ensure_data_dirs
from devplacepy.database import INTERNAL_GATEWAY_URL, internal_gateway_key
from devplacepy.models import IsslopRunForm
from devplacepy.services.jobs.isslop import store
from devplacepy.services.jobs.isslop.acquisition.workspace import remove_workspace, workspace_for
from devplacepy.services.jobs.isslop.config import settings_from_payload
from devplacepy.services.jobs.isslop.events import KIND_DONE, KIND_ERROR
from devplacepy.services.jobs.isslop.persistence import EventPersister
from devplacepy.services.jobs.isslop.pipeline import run_pipeline
from devplacepy.utils import generate_uid
url = IsslopRunForm(url=args.url).url
ensure_data_dirs()
uid = generate_uid()
settings = settings_from_payload(
{
"url": url,
"llm_endpoint": INTERNAL_GATEWAY_URL,
"api_key": internal_gateway_key(),
"allow_private": bool(args.allow_private),
"media_dir": str(store.media_dir_for(uid)),
}
)
store.create_analysis(uid, url, "system", "cli")
persister = EventPersister(uid)
store.update_analysis(uid, status="running")
workspace = workspace_for(ISSLOP_WORKSPACES_DIR, url, uid)
async def run() -> int:
failed = False
try:
async for event in run_pipeline(url, workspace, settings):
persister.apply(event)
if args.json:
print(event.to_json(), flush=True)
else:
print(f"[{event.kind}] {event.message}", flush=True)
if event.kind == KIND_ERROR:
failed = True
if event.kind == KIND_DONE and not args.json:
print(f"Report: /tools/isslop/{uid}/report")
print(f"Badge: /tools/isslop/{uid}/badge.svg")
finally:
remove_workspace(workspace)
return 1 if failed else 0
exit_code = asyncio.run(run())
_audit_cli(
"cli.isslop.analyze",
f"CLI AI usage analysis of {url}",
metadata={"uid": uid, "failed": bool(exit_code)},
)
raise SystemExit(exit_code)
def register_jobs(subparsers):
zips = subparsers.add_parser("zips", help="Zip archive job management")
zips_sub = zips.add_subparsers(title="action", dest="action")
@@ -265,3 +363,21 @@ def register_jobs(subparsers):
"clear", help="Delete every DeepSearch session and job row"
)
deepsearch_clear.set_defaults(func=cmd_deepsearch_clear)
isslop = subparsers.add_parser("isslop", help="AI Usage Analyzer job management")
isslop_sub = isslop.add_subparsers(title="action", dest="action")
isslop_prune = isslop_sub.add_parser(
"prune", help="Delete expired AI usage analysis job rows (analyses and reports persist)"
)
isslop_prune.set_defaults(func=cmd_isslop_prune)
isslop_clear = isslop_sub.add_parser(
"clear", help="Delete every AI usage analysis, its report and job rows"
)
isslop_clear.set_defaults(func=cmd_isslop_clear)
isslop_analyze = isslop_sub.add_parser(
"analyze", help="Run a AI usage analysis from the terminal and persist its report"
)
isslop_analyze.add_argument("url", help="Repository or website URL to classify")
isslop_analyze.add_argument("--json", action="store_true", help="Emit raw JSON events")
isslop_analyze.add_argument("--allow-private", action="store_true", dest="allow_private", help="Permit private and loopback hosts")
isslop_analyze.set_defaults(func=cmd_isslop_analyze)