alissa-tools-github-devloop 0.8.5__tar.gz → 0.8.7__tar.gz

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.
Files changed (32) hide show
  1. {alissa_tools_github_devloop-0.8.5/src/main/alissa_tools_github_devloop.egg-info → alissa_tools_github_devloop-0.8.7}/PKG-INFO +1 -1
  2. alissa_tools_github_devloop-0.8.7/src/main/alissa/tools/github/devloop/version +1 -0
  3. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/src/main/alissa/tools/github/devloop/webui/sources.py +62 -13
  4. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7/src/main/alissa_tools_github_devloop.egg-info}/PKG-INFO +1 -1
  5. alissa_tools_github_devloop-0.8.5/src/main/alissa/tools/github/devloop/version +0 -1
  6. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/LICENSE +0 -0
  7. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/MANIFEST.in +0 -0
  8. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/NOTICE +0 -0
  9. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/README.md +0 -0
  10. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/requirements.txt +0 -0
  11. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/setup.cfg +0 -0
  12. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/setup.py +0 -0
  13. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/src/main/alissa/tools/github/devloop/__init__.py +0 -0
  14. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/src/main/alissa/tools/github/devloop/__main__.py +0 -0
  15. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/src/main/alissa/tools/github/devloop/alissa.py +0 -0
  16. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/src/main/alissa/tools/github/devloop/config.py +0 -0
  17. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/src/main/alissa/tools/github/devloop/ghclient.py +0 -0
  18. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/src/main/alissa/tools/github/devloop/janitor.py +0 -0
  19. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/src/main/alissa/tools/github/devloop/loop.py +0 -0
  20. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/src/main/alissa/tools/github/devloop/proc.py +0 -0
  21. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/src/main/alissa/tools/github/devloop/state.py +0 -0
  22. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/src/main/alissa/tools/github/devloop/version.py +0 -0
  23. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/src/main/alissa/tools/github/devloop/webui/__init__.py +0 -0
  24. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/src/main/alissa/tools/github/devloop/webui/__main__.py +0 -0
  25. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/src/main/alissa/tools/github/devloop/webui/auth.py +0 -0
  26. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/src/main/alissa/tools/github/devloop/webui/page.py +0 -0
  27. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/src/main/alissa/tools/github/devloop/webui/server.py +0 -0
  28. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/src/main/alissa/tools/github/devloop/webui/sysinfo.py +0 -0
  29. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/src/main/alissa_tools_github_devloop.egg-info/SOURCES.txt +0 -0
  30. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/src/main/alissa_tools_github_devloop.egg-info/dependency_links.txt +0 -0
  31. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/src/main/alissa_tools_github_devloop.egg-info/entry_points.txt +0 -0
  32. {alissa_tools_github_devloop-0.8.5 → alissa_tools_github_devloop-0.8.7}/src/main/alissa_tools_github_devloop.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: alissa-tools-github-devloop
3
- Version: 0.8.5
3
+ Version: 0.8.7
4
4
  Summary: ALISSA-TOOLS-GITHUB-DEVLOOP
5
5
  Home-page: https://alissa.app
6
6
  Author: Fahera
@@ -8,10 +8,12 @@ in strict budget order:
8
8
  call: the daemon already wrote everything down.
9
9
  2. **Local process state** -- `alissa tmux ls --json` for the session list, and
10
10
  a `/proc` walk (sysinfo) of each session's pane-PID tree for CPU%/RSS.
11
- 3. **Two cached remote checks** -- `gh api rate_limit` (60s cache) for the rate
12
- meter, and the PyPI version JSON (10m cache) for the running-vs-latest drift
13
- chip. These are the *only* network calls, and both are cached so a room full
14
- of refreshing operators cannot move the daemon's rate budget.
11
+ 3. **Three cached remote checks** -- `gh api rate_limit` (60s cache) for the
12
+ rate meter, the PyPI version JSON (10m cache) for the running-vs-latest
13
+ drift chip, and `alissa task list` (5m cache, self-scoped where the CLI
14
+ allows it) for the tasks pane. These are the *only* network calls, and all
15
+ three are cached so a room full of refreshing operators cannot move the
16
+ daemon's rate budget -- nor the sponsor's.
15
17
  4. **Config echo + log tail** -- the effective config the daemon resolved, and
16
18
  the tail of its log file.
17
19
 
@@ -49,7 +51,14 @@ RATE_CACHE_TTL = 60.0
49
51
  VERSION_CACHE_TTL = 600.0
50
52
  # `alissa task list` rides the shared ALISSA_API_TOKEN, so it is cached like the
51
53
  # other remote checks to keep a room of open tabs off the daemon's rate budget.
52
- TASKS_CACHE_TTL = 60.0
54
+ # Five minutes rather than the rate meter's sixty seconds: the pane is a
55
+ # monitoring glance, not a live feed, and every uncached read is served
56
+ # sponsor-scoped -- a tab left open on the 60s TTL paid the sponsor's entire
57
+ # non-terminal task corpus 1,440x/day.
58
+ TASKS_CACHE_TTL = 300.0
59
+ # The flag that narrows `alissa task list` to the calling actor's own rows
60
+ # instead of the sponsor's corpus. Newer CLIs only -- see `_supports_self_scope`.
61
+ TASKS_SELF_FLAG = "--self"
53
62
  # PyPI JSON endpoint for the running-vs-latest drift chip.
54
63
  PYPI_URL = "https://pypi.org/pypi/alissa-tools-github-devloop/json"
55
64
  # How many minutes past the stale window retry-now ages a row: the daemon
@@ -132,6 +141,8 @@ class Sources:
132
141
  self._rate_cache = _Cache(RATE_CACHE_TTL, clock)
133
142
  self._version_cache = _Cache(VERSION_CACHE_TTL, clock)
134
143
  self._tasks_cache = _Cache(TASKS_CACHE_TTL, clock)
144
+ # Tri-state: None = not probed yet (see `_supports_self_scope`).
145
+ self._self_scope: "bool | None" = None
135
146
  self.boot_wall = int(wall_clock())
136
147
 
137
148
  # -- thin, failure-tolerant subprocess helpers -------------------------
@@ -160,9 +171,9 @@ class Sources:
160
171
  with a daemon write and raise `sqlite3.OperationalError` (State's
161
172
  default 5s busy_timeout narrows this window but does not close it, and
162
173
  a corrupt db raises regardless). Catching here honors this module's
163
- contract (line 19): a state access never raises an exception that would
164
- blank the dashboard or 500 the retry action -- it degrades like every
165
- other source."""
174
+ failure-tolerance contract (the module docstring): a state access never
175
+ raises an exception that would blank the dashboard or 500 the retry
176
+ action -- it degrades like every other source."""
166
177
  try:
167
178
  with State(self.config.state_db) as st:
168
179
  return fn(st)
@@ -239,19 +250,57 @@ class Sources:
239
250
  )
240
251
  return out
241
252
 
253
+ def _supports_self_scope(self) -> bool:
254
+ """Whether the installed `alissa` CLI understands `task list --self`.
255
+
256
+ Read off the CLI's own `--help`, which is local, tokenless and free.
257
+ The alternative -- send the flag and fall back when the call fails --
258
+ cannot tell an unknown flag from an auth hiccup, so it would spend a
259
+ second sponsor-scoped call on every unlucky refresh, which is the cost
260
+ this whole path exists to avoid.
261
+
262
+ A probe that *answers* is memoized for the process (the CLI cannot
263
+ change under a running console). A probe that fails is deliberately
264
+ NOT memoized: a transient `alissa` failure then degrades this refresh
265
+ only, instead of pinning the console to the expensive unscoped call
266
+ until someone restarts it."""
267
+ if self._self_scope is None:
268
+ helptext = self._safe_run(
269
+ ["alissa", "task", "list", "--help"], timeout=20
270
+ )
271
+ if helptext is None:
272
+ return False
273
+ self._self_scope = TASKS_SELF_FLAG in helptext
274
+ return self._self_scope
275
+
242
276
  def worker_tasks(self, limit: int = 25) -> "list[dict]":
243
277
  """The worker actor's own tasks via `alissa task list` -- the
244
278
  actor-partition bridge (the console runs as the operator, whose actor
245
279
  owns the implementation tasks the dev sessions created). Best-effort:
246
280
  an old CLI or an auth hiccup just yields an empty list.
247
281
 
248
- Cached (TASKS_CACHE_TTL) exactly like the two remote checks: this call
249
- rides the shared ALISSA_API_TOKEN the daemon uses, so on the ~10s poll
250
- an unbounded call per open tab would contend with the daemon for the
251
- API budget. A fetch that fails returns None and keeps the last good
282
+ Self-scoped (`--self`) wherever the installed CLI offers it, so a poll
283
+ reads the console actor's own rows rather than the sponsor's whole
284
+ non-terminal corpus -- the pane only ever displays the former. An
285
+ older CLI, or a `--self` call that comes back empty-handed, degrades to
286
+ the unflagged call: a slower, larger read beats a blank pane.
287
+
288
+ Cached (TASKS_CACHE_TTL) exactly like the two other remote checks: this
289
+ call rides the shared ALISSA_API_TOKEN the daemon uses, so on the ~10s
290
+ poll an unbounded call per open tab would contend with the daemon for
291
+ the API budget. A fetch that fails returns None and keeps the last good
252
292
  list (the _Cache contract), never overwriting it with junk."""
253
293
  def fetch() -> "list[dict] | None":
254
- raw = self._safe_json(["alissa", "task", "list", "--json"], timeout=45)
294
+ unscoped = ["alissa", "task", "list", "--json"]
295
+ self_scoped = self._supports_self_scope()
296
+ argv = (unscoped + [TASKS_SELF_FLAG]) if self_scoped else unscoped
297
+ raw = self._safe_json(argv, timeout=45)
298
+ if raw is None and self_scoped:
299
+ # The CLI advertised the flag but the call brought nothing
300
+ # back -- an API that does not serve the scope yet, say. One
301
+ # unflagged retry keeps the pane populated. A valid but empty
302
+ # `[]` is a real answer, not a failure, and is never retried.
303
+ raw = self._safe_json(unscoped, timeout=45)
255
304
  if not isinstance(raw, list):
256
305
  return None
257
306
  rows = [t for t in raw if isinstance(t, dict)]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: alissa-tools-github-devloop
3
- Version: 0.8.5
3
+ Version: 0.8.7
4
4
  Summary: ALISSA-TOOLS-GITHUB-DEVLOOP
5
5
  Home-page: https://alissa.app
6
6
  Author: Fahera