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
2 changes: 1 addition & 1 deletion Agent.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -119,7 +119,7 @@ Community needs voiced in HN agent-UI discussions map directly to EMRG's design:
pkill -f "emrg.server"; rm -f ~/.emrg/emrgd.token; python -m emrg
```

Python: `uv run pytest tests/ -v` (1121) — import check: `uv run python -c "from emrg.client.app import run_client"`
Python: `uv run pytest tests/ -v` (1123) — import check: `uv run python -c "from emrg.client.app import run_client"`
GUI: `cd emrg/gui && npm test` (89: 45 daemon_client + 20 conn-manager + 8 integration + 6 build-config + 7 gui-state + 3 preload-api) — syntax: `node --check main.js preload.js daemon_client.js`
Renderer: `cd emrg/gui/renderer && npm run typecheck && npm test` (426: 5 snapshot-store + 9 utils + 3 ErrorBoundary + 2 App smoke + 11 commands + 4 copywriting + 11 i18n + 11 markdown + 15 transcript + 7 TranscriptView + 15 history + 22 composer + 14 Composer + 12 sidebar + 17 Sidebar + 9 fileTree + 9 FileTree + 16 resultPanel + 8 ResultPanel + 29 workspaceView + 8 WorkspaceView + 10 dialog + 6 Dialog + 9 ConfirmDialog + 9 RenameDialog + 10 dialogLists + 3 HelpDialog + 9 MemoryDialog + 6 SkillsDialog + 9 openSession + 6 WelcomeDialog + 8 OpenSessionDialog + 7 NewSessionDialog + 7 rewind + 8 RewindDialog + 7 GithubDeviceDialog + 12 daemonBridge + 6 DaemonBridgeProvider + 19 Shell + 15 DialogHost + 19 SettingsPanel + 4 vendorMarkdown) + `npm run build` → `renderer/dist/`
CI: `uv run pytest` (ubuntu + **windows-2025 matrix** — Windows pytest 回归在 PR CI 即失败,v0.2.29 教训 #725) + GUI tests + **actionlint workflow lint** (`rhysd/actionlint@v1.7.12` gate, #444 — workflow 解析错误在 PR CI 即失败,如 `if:` secrets 上下文)
Expand Down
16 changes: 15 additions & 1 deletion emrg/server/scheduler.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -1362,7 +1362,21 @@ def list_tasks(self) -> list[dict]:
per_handler: list[str] = []
for handler in self._handlers:
h_start = time.monotonic()
results.append(handler.status())
status = handler.status()
# Task config enrichment (R2245): handler.status() exposes only
# runtime state — the GUI tasks panel + edit form need the task's
# static config (type/enabled/config/sandbox) to render type
# badges, enabled hints, project links, and prefill the edit form
# (previously undefined → GUI fell back to "evolution"/defaults).
# Merged from _handler_cfgs (pure in-memory — keeps list_tasks
# I/O-free per rant 2026-08-18T20:48:45).
cfg = self._handler_cfgs.get(handler.name)
if cfg:
status["type"] = cfg.get("type", "evolution")
status["enabled"] = cfg.get("enabled", True)
status["config"] = cfg.get("config", {})
status["sandbox"] = cfg.get("sandbox")
results.append(status)
per_handler.append(f"{handler.name}={1000 * (time.monotonic() - h_start):.1f}ms")
elapsed_ms = 1000 * (time.monotonic() - start)
if elapsed_ms > 200:
Expand Down
48 changes: 48 additions & 0 deletions tests/test_scheduler.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -2181,6 +2181,54 @@ def slow_status():
assert handler.name in msgs, "per-handler breakdown must name the slow handler"


def test_list_tasks_includes_static_task_config(tmp_path):
"""list_tasks must merge the task's static config (type/enabled/config/
sandbox) into the runtime status — the GUI tasks panel renders type
badges + enabled hints and the edit form prefills from these fields;
without them type falls back to "evolution" and project/repo/sandbox are
lost (R2245 data-shape gap: handler.status() only exposes runtime state).
"""
from emrg.server.scheduler import TaskScheduler

handler = _make_handler(tmp_path, name="journal", project="sci")
sched = TaskScheduler(InstanceIdentity())
sched._handlers = [handler]
sched._handler_cfgs[handler.name] = {
"name": "journal",
"type": "journal",
"config": {"project": "sci", "repo": "argszero/sci"},
"interval": 3600,
"enabled": False,
"sandbox": "read-only",
}
tasks = sched.list_tasks()
assert len(tasks) == 1
row = tasks[0]
assert row["name"] == "journal"
assert row["type"] == "journal"
assert row["enabled"] is False
assert row["config"] == {"project": "sci", "repo": "argszero/sci"}
assert row["sandbox"] == "read-only"
# runtime fields must survive the merge
assert "running" in row and "interval" in row and row["interval"] == 60


def test_list_tasks_without_cfg_leaves_status_untouched(tmp_path):
"""A handler not present in _handler_cfgs (edge: hot-reload race) must not
be decorated — status fields stay as-is."""
from emrg.server.scheduler import TaskScheduler

handler = _make_handler(tmp_path, name="plain", project="emrg")
sched = TaskScheduler(InstanceIdentity())
sched._handlers = [handler]
# no _handler_cfgs entry for this handler
tasks = sched.list_tasks()
assert len(tasks) == 1
assert tasks[0]["name"] == "plain"
assert "type" not in tasks[0]
assert "config" not in tasks[0]


# ── Task CRUD + hot reload + templates (rant 2026-08-12T18:23:15 P2) ──


Expand Down
Loading