alissa-tools-github-devloop 0.8.29__tar.gz → 0.8.31__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.
- alissa_tools_github_devloop-0.8.31/PKG-INFO +124 -0
- alissa_tools_github_devloop-0.8.31/README.md +102 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa/tools/github/devloop/alissa.py +37 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa/tools/github/devloop/loop.py +563 -29
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa/tools/github/devloop/loop_events.py +189 -3
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa/tools/github/devloop/prompts.py +346 -7
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa/tools/github/devloop/state.py +101 -8
- alissa_tools_github_devloop-0.8.31/src/main/alissa/tools/github/devloop/version +1 -0
- alissa_tools_github_devloop-0.8.31/src/main/alissa_tools_github_devloop.egg-info/PKG-INFO +124 -0
- alissa_tools_github_devloop-0.8.29/PKG-INFO +0 -78
- alissa_tools_github_devloop-0.8.29/README.md +0 -56
- alissa_tools_github_devloop-0.8.29/src/main/alissa/tools/github/devloop/version +0 -1
- alissa_tools_github_devloop-0.8.29/src/main/alissa_tools_github_devloop.egg-info/PKG-INFO +0 -78
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/LICENSE +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/MANIFEST.in +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/NOTICE +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/requirements.txt +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/setup.cfg +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/setup.py +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa/tools/github/devloop/__init__.py +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa/tools/github/devloop/__main__.py +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa/tools/github/devloop/alissa_client.py +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa/tools/github/devloop/bows.py +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa/tools/github/devloop/config.py +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa/tools/github/devloop/fleet_vitals.py +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa/tools/github/devloop/ghclient.py +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa/tools/github/devloop/hubs.py +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa/tools/github/devloop/janitor.py +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa/tools/github/devloop/proc.py +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa/tools/github/devloop/version.py +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa/tools/github/devloop/webui/__init__.py +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa/tools/github/devloop/webui/__main__.py +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa/tools/github/devloop/webui/auth.py +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa/tools/github/devloop/webui/page.py +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa/tools/github/devloop/webui/server.py +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa/tools/github/devloop/webui/sources.py +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa/tools/github/devloop/webui/sysinfo.py +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa_tools_github_devloop.egg-info/SOURCES.txt +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa_tools_github_devloop.egg-info/dependency_links.txt +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa_tools_github_devloop.egg-info/entry_points.txt +0 -0
- {alissa_tools_github_devloop-0.8.29 → alissa_tools_github_devloop-0.8.31}/src/main/alissa_tools_github_devloop.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: alissa-tools-github-devloop
|
|
3
|
+
Version: 0.8.31
|
|
4
|
+
Summary: ALISSA-TOOLS-GITHUB-DEVLOOP
|
|
5
|
+
Home-page: https://alissa.app
|
|
6
|
+
Author: Fahera
|
|
7
|
+
Author-email: support@alissa.app
|
|
8
|
+
License: Apache-2.0
|
|
9
|
+
Requires-Python: >=3.11
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
License-File: NOTICE
|
|
13
|
+
Dynamic: author
|
|
14
|
+
Dynamic: author-email
|
|
15
|
+
Dynamic: description
|
|
16
|
+
Dynamic: description-content-type
|
|
17
|
+
Dynamic: home-page
|
|
18
|
+
Dynamic: license
|
|
19
|
+
Dynamic: license-file
|
|
20
|
+
Dynamic: requires-python
|
|
21
|
+
Dynamic: summary
|
|
22
|
+
|
|
23
|
+
# alissa-tools-github-devloop
|
|
24
|
+
|
|
25
|
+
The `alissa.tools.github.devloop` module: a GitHub watcher that turns
|
|
26
|
+
`alissa:develop`-labeled issues into fresh developer sessions — the
|
|
27
|
+
developer-side counterpart of
|
|
28
|
+
[`alissa-tools-github-reviewloop`](https://github.com/fahera-mx/alissa-github-review-daemon).
|
|
29
|
+
|
|
30
|
+
This distribution ships **only** that module. Everything above it —
|
|
31
|
+
`alissa`, `alissa.tools`, `alissa.tools.github` — is a
|
|
32
|
+
[PEP 420](https://peps.python.org/pep-0420/) namespace package with no
|
|
33
|
+
`__init__.py`, so other distributions in other repositories can contribute
|
|
34
|
+
their own packages under the same namespace:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
alissa/ ← namespace (no __init__.py)
|
|
38
|
+
└── tools/ ← namespace
|
|
39
|
+
└── github/ ← namespace
|
|
40
|
+
├── devloop/ __init__.py ← THIS distribution
|
|
41
|
+
└── reviewloop/ __init__.py ← ships from alissa-github-review-daemon
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The rule: a distribution owns a leaf package and declares only that subtree
|
|
45
|
+
(`find_namespace_packages(include=[PACKAGE, f"{PACKAGE}.*"])`). Adding an
|
|
46
|
+
`__init__.py` at any namespace level would claim it for one distribution and
|
|
47
|
+
shadow the others.
|
|
48
|
+
|
|
49
|
+
## Install
|
|
50
|
+
|
|
51
|
+
```sh
|
|
52
|
+
pip install -e ./alissa-tools-github-devloop
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Console scripts
|
|
56
|
+
|
|
57
|
+
| Command | Entry point |
|
|
58
|
+
| --- | --- |
|
|
59
|
+
| `alissa-devloop` | `alissa.tools.github.devloop.__main__:main` |
|
|
60
|
+
|
|
61
|
+
## Layout
|
|
62
|
+
|
|
63
|
+
`src/main` holds the package tree, `src/test` mirrors it as `test_*`. The
|
|
64
|
+
distribution version lives in the plain-text `version` file next to the module
|
|
65
|
+
it versions (`src/main/alissa/tools/github/devloop/version`), read by both
|
|
66
|
+
`setup.py` and `version.py`.
|
|
67
|
+
|
|
68
|
+
## Account-level conditions
|
|
69
|
+
|
|
70
|
+
The prompt responder (`prompts.py` classifies, `loop.py` acts) treats four
|
|
71
|
+
pane conditions as the ACCOUNT's, not the worker's — nothing a keystroke can
|
|
72
|
+
answer: `login_expired`, `auth_rejected` (a 401), `usage_limit` and
|
|
73
|
+
`out_of_credits`. Each pages the operator once per kind per 6 h on the lane's
|
|
74
|
+
issue/PR and holds every new spawn while it stands (at most 1 h on one pane,
|
|
75
|
+
then kill-and-retry re-confirms).
|
|
76
|
+
|
|
77
|
+
**Usage limits** (issue #142). `usage_limit` admits the window wordings
|
|
78
|
+
(`You've hit your weekly limit`, `Usage limit reached`, …) and the
|
|
79
|
+
MODEL-named one Claude Code prints now — `You've reached your Fable limit.
|
|
80
|
+
Run /usage-credits to continue or switch models with /model.` (also `Opus`,
|
|
81
|
+
`Sonnet`, …): one capitalised model token, a known family name or any token
|
|
82
|
+
corroborated by that trailing hint on the same line. An over-limit account
|
|
83
|
+
answers the directive with that notice as the worker's ONLY assistant turn
|
|
84
|
+
and leaves the session idle at `❯`, which the banner rule (never a `●` row)
|
|
85
|
+
cannot see, so the **first-turn limit check** reads the responder's capture of
|
|
86
|
+
any young worker (`develop-*`, `fix-*`, `maintain-*`, `revert-*`, spawned by
|
|
87
|
+
this ledger inside the last `stale_minutes`): the notice, above an idle
|
|
88
|
+
prompt, with no other `●` turn since the directive. A match
|
|
89
|
+
(`source: "first_turn"`, `matched: "model_limit"`, the model) is:
|
|
90
|
+
|
|
91
|
+
- **held** — the daemon-wide spawn hold, clocked on the ledger for 1 h from
|
|
92
|
+
the newest limit (it outlives the killed session and a restart); when it
|
|
93
|
+
expires the retry edges respawn as they would have, and a fresh pane still
|
|
94
|
+
showing the notice re-arms it;
|
|
95
|
+
- **paged** — once per 6 h window, through the account-kind page;
|
|
96
|
+
- **killed** — the session is idle and useless;
|
|
97
|
+
- **refunded** — the spawn row is stamped `limited_at`, and every
|
|
98
|
+
`attempt_cap` count leaves limited rows out (numbering stays monotonic, so
|
|
99
|
+
session names never repeat). An account over its limit never caps a lane.
|
|
100
|
+
|
|
101
|
+
The same notice after real worker output (a tool call, the worker's own
|
|
102
|
+
prose, a quoted tool row) stays worker output. Each observation is one
|
|
103
|
+
`usage.limited` loop event per session: `data: { kind: "usage_limit", source:
|
|
104
|
+
"pane" | "first_turn", matched: "model_limit" | "usage_limit", model }` — no
|
|
105
|
+
pane text, no credential material.
|
|
106
|
+
|
|
107
|
+
**The fix edge stops presuming.** A stale fix round with no triage reply from
|
|
108
|
+
the author used to be re-enqueued on the timer alone ("presumed dead"). It now
|
|
109
|
+
reads the tmux roster first: ALIVE is in flight (the responder owns a live
|
|
110
|
+
idle pane; a once-per-episode "Fix loop stalled?" ping floors the wait),
|
|
111
|
+
INDETERMINATE defers one pass, and only DEAD respawns — "CONFIRMED dead", or,
|
|
112
|
+
after a refunded limit, "previous session limited (… attempt refunded)".
|
|
113
|
+
|
|
114
|
+
## License
|
|
115
|
+
|
|
116
|
+
Licensed under the
|
|
117
|
+
[Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) — the
|
|
118
|
+
`LICENSE` and `NOTICE` files shipped with this distribution carry the full text
|
|
119
|
+
and the attribution and trademark terms. Both ship inside the sdist and the
|
|
120
|
+
wheel's `.dist-info`.
|
|
121
|
+
|
|
122
|
+
"Alissa" and "Fahera" are trademarks of CORE FAHERA ENTERPRISE HOLDINGS
|
|
123
|
+
S. DE R.L. and are not covered by the license — the grant covers the code, not
|
|
124
|
+
the names.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# alissa-tools-github-devloop
|
|
2
|
+
|
|
3
|
+
The `alissa.tools.github.devloop` module: a GitHub watcher that turns
|
|
4
|
+
`alissa:develop`-labeled issues into fresh developer sessions — the
|
|
5
|
+
developer-side counterpart of
|
|
6
|
+
[`alissa-tools-github-reviewloop`](https://github.com/fahera-mx/alissa-github-review-daemon).
|
|
7
|
+
|
|
8
|
+
This distribution ships **only** that module. Everything above it —
|
|
9
|
+
`alissa`, `alissa.tools`, `alissa.tools.github` — is a
|
|
10
|
+
[PEP 420](https://peps.python.org/pep-0420/) namespace package with no
|
|
11
|
+
`__init__.py`, so other distributions in other repositories can contribute
|
|
12
|
+
their own packages under the same namespace:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
alissa/ ← namespace (no __init__.py)
|
|
16
|
+
└── tools/ ← namespace
|
|
17
|
+
└── github/ ← namespace
|
|
18
|
+
├── devloop/ __init__.py ← THIS distribution
|
|
19
|
+
└── reviewloop/ __init__.py ← ships from alissa-github-review-daemon
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The rule: a distribution owns a leaf package and declares only that subtree
|
|
23
|
+
(`find_namespace_packages(include=[PACKAGE, f"{PACKAGE}.*"])`). Adding an
|
|
24
|
+
`__init__.py` at any namespace level would claim it for one distribution and
|
|
25
|
+
shadow the others.
|
|
26
|
+
|
|
27
|
+
## Install
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
pip install -e ./alissa-tools-github-devloop
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Console scripts
|
|
34
|
+
|
|
35
|
+
| Command | Entry point |
|
|
36
|
+
| --- | --- |
|
|
37
|
+
| `alissa-devloop` | `alissa.tools.github.devloop.__main__:main` |
|
|
38
|
+
|
|
39
|
+
## Layout
|
|
40
|
+
|
|
41
|
+
`src/main` holds the package tree, `src/test` mirrors it as `test_*`. The
|
|
42
|
+
distribution version lives in the plain-text `version` file next to the module
|
|
43
|
+
it versions (`src/main/alissa/tools/github/devloop/version`), read by both
|
|
44
|
+
`setup.py` and `version.py`.
|
|
45
|
+
|
|
46
|
+
## Account-level conditions
|
|
47
|
+
|
|
48
|
+
The prompt responder (`prompts.py` classifies, `loop.py` acts) treats four
|
|
49
|
+
pane conditions as the ACCOUNT's, not the worker's — nothing a keystroke can
|
|
50
|
+
answer: `login_expired`, `auth_rejected` (a 401), `usage_limit` and
|
|
51
|
+
`out_of_credits`. Each pages the operator once per kind per 6 h on the lane's
|
|
52
|
+
issue/PR and holds every new spawn while it stands (at most 1 h on one pane,
|
|
53
|
+
then kill-and-retry re-confirms).
|
|
54
|
+
|
|
55
|
+
**Usage limits** (issue #142). `usage_limit` admits the window wordings
|
|
56
|
+
(`You've hit your weekly limit`, `Usage limit reached`, …) and the
|
|
57
|
+
MODEL-named one Claude Code prints now — `You've reached your Fable limit.
|
|
58
|
+
Run /usage-credits to continue or switch models with /model.` (also `Opus`,
|
|
59
|
+
`Sonnet`, …): one capitalised model token, a known family name or any token
|
|
60
|
+
corroborated by that trailing hint on the same line. An over-limit account
|
|
61
|
+
answers the directive with that notice as the worker's ONLY assistant turn
|
|
62
|
+
and leaves the session idle at `❯`, which the banner rule (never a `●` row)
|
|
63
|
+
cannot see, so the **first-turn limit check** reads the responder's capture of
|
|
64
|
+
any young worker (`develop-*`, `fix-*`, `maintain-*`, `revert-*`, spawned by
|
|
65
|
+
this ledger inside the last `stale_minutes`): the notice, above an idle
|
|
66
|
+
prompt, with no other `●` turn since the directive. A match
|
|
67
|
+
(`source: "first_turn"`, `matched: "model_limit"`, the model) is:
|
|
68
|
+
|
|
69
|
+
- **held** — the daemon-wide spawn hold, clocked on the ledger for 1 h from
|
|
70
|
+
the newest limit (it outlives the killed session and a restart); when it
|
|
71
|
+
expires the retry edges respawn as they would have, and a fresh pane still
|
|
72
|
+
showing the notice re-arms it;
|
|
73
|
+
- **paged** — once per 6 h window, through the account-kind page;
|
|
74
|
+
- **killed** — the session is idle and useless;
|
|
75
|
+
- **refunded** — the spawn row is stamped `limited_at`, and every
|
|
76
|
+
`attempt_cap` count leaves limited rows out (numbering stays monotonic, so
|
|
77
|
+
session names never repeat). An account over its limit never caps a lane.
|
|
78
|
+
|
|
79
|
+
The same notice after real worker output (a tool call, the worker's own
|
|
80
|
+
prose, a quoted tool row) stays worker output. Each observation is one
|
|
81
|
+
`usage.limited` loop event per session: `data: { kind: "usage_limit", source:
|
|
82
|
+
"pane" | "first_turn", matched: "model_limit" | "usage_limit", model }` — no
|
|
83
|
+
pane text, no credential material.
|
|
84
|
+
|
|
85
|
+
**The fix edge stops presuming.** A stale fix round with no triage reply from
|
|
86
|
+
the author used to be re-enqueued on the timer alone ("presumed dead"). It now
|
|
87
|
+
reads the tmux roster first: ALIVE is in flight (the responder owns a live
|
|
88
|
+
idle pane; a once-per-episode "Fix loop stalled?" ping floors the wait),
|
|
89
|
+
INDETERMINATE defers one pass, and only DEAD respawns — "CONFIRMED dead", or,
|
|
90
|
+
after a refunded limit, "previous session limited (… attempt refunded)".
|
|
91
|
+
|
|
92
|
+
## License
|
|
93
|
+
|
|
94
|
+
Licensed under the
|
|
95
|
+
[Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) — the
|
|
96
|
+
`LICENSE` and `NOTICE` files shipped with this distribution carry the full text
|
|
97
|
+
and the attribution and trademark terms. Both ship inside the sdist and the
|
|
98
|
+
wheel's `.dist-info`.
|
|
99
|
+
|
|
100
|
+
"Alissa" and "Fahera" are trademarks of CORE FAHERA ENTERPRISE HOLDINGS
|
|
101
|
+
S. DE R.L. and are not covered by the license — the grant covers the code, not
|
|
102
|
+
the names.
|
|
@@ -80,6 +80,26 @@ def pane_path_argv(name: str) -> "list[str]":
|
|
|
80
80
|
]
|
|
81
81
|
|
|
82
82
|
|
|
83
|
+
# What `#{pane_current_command}` reads on a worker pane whose `claude` has
|
|
84
|
+
# EXITED (issue #140): the shell `alissa tmux new` launched it from, back in
|
|
85
|
+
# the foreground. A live worker reads `node` (Claude Code's runtime); a
|
|
86
|
+
# name here means the process the session was spawned for is gone, whatever
|
|
87
|
+
# the session listing says about liveness.
|
|
88
|
+
SHELL_COMMANDS = frozenset((
|
|
89
|
+
"bash", "sh", "zsh", "fish", "dash", "ksh", "ash", "tcsh", "csh",
|
|
90
|
+
))
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def pane_command_argv(name: str) -> "list[str]":
|
|
94
|
+
"""`tmux -S <socket> display-message -p -t =<real>: #{pane_current_command}`:
|
|
95
|
+
the foreground process of the session's active pane, by name."""
|
|
96
|
+
check_session_name(name)
|
|
97
|
+
return [
|
|
98
|
+
"tmux", "-S", tmux_socket(), "display-message", "-p",
|
|
99
|
+
"-t", tmux_target(name), "#{pane_current_command}",
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
|
|
83
103
|
def send_keys_argv(name: str, keys: "tuple[str, ...]") -> "list[str]":
|
|
84
104
|
"""`tmux -S <socket> send-keys -t =<real> <key>…` with every key drawn
|
|
85
105
|
from `prompts.ALLOWED_KEYS`. Anything else -- a letter, a word, a path --
|
|
@@ -270,6 +290,23 @@ class Alissa:
|
|
|
270
290
|
log.debug("could not read the pane path of %s (%s)", name, exc)
|
|
271
291
|
return ""
|
|
272
292
|
|
|
293
|
+
def pane_command(self, name: str) -> str:
|
|
294
|
+
"""The session's pane current command (`#{pane_current_command}`),
|
|
295
|
+
or "" when tmux cannot answer. The first-turn death check's one
|
|
296
|
+
liveness probe (issue #140): a worker whose pane reads a shell
|
|
297
|
+
(`SHELL_COMMANDS`) has lost its `claude`, however alive the tmux
|
|
298
|
+
session itself is. A READ: runs under dry-run too."""
|
|
299
|
+
try:
|
|
300
|
+
argv = pane_command_argv(name)
|
|
301
|
+
except ValueError as exc:
|
|
302
|
+
log.warning("pane_command refused: %s", exc)
|
|
303
|
+
return ""
|
|
304
|
+
try:
|
|
305
|
+
return run(argv, timeout=15).strip()
|
|
306
|
+
except CommandError as exc:
|
|
307
|
+
log.debug("could not read the pane command of %s (%s)", name, exc)
|
|
308
|
+
return ""
|
|
309
|
+
|
|
273
310
|
def send_keys(self, name: str, *keys: str, dry_run: bool = False) -> bool:
|
|
274
311
|
"""Press `keys` -- each one of `prompts.ALLOWED_KEYS`, nothing else
|
|
275
312
|
-- on ONE managed session's pane. True when tmux accepted them.
|