pocketshell 0.3.2__tar.gz → 0.3.6__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 (29) hide show
  1. {pocketshell-0.3.2 → pocketshell-0.3.6}/PKG-INFO +79 -7
  2. {pocketshell-0.3.2 → pocketshell-0.3.6}/README.md +78 -6
  3. {pocketshell-0.3.2 → pocketshell-0.3.6}/pyproject.toml +1 -1
  4. {pocketshell-0.3.2 → pocketshell-0.3.6}/src/pocketshell/__init__.py +1 -1
  5. {pocketshell-0.3.2 → pocketshell-0.3.6}/src/pocketshell/cli.py +6 -0
  6. pocketshell-0.3.6/src/pocketshell/env.py +681 -0
  7. pocketshell-0.3.6/src/pocketshell/hooks.py +926 -0
  8. {pocketshell-0.3.2 → pocketshell-0.3.6}/src/pocketshell/jobs.py +4 -4
  9. pocketshell-0.3.6/src/pocketshell/logs.py +668 -0
  10. {pocketshell-0.3.2 → pocketshell-0.3.6}/src/pocketshell/sessions.py +4 -4
  11. {pocketshell-0.3.2 → pocketshell-0.3.6}/src/pocketshell/usage.py +4 -4
  12. pocketshell-0.3.6/tests/test_env.py +415 -0
  13. pocketshell-0.3.6/tests/test_hooks.py +521 -0
  14. pocketshell-0.3.6/tests/test_logs.py +346 -0
  15. {pocketshell-0.3.2 → pocketshell-0.3.6}/uv.lock +2 -2
  16. {pocketshell-0.3.2 → pocketshell-0.3.6}/.gitignore +0 -0
  17. {pocketshell-0.3.2 → pocketshell-0.3.6}/src/pocketshell/__main__.py +0 -0
  18. {pocketshell-0.3.2 → pocketshell-0.3.6}/src/pocketshell/agent_log.py +0 -0
  19. {pocketshell-0.3.2 → pocketshell-0.3.6}/src/pocketshell/daemon.py +0 -0
  20. {pocketshell-0.3.2 → pocketshell-0.3.6}/src/pocketshell/qr_share.py +0 -0
  21. {pocketshell-0.3.2 → pocketshell-0.3.6}/src/pocketshell/repos.py +0 -0
  22. {pocketshell-0.3.2 → pocketshell-0.3.6}/tests/__init__.py +0 -0
  23. {pocketshell-0.3.2 → pocketshell-0.3.6}/tests/test_agent_log.py +0 -0
  24. {pocketshell-0.3.2 → pocketshell-0.3.6}/tests/test_daemon.py +0 -0
  25. {pocketshell-0.3.2 → pocketshell-0.3.6}/tests/test_jobs.py +0 -0
  26. {pocketshell-0.3.2 → pocketshell-0.3.6}/tests/test_qr_share.py +0 -0
  27. {pocketshell-0.3.2 → pocketshell-0.3.6}/tests/test_repos.py +0 -0
  28. {pocketshell-0.3.2 → pocketshell-0.3.6}/tests/test_sessions.py +0 -0
  29. {pocketshell-0.3.2 → pocketshell-0.3.6}/tests/test_usage.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pocketshell
3
- Version: 0.3.2
3
+ Version: 0.3.6
4
4
  Summary: Unified server-side Python utility for the PocketShell Android client.
5
5
  Project-URL: Homepage, https://github.com/alexeygrigorev/pocketshell
6
6
  Project-URL: Issues, https://github.com/alexeygrigorev/pocketshell/issues
@@ -173,6 +173,75 @@ Requires the optional `qr` extra (see [Optional extras](#optional-extras)).
173
173
  Without it, the command exits 127 with the install hint and every other
174
174
  subcommand keeps working.
175
175
 
176
+ #### Running from a repo clone (no install)
177
+
178
+ To run `qr-share` straight from a checkout without installing the tool,
179
+ use `uv run` from `tools/pocketshell` and include the `qr` extra:
180
+
181
+ ```bash
182
+ cd tools/pocketshell
183
+ uv run --extra qr pocketshell qr-share prod
184
+ ```
185
+
186
+ The first run creates `.venv` and installs the QR dependency; later runs
187
+ are instant. Run it in an interactive terminal so stdout is a TTY and the
188
+ QR renders inline — otherwise it falls back to writing PNGs (add
189
+ `--png --out-dir ./qr` to force PNGs). Omitting `--extra qr` makes the
190
+ command exit 127 with the install hint.
191
+
192
+ ### `pocketshell hooks`
193
+
194
+ Installs agent **stop / idle-detection** hooks across Claude Code,
195
+ Codex, and OpenCode and normalizes their events into a single
196
+ append-only JSONL bus the app can read back. Server-side only;
197
+ integration only — no "tell the agent to continue" action yet (deferred;
198
+ see issue #267 and locked decision **D26** in `docs/decisions.md`).
199
+
200
+ ```bash
201
+ pocketshell hooks install [--engine claude|codex|opencode|all] # default: all
202
+ pocketshell hooks status [--engine ...] [--json] [--last N]
203
+ pocketshell hooks events [--since ISO8601] [--limit N] [--json]
204
+ pocketshell hooks uninstall [--engine ...]
205
+ ```
206
+
207
+ `install` is **non-destructive — it merges, it never clobbers**:
208
+
209
+ - **Claude Code** — adds a `{type: "command", command: "python3 <handler>"}`
210
+ entry under the `Stop`, `SubagentStop`, and `Notification` hook events
211
+ in `~/.claude/settings.json`, only when absent. All other top-level
212
+ keys and any pre-existing user hooks are preserved.
213
+ - **Codex** — sets the top-level `notify` program in `~/.codex/config.toml`
214
+ to our handler (Codex hooks do not fire under `codex exec`, so `notify`
215
+ is the headless-safe signal). If `notify` is already set to something
216
+ else, it warns and **skips** rather than overwriting. The rest of the
217
+ TOML is preserved.
218
+ - **OpenCode** — drops a `pocketshell-idle-signal.js` plugin into
219
+ `~/.config/opencode/plugin/` without disturbing other plugins.
220
+
221
+ `install` is idempotent (running twice adds nothing new). Handler scripts
222
+ and the event bus live under `~/.cache/pocketshell/hooks/` (override with
223
+ `$POCKETSHELL_HOOKS_DIR`); each handler appends a normalized record
224
+ `{ts, engine, state, source, session_id, cwd, ...}` to
225
+ `events.jsonl`.
226
+
227
+ **Per-engine uninstall** (`pocketshell hooks uninstall`) removes only what
228
+ we added and is idempotent:
229
+
230
+ - **Claude Code** — drops our command group from each hook event; an
231
+ event key (and the top-level `hooks` object) is deleted only if we
232
+ created it and it ends up empty. A user's pre-existing hooks always
233
+ survive, so a pre-populated `settings.json` comes back
234
+ byte-equivalent for the unrelated parts.
235
+ - **Codex** — removes the top-level `notify` line only when it still
236
+ points at our handler. A `notify` the user pointed elsewhere is left
237
+ alone.
238
+ - **OpenCode** — deletes our plugin file; other plugins and the dir
239
+ itself are left in place.
240
+
241
+ The event bus (`events.jsonl`) is preserved on uninstall so
242
+ already-emitted records stay readable; only the generated handler
243
+ scripts are cleaned up.
244
+
176
245
  ## Development
177
246
 
178
247
  ```bash
@@ -297,10 +366,13 @@ as a permanent fallback.
297
366
 
298
367
  The PocketShell app previously probed for two binaries (`quse`,
299
368
  `tmuxctl`) on every host. That meant two installs to keep up to date,
300
- two probes to surface failures from, and two PATH-discovery edge cases
301
- (see [issue #41](https://github.com/alexeygrigorev/pocketshell/issues/41)).
369
+ two probes to surface failures from, and two PATH-discovery edge cases.
302
370
  A single `pocketshell` binary collapses those into one install, one
303
- probe, one bootstrap row. The app keeps detecting `quse` and `tmuxctl`
304
- as a parallel path while `pocketshell` ramps up to feature parity; once
305
- parity is reached, the legacy probes are removed in a hard-cut follow-up
306
- (no compat shim see decision D22 in `docs/decisions.md`).
371
+ probe, one bootstrap row. The Android bootstrap probe now derives PATH
372
+ from the user's shell rc and prepends `$HOME/.local/bin`, `$HOME/bin`,
373
+ and `$HOME/.cargo/bin` before probing, so cloned-repo or venv installs
374
+ can be discovered without a manual app-side PATH field. The app keeps
375
+ detecting `quse` and `tmuxctl` as a parallel path while `pocketshell`
376
+ ramps up to feature parity; once parity is reached, the legacy probes
377
+ are removed in a hard-cut follow-up (no compat shim — see decision D22
378
+ in `docs/decisions.md`).
@@ -145,6 +145,75 @@ Requires the optional `qr` extra (see [Optional extras](#optional-extras)).
145
145
  Without it, the command exits 127 with the install hint and every other
146
146
  subcommand keeps working.
147
147
 
148
+ #### Running from a repo clone (no install)
149
+
150
+ To run `qr-share` straight from a checkout without installing the tool,
151
+ use `uv run` from `tools/pocketshell` and include the `qr` extra:
152
+
153
+ ```bash
154
+ cd tools/pocketshell
155
+ uv run --extra qr pocketshell qr-share prod
156
+ ```
157
+
158
+ The first run creates `.venv` and installs the QR dependency; later runs
159
+ are instant. Run it in an interactive terminal so stdout is a TTY and the
160
+ QR renders inline — otherwise it falls back to writing PNGs (add
161
+ `--png --out-dir ./qr` to force PNGs). Omitting `--extra qr` makes the
162
+ command exit 127 with the install hint.
163
+
164
+ ### `pocketshell hooks`
165
+
166
+ Installs agent **stop / idle-detection** hooks across Claude Code,
167
+ Codex, and OpenCode and normalizes their events into a single
168
+ append-only JSONL bus the app can read back. Server-side only;
169
+ integration only — no "tell the agent to continue" action yet (deferred;
170
+ see issue #267 and locked decision **D26** in `docs/decisions.md`).
171
+
172
+ ```bash
173
+ pocketshell hooks install [--engine claude|codex|opencode|all] # default: all
174
+ pocketshell hooks status [--engine ...] [--json] [--last N]
175
+ pocketshell hooks events [--since ISO8601] [--limit N] [--json]
176
+ pocketshell hooks uninstall [--engine ...]
177
+ ```
178
+
179
+ `install` is **non-destructive — it merges, it never clobbers**:
180
+
181
+ - **Claude Code** — adds a `{type: "command", command: "python3 <handler>"}`
182
+ entry under the `Stop`, `SubagentStop`, and `Notification` hook events
183
+ in `~/.claude/settings.json`, only when absent. All other top-level
184
+ keys and any pre-existing user hooks are preserved.
185
+ - **Codex** — sets the top-level `notify` program in `~/.codex/config.toml`
186
+ to our handler (Codex hooks do not fire under `codex exec`, so `notify`
187
+ is the headless-safe signal). If `notify` is already set to something
188
+ else, it warns and **skips** rather than overwriting. The rest of the
189
+ TOML is preserved.
190
+ - **OpenCode** — drops a `pocketshell-idle-signal.js` plugin into
191
+ `~/.config/opencode/plugin/` without disturbing other plugins.
192
+
193
+ `install` is idempotent (running twice adds nothing new). Handler scripts
194
+ and the event bus live under `~/.cache/pocketshell/hooks/` (override with
195
+ `$POCKETSHELL_HOOKS_DIR`); each handler appends a normalized record
196
+ `{ts, engine, state, source, session_id, cwd, ...}` to
197
+ `events.jsonl`.
198
+
199
+ **Per-engine uninstall** (`pocketshell hooks uninstall`) removes only what
200
+ we added and is idempotent:
201
+
202
+ - **Claude Code** — drops our command group from each hook event; an
203
+ event key (and the top-level `hooks` object) is deleted only if we
204
+ created it and it ends up empty. A user's pre-existing hooks always
205
+ survive, so a pre-populated `settings.json` comes back
206
+ byte-equivalent for the unrelated parts.
207
+ - **Codex** — removes the top-level `notify` line only when it still
208
+ points at our handler. A `notify` the user pointed elsewhere is left
209
+ alone.
210
+ - **OpenCode** — deletes our plugin file; other plugins and the dir
211
+ itself are left in place.
212
+
213
+ The event bus (`events.jsonl`) is preserved on uninstall so
214
+ already-emitted records stay readable; only the generated handler
215
+ scripts are cleaned up.
216
+
148
217
  ## Development
149
218
 
150
219
  ```bash
@@ -269,10 +338,13 @@ as a permanent fallback.
269
338
 
270
339
  The PocketShell app previously probed for two binaries (`quse`,
271
340
  `tmuxctl`) on every host. That meant two installs to keep up to date,
272
- two probes to surface failures from, and two PATH-discovery edge cases
273
- (see [issue #41](https://github.com/alexeygrigorev/pocketshell/issues/41)).
341
+ two probes to surface failures from, and two PATH-discovery edge cases.
274
342
  A single `pocketshell` binary collapses those into one install, one
275
- probe, one bootstrap row. The app keeps detecting `quse` and `tmuxctl`
276
- as a parallel path while `pocketshell` ramps up to feature parity; once
277
- parity is reached, the legacy probes are removed in a hard-cut follow-up
278
- (no compat shim see decision D22 in `docs/decisions.md`).
343
+ probe, one bootstrap row. The Android bootstrap probe now derives PATH
344
+ from the user's shell rc and prepends `$HOME/.local/bin`, `$HOME/bin`,
345
+ and `$HOME/.cargo/bin` before probing, so cloned-repo or venv installs
346
+ can be discovered without a manual app-side PATH field. The app keeps
347
+ detecting `quse` and `tmuxctl` as a parallel path while `pocketshell`
348
+ ramps up to feature parity; once parity is reached, the legacy probes
349
+ are removed in a hard-cut follow-up (no compat shim — see decision D22
350
+ in `docs/decisions.md`).
@@ -8,7 +8,7 @@ name = "pocketshell"
8
8
  # scripts/check-pypi-version.sh enforces this; .github/workflows/build.yml
9
9
  # runs that check before publishing to PyPI. See
10
10
  # tools/pocketshell/README.md ("Release flow") for the bump procedure.
11
- version = "0.3.2"
11
+ version = "0.3.6"
12
12
  description = "Unified server-side Python utility for the PocketShell Android client."
13
13
  readme = "README.md"
14
14
  requires-python = ">=3.11"
@@ -11,4 +11,4 @@ See https://github.com/alexeygrigorev/pocketshell/issues/170.
11
11
  from __future__ import annotations
12
12
 
13
13
  __all__ = ["__version__"]
14
- __version__ = "0.1.0"
14
+ __version__ = "0.3.6"
@@ -23,7 +23,10 @@ import click
23
23
 
24
24
  from pocketshell import __version__
25
25
  from pocketshell.agent_log import agent_log_command
26
+ from pocketshell.env import env_group
27
+ from pocketshell.hooks import hooks_group
26
28
  from pocketshell.jobs import jobs_group
29
+ from pocketshell.logs import logs_group
27
30
  from pocketshell.qr_share import qr_share_command
28
31
  from pocketshell.repos import repos_group
29
32
  from pocketshell.sessions import sessions_group
@@ -50,6 +53,9 @@ cli.add_command(jobs_group, name="jobs")
50
53
  cli.add_command(sessions_group, name="sessions")
51
54
  cli.add_command(agent_log_command, name="agent-log")
52
55
  cli.add_command(repos_group, name="repos")
56
+ cli.add_command(env_group, name="env")
57
+ cli.add_command(hooks_group, name="hooks")
58
+ cli.add_command(logs_group, name="logs")
53
59
  cli.add_command(qr_share_command, name="qr-share")
54
60
 
55
61