alissa-tools-github-devloop 0.8.43__py3-none-any.whl → 0.8.44__py3-none-any.whl

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.
@@ -1 +1 @@
1
- 0.8.43
1
+ 0.8.44
@@ -31,6 +31,7 @@ logic lives here -- the console only moves a clock the daemon already reads.
31
31
  from __future__ import annotations
32
32
 
33
33
  import json
34
+ import re
34
35
  import sqlite3
35
36
  import time
36
37
  import urllib.error
@@ -111,8 +112,20 @@ VERSION_CACHE_TTL = 600.0
111
112
  # non-terminal task corpus 1,440x/day.
112
113
  TASKS_CACHE_TTL = 300.0
113
114
  # The flag that narrows `alissa task list` to the calling actor's own rows
114
- # instead of the sponsor's corpus. Newer CLIs only -- see `_supports_self_scope`.
115
+ # instead of the sponsor's corpus. Newer CLIs only -- see `_task_list_flags`.
115
116
  TASKS_SELF_FLAG = "--self"
117
+ # The pane shows live work only, so the read asks for exactly those statuses
118
+ # rather than every non-terminal row: the pending_validation backlog alone was
119
+ # ~2,600 rows (~3.5 MB) per refresh on prod (issue #168).
120
+ TASKS_STATUS_FLAG = "--status"
121
+ TASKS_LIVE_STATUSES = ("draft", "committed", "in_progress", "blocked")
122
+ # A row cap, a small multiple of what the pane displays, for a CLI that offers
123
+ # one. Kept within the 1..100 the CLI's paged listings accept.
124
+ TASKS_LIMIT_FLAG = "--limit"
125
+ TASKS_LIMIT_FACTOR = 4
126
+ TASKS_LIMIT_MAX = 100
127
+ # The pane's displayed row count (`worker_tasks`' default limit).
128
+ TASKS_DISPLAYED = 25
116
129
  # PyPI JSON endpoint for the running-vs-latest drift chip.
117
130
  PYPI_URL = "https://pypi.org/pypi/alissa-tools-github-devloop/json"
118
131
  # How many minutes past the stale window retry-now ages a row: the daemon
@@ -194,6 +207,12 @@ def edge_of(name: "str | None") -> "str | None":
194
207
  return None
195
208
 
196
209
 
210
+ def _offers_flag(helptext: str, flag: str) -> bool:
211
+ """Whether a CLI `--help` text lists `flag` as an option of its own --
212
+ `--self` must not be read off a longer `--self-x` it happens to prefix."""
213
+ return re.search(re.escape(flag) + r"(?![\w-])", helptext) is not None
214
+
215
+
197
216
  def _default_http_get(url: str, timeout: float) -> "bytes | None":
198
217
  try:
199
218
  with urllib.request.urlopen(url, timeout=timeout) as resp: # noqa: S310
@@ -250,8 +269,8 @@ class Sources:
250
269
  self._rate_cache = _Cache(RATE_CACHE_TTL, clock)
251
270
  self._version_cache = _Cache(VERSION_CACHE_TTL, clock)
252
271
  self._tasks_cache = _Cache(TASKS_CACHE_TTL, clock)
253
- # Tri-state: None = not probed yet (see `_supports_self_scope`).
254
- self._self_scope: "bool | None" = None
272
+ # None = not probed yet (see `_task_list_flags`).
273
+ self._list_flags: "frozenset[str] | None" = None
255
274
  self.boot_wall = int(wall_clock())
256
275
 
257
276
  # -- thin, failure-tolerant subprocess helpers -------------------------
@@ -460,40 +479,67 @@ class Sources:
460
479
  drain=self.drain(), now=self._wall(),
461
480
  )
462
481
 
463
- def _supports_self_scope(self) -> bool:
464
- """Whether the installed `alissa` CLI understands `task list --self`.
482
+ def _task_list_flags(self) -> "frozenset[str]":
483
+ """Which of the narrowing flags (`--self`, `--status`, `--limit`) the
484
+ installed `alissa` CLI offers on `task list`.
465
485
 
466
486
  Read off the CLI's own `--help`, which is local, tokenless and free.
467
- The alternative -- send the flag and fall back when the call fails --
487
+ The alternative -- send a flag and fall back when the call fails --
468
488
  cannot tell an unknown flag from an auth hiccup, so it would spend a
469
- second sponsor-scoped call on every unlucky refresh, which is the cost
470
- this whole path exists to avoid.
489
+ second, wider call on every unlucky refresh, which is the cost this
490
+ whole path exists to avoid.
471
491
 
472
492
  A probe that *answers* is memoized for the process (the CLI cannot
473
493
  change under a running console). A probe that fails is deliberately
474
494
  NOT memoized: a transient `alissa` failure then degrades this refresh
475
- only, instead of pinning the console to the expensive unscoped call
495
+ only, instead of pinning the console to the expensive unflagged call
476
496
  until someone restarts it."""
477
- if self._self_scope is None:
497
+ if self._list_flags is None:
478
498
  helptext = self._safe_run(
479
499
  ["alissa", "task", "list", "--help"], timeout=20
480
500
  )
481
501
  if helptext is None:
482
- return False
483
- self._self_scope = TASKS_SELF_FLAG in helptext
484
- return self._self_scope
502
+ return frozenset()
503
+ self._list_flags = frozenset(
504
+ flag for flag in
505
+ (TASKS_SELF_FLAG, TASKS_STATUS_FLAG, TASKS_LIMIT_FLAG)
506
+ if _offers_flag(helptext, flag)
507
+ )
508
+ return self._list_flags
485
509
 
486
- def worker_tasks(self, limit: int = 25) -> "list[dict]":
510
+ def _supports_self_scope(self) -> bool:
511
+ """Whether the installed `alissa` CLI understands `task list --self`."""
512
+ return TASKS_SELF_FLAG in self._task_list_flags()
513
+
514
+ def _task_list_argv(self) -> "list[str]":
515
+ """The `alissa task list` read the pane refreshes from: narrowed by
516
+ every flag the CLI offers -- the actor's own rows (`--self`), the live
517
+ statuses the pane shows (`--status`) and a row cap a small multiple
518
+ of the displayed count (`--limit`). A flag the CLI lacks is simply left
519
+ off; that per-flag degrade is the ONLY way the read widens."""
520
+ flags = self._task_list_flags()
521
+ argv = ["alissa", "task", "list", "--json"]
522
+ if TASKS_SELF_FLAG in flags:
523
+ argv.append(TASKS_SELF_FLAG)
524
+ if TASKS_STATUS_FLAG in flags:
525
+ argv += [TASKS_STATUS_FLAG, ",".join(TASKS_LIVE_STATUSES)]
526
+ if TASKS_LIMIT_FLAG in flags:
527
+ cap = min(TASKS_DISPLAYED * TASKS_LIMIT_FACTOR, TASKS_LIMIT_MAX)
528
+ argv += [TASKS_LIMIT_FLAG, str(cap)]
529
+ return argv
530
+
531
+ def worker_tasks(self, limit: int = TASKS_DISPLAYED) -> "list[dict]":
487
532
  """The worker actor's own tasks via `alissa task list` -- the
488
533
  actor-partition bridge (the console runs as the operator, whose actor
489
534
  owns the implementation tasks the dev sessions created). Best-effort:
490
535
  an old CLI or an auth hiccup just yields an empty list.
491
536
 
492
- Self-scoped (`--self`) wherever the installed CLI offers it, so a poll
493
- reads the console actor's own rows rather than the sponsor's whole
494
- non-terminal corpus -- the pane only ever displays the former. An
495
- older CLI, or a `--self` call that comes back empty-handed, degrades to
496
- the unflagged call: a slower, larger read beats a blank pane.
537
+ Narrowed (`_task_list_argv`) to what the pane displays wherever the
538
+ installed CLI offers the flags, so a refresh reads the console actor's
539
+ live rows rather than the sponsor's whole non-terminal corpus. Only a
540
+ CLI that lacks a flag reads wider. A narrowed call that fails is never
541
+ retried unflagged (issue #168: that fallback re-read the sponsor's
542
+ whole corpus), and a valid but empty `[]` is a real answer.
497
543
 
498
544
  Cached (TASKS_CACHE_TTL) exactly like the two other remote checks: this
499
545
  call rides the shared ALISSA_API_TOKEN the daemon uses, so on the ~10s
@@ -501,16 +547,7 @@ class Sources:
501
547
  the API budget. A fetch that fails returns None and keeps the last good
502
548
  list (the _Cache contract), never overwriting it with junk."""
503
549
  def fetch() -> "list[dict] | None":
504
- unscoped = ["alissa", "task", "list", "--json"]
505
- self_scoped = self._supports_self_scope()
506
- argv = (unscoped + [TASKS_SELF_FLAG]) if self_scoped else unscoped
507
- raw = self._safe_json(argv, timeout=45)
508
- if raw is None and self_scoped:
509
- # The CLI advertised the flag but the call brought nothing
510
- # back -- an API that does not serve the scope yet, say. One
511
- # unflagged retry keeps the pane populated. A valid but empty
512
- # `[]` is a real answer, not a failure, and is never retried.
513
- raw = self._safe_json(unscoped, timeout=45)
550
+ raw = self._safe_json(self._task_list_argv(), timeout=45)
514
551
  if not isinstance(raw, list):
515
552
  return None
516
553
  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.43
3
+ Version: 0.8.44
4
4
  Summary: ALISSA-TOOLS-GITHUB-DEVLOOP
5
5
  Home-page: https://alissa.app
6
6
  Author: Fahera
@@ -14,19 +14,19 @@ alissa/tools/github/devloop/parking.py,sha256=vEf-qprN14-I4vu4M53tIFaA3827FiHLpK
14
14
  alissa/tools/github/devloop/proc.py,sha256=nzfsxJSHFWRQcrXmfv588KazFysv8dVQrhMPH1q5eRk,3134
15
15
  alissa/tools/github/devloop/prompts.py,sha256=VzN6ec5eF2wwg7QSCRg52WLcxo-tGbGRgQbc4HSahUc,55169
16
16
  alissa/tools/github/devloop/state.py,sha256=uVwhbkogUTjWXXFq-COKzUeYrpuGbHzi05CjfEzAtPA,88668
17
- alissa/tools/github/devloop/version,sha256=w6XCzs4ibf7WAa6RiS5RhCLRVAdNmHRvxJaC9NKDINI,7
17
+ alissa/tools/github/devloop/version,sha256=va232A0BU1OdMrEBtZ5PyqpxusfsBdgt4whBySGjLHY,7
18
18
  alissa/tools/github/devloop/version.py,sha256=znuuOaitXGrBpbskNy78_rlVpFdtmKmk_3k1ACxZrl0,1418
19
19
  alissa/tools/github/devloop/webui/__init__.py,sha256=vdXYoyGYzD7BrJ5lV6XdH8Bpw_pej8-RK0hjfxop7-8,1513
20
20
  alissa/tools/github/devloop/webui/__main__.py,sha256=wORyW5AkgsniK0TZcrOrvm_P7Q4Mr-fH-4S6qj9XcgA,6137
21
21
  alissa/tools/github/devloop/webui/auth.py,sha256=g9YEDao9nKt-cBEENp7vFqwJ-T8olN6uLiCzVIN8yhA,7890
22
22
  alissa/tools/github/devloop/webui/page.py,sha256=4OD3e01ByvVM4Wo04AZyFuyOYTFEMT2lagktZAvyCKk,30862
23
23
  alissa/tools/github/devloop/webui/server.py,sha256=YuUmcng5qdWqSurcuyxH3FKKkBBfrpDtvtZLidJOGiU,26226
24
- alissa/tools/github/devloop/webui/sources.py,sha256=8_f5kQv6DGD0A2Y4goKH-TSIQAab-O5uoO3f2nNRhI0,37209
24
+ alissa/tools/github/devloop/webui/sources.py,sha256=JJXJEkLKh2qRbpTaIyQwCTu90DuKq_Z3nz6DwLhzlr4,38900
25
25
  alissa/tools/github/devloop/webui/sysinfo.py,sha256=ptlogH9alFv0vZ-pQfyUaA3w-K7LQS3tQHGv0d8Tdlk,9649
26
- alissa_tools_github_devloop-0.8.43.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
27
- alissa_tools_github_devloop-0.8.43.dist-info/licenses/NOTICE,sha256=FKstNs3uw_tQod4_1XcFLD1FUTJQXf4FC0oXJAOA_HE,260
28
- alissa_tools_github_devloop-0.8.43.dist-info/METADATA,sha256=ostOBBFoEkmV42blENKqNX5CrVK2dCdPHLIxfYVrzuY,12222
29
- alissa_tools_github_devloop-0.8.43.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
30
- alissa_tools_github_devloop-0.8.43.dist-info/entry_points.txt,sha256=8aC7Ajzx4bu9ZRR37a40IDfuStacvZP5KsAxY1dbFKU,145
31
- alissa_tools_github_devloop-0.8.43.dist-info/top_level.txt,sha256=DodjDg-l-TWQnlxG-Vuc3G5sB4O7cWGQwe6XrVx3u-A,7
32
- alissa_tools_github_devloop-0.8.43.dist-info/RECORD,,
26
+ alissa_tools_github_devloop-0.8.44.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
27
+ alissa_tools_github_devloop-0.8.44.dist-info/licenses/NOTICE,sha256=FKstNs3uw_tQod4_1XcFLD1FUTJQXf4FC0oXJAOA_HE,260
28
+ alissa_tools_github_devloop-0.8.44.dist-info/METADATA,sha256=s-GkeBOMMoSQatUPgO0Hg_HgIyoe5TlcNi-8D-NwSYQ,12222
29
+ alissa_tools_github_devloop-0.8.44.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
30
+ alissa_tools_github_devloop-0.8.44.dist-info/entry_points.txt,sha256=8aC7Ajzx4bu9ZRR37a40IDfuStacvZP5KsAxY1dbFKU,145
31
+ alissa_tools_github_devloop-0.8.44.dist-info/top_level.txt,sha256=DodjDg-l-TWQnlxG-Vuc3G5sB4O7cWGQwe6XrVx3u-A,7
32
+ alissa_tools_github_devloop-0.8.44.dist-info/RECORD,,