arkaos 3.70.9 → 3.71.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/VERSION CHANGED
@@ -1 +1 @@
1
- 3.70.9
1
+ 3.71.0
@@ -155,6 +155,7 @@ class ObsidianPersonaStore:
155
155
  communication=PersonaCommunication(
156
156
  **_filter_known(PersonaCommunication, comm_fm),
157
157
  ),
158
+ bio_md=str(fm.get("bio_md") or ""),
158
159
  created_at=str(fm.get("created_at") or ""),
159
160
  updated_at=str(fm.get("updated_at") or ""),
160
161
  )
@@ -236,6 +237,12 @@ class ObsidianPersonaStore:
236
237
  "created_at": persona.created_at or now,
237
238
  "updated_at": now,
238
239
  }
240
+ # v3.70.10 — long-form Markdown bio. Stored as a frontmatter
241
+ # block scalar so it survives round-trips; only emitted when set
242
+ # to keep bio-less persona files clean. YAML handles the multi-line
243
+ # value; the no-yaml fallback below can't, so skip it there.
244
+ if persona.bio_md and yaml is not None:
245
+ frontmatter["bio_md"] = persona.bio_md
239
246
  if yaml is not None:
240
247
  fm_block = yaml.safe_dump(
241
248
  frontmatter,
@@ -46,6 +46,13 @@ def _default_cwd() -> str:
46
46
  return os.path.expanduser("~")
47
47
 
48
48
 
49
+ # v3.71.0 — in-memory scrollback so a reconnecting client (after the
50
+ # operator navigates away or reloads the dashboard) can replay recent
51
+ # output and find its session as it left it. Bounded, RAM-only, cleared
52
+ # on close, never written to disk and never sent to the audit log.
53
+ DEFAULT_SCROLLBACK_BYTES = 512 * 1024
54
+
55
+
49
56
  class TerminalSession:
50
57
  """A single forked PTY + the bookkeeping needed to drive it.
51
58
 
@@ -60,6 +67,7 @@ class TerminalSession:
60
67
  cwd: str,
61
68
  cols: int = 120,
62
69
  rows: int = 32,
70
+ scrollback_bytes: int = DEFAULT_SCROLLBACK_BYTES,
63
71
  ) -> None:
64
72
  self.session_id = session_id
65
73
  self.shell = shell
@@ -68,6 +76,8 @@ class TerminalSession:
68
76
  self.last_activity = time.monotonic()
69
77
  self.exit_code: Optional[int] = None
70
78
  self.title: str = ""
79
+ self.scrollback_max = max(0, int(scrollback_bytes))
80
+ self._scrollback = bytearray()
71
81
  self._closed = False
72
82
  self.pid, self.master_fd = pty.fork()
73
83
  if self.pid == 0:
@@ -104,8 +114,21 @@ class TerminalSession:
104
114
  raise
105
115
  if data:
106
116
  self.last_activity = time.monotonic()
117
+ self._record(data)
107
118
  return data
108
119
 
120
+ def _record(self, data: bytes) -> None:
121
+ """Append output to the bounded scrollback, evicting the oldest."""
122
+ if self.scrollback_max <= 0:
123
+ return
124
+ self._scrollback += data
125
+ if len(self._scrollback) > self.scrollback_max:
126
+ del self._scrollback[: -self.scrollback_max]
127
+
128
+ def scrollback(self) -> bytes:
129
+ """Snapshot of recent output, for replay on (re)connect."""
130
+ return bytes(self._scrollback)
131
+
109
132
  def write(self, data: bytes) -> int:
110
133
  if self._closed or self.master_fd < 0 or not data:
111
134
  return 0
@@ -172,6 +195,7 @@ class TerminalSession:
172
195
  except OSError:
173
196
  pass
174
197
  self.master_fd = -1
198
+ self._scrollback.clear()
175
199
  self._closed = True
176
200
 
177
201
  def to_dict(self) -> dict[str, Any]:
@@ -207,6 +231,9 @@ class TerminalSessionManager:
207
231
  self.idle_timeout_s = int(
208
232
  os.environ.get("ARKAOS_TERMINAL_IDLE_S", idle_default)
209
233
  )
234
+ self.scrollback_bytes = int(
235
+ os.environ.get("ARKAOS_TERMINAL_SCROLLBACK_BYTES", DEFAULT_SCROLLBACK_BYTES)
236
+ )
210
237
  self._sessions: dict[str, TerminalSession] = {}
211
238
 
212
239
  def create(
@@ -230,6 +257,7 @@ class TerminalSessionManager:
230
257
  cwd=chosen_cwd,
231
258
  cols=cols,
232
259
  rows=rows,
260
+ scrollback_bytes=self.scrollback_bytes,
233
261
  )
234
262
  self._sessions[sid] = session
235
263
  audit.log_start(sid, chosen_shell, chosen_cwd)