Skip to content
Merged
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
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,29 @@

## Unreleased

- Console operator surface: treat doctor FAIL findings as something the
page must show even when `next` reports ready with empty commands.
Overview heading and 现在需要你 surface those FAILs; the primary copy
command is `doctor` (or another allowlisted next command), never a
bare `dyro --workspace <alias>`.
- Console tabs `#w/<alias>/family|events|channel` show only that pane.
Refresh re-fetches the overview and any open workspace so captured-at
moves. Spawn/merge/sync copy no longer invents `<parent>_new`.
- `dyro console --no-open` flushes the one-time URL. A missing or
expired bootstrap paints the door on the command-center heading
and primary (not only session-status) and tells the operator to
run `dyro console` again. Empty twin/inventory copy is one honest
sentence; line badges do not paint 未检查 when a FAIL finding
exists for that line.
- Unscoped `dyro console` no longer lets vanished registry rows
(missing roots, including dead `/tmp/dyro-test-*` aliases) win
现在需要你 or the primary CTA. Those cards fold under 读不到.
Inspection timeout is not painted as “project gone”: missing-root
and read-timeout get different copy and sort below a healthy
default workspace. Family picker defaults to root parents plus the
focused parent. An overlay with lines but no Task/Objective says
so in one sentence instead of only “没有目标”.

## 0.7.9 - 2026-08-21

- Console P4: workspace detail now projects a read-only operator twin after
Expand Down
68 changes: 29 additions & 39 deletions src/dyro/console/_inspect_worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,15 @@

from ..config import load
from ..hub import WorkspaceRecord, WorkspaceRegistry
from .overview import ConsoleOverviewError, ConsoleOverviewService
from .overview import (
ConsoleOverviewError,
ConsoleOverviewService,
WORKSPACE_MISSING_ROOT,
WORKSPACE_TIMEOUT,
WORKSPACE_UNAVAILABLE,
unavailable_workspace_summary,
workspace_root_missing,
)


_CURSOR_SECRET_ENV = "DYRO_CONSOLE_CURSOR_SECRET"
Expand All @@ -31,33 +39,7 @@


def _unavailable_summary(alias: str, code: str) -> dict[str, object]:
return {
"alias": alias,
"display_name": alias,
"is_default": False,
"availability": "unavailable",
"health": "unavailable",
"freshness": "partial",
"repository_count": 0,
"line_count": 0,
"objective_count": 0,
"active_objective_count": 0,
"task_count": 0,
"task_status_counts": {},
"attention_counts": {
"repair_required": 0,
"needs_user": 0,
"ready": 0,
"paused": 0,
"waiting": 0,
},
"recommendation": {
"reason": code,
"command": f"dyro --workspace {alias} doctor",
},
"snapshot_sha256": "",
"proof_inspection": "not_inspected",
}
return unavailable_workspace_summary(alias, False, reason=code)


def _capture_workspace_summary(
Expand All @@ -67,6 +49,14 @@ def _capture_workspace_summary(
) -> None:
"""Capture one workspace only, returning a JSON-safe value through IPC."""
try:
if workspace_root_missing(record.root):
result_queue.put(
{
"summary": _unavailable_summary(record.name, WORKSPACE_MISSING_ROOT),
"warnings": [WORKSPACE_MISSING_ROOT],
}
)
return
registry = WorkspaceRegistry(
default=record.name if is_default else "",
workspaces=(record,),
Expand All @@ -79,8 +69,8 @@ def _capture_workspace_summary(
except Exception:
result_queue.put(
{
"summary": _unavailable_summary(record.name, "WORKSPACE_UNAVAILABLE"),
"warnings": ["WORKSPACE_UNAVAILABLE"],
"summary": _unavailable_summary(record.name, WORKSPACE_UNAVAILABLE),
"warnings": [WORKSPACE_UNAVAILABLE],
}
)

Expand All @@ -89,8 +79,8 @@ def _parse_child_result(
value: object, record: WorkspaceRecord, *, is_default: bool
) -> tuple[dict[str, object], set[str]]:
if not isinstance(value, dict):
return _unavailable_summary(record.name, "WORKSPACE_UNAVAILABLE"), {
"WORKSPACE_UNAVAILABLE"
return _unavailable_summary(record.name, WORKSPACE_UNAVAILABLE), {
WORKSPACE_UNAVAILABLE
}
summary = value.get("summary")
warnings = value.get("warnings")
Expand All @@ -99,8 +89,8 @@ def _parse_child_result(
or not isinstance(warnings, list)
or not all(isinstance(item, str) for item in warnings)
):
return _unavailable_summary(record.name, "WORKSPACE_UNAVAILABLE"), {
"WORKSPACE_UNAVAILABLE"
return _unavailable_summary(record.name, WORKSPACE_UNAVAILABLE), {
WORKSPACE_UNAVAILABLE
}
copied = dict(summary)
copied["alias"] = record.name
Expand Down Expand Up @@ -137,8 +127,8 @@ def finish(record: WorkspaceRecord, value: object, *, default: bool) -> None:
finish(
record,
{
"summary": _unavailable_summary(record.name, "WORKSPACE_TIMEOUT"),
"warnings": ["WORKSPACE_TIMEOUT"],
"summary": _unavailable_summary(record.name, WORKSPACE_TIMEOUT),
"warnings": [WORKSPACE_TIMEOUT],
},
default=record.name == registry.default,
)
Expand All @@ -147,8 +137,8 @@ def finish(record: WorkspaceRecord, value: object, *, default: bool) -> None:
finish(
record,
{
"summary": _unavailable_summary(record.name, "WORKSPACE_TIMEOUT"),
"warnings": ["WORKSPACE_TIMEOUT"],
"summary": _unavailable_summary(record.name, WORKSPACE_TIMEOUT),
"warnings": [WORKSPACE_TIMEOUT],
},
default=record.name == registry.default,
)
Expand Down Expand Up @@ -188,7 +178,7 @@ def finish(record: WorkspaceRecord, value: object, *, default: bool) -> None:
if has_value:
finish(record, value, default=record.name == registry.default)
else:
code = "WORKSPACE_TIMEOUT" if timed_out else "WORKSPACE_UNAVAILABLE"
code = WORKSPACE_TIMEOUT if timed_out else WORKSPACE_UNAVAILABLE
finish(
record,
{
Expand Down
8 changes: 4 additions & 4 deletions src/dyro/console/assets.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ class ConsoleAsset:
),
"app.js": (
"text/javascript; charset=utf-8",
"19a665f3da67838802cefaaab6a9d5030e585e3d9a9828002ee796355cafac52",
85461,
"d3a2787202bd1b42dc924c7b7417dedaf2d3415f1efd5bcfab68b63f010bbe07",
97664,
),
"styles.css": (
"text/css; charset=utf-8",
"8bdb1b8db171a130e2f1d5de0d432b8c9ce9c7c55722b8a2f043befcab8db057",
24589,
"1a95a44a76c6f884b6d839e6b404fc79a8977ea963f2ec65a014410dde1c2947",
24718,
),
}

Expand Down
Loading