Port the sssf skill from ~/.agents/skills/sssf into this repo so it can be distributed and installed with the skills CLI (skills add INDigitalStudio/skills --skill sssf). - Copy the skill (SKILL.md, cookbooks, references, scripts, templates, and the visualizer app source) into sssf/. - Gitignore build/runtime artifacts: the visualizer's node_modules/ and dist/, Python bytecode, and the machine-specific repos.json. - Make the skill location-independent: install.py now stamps the skill's real path into the stamped justfile's skill_dir (replacing the hardcoded ~/.agents/skills/sssf), so 'just obs' finds the visualizer wherever the CLI installed the skill. - Update cookbooks to use <skill>/scripts/... instead of the hardcoded path, and document the skills CLI install command. - Update the repo README with install instructions.
50 lines
1.9 KiB
Python
50 lines
1.9 KiB
Python
"""Session lifecycle: pin-or-create an adw_id, build the Run object.
|
|
|
|
`ensure(cfg, adw_id)` joins the session if it exists or creates it under
|
|
exactly that id (pinned ids for repeatable runs); omitted, a fresh id is
|
|
minted and printed so the next ADW can pick it up.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import signal
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
from .data_types import SSSFConfig
|
|
from .runner import Run
|
|
from .tracer import Tracer
|
|
from .utils import engineer_name, new_id
|
|
|
|
|
|
def _finalize_when_killed(run: Run) -> None:
|
|
"""A killed run still closes its own trace.
|
|
|
|
Python's default SIGTERM handling exits without unwinding, so `just kill`
|
|
(or any `kill <pid>`) would leave the session reading `running` forever and
|
|
its process rows open — the trace would claim work is in flight that is
|
|
already dead. Turning the signal into SystemExit both finalizes here and
|
|
lets the phase context manager record the phase as failed on the way out.
|
|
"""
|
|
def handler(signum, _frame):
|
|
run.tracer.session_finish(run.adw_id, ok=False) # also closes process rows
|
|
raise SystemExit(128 + signum)
|
|
|
|
for sig in (signal.SIGTERM, signal.SIGINT):
|
|
signal.signal(sig, handler)
|
|
|
|
|
|
def ensure(cfg: SSSFConfig, adw_id: str | None = None) -> Run:
|
|
adw_id = adw_id or new_id(8)
|
|
tracer = Tracer(cfg.observability.db,
|
|
f"{cfg.defaults.data_dir}/sessions/{adw_id}/events.jsonl")
|
|
run = Run(cfg=cfg, adw_id=adw_id, tracer=tracer, engineer=engineer_name())
|
|
tracer.session_start(adw_id, run.engineer, adw_name=Path(sys.argv[0]).stem)
|
|
# This process is the run. Record it before any phase opens, so a run that
|
|
# hangs in its first agent call is still killable by adw_id.
|
|
tracer.process_start(adw_id, "adw", "", os.getpid(),
|
|
" ".join([Path(sys.argv[0]).name, *sys.argv[1:]]))
|
|
_finalize_when_killed(run)
|
|
run.console.session_started(adw_id, run.engineer)
|
|
return run
|