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.
Files changed (156) hide show
  1. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/PKG-INFO +1 -1
  2. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/pyproject.toml +1 -1
  3. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/__init__.py +1 -1
  4. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/pi_process.py +4 -0
  5. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/progress.py +70 -0
  6. orbi_cli-0.6.4/src/orbi/review_merge.py +1913 -0
  7. orbi_cli-0.6.4/src/orbi/run_state.py +366 -0
  8. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/runner.py +30 -2139
  9. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi_cli.egg-info/PKG-INFO +1 -1
  10. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi_cli.egg-info/SOURCES.txt +2 -0
  11. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_bootstrap_runner.py +99 -63
  12. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_comment_readers_contract.py +1 -1
  13. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_concurrency_e2e.py +2 -1
  14. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_delivery_branch_delete.py +6 -5
  15. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_docs_i18n.py +22 -8
  16. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_docs_site.py +96 -0
  17. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_fix_needed_loop.py +29 -27
  18. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_git_merge_smoke.py +11 -10
  19. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_human_review.py +4 -3
  20. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_progress.py +3 -3
  21. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_progress_wiring.py +7 -6
  22. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_repo_config.py +3 -1
  23. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_resume_e2e.py +3 -2
  24. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_resume_pr.py +38 -36
  25. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_review_merge.py +368 -251
  26. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/LICENSE +0 -0
  27. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/README.md +0 -0
  28. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/docs/licenses/sustainable-use-license.md +0 -0
  29. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/setup.cfg +0 -0
  30. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/branch_reclaim.py +0 -0
  31. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/checks.py +0 -0
  32. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/claim.py +0 -0
  33. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/clarify.py +0 -0
  34. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/cli.py +0 -0
  35. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/cli_source.py +0 -0
  36. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/config.py +0 -0
  37. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/delivery_labels.py +0 -0
  38. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/delivery_scene.py +0 -0
  39. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/engine_source.py +0 -0
  40. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/example_config.toml +0 -0
  41. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/failure.py +0 -0
  42. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/failure_report.py +0 -0
  43. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/git_identity.py +0 -0
  44. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/git_transport.py +0 -0
  45. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/github.py +0 -0
  46. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/gitops.py +0 -0
  47. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/human_review.py +0 -0
  48. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/journal.py +0 -0
  49. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/launchd_deploy.py +0 -0
  50. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/merge_gate.py +0 -0
  51. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/merge_handoff.py +0 -0
  52. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/milestone.py +0 -0
  53. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/milestone_command.py +0 -0
  54. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/pi_activity.py +0 -0
  55. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/pi_command.py +0 -0
  56. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/pi_recovery.py +0 -0
  57. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/pi_session.py +0 -0
  58. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/pilot_setup.py +0 -0
  59. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/pilot_slots.py +0 -0
  60. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/release.py +0 -0
  61. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/release_git.py +0 -0
  62. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/release_notes.py +0 -0
  63. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/repo_config.py +0 -0
  64. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/runner_health.py +0 -0
  65. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/scene.py +0 -0
  66. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/scheduler.py +0 -0
  67. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/scheduler_units.py +0 -0
  68. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/source_pool.py +0 -0
  69. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/systemd_deploy.py +0 -0
  70. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi/ticket_command.py +0 -0
  71. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi_cli.egg-info/dependency_links.txt +0 -0
  72. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi_cli.egg-info/entry_points.txt +0 -0
  73. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/src/orbi_cli.egg-info/top_level.txt +0 -0
  74. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_agents_md.py +0 -0
  75. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_apply_label_patch.py +0 -0
  76. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_branch_reclaim.py +0 -0
  77. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_ci_failure_issue_workflow.py +0 -0
  78. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_ci_failure_triage.py +0 -0
  79. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_ci_macos_workflow.py +0 -0
  80. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_ci_workflow.py +0 -0
  81. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_clarify.py +0 -0
  82. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_claude_plugin.py +0 -0
  83. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_cli_install.py +0 -0
  84. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_cli_milestone.py +0 -0
  85. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_cli_packaging.py +0 -0
  86. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_cli_source.py +0 -0
  87. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_constitution.py +0 -0
  88. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_coverage_gate.py +0 -0
  89. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_deliver_pr_fakes.py +0 -0
  90. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_delivery_labels.py +0 -0
  91. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_delivery_scene.py +0 -0
  92. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_docker_docs.py +0 -0
  93. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_docker_entrypoint.py +0 -0
  94. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_docker_image_workflow.py +0 -0
  95. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_docs_issue_shapes.py +0 -0
  96. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_docs_labels.py +0 -0
  97. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_docs_mermaid.py +0 -0
  98. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_docs_releases.py +0 -0
  99. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_docs_single_source.py +0 -0
  100. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_engine_source.py +0 -0
  101. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_failure.py +0 -0
  102. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_failure_report.py +0 -0
  103. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_gh_read_retry.py +0 -0
  104. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_git_base_smoke.py +0 -0
  105. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_git_network_retry.py +0 -0
  106. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_git_transport.py +0 -0
  107. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_github.py +0 -0
  108. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_github_fakes.py +0 -0
  109. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_gitops.py +0 -0
  110. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_gitops_fakes.py +0 -0
  111. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_import_graph.py +0 -0
  112. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_install_sh.py +0 -0
  113. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_issue_1367.py +0 -0
  114. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_issue_461.py +0 -0
  115. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_issue_template_config.py +0 -0
  116. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_journal.py +0 -0
  117. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_journal_events.py +0 -0
  118. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_launchd_deploy.py +0 -0
  119. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_license.py +0 -0
  120. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_milestone_command.py +0 -0
  121. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_ops_e2e.py +0 -0
  122. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_orbi.py +0 -0
  123. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_orbi_dashboard.py +0 -0
  124. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_orbi_exporter.py +0 -0
  125. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_patch_ratchet.py +0 -0
  126. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_pi_activity.py +0 -0
  127. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_pi_command.py +0 -0
  128. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_pi_extensions.py +0 -0
  129. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_pi_provider_templates.py +0 -0
  130. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_pi_recovery.py +0 -0
  131. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_pi_session.py +0 -0
  132. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_pilot_setup.py +0 -0
  133. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_pilot_slots.py +0 -0
  134. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_pr_issue_link_workflow.py +0 -0
  135. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_prerequisite_check.py +0 -0
  136. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_prompt_contract.py +0 -0
  137. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_publish_workflow.py +0 -0
  138. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_release_docs_workflow.py +0 -0
  139. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_release_ticket_templates.py +0 -0
  140. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_resume_continue_e2e.py +0 -0
  141. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_run_artifacts.py +0 -0
  142. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_run_id_e2e.py +0 -0
  143. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_runner_config.py +0 -0
  144. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_runner_health.py +0 -0
  145. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_runner_source_freshness.py +0 -0
  146. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_scene.py +0 -0
  147. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_scheduler.py +0 -0
  148. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_size_ratchet.py +0 -0
  149. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_src_layout.py +0 -0
  150. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_steering_review.py +0 -0
  151. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_suite_hygiene.py +0 -0
  152. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_systemd_deploy.py +0 -0
  153. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_systemd_timer.py +0 -0
  154. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_ticket_command.py +0 -0
  155. {orbi_cli-0.6.2 → orbi_cli-0.6.4}/tests/test_user_acceptance_contract.py +0 -0
  156. {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.2
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.2"
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"
@@ -18,4 +18,4 @@ the package would shadow the installed package for every process with
18
18
  the checkout root on sys.path. The direct-execution compatibility entry
19
19
  is `python3 -m orbi.cli` (development path only).
20
20
  """
21
- __version__ = "0.6.2"
21
+ __version__ = "0.6.4"
@@ -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)