Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Enabled extended thinking for `claude-opus-4.7`, `claude-opus-4.8`, `gpt-5.4`, `gpt-5.5`, and `gpt-5.6`. Selecting one of these models with a thinking level now activates the provider's reasoning/extended-thinking budget; previously it was silently skipped for these newer models.
- Sandbox environments now automatically allow and authenticate their repository's git platform (GitLab/GitHub) for git operations over HTTPS in the sandbox. DAIV injects an `Authorization: Basic` credential at the egress proxy, built from a short-lived token — the same project-scoped ephemeral clone token for GitLab, and a `contents:write` installation token for GitHub — so `git fetch`/clone/push of the repository works without configuring a per-environment host rule. Because DAIV pushes from inside the sandbox, this applies even to **Network Off** environments when a push token exists: the environment is opened solely for its git platform (everything else stays blocked) so publishing always works, while token-less eval/benchmark runs stay fully network-isolated. The rule is applied at runtime (never stored on the environment) and takes precedence over a user-defined rule for the same host.
- Added a per-environment **network egress policy** for sandbox environments, configurable from the environment form when network is enabled. Restrict outbound traffic to an allow-list of hosts (glob patterns), attach per-host HTTP credentials (header name + value, encrypted at rest and never rendered back), scope each host to **all methods** or **read-only** (`GET, HEAD, OPTIONS`), and set the `default` (deny/allow) reachability for unlisted hosts. The proxy always TLS-inspects every reachable host, so per-host credentials and method rules are always enforced. Credentials are injected by the daiv-sandbox egress proxy and never enter the sandbox container. The egress proxy is mandatory for network-enabled sessions: if the sandbox deployment has no egress proxy configured, a network-enabled run is rejected rather than falling back to unrestricted network.
- Added `release_orphan_queued_threads` management command to recover `QUEUED` activities left behind on threads with no active sibling (rare TOCTOU loss).
Expand Down
4 changes: 3 additions & 1 deletion daiv/accounts/context_processors.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
NAV_SECTION_MCP_GLOBAL = "mcp_servers_global"

SECTION_URL_NAMES: dict[str, set[str]] = {
"dashboard": {"dashboard"},
# The admin Manager Lens is a console surface under Dashboard — keep the Dashboard
# sidebar item highlighted when it is open.
"dashboard": {"dashboard", "manager_lens"},
"sessions": {
"session_list",
"session_new",
Expand Down
94 changes: 78 additions & 16 deletions daiv/accounts/locale/pt/LC_MESSAGES/django.po
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-17 11:20+0100\n"
"POT-Creation-Date: 2026-07-17 08:39-0500\n"
"PO-Revision-Date: 2026-04-04 22:34+0100\n"
"Last-Translator: \n"
"Language-Team: Portuguese <pt@li.org>\n"
Expand Down Expand Up @@ -95,6 +95,68 @@ msgstr "Feed"
msgid "what happened"
msgstr "o que aconteceu"

msgid "Org impact"
msgstr "Impacto da organização"

msgid "Code Velocity"
msgstr "Velocidade de código"

msgid "team members"
msgstr "membros da equipa"

msgid "merges into default branches"
msgstr "merges nos ramos predefinidos"

msgid "Lines changed"
msgstr "Linhas alteradas"

#, python-format
msgid "Net change: %(net)s lines"
msgstr "Variação líquida: %(net)s linhas"

msgid "DAIV attribution"
msgstr "Atribuição ao DAIV"

msgid "MRs involving DAIV"
msgstr "MRs com participação do DAIV"

#, python-format
msgid "DAIV: %(n)s MRs"
msgstr "DAIV: %(n)s MRs"

#, python-format
msgid "Human: %(n)s MRs"
msgstr "Humano: %(n)s MRs"

msgid "Commits authored by DAIV"
msgstr "Commits da autoria do DAIV"

#, python-format
msgid "DAIV: %(n)s commits"
msgstr "DAIV: %(n)s commits"

#, python-format
msgid "Human: %(n)s commits"
msgstr "Humano: %(n)s commits"

msgid "Computing org impact…"
msgstr "A calcular o impacto da organização…"

msgid "Console view"
msgstr "Vista da consola"

msgid "Personal"
msgstr "Pessoal"

msgid "Manager Lens"
msgstr "Vista de gestor"

msgid "Manager Lens."
msgstr "Vista de gestor."

msgid "Review console."
msgstr "Consola de revisão."

msgid "New"
msgstr "Novo"

Expand Down Expand Up @@ -155,6 +217,21 @@ msgstr "Terminar sessão"
msgid "No users found."
msgstr "Nenhum utilizador encontrado."

msgid "Time range"
msgstr "Intervalo de tempo"

msgid "7 days"
msgstr "7 dias"

msgid "30 days"
msgstr "30 dias"

msgid "90 days"
msgstr "90 dias"

msgid "All time"
msgstr "Desde sempre"

msgid "Welcome to DAIV"
msgstr "Bem-vindo ao DAIV"

Expand Down Expand Up @@ -199,21 +276,6 @@ msgstr "Pode autenticar-se com um código único enviado para o seu email, ou us
msgid "Open navigation"
msgstr "Abrir navegação"

msgid "Time range"
msgstr "Intervalo de tempo"

msgid "7 days"
msgstr "7 dias"

msgid "30 days"
msgstr "30 dias"

msgid "90 days"
msgstr "90 dias"

msgid "All time"
msgstr "Desde sempre"

msgid "Primary"
msgstr "Principal"

Expand Down
14 changes: 8 additions & 6 deletions daiv/accounts/templates/accounts/_console_body.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
{% load i18n %}
{# Review Console main column — three stacked placeholder regions (Story 2.1).
Structural skeletons only; Hero/Queue/Feed content and the "you have N" count
are wired by later stories (Epic 3 / Epic 4 / Story 2.3). This partial carries
NO job-creation control (FR-3). Reused verbatim as the HTMX body fragment.
Each region is marked aria-busy while its content is pending; the decorative
shimmer skeletons are aria-hidden so assistive tech is not read empty rows. #}
{% comment %}
Review Console main column — three stacked placeholder regions (Story 2.1).
Structural skeletons only; Hero/Queue/Feed content and the "you have N" count
are wired by later stories (Epic 3 / Epic 4 / Story 2.3). This partial carries
NO job-creation control (FR-3). Reused verbatim as the HTMX body fragment.
Each region is marked aria-busy while its content is pending; the decorative
shimmer skeletons are aria-hidden so assistive tech is not read empty rows.
{% endcomment %}
<div class="flex flex-col gap-5">
{# ── Hero ─────────────────────────────────────────────────────────────── #}
<section data-testid="console-hero" aria-labelledby="console-hero-heading" aria-busy="true"
Expand Down
130 changes: 130 additions & 0 deletions daiv/accounts/templates/accounts/_manager_lens.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
{% load i18n icon_tags %}
{% comment %}
Manager Lens body fragment (Story 2.2) — the RELOCATED org Code-Velocity + DAIV-attribution
content that no longer appears on the personal default console (AC1/AC3). Restyled onto the
2.1 dark token system: surface-2 cards on ground, hairline border, FLAT (no shadow), every
figure in font-mono + tabular-nums, glyphs via the icon tag. Reused verbatim as the HTMX swap
fragment (get_template_names) and as the full-page include.

Facts (counts / percentages) render solid + mono — never dressed up, never inflated. When
velocity is None (zero MergeMetric rows / not-yet-computed) we render a shimmer SKELETON matching
this exact layout — NEVER a literal 0 reading as "DAIV did nothing", never hidden (AC5).
{% endcomment %}
<div class="flex flex-col gap-5">
<section data-testid="manager-lens" aria-labelledby="manager-lens-heading"
class="rounded-xl border border-border bg-surface-2 p-[22px]">
<header class="mb-5 flex flex-wrap items-center justify-between gap-3">
<div class="flex items-center gap-2.5">
<span class="flex h-7 w-7 items-center justify-center rounded-lg border border-border bg-surface-3">
{% icon "chart-bar" "h-3.5 w-3.5 text-text-muted" %}
</span>
<div>
<p class="font-mono text-[11px] font-medium uppercase tracking-[0.14em] text-text-faint">
{% translate "Org impact" %}
</p>
<h2 id="manager-lens-heading" class="text-[15px] font-semibold tracking-tight text-text">
{% translate "Code Velocity" %}
</h2>
</div>
</div>
{# total_users is a real org count — safe to surface whether or not velocity has computed. #}
<p class="font-mono text-[12px] tabular-nums text-text-muted">
<span class="text-text-strong">{{ total_users }}</span> {% translate "team members" %}
</p>
</header>

{% if velocity %}
{# ── Merges + lines changed ─────────────────────────────────────────── #}
<div class="grid grid-cols-1 gap-6 sm:grid-cols-5">
<div class="sm:col-span-2">
<p data-testid="lens-total-merges"
class="font-mono text-[44px] font-semibold leading-none tracking-tight tabular-nums text-text-strong">
{{ velocity.total_merges }}
</p>
<p class="mt-2 text-sm text-text-muted">{% translate "merges into default branches" %}</p>
</div>
<div class="sm:col-span-3">
<p class="mb-3 font-mono text-[11px] font-medium uppercase tracking-[0.14em] text-text-faint">
{% translate "Lines changed" %}
</p>
<div class="flex items-center gap-3">
<span class="w-16 text-right font-mono text-sm font-semibold tabular-nums text-status-clear">+{{ velocity.lines_added }}</span>
<div class="h-5 flex-1 overflow-hidden rounded-md bg-surface-3">
<div class="h-full rounded-md bg-status-clear/30" style="width: {{ velocity.lines_added_pct }}%"></div>
</div>
</div>
<div class="h-2"></div>
<div class="flex items-center gap-3">
<span class="w-16 text-right font-mono text-sm font-semibold tabular-nums text-status-fail">-{{ velocity.lines_removed }}</span>
<div class="h-5 flex-1 overflow-hidden rounded-md bg-surface-3">
<div class="h-full rounded-md bg-status-fail/40" style="width: {{ velocity.lines_removed_pct }}%"></div>
</div>
</div>
<p class="mt-2 font-mono text-xs tabular-nums text-text-faint">
{% blocktranslate with net=velocity.net_lines %}Net change: {{ net }} lines{% endblocktranslate %}
</p>
</div>
</div>

{# ── DAIV attribution ───────────────────────────────────────────────── #}
<div class="mt-6 border-t border-border pt-6">
<p class="mb-4 flex items-center gap-2 font-mono text-[11px] font-medium uppercase tracking-[0.14em] text-text-faint">
{% icon "beaker" "h-3.5 w-3.5 text-text-faint" %}
{% translate "DAIV attribution" %}
</p>
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
<div class="rounded-xl border border-border bg-surface-3 px-5 py-4">
<div class="flex items-baseline justify-between gap-2">
<span class="text-sm text-text-muted">{% translate "MRs involving DAIV" %}</span>
<span class="font-mono text-[20px] font-bold tabular-nums text-text-strong">{{ velocity.daiv_merges_pct }}</span>
</div>
<div class="mt-3 flex h-2 w-full overflow-hidden rounded-full bg-ground">
<div class="h-full rounded-full bg-accent/40" style="width: {{ velocity.daiv_merges_pct_raw }}%"></div>
</div>
<div class="mt-2 flex justify-between font-mono text-xs tabular-nums text-text-faint">
<span>{% blocktranslate with n=velocity.daiv_merges %}DAIV: {{ n }} MRs{% endblocktranslate %}</span>
<span>{% blocktranslate with n=velocity.human_merges %}Human: {{ n }} MRs{% endblocktranslate %}</span>
</div>
</div>
<div class="rounded-xl border border-border bg-surface-3 px-5 py-4">
<div class="flex items-baseline justify-between gap-2">
<span class="text-sm text-text-muted">{% translate "Commits authored by DAIV" %}</span>
<span class="font-mono text-[20px] font-bold tabular-nums text-text-strong">{{ velocity.daiv_commits_pct }}</span>
</div>
<div class="mt-3 flex h-2 w-full overflow-hidden rounded-full bg-ground">
<div class="h-full rounded-full bg-accent/40" style="width: {{ velocity.daiv_commits_pct_raw }}%"></div>
</div>
<div class="mt-2 flex justify-between font-mono text-xs tabular-nums text-text-faint">
<span>{% blocktranslate with n=velocity.daiv_commits %}DAIV: {{ n }} commits{% endblocktranslate %}</span>
<span>{% blocktranslate with n=velocity.human_commits %}Human: {{ n }} commits{% endblocktranslate %}</span>
</div>
</div>
</div>
</div>
{% else %}
{# Cold-load skeleton (AC5): shimmer rows mirror the velocity/attribution layout, no zeros, not hidden. #}
<div data-testid="manager-lens-skeleton" aria-busy="true" aria-label="{% translate 'Computing org impact…' %}">
<div class="space-y-6" aria-hidden="true">
<div class="grid grid-cols-1 gap-6 sm:grid-cols-5">
<div class="space-y-3 sm:col-span-2">
<div class="skeleton h-11 w-2/3 rounded-md"></div>
<div class="skeleton h-4 w-1/2 rounded-md"></div>
</div>
<div class="space-y-3 sm:col-span-3">
<div class="skeleton h-3 w-1/4 rounded-md"></div>
<div class="skeleton h-5 w-full rounded-md"></div>
<div class="skeleton h-5 w-full rounded-md"></div>
</div>
</div>
<div class="border-t border-border pt-6">
<div class="skeleton mb-4 h-3 w-1/4 rounded-md"></div>
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
<div class="skeleton h-[104px] rounded-xl"></div>
<div class="skeleton h-[104px] rounded-xl"></div>
</div>
</div>
</div>
</div>
{% endif %}
</section>
</div>
44 changes: 44 additions & 0 deletions daiv/accounts/templates/accounts/_manager_lens_toggle.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{% load i18n %}
{% comment %}
Admin-only, NON-PERSISTENT console surface toggle (Personal | Manager Lens).
Rendered in the top-bar left slot of BOTH dashboard.html and manager_lens.html;
pass the current surface in via {% include ... with surface="personal|manager" %}.

- Gated with user.is_admin so non-admins get NO toggle in the DOM (absent, not
shown-then-blocked, AC2). The route itself is denied server-side by
AdminRequiredMixin (AC6) as belt-and-braces.
- The two <a> links carry BOTH hx-get (calm partial swap of the console main
column) and a plain href (no-JS fallback; the full page is deep-link safe).
- Stateless: nothing is written (no session key, no user field), so the next
fresh landing is always /dashboard/ and the surface never persists (AC4).
- Alpine keeps the active/aria-current state in sync after an HTMX swap (the
toggle sits OUTSIDE the swapped #console-main); a hard load is already correct
because Alpine seeds `surface` from the server-passed value. Teal = active/DO
(never brand/violet). Touch targets are >= 44px and it is not hover-only.
{% endcomment %}
{% if user.is_admin %}
<div data-testid="manager-lens-toggle"
x-data="{ surface: '{{ surface|default:'personal' }}' }"
role="group" aria-label="{% translate 'Console view' %}"
class="hidden items-center gap-0.5 rounded-md border border-border bg-ground p-0.5 sm:inline-flex">
<a href="{% url 'dashboard' %}"
hx-get="{% url 'dashboard' %}" hx-target="#console-main" hx-push-url="true"
@click="surface = 'personal'"
:aria-current="surface === 'personal' ? 'page' : null"
:class="surface === 'personal' ? 'bg-accent/15 text-accent-bright' : 'text-text-muted hover:text-text'"
class="inline-flex min-h-[44px] items-center rounded-md px-3 py-1.5 font-mono text-[12.5px] font-semibold tabular-nums no-underline transition-colors md:min-h-0 md:py-1">
{% translate "Personal" %}
</a>
<a href="{% url 'manager_lens' %}"
hx-get="{% url 'manager_lens' %}" hx-target="#console-main" hx-push-url="true"
@click="surface = 'manager'"
:aria-current="surface === 'manager' ? 'page' : null"
:class="surface === 'manager' ? 'bg-accent/15 text-accent-bright' : 'text-text-muted hover:text-text'"
class="inline-flex min-h-[44px] items-center rounded-md px-3 py-1.5 font-mono text-[12.5px] font-semibold tabular-nums no-underline transition-colors md:min-h-0 md:py-1">
{% translate "Manager Lens" %}
</a>
{# Announce the surface change to assistive tech on toggle (polite). #}
<span class="sr-only" aria-live="polite"
x-text="surface === 'manager' ? '{% translate 'Manager Lens.' %}' : '{% translate 'Review console.' %}'"></span>
</div>
{% endif %}
12 changes: 9 additions & 3 deletions daiv/accounts/templates/accounts/dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,13 @@
{% block container_width %}max-w-screen-2xl{% endblock %}

{% block topbar_start %}
{# Range-switcher — console-only, static placeholder in 2.1; wired in Epic 3.
Active pill is teal; labels use the mono face + tabular figures. #}
{# Admin-gated console surface toggle, active on "Personal" (the default); absent for non-admins (AC2). #}
{% include "accounts/_manager_lens_toggle.html" with surface="personal" %}

{% comment %}
Range-switcher — console-only, static placeholder in 2.1; wired in Epic 3.
Active pill is teal; labels use the mono face + tabular figures.
{% endcomment %}
<div data-testid="range-switcher" role="group" aria-label="{% translate 'Time range' %}"
class="hidden items-center gap-0.5 rounded-md border border-border bg-ground p-0.5 md:flex">
<button type="button" disabled aria-disabled="true" data-range="today"
Expand All @@ -34,5 +39,6 @@
{% endblock topbar_start %}

{% block app_content %}
{% include "accounts/_console_body.html" %}
{# #console-main is the HTMX swap target for the top-bar Manager-Lens toggle. #}
<div id="console-main">{% include "accounts/_console_body.html" %}</div>
{% endblock app_content %}
16 changes: 16 additions & 0 deletions daiv/accounts/templates/accounts/manager_lens.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{% extends "base_app.html" %}
{% load i18n %}

{% block title %}{% translate "Manager Lens" %} — DAIV{% endblock %}

{% block container_width %}max-w-screen-2xl{% endblock %}

{% block topbar_start %}
{# Admin-gated console surface toggle, active on "Manager Lens". #}
{% include "accounts/_manager_lens_toggle.html" with surface="manager" %}
{% endblock topbar_start %}

{% block app_content %}
{# #console-main is the HTMX swap target for the top-bar toggle (see the toggle partial). #}
<div id="console-main">{% include "accounts/_manager_lens.html" %}</div>
{% endblock app_content %}
Loading
Loading