3 Commits
Author SHA1 Message Date
gac bernina c7f653ba7c Log activity from terminal console and JupyterLab/Voila kernels too, merge multi-stream logs with separable filters
Previously only eco desktop's console had an activity log (via
eco.widgets.console_kernel's ZMQ-message interception, which only works
for a kernel with a real iopub channel a Qt widget attaches to) -- a
plain terminal `eco console` session and JupyterLab-native/Voila kernels
had none. eco.widgets.kernel_registry.install_shell_logger() closes that
gap using IPython's pre_run_cell/post_run_cell events instead, which work
identically for any real InteractiveShell. Wired into startup_inline.py
(terminal), eco_cli.py's generated kernel profile (JupyterLab-native), and
voila_app.ipynb/jupyterlab_app.ipynb (Voila / bare `eco jupyterlab`).
Narrower than console_kernel's approach by design: only input plus the
resulting value/error are captured, not raw stdout/stderr streaming.

Also proactively set use_jedi=False for the terminal's `eco console`
startup script, matching the reasoning already applied to desktop's
console (see console_kernel.build_console_widget's docstring) -- Jedi's
introspection was measured slower and less correct against eco's dynamic,
lazily-resolving namespace.

Every kernel log's entries are now tagged with which stream they came
from (TimelineEntry.session, a "kind:label · HHMMSS" label derived from
the log's own session_start record) so eco.logs's timeline keeps merging
every session by default but LogTimelineQt gained a second, AND-combined
"Stream:" filter row alongside the existing "Show:" kind row to separate
them back out on demand. Fixed a same-second label collision the first
version of the label had (two sessions of the same kind+label started
within the same second, e.g. under test, produced identical labels) by
falling back to a trailing id fragment from the log filename.

Cross-user session browsing (the log_dir parameter already supports it)
is deliberately deferred, not built this pass.
2026-08-22 09:30:28 +02:00
gac berninaandClaude Sonnet 5 0f081885d5 Add filtering, multi-select, and copy-as-script to the Qt log timeline viewer
New capability requested for eco desktop's (and, via eco.logs.widget(),
any) log viewer: filter entries by kind, select a range, and copy that
selection as a runnable Python script -- optionally replaying the
original pacing via inserted time.sleep() calls between lines.

- KernelSession.log_widget_control(code): a new event kind for GUI
  actions that never went through the console at all -- e.g. clicking
  "Open" in the Namespace launcher. Same "code IS the text" contract as
  log_input (not a description -- actual runnable Python), so it's usable
  in generated scripts the same way console input already is.
- EcoDesktopApp._open_widget now logs one of these on every successful
  open, as a bare name (`<name>.widget()`) -- not `namespace.<name>`,
  which per build_namespace's own docstring doesn't actually resolve
  (Namespace.append_obj writes devices onto the scope module, not the
  Namespace instance); the bare form is exactly what build_namespace_vars
  already makes available in that console.
- eco.logs._kernel_record_to_entry maps "widget_control" events to their
  own TimelineEntry kind, alongside the existing input/result/stream/
  error/session ones.
- LogTimelineQt: a "Show:" row of one checkbox per distinct kind present
  (hide/show via setHidden, no rebuild); ExtendedSelection on the list
  (Qt's own click/Shift+click/Ctrl+click/drag range selection, nothing
  else to wire up); a "Copy Selected as Script" button + "Replicate
  timing" checkbox -- input/widget_control entries in the selection
  become script lines verbatim, everything else becomes a `# [kind] ...`
  comment for context; timing mode inserts time.sleep(dt) between lines
  using the real gap between those two entries' timestamps.

Verified via scripted offscreen construction (filter checkboxes present
and working, selection mode set, script content correct both with and
without timing, hidden/filtered rows correctly excluded from a selection
that still nominally contains them) and end-to-end through a real
EcoDesktopApp (_open_widget really writes a widget_control JSONL line,
eco.logs reads it back with the right kind/text) -- plus the full test
suite (361/363, the 2 failures pre-existing in test_config_lazy_init.py,
unrelated).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-22 08:53:09 +02:00
gac bernina 97a9020149 updates to run 2026-08-21 15:10:25 +02:00