orbi-cli 0.6.2__tar.gz → 0.6.4__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.
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/PKG-INFO +1 -1
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/pyproject.toml +1 -1
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/__init__.py +1 -1
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/pi_process.py +4 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/progress.py +70 -0
- orbi_cli-0.6.4/src/orbi/review_merge.py +1913 -0
- orbi_cli-0.6.4/src/orbi/run_state.py +366 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/runner.py +30 -2139
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi_cli.egg-info/PKG-INFO +1 -1
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi_cli.egg-info/SOURCES.txt +2 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_bootstrap_runner.py +99 -63
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_comment_readers_contract.py +1 -1
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_concurrency_e2e.py +2 -1
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_delivery_branch_delete.py +6 -5
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_docs_i18n.py +22 -8
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_docs_site.py +96 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_fix_needed_loop.py +29 -27
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_git_merge_smoke.py +11 -10
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_human_review.py +4 -3
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_progress.py +3 -3
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_progress_wiring.py +7 -6
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_repo_config.py +3 -1
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_resume_e2e.py +3 -2
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_resume_pr.py +38 -36
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_review_merge.py +368 -251
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/LICENSE +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/README.md +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/docs/licenses/sustainable-use-license.md +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/setup.cfg +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/branch_reclaim.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/checks.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/claim.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/clarify.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/cli.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/cli_source.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/config.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/delivery_labels.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/delivery_scene.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/engine_source.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/example_config.toml +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/failure.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/failure_report.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/git_identity.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/git_transport.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/github.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/gitops.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/human_review.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/journal.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/launchd_deploy.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/merge_gate.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/merge_handoff.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/milestone.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/milestone_command.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/pi_activity.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/pi_command.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/pi_recovery.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/pi_session.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/pilot_setup.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/pilot_slots.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/release.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/release_git.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/release_notes.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/repo_config.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/runner_health.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/scene.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/scheduler.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/scheduler_units.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/source_pool.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/systemd_deploy.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/ticket_command.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi_cli.egg-info/dependency_links.txt +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi_cli.egg-info/entry_points.txt +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi_cli.egg-info/top_level.txt +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_agents_md.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_apply_label_patch.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_branch_reclaim.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_ci_failure_issue_workflow.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_ci_failure_triage.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_ci_macos_workflow.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_ci_workflow.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_clarify.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_claude_plugin.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_cli_install.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_cli_milestone.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_cli_packaging.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_cli_source.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_constitution.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_coverage_gate.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_deliver_pr_fakes.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_delivery_labels.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_delivery_scene.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_docker_docs.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_docker_entrypoint.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_docker_image_workflow.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_docs_issue_shapes.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_docs_labels.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_docs_mermaid.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_docs_releases.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_docs_single_source.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_engine_source.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_failure.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_failure_report.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_gh_read_retry.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_git_base_smoke.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_git_network_retry.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_git_transport.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_github.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_github_fakes.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_gitops.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_gitops_fakes.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_import_graph.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_install_sh.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_issue_1367.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_issue_461.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_issue_template_config.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_journal.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_journal_events.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_launchd_deploy.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_license.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_milestone_command.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_ops_e2e.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_orbi.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_orbi_dashboard.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_orbi_exporter.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_patch_ratchet.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_pi_activity.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_pi_command.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_pi_extensions.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_pi_provider_templates.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_pi_recovery.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_pi_session.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_pilot_setup.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_pilot_slots.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_pr_issue_link_workflow.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_prerequisite_check.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_prompt_contract.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_publish_workflow.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_release_docs_workflow.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_release_ticket_templates.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_resume_continue_e2e.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_run_artifacts.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_run_id_e2e.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_runner_config.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_runner_health.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_runner_source_freshness.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_scene.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_scheduler.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_size_ratchet.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_src_layout.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_steering_review.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_suite_hygiene.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_systemd_deploy.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_systemd_timer.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_ticket_command.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_user_acceptance_contract.py +0 -0
- {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_worktree_reclaim.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: orbi-cli
|
|
3
|
-
Version: 0.6.
|
|
3
|
+
Version: 0.6.4
|
|
4
4
|
Summary: Orbi — local AI development worker: claims GitHub Issues, runs Pi in isolated worktrees, and delivers PRs (GitHub Issues + labels are the only state store).
|
|
5
5
|
Author: xqliu
|
|
6
6
|
License-Expression: AGPL-3.0-only OR LicenseRef-Sustainable-Use-1.0
|
|
@@ -44,7 +44,7 @@ build-backend = "setuptools.build_meta"
|
|
|
44
44
|
|
|
45
45
|
[project]
|
|
46
46
|
name = "orbi-cli"
|
|
47
|
-
version = "0.6.
|
|
47
|
+
version = "0.6.4"
|
|
48
48
|
description = "Orbi — local AI development worker: claims GitHub Issues, runs Pi in isolated worktrees, and delivers PRs (GitHub Issues + labels are the only state store)."
|
|
49
49
|
readme = "README.md"
|
|
50
50
|
requires-python = ">=3.14"
|
|
@@ -1258,6 +1258,10 @@ def _stream_pi_once(
|
|
|
1258
1258
|
# inherits the Runner's environment unchanged (pre-#157 shape).
|
|
1259
1259
|
process = subprocess.Popen(
|
|
1260
1260
|
command, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
|
1261
|
+
# Pi's print mode reads piped stdin until it closes and prepends
|
|
1262
|
+
# it to the prompt (Issue #1562): the child must get /dev/null,
|
|
1263
|
+
# never the Runner's possibly-open stdin pipe.
|
|
1264
|
+
stdin=subprocess.DEVNULL,
|
|
1261
1265
|
env=None if pi_env is None else {**os.environ, **pi_env},
|
|
1262
1266
|
)
|
|
1263
1267
|
# Track the live Pi child for the stop handler: a
|
|
@@ -913,3 +913,73 @@ def _finish_progress_body(*, number: int, title: str, run_id: str,
|
|
|
913
913
|
number=number, source_repo=source_repo, action=action,
|
|
914
914
|
reason=reason, diagnosis=diagnosis,
|
|
915
915
|
))
|
|
916
|
+
|
|
917
|
+
# Automatic observability: the GitHub progress comment is
|
|
918
|
+
# PATCHed on every activity change and at most every 30 seconds while a
|
|
919
|
+
# Pi session runs, so a mobile user sees live progress without any
|
|
920
|
+
# command. The journal cadence is the poll interval above.
|
|
921
|
+
PI_HEARTBEAT_SECONDS = 30.0
|
|
922
|
+
|
|
923
|
+
def _live_progress(ctx: RunContext, publisher: ProgressPublisher, *,
|
|
924
|
+
title: str, role: str, started: float,
|
|
925
|
+
pr_url: str | None, review_round: int, priority: str,
|
|
926
|
+
activity: dict | None = None) -> None:
|
|
927
|
+
"""One live GitHub progress update while a Pi session is running.
|
|
928
|
+
|
|
929
|
+
Called from the `stream_pi` poll loop (every activity change or
|
|
930
|
+
heartbeat): the same run-marker comment is PATCHed in
|
|
931
|
+
place at most every `PI_HEARTBEAT_SECONDS` or when the visible
|
|
932
|
+
activity changed. `activity` is the watcher state of that poll, so
|
|
933
|
+
the live comment shows the session exactly as the journal reports
|
|
934
|
+
it. The publisher already knows the comment id after `ensure`, so a
|
|
935
|
+
callback before it would fail fast here — and the wiring always
|
|
936
|
+
ensures first.
|
|
937
|
+
"""
|
|
938
|
+
state = _progress_state(
|
|
939
|
+
ctx, title=title, role=role, started=started,
|
|
940
|
+
pr_url=pr_url, review_round=review_round, priority=priority,
|
|
941
|
+
activity=activity,
|
|
942
|
+
)
|
|
943
|
+
publisher.patch(_progress_body(state))
|
|
944
|
+
|
|
945
|
+
class LiveProgressThrottle:
|
|
946
|
+
"""Throttle live GitHub PATCHes to change-driven or <=30-second cadence.
|
|
947
|
+
|
|
948
|
+
The `stream_pi` poll loop fires on every poll (15 s default); PATCHing
|
|
949
|
+
GitHub on every poll would double the traffic for no visible gain.
|
|
950
|
+
The throttle passes an update through when the visible activity
|
|
951
|
+
(phase, action, result, model_wait) changed since the last PATCH or
|
|
952
|
+
when at least `PI_HEARTBEAT_SECONDS` passed since it.
|
|
953
|
+
"""
|
|
954
|
+
|
|
955
|
+
def __init__(self, ctx: RunContext, publisher: ProgressPublisher, *,
|
|
956
|
+
title: str, role: str, started: float,
|
|
957
|
+
pr_url: str | None, review_round: int,
|
|
958
|
+
priority: str) -> None:
|
|
959
|
+
def publish(activity: dict) -> None:
|
|
960
|
+
_live_progress(
|
|
961
|
+
ctx, publisher, title=title, role=role,
|
|
962
|
+
started=started, pr_url=pr_url,
|
|
963
|
+
review_round=review_round, priority=priority,
|
|
964
|
+
activity=activity,
|
|
965
|
+
)
|
|
966
|
+
|
|
967
|
+
self._publish = publish
|
|
968
|
+
self._last_visible: tuple | None = None
|
|
969
|
+
self._last_patch = 0.0
|
|
970
|
+
|
|
971
|
+
def __call__(self, activity: dict) -> None:
|
|
972
|
+
visible = (
|
|
973
|
+
activity["phase"], activity["action"], activity["result"],
|
|
974
|
+
activity["model_wait"],
|
|
975
|
+
# The idle-recovery state is visible progress:
|
|
976
|
+
# entering/leaving it PATCHes the live comment immediately.
|
|
977
|
+
activity.get("recovery"),
|
|
978
|
+
)
|
|
979
|
+
now = time.monotonic()
|
|
980
|
+
if visible == self._last_visible and \
|
|
981
|
+
now - self._last_patch < PI_HEARTBEAT_SECONDS:
|
|
982
|
+
return
|
|
983
|
+
self._last_visible = visible
|
|
984
|
+
self._last_patch = now
|
|
985
|
+
self._publish(activity)
|