pocketshell 0.4.12__tar.gz → 0.4.14__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.
- {pocketshell-0.4.12 → pocketshell-0.4.14}/PKG-INFO +1 -1
- {pocketshell-0.4.12 → pocketshell-0.4.14}/pyproject.toml +1 -1
- {pocketshell-0.4.12 → pocketshell-0.4.14}/src/pocketshell/agents.py +67 -15
- pocketshell-0.4.14/src/pocketshell/cards.py +663 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/src/pocketshell/cli.py +5 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/src/pocketshell/tree.py +23 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/tests/test_agents.py +262 -7
- pocketshell-0.4.14/tests/test_cards.py +391 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/tests/test_tree.py +31 -1
- {pocketshell-0.4.12 → pocketshell-0.4.14}/uv.lock +2 -2
- {pocketshell-0.4.12 → pocketshell-0.4.14}/.gitignore +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/README.md +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/scheduler/README.md +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/scheduler/pocketshell-usage-capture.service +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/scheduler/pocketshell-usage-capture.timer +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/src/pocketshell/__init__.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/src/pocketshell/__main__.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/src/pocketshell/agent_log.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/src/pocketshell/agents_kind.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/src/pocketshell/cgroup_agents.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/src/pocketshell/daemon.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/src/pocketshell/env.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/src/pocketshell/github.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/src/pocketshell/hooks.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/src/pocketshell/jobs.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/src/pocketshell/logs.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/src/pocketshell/profiles.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/src/pocketshell/prune_attachments.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/src/pocketshell/push.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/src/pocketshell/qr_share.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/src/pocketshell/repos.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/src/pocketshell/resume.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/src/pocketshell/sessions.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/src/pocketshell/usage.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/src/pocketshell/usage_capture.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/src/pocketshell/usage_reset.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/tests/__init__.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/tests/test_agent_log.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/tests/test_agents_kind.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/tests/test_cgroup_agents.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/tests/test_cli.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/tests/test_daemon.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/tests/test_env.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/tests/test_github.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/tests/test_hooks.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/tests/test_jobs.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/tests/test_logs.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/tests/test_profiles.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/tests/test_prune_attachments.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/tests/test_push.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/tests/test_qr_share.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/tests/test_repos.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/tests/test_resume.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/tests/test_sessions.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/tests/test_usage.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/tests/test_usage_capture.py +0 -0
- {pocketshell-0.4.12 → pocketshell-0.4.14}/tests/test_usage_reset.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pocketshell
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.14
|
|
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
|
|
@@ -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.4.
|
|
11
|
+
version = "0.4.14"
|
|
12
12
|
description = "Unified server-side Python utility for the PocketShell Android client."
|
|
13
13
|
readme = "README.md"
|
|
14
14
|
requires-python = ">=3.11"
|
|
@@ -359,6 +359,7 @@ def record_agent_kind(
|
|
|
359
359
|
kind: str,
|
|
360
360
|
env: Optional[dict[str, str]] = None,
|
|
361
361
|
runner=None,
|
|
362
|
+
profile: Optional[str] = None,
|
|
362
363
|
) -> bool:
|
|
363
364
|
"""Record the launched agent ``kind`` as a per-session tmux user option.
|
|
364
365
|
|
|
@@ -371,10 +372,25 @@ def record_agent_kind(
|
|
|
371
372
|
change. The client reads it back through its session enumeration
|
|
372
373
|
(``tmux list-sessions -F '…#{@ps_agent_kind}'``).
|
|
373
374
|
|
|
374
|
-
|
|
375
|
+
``profile`` (issue #858) is the human label of the *non-default* profile
|
|
376
|
+
the agent was launched with — e.g. ``"Claude (Z.AI)"`` for a z.ai Claude
|
|
377
|
+
session, so the tree can distinguish it from a default Anthropic Claude.
|
|
378
|
+
It is the same launch-time-recordable dimension as the kind (the selected
|
|
379
|
+
profile name is known here, before ``os.execvpe``; #826 record-at-start
|
|
380
|
+
hard-cut — no detection/parse path). When set, it is written as the
|
|
381
|
+
per-session ``@ps_agent_profile`` user option alongside ``@ps_agent_kind``.
|
|
382
|
+
A default / no-profile launch passes ``None`` and the option is
|
|
383
|
+
RECONCILED to the current launch by UNSETTING it
|
|
384
|
+
(``tmux set-option -uq @ps_agent_profile``), so a session previously
|
|
385
|
+
launched with a non-default profile and then relaunched as a default
|
|
386
|
+
agent in the SAME tmux session does not keep the stale profile label
|
|
387
|
+
(issue #889). ``@ps_agent_kind`` is always overwritten on every launch
|
|
388
|
+
so it has no equivalent stale hazard.
|
|
389
|
+
|
|
390
|
+
The options are session-scoped (not global): ``tmux set-option`` without
|
|
375
391
|
``-g`` sets it on the current session, which is the session the agent
|
|
376
392
|
was launched into. tmux session options persist for the life of the
|
|
377
|
-
session, so the recorded kind survives reconnect / app restart /
|
|
393
|
+
session, so the recorded kind/profile survives reconnect / app restart /
|
|
378
394
|
app-kill / reinstall — exactly the durability the epic requires.
|
|
379
395
|
|
|
380
396
|
No-op (returns ``False``) when not running inside tmux (``$TMUX``
|
|
@@ -399,6 +415,27 @@ def record_agent_kind(
|
|
|
399
415
|
["tmux", "set-option", "@ps_agent_kind", kind],
|
|
400
416
|
check=False,
|
|
401
417
|
)
|
|
418
|
+
if profile:
|
|
419
|
+
# A non-default profile is recorded so the tree shows its label.
|
|
420
|
+
runner(
|
|
421
|
+
["tmux", "set-option", "@ps_agent_profile", profile],
|
|
422
|
+
check=False,
|
|
423
|
+
)
|
|
424
|
+
else:
|
|
425
|
+
# A default / no-profile launch must RECONCILE the option to the
|
|
426
|
+
# current launch by UNSETTING it (issue #889). tmux session
|
|
427
|
+
# options persist for the life of the session, so a session
|
|
428
|
+
# launched once with a non-default profile (e.g. z.ai) and then
|
|
429
|
+
# relaunched as a default agent in the SAME session would keep the
|
|
430
|
+
# stale @ps_agent_profile and be mislabelled in the tree. The
|
|
431
|
+
# ``-u`` unsets the session option; ``-q`` makes unsetting an
|
|
432
|
+
# already-absent option a no-op (a fresh default session stays
|
|
433
|
+
# clean). The kind itself (set above) is always overwritten, so it
|
|
434
|
+
# has no equivalent stale hazard.
|
|
435
|
+
runner(
|
|
436
|
+
["tmux", "set-option", "-uq", "@ps_agent_profile"],
|
|
437
|
+
check=False,
|
|
438
|
+
)
|
|
402
439
|
except Exception:
|
|
403
440
|
# Recording the kind is best-effort; never block the launch on it.
|
|
404
441
|
return False
|
|
@@ -413,6 +450,7 @@ def launch_agent(
|
|
|
413
450
|
skip_permissions: bool,
|
|
414
451
|
config_dir: Optional[str],
|
|
415
452
|
extra_env: Optional[dict[str, str]] = None,
|
|
453
|
+
profile: Optional[str] = None,
|
|
416
454
|
execvpe=None,
|
|
417
455
|
record_kind=None,
|
|
418
456
|
) -> None:
|
|
@@ -422,6 +460,11 @@ def launch_agent(
|
|
|
422
460
|
#732); it layers onto the launch environment under the #703 provider
|
|
423
461
|
strip (see :func:`build_env`).
|
|
424
462
|
|
|
463
|
+
``profile`` (issue #858) is the human label of the *non-default* profile
|
|
464
|
+
the launch used (``None`` for the engine default). It is recorded
|
|
465
|
+
alongside the kind as the ``@ps_agent_profile`` tmux user option so the
|
|
466
|
+
session tree can distinguish e.g. a z.ai Claude from a default Claude.
|
|
467
|
+
|
|
425
468
|
``execvpe`` is injected so tests can assert the exact call without
|
|
426
469
|
actually replacing the process. When ``None`` (production) it resolves
|
|
427
470
|
to :func:`os.execvpe` *at call time* — looking it up on the module's
|
|
@@ -473,7 +516,7 @@ def launch_agent(
|
|
|
473
516
|
# this process (epic #821 Workstream A). Use this wrapper's own
|
|
474
517
|
# environment (os.environ) for the TMUX detection — `env` is the
|
|
475
518
|
# provider-stripped launch env that does not necessarily carry $TMUX.
|
|
476
|
-
record_kind(kind, dict(os.environ))
|
|
519
|
+
record_kind(kind, dict(os.environ), profile=profile)
|
|
477
520
|
|
|
478
521
|
# Replace this process with the agent so it owns the pty cleanly.
|
|
479
522
|
execvpe(argv[0], argv, env)
|
|
@@ -484,17 +527,22 @@ def _resolve_config_dir(
|
|
|
484
527
|
kind: str,
|
|
485
528
|
config_dir: Optional[str],
|
|
486
529
|
profile: Optional[str],
|
|
487
|
-
) -> tuple[Optional[str], dict[str, str]]:
|
|
488
|
-
"""Resolve config dir + extra env from
|
|
530
|
+
) -> tuple[Optional[str], dict[str, str], Optional[str]]:
|
|
531
|
+
"""Resolve config dir + extra env + profile label from the launch flags.
|
|
489
532
|
|
|
490
|
-
Returns ``(config_dir, extra_env)``. ``--config-dir`` and
|
|
491
|
-
are mutually exclusive (passing both is an error). When
|
|
492
|
-
given, it resolves the named host profile (via
|
|
533
|
+
Returns ``(config_dir, extra_env, profile_label)``. ``--config-dir`` and
|
|
534
|
+
``--profile`` are mutually exclusive (passing both is an error). When
|
|
535
|
+
``--profile`` is given, it resolves the named host profile (via
|
|
493
536
|
:func:`pocketshell.profiles.resolve_profile`) to its ``config_dir`` AND
|
|
494
|
-
its ``env:`` block (issue #732) — an unknown profile is a clear error.
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
537
|
+
its ``env:`` block (issue #732) — an unknown profile is a clear error.
|
|
538
|
+
|
|
539
|
+
``profile_label`` (issue #858) is the resolved profile's human ``name``
|
|
540
|
+
for a *non-default* profile (e.g. ``"Claude (Z.AI)"``), so the session
|
|
541
|
+
tree can tell a z.ai Claude apart from a default Claude. The engine's
|
|
542
|
+
default profile, ``--config-dir`` (which carries no named profile), and
|
|
543
|
+
omitting both flags all resolve ``profile_label`` to ``None`` — so a
|
|
544
|
+
default launch clears any stale ``@ps_agent_profile`` option (issue
|
|
545
|
+
#889) rather than leaving a profile label behind.
|
|
498
546
|
"""
|
|
499
547
|
if config_dir is not None and profile is not None:
|
|
500
548
|
click.echo(
|
|
@@ -504,7 +552,7 @@ def _resolve_config_dir(
|
|
|
504
552
|
)
|
|
505
553
|
ctx.exit(2)
|
|
506
554
|
if profile is None:
|
|
507
|
-
return config_dir, {}
|
|
555
|
+
return config_dir, {}, None
|
|
508
556
|
|
|
509
557
|
# Lazy import keeps the agent launch path from importing yaml unless a
|
|
510
558
|
# profile is actually requested.
|
|
@@ -519,7 +567,10 @@ def _resolve_config_dir(
|
|
|
519
567
|
err=True,
|
|
520
568
|
)
|
|
521
569
|
ctx.exit(2)
|
|
522
|
-
|
|
570
|
+
# Only a non-default profile is surfaced as a label; the default profile
|
|
571
|
+
# is the plain kind (no spurious chip in the tree).
|
|
572
|
+
label = None if resolved.default else resolved.name
|
|
573
|
+
return resolved.config_dir, dict(resolved.env), label
|
|
523
574
|
|
|
524
575
|
|
|
525
576
|
def _make_agent_command(kind: str):
|
|
@@ -575,7 +626,7 @@ def _make_agent_command(kind: str):
|
|
|
575
626
|
config_dir: Optional[str],
|
|
576
627
|
profile: Optional[str],
|
|
577
628
|
) -> None:
|
|
578
|
-
config_dir, extra_env = _resolve_config_dir(
|
|
629
|
+
config_dir, extra_env, profile_label = _resolve_config_dir(
|
|
579
630
|
ctx, kind, config_dir, profile
|
|
580
631
|
)
|
|
581
632
|
launch_agent(
|
|
@@ -585,6 +636,7 @@ def _make_agent_command(kind: str):
|
|
|
585
636
|
skip_permissions=skip_permissions,
|
|
586
637
|
config_dir=config_dir,
|
|
587
638
|
extra_env=extra_env,
|
|
639
|
+
profile=profile_label,
|
|
588
640
|
)
|
|
589
641
|
|
|
590
642
|
return _cmd
|