Runtime state for a background-bash task. Extension fields beyond ``TaskStateBase``: * ``command`` — the literal shell command the model requested. * ``cwd`` — the working directory (string for serializability; the spawner converts back to ``Path`` where needed). * ``pid`` —
| 27 | |
| 28 | @dataclass(kw_only=True) |
| 29 | class LocalShellTaskState(TaskStateBase): |
| 30 | """Runtime state for a background-bash task. |
| 31 | |
| 32 | Extension fields beyond ``TaskStateBase``: |
| 33 | |
| 34 | * ``command`` — the literal shell command the model requested. |
| 35 | * ``cwd`` — the working directory (string for serializability; the |
| 36 | spawner converts back to ``Path`` where needed). |
| 37 | * ``pid`` — OS process id of the wrapped ``bash -lc`` invocation. |
| 38 | * ``output_path`` — the on-disk capture file (combined stdout/stderr). |
| 39 | ``output_file`` on the base carries the same string for chapter-10 |
| 40 | uniformity; ``output_path`` is kept as the bash-specific name to |
| 41 | avoid breaking existing readers. |
| 42 | * ``exit_code`` — populated by the reaper thread once the process exits; |
| 43 | ``None`` while running. |
| 44 | * ``finished_at`` — populated alongside ``exit_code``. |
| 45 | * ``proc`` / ``handle`` — runtime-only handles. Underscore-prefixed in |
| 46 | the legacy dict-of-dicts; here they're regular attributes guarded by |
| 47 | ``field(repr=False)`` so they don't leak into snapshots / logs. |
| 48 | """ |
| 49 | |
| 50 | type: Literal["local_bash"] = "local_bash" # type: ignore[assignment] |
| 51 | command: str = "" |
| 52 | cwd: str = "" |
| 53 | pid: int | None = None |
| 54 | output_path: str = "" |
| 55 | exit_code: int | None = None |
| 56 | finished_at: float | None = None |
| 57 | proc: subprocess.Popen | None = field(default=None, repr=False, compare=False) |
| 58 | handle: IO[bytes] | None = field(default=None, repr=False, compare=False) |
| 59 | |
| 60 | def derived_status(self) -> Literal["running", "completed", "failed"]: |
| 61 | """Compute the legacy three-value status string used by the bash |
| 62 | background reader. Independent of ``self.status`` (which uses the |
| 63 | canonical 5-value chapter-10 vocabulary).""" |
| 64 | rc = self.exit_code |
| 65 | if rc is None: |
| 66 | return "running" |
| 67 | return "completed" if rc == 0 else "failed" |
| 68 | |
| 69 | def to_legacy_dict(self) -> dict[str, Any]: |
| 70 | """Project back to the dict-of-dicts shape that the pre-Chunk-B |
| 71 | readers used. Kept for back-compat during the migration cycle so |
| 72 | the deprecated ``ToolContext.background_bash_tasks`` view exposes |
| 73 | the historical key set unchanged. |
| 74 | """ |
| 75 | return { |
| 76 | "task_id": self.id, |
| 77 | "command": self.command, |
| 78 | "description": self.description, |
| 79 | "cwd": self.cwd, |
| 80 | "started_at": self.start_time, |
| 81 | "output_path": self.output_path, |
| 82 | "pid": self.pid, |
| 83 | "_proc": self.proc, |
| 84 | "_handle": self.handle, |
| 85 | "exit_code": self.exit_code, |
| 86 | "finished_at": self.finished_at, |
no outgoing calls