mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
Co-authored-by: roboco-app[bot] <302741806+roboco-app[bot]@users.noreply.github.com> Co-authored-by: Backend Developer 1 <be-dev-1@roboco.tech>
This commit is contained in:
co-authored by
roboco-app[bot] <302741806+roboco-app[bot]@users.noreply.github.com>
Backend Developer 1
parent
e1f5e0950e
commit
9f07183b01
@@ -107,3 +107,22 @@ waivers:
|
||||
not a production component — the same pattern already used by the
|
||||
pre-existing use-agents.test.tsx / use-observability.test.tsx hook
|
||||
tests colocated under hooks/__tests__/.
|
||||
- path: roboco/api/routes/prompter_live.py
|
||||
rule: no_lint_suppressions
|
||||
reason: >-
|
||||
preview_live_batch's `session_id` path parameter is unused in the
|
||||
function body (the endpoint is a pure precompute) but must stay in the
|
||||
signature under that exact name for FastAPI to bind the
|
||||
`/live/{session_id}/preview-batch` path — renaming or dropping it
|
||||
breaks routing, so the ARG001 suppression is a permanent framework
|
||||
constraint, not silenced debt.
|
||||
- path: roboco/foundation/policy/lifecycle.py
|
||||
rule: no_lint_suppressions
|
||||
reason: >-
|
||||
The module-load-time `_run_all_lifecycle_validators` import sits below
|
||||
other module code deliberately: its validators live in
|
||||
`roboco.foundation._validate_lifecycle`, a sibling of
|
||||
`foundation/_validate.py`, and `roboco.foundation.__init__` eagerly
|
||||
imports `_validate` — importing it at the top of this file would
|
||||
create a real import cycle. The E402 suppression documents a genuine
|
||||
circular-import constraint, not silenced debt.
|
||||
|
||||
+1
-2
@@ -8,6 +8,7 @@ for production and colored console output for development.
|
||||
import logging
|
||||
import logging.handlers
|
||||
import os
|
||||
import re as _re
|
||||
import sys
|
||||
from collections.abc import Mapping, MutableMapping
|
||||
from pathlib import Path
|
||||
@@ -39,8 +40,6 @@ def add_app_context(
|
||||
# `ghs_`/`gho_`) plus bearer tokens and generic "key = <value>" shapes. The
|
||||
# regex is intentionally loose on length so it catches tokens regardless of
|
||||
# future format tweaks.
|
||||
import re as _re # noqa: E402 — module-local alias only
|
||||
|
||||
_SECRET_PATTERNS: list[_re.Pattern[str]] = [
|
||||
_re.compile(r"(github_pat_[A-Za-z0-9_]{20,})"),
|
||||
_re.compile(r"(ghp_[A-Za-z0-9_]{20,})"),
|
||||
|
||||
@@ -54,7 +54,10 @@ class JournalEntry(TimestampMixin):
|
||||
# Sentiment/mood tracking (for growth analysis)
|
||||
sentiment: str | None = Field(
|
||||
default=None,
|
||||
description="Sentiment indicator (positive, neutral, negative, frustrated, confident, etc.)", # noqa: E501
|
||||
description=(
|
||||
"Sentiment indicator (positive, neutral, negative, frustrated, "
|
||||
"confident, etc.)"
|
||||
),
|
||||
)
|
||||
|
||||
# Visibility
|
||||
|
||||
@@ -10940,12 +10940,13 @@ Start by:
|
||||
from roboco.utils.converters import require_uuid
|
||||
|
||||
# Compute human-friendly duration
|
||||
_MINUTES_PER_HOUR = 60
|
||||
duration_desc = "unknown duration"
|
||||
try:
|
||||
activated_at = datetime.fromisoformat(activated_at_str)
|
||||
elapsed = datetime.now(UTC) - activated_at
|
||||
total_minutes = int(elapsed.total_seconds() / 60)
|
||||
if total_minutes < 60: # noqa: PLR2004
|
||||
if total_minutes < _MINUTES_PER_HOUR:
|
||||
duration_desc = f"{total_minutes} minute(s)"
|
||||
else:
|
||||
duration_desc = f"{total_minutes // 60}h {total_minutes % 60}m"
|
||||
|
||||
@@ -198,7 +198,7 @@ class KanbanService(BaseService):
|
||||
|
||||
return KanbanBoard(
|
||||
id=f"{board_type.value}-{team.value if team else 'all'}",
|
||||
title=f"{team.value.title() if team else 'All'} {board_type.value.title()} Board", # noqa: E501
|
||||
title=self._board_title(team, board_type),
|
||||
board_type=board_type,
|
||||
team=team,
|
||||
columns=column_list,
|
||||
@@ -207,6 +207,11 @@ class KanbanService(BaseService):
|
||||
last_updated=datetime.now(UTC),
|
||||
)
|
||||
|
||||
def _board_title(self, team: Team | None, board_type: KanbanBoardType) -> str:
|
||||
"""Shared board title: '<Team|All> <BoardType> Board'."""
|
||||
team_label = team.value.title() if team else "All"
|
||||
return f"{team_label} {board_type.value.title()} Board"
|
||||
|
||||
def _get_swimlane_key(self, task: TaskTable, swimlane_by: str) -> str:
|
||||
"""Get the swimlane key for a task."""
|
||||
if swimlane_by == "priority":
|
||||
@@ -319,7 +324,7 @@ class KanbanService(BaseService):
|
||||
|
||||
return KanbanBoard(
|
||||
id=f"{board_type.value}-{team.value if team else 'all'}-swimlane",
|
||||
title=f"{team.value.title() if team else 'All'} {board_type.value.title()} Board", # noqa: E501
|
||||
title=self._board_title(team, board_type),
|
||||
board_type=board_type,
|
||||
team=team,
|
||||
swimlanes=swimlanes,
|
||||
|
||||
@@ -28,6 +28,7 @@ from sqlalchemy import select
|
||||
if TYPE_CHECKING:
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from roboco.foundation.identity import PM_ROLES
|
||||
from roboco.foundation.identity import Role as _FoundationRole
|
||||
from roboco.foundation.policy.communications import NOTIFY_SENDER_ROLES
|
||||
from roboco.models import AgentRole, Team
|
||||
@@ -41,6 +42,11 @@ from roboco.models.permissions import (
|
||||
)
|
||||
from roboco.services.base import SingletonService
|
||||
|
||||
# PM_ROLES is canonical in foundation.identity; re-exported here for
|
||||
# backwards compatibility with existing `from roboco.services.permissions
|
||||
# import PM_ROLES` consumers.
|
||||
__all__ = ["PM_ROLES"]
|
||||
|
||||
# =============================================================================
|
||||
# NOTIFICATION PERMISSIONS (derived from foundation.NOTIFY_SENDER_ROLES)
|
||||
# =============================================================================
|
||||
@@ -264,10 +270,6 @@ async def has_privileged_access(db: "AsyncSession", agent_id: UUID) -> bool:
|
||||
return role in PRIVILEGED_ROLES if role else False
|
||||
|
||||
|
||||
# PM_ROLES is canonical in foundation.identity. Re-export for backwards
|
||||
# compatibility; new consumers import from foundation directly.
|
||||
from roboco.foundation.identity import PM_ROLES # noqa: F401, E402
|
||||
|
||||
MANAGEMENT_ROLES = frozenset(
|
||||
{AgentRole.CEO, AgentRole.PRODUCT_OWNER, AgentRole.CELL_PM, AgentRole.MAIN_PM}
|
||||
)
|
||||
|
||||
@@ -157,9 +157,12 @@ class TgCockpitService(BaseService):
|
||||
tokens_by_day,
|
||||
models_by_day,
|
||||
) = await self._session_metrics_by_day(days)
|
||||
_MIN_DAYS_FOR_PRIOR_COMPARISON = 2
|
||||
series = [round(cost_by_day.get(d, 0.0), 4) for d in days]
|
||||
today_cost = series[-1] if series else 0.0
|
||||
prior_cost = series[-2] if len(series) >= 2 else 0.0 # noqa: PLR2004
|
||||
prior_cost = (
|
||||
series[-2] if len(series) >= _MIN_DAYS_FOR_PRIOR_COMPARISON else 0.0
|
||||
)
|
||||
today_tokens = tokens_by_day.get(days[-1], 0) if days else 0
|
||||
today_models = models_by_day.get(days[-1], set()) if days else set()
|
||||
# $0 with real tokens spent, on a subscription-billed-but-
|
||||
|
||||
Reference in New Issue
Block a user