Skip to content
Merged
43 changes: 43 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- The Git page's **Issues** and **Pull requests** forms now discover the repository's own
templates (`.github/ISSUE_TEMPLATE/` Markdown and YAML issue forms, plus
`.github/PULL_REQUEST_TEMPLATE.md` and its variants). A lone template applies
automatically; with several, a **Template** picker (including **Blank**) chooses one.
The choice prefills the title prefix and body skeleton — a YAML issue form is flattened
into Markdown — and its `labels:` ride along on **Create**.

- The Git page's **Issues** and **Pull requests** forms can now draft their title and
Markdown body with a **Generate** button. Add optional notes (or leave them blank) and
Orbit makes the same one-shot, tool-free `pi -p` call the commit-message generator uses,
reading the branch, its commits, and its changed files; when pi is missing or has no
credentials it falls back to a local heuristic built from those same facts. Nothing is
created until you review the draft and press **Create**.

- Every icon-only button across the app now carries the same native tooltip the
send / stop button has — a localized label, usually with its keyboard shortcut
(e.g. `Toggle Terminal (⌘J)`). Covers the top bar, sidebar, transcript copy /
Expand All @@ -29,6 +43,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- Images in issue/PR bodies, comments, and transcripts now render. The markdown image
element forced a definite `height: 0`, and gpui derives a missing width from a definite
height before the image decodes (0 × ratio), so a loaded screenshot collapsed to a 0×0
box with only its border visible. The height is left auto now: the image scales to the
reading column and taffy keeps its aspect ratio.

- Screenshots in replies load again when GitHub stored them as signed
`private-user-images.githubusercontent.com/…?jwt=…` URLs. That JWT expires within
minutes, so the app got a 404 and showed the alt-text fallback; the renderer rewrites
the URL to the durable `github.com/user-attachments/assets/<uuid>` form encoded in the
filename, which serves the same image.

- GitHub issue/PR bodies and comments now render screenshots that GitHub stored as raw
HTML `<img src="…">` tags when the line is inside a blockquote or list item — a quoted
bug report is a common case. Previously only a standalone top-level `<img>` line became
an image, so these showed the tag as text; the whole tag/its URL rendered as a link.

- The **New pull request** form's **Base branch** picker, and the **Template** pickers on
both new-issue/new-PR forms, no longer float over the wrong part of the form or paint
behind its fields. They are anchored to the chip that opens them (opening upward at the
bottom of the PR form), draw above the form, and use the top branch selector's dropdown
chip (glyph, value, chevron) and picker surface — list inset, rows, and search row for
the branch list.

- The **Issues** tab's **Label** picker — the list filter chip and the detail view's
**Edit labels** button — no longer opens at the page's top-right over the issue list.
It anchors to the button that opened it, opens directly beneath it, and uses the same
picker surface and rows as the branch selector.

- The conversation rail's active tick now follows every navigation path, not
just wheel and scrollbar gestures. Clicking a tick and pressing ⌘↑/⌘↓ scroll
the list programmatically, which never fired gpui's scroll handler, so the
Expand Down
14 changes: 14 additions & 0 deletions INTENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,20 @@ bar, sidebar, transcript copy / diff controls, composer add button, window capti
buttons, Explorer, Review pane, Git, Usage, terminal, settings, and the picker / dialog
controls, so no glyph is a guess.

The Git page's **Issues** and **Pull requests** tabs gained a **Generate** action: the
**New issue** and **New pull request** forms take optional free-form notes, then draft a
title and Markdown body with the same one-shot, tool-free `pi -p` call the commit-message
button uses (`issue_message.rs`), falling back to a local heuristic built from the branch's
commits and changed files when pi is unavailable. The forms also read the repository's own
templates (`gh_templates.rs`): a lone issue/PR template applies automatically, several are
chosen from a **Template** picker, the body is prefilled with the template's skeleton (YAML
issue forms are flattened to Markdown), the template's title prefix and labels are applied,
and the generator is told to fill the template faithfully. Those tabs were also tightened
for scanning — labels collapse to `+N`, every row ends in a fixed relative-time column, and
the PR list drops its duplicated state pill — and the PR detail now shares the issue
detail's reading-column + metadata-rail layout (review, checks, changes, branches,
timeline).

Composer sending is configurable in Settings → Agent → Behavior: Enter queues a follow-up
by default or steers the running task, with Alt/Option+Enter selecting the opposite mode.
The explicit ⌘⇧Enter / Ctrl+Shift+Enter steering shortcut stays fixed. The choice is a
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ Usage — requests, tokens, cost, and cache, read from your own sessions:

- Side pane with a live `git diff HEAD` of the workspace, refreshed when a run settles
- Git page for Changes / History / Graph, staging, and commit
- Git page's Issues and Pull requests tabs: browse and file issues and PRs through `gh`, with an AI **Generate** action that drafts a title and body from the branch, its commits, optional notes, and the repository's own issue/PR template

**Workbench**

Expand Down Expand Up @@ -126,7 +127,7 @@ issue before starting.
| Workflow modes | Composer | Start a session scoped to **Plan Mode**, **Build Mode**, or **Ask Mode** instead of one undifferentiated chat. | Shipped | — |
| Follow-up on settle | Transcript | Show a queued follow-up inline once a run ends, not only in the compose queue. | Planned | — |
| Suggested follow-ups | Transcript | Propose 2–3 context-grounded next prompts as composer inserts after a run settles. | Proposed | [#10](https://github.com/imrj05/orbit/issues/10) |
| GitHub client | Workbench | Browse and manage remote commits, graph, issues, and pull requests in-app. | In progress — issues and PRs tabs ship today | [#8](https://github.com/imrj05/orbit/issues/8) |
| GitHub client | Workbench | Browse and manage remote commits, graph, issues, and pull requests in-app. | In progress — issues and PRs tabs ship today, with AI-drafted issue/PR bodies | [#8](https://github.com/imrj05/orbit/issues/8) |
| Pi extension support | Workbench | First-class list / install / enable / configure / debug of pi extensions, including community ones. | Proposed | [#7](https://github.com/imrj05/orbit/issues/7) |
| Global default model | Models | Pin pi's global default model and thinking effort from within Orbit. | Proposed | [#9](https://github.com/imrj05/orbit/issues/9) |
| Voice dictation | Composer | Dictate prompts into the composer. | Planned | — |
Expand Down
43 changes: 41 additions & 2 deletions crates/orbit-pi/docs/git-page.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ push** row or the top-bar Git affordance; `escape` / **Back** returns.
| **Changes** | `git status --porcelain` | Staged/unstaged lists with per-file stage/unstage and confirmed discard; Include-unstaged toggle; commit bar (branch menu, conventional-commit input, **Generate**); a collapsible **Stashes** section (stash all, pop, apply, drop). |
| **History** | `git log` | Commit rows with ref badges, author, relative time, paged. Clicking a row expands it in place: full body, author/committer facts, **Open on GitHub**, copy hash, and the changed files with a per-file actions menu. |
| **Graph** | `git log --branches HEAD` (plus `--remotes --tags` with **All refs**) | Lane graph laid out by `git::layout_graph`, with the same expandable commit detail as History. |
| **Issues** | `gh issue …` | Open/Closed/All, search, label filter/picker, **New issue**, list, and a detail view with the rendered Markdown body, comments, a comment composer, **Close/Reopen**, **Edit labels**, and **Open on GitHub**. |
| **Pull requests** | `gh pr …` | Open/Closed/Merged/All, search, **New pull request** (title, body, base picker, draft), list with CI rollup and review-decision chips, and a detail view with description, checks, commits, changed files, comments, reviews, **Approve** / **Request changes**, **Merge** (method + delete-branch confirm), **Close/Reopen**, and **Checkout branch**. |
| **Issues** | `gh issue …` | Open/Closed/All, search, label filter/picker, **New issue** (with **Generate**), list, and a detail view with the rendered Markdown body, comments, a comment composer, **Close/Reopen**, **Edit labels**, and **Open on GitHub**. |
| **Pull requests** | `gh pr …` | Open/Closed/Merged/All, search, **New pull request** (title, body, base picker, draft, **Generate**), list with CI rollup and review-decision chips, and a detail view with description, checks, commits, changed files, comments, reviews, **Approve** / **Request changes**, **Merge** (method + delete-branch confirm), **Close/Reopen**, and **Checkout branch**. |

The Issues and Pull requests tabs only appear when `gh` is installed. A missing
`gh` or a signed-out CLI renders an honest setup state instead of an empty tab.
Expand All @@ -27,6 +27,45 @@ Commit message auto-generates through `commit_message.rs`
(`pi -p --no-tools --no-session --no-extensions --no-skills --no-context-files`,
falling back to a local `type(scope): …` heuristic).

## Issue and pull-request draft generation

The **New issue** and **New pull request** forms have a **Generate** button beside their
heading. An optional **Notes** field steers the draft; leave it blank to infer the subject
from the repository context. Generation reuses the commit-message pattern: a one-shot,
tool-free `pi -p` call (`issue_message.rs`) that reads the current branch, the branch's
commits (against the chosen base for a PR), and its changed-file stat — never writing to
the working tree or the active session. The model is asked for a single fenced block with
the title on the first line and a Markdown body below it.

### Repository templates

Both forms discover the repository's own templates (`gh_templates.rs`, mirroring GitHub's
lookup): the `.github/ISSUE_TEMPLATE/` directory (Markdown templates with YAML front
matter, and the newer YAML issue forms, `config.yml` skipped) plus the legacy
single-file locations, and `.github/PULL_REQUEST_TEMPLATE.md` plus its variants. A form
with exactly one template applies it automatically; with several, a **Template** chip
opens a picker (including a **Blank** choice). Choosing a template prefills the title
prefix (`bug: `) and the body skeleton, and **Create** passes the template's `labels:` to
`gh`. An issue form is flattened into Markdown — each field's label becomes a heading,
its description a guidance comment, dropdown/checkbox options rendered as comments and
checkboxes — since Orbit edits plain Markdown rather than GitHub's dynamic form.

The **Generate** prompt hands the model the selected template and asks it to fill every
heading faithfully, preserving the template's checkboxes and sections. Without pi, the
heuristic drops the notes (or the branch's commit subjects) into the template's first
section.

When pi is missing, unauthenticated, or times out, the button falls back to a local
heuristic: the title comes from the first note line, else the latest commit subject, else
the branch name read as words; the body lists the branch's commits and changed files under
`## Summary` / `## What happened`. Either way the result lands in the editable title and
body fields, and **Create** is still a separate, deliberate press.

The Issues and Pull requests lists are built to scan: labels collapse to a `+N` chip, each
row ends in a fixed relative-time column, and closed items are de-emphasized. The issue
detail's reading-column + metadata-rail layout is now shared by the pull-request detail,
whose rail summarizes review, checks, changes, branches, and the timeline.

The branch chip opens a menu with **Merge branch…**, **Rebase onto…**, every
local branch (checkout; delete uses safe `-d` first, then a confirmed `-D`),
**New branch…**, and **Rename current branch…**. Merge can fast-forward, create
Expand Down
21 changes: 21 additions & 0 deletions crates/orbit-pi/locales/de.yml
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,20 @@ git_panel.pr_merged: "Zusammengeführt"
git_panel.new_pull: "New pull request"
git_panel.new_pull_title: "New pull request"
git_panel.create_pull: "Create pull request"
git_panel.draft_notes_label: "Notes"
git_panel.template: "Template"
git_panel.template_blank: "Blank"
git_panel.template_none: "No template in this repository"
git_panel.draft_notes_placeholder: "Optional: describe the change, problem, or goal…"
git_panel.generate_draft: "Generieren"
git_panel.generating_draft: "Wird generiert…"
git_panel.draft_ready: "Draft ready — review before creating"
git_panel.draft_issue_fallback_title: "New issue"
git_panel.draft_pull_fallback_title: "New pull request"
git_panel.draft_what_happened: "What happened"
git_panel.draft_summary: "Zusammenfassung"
git_panel.draft_placeholder: "Describe the change."
git_panel.draft_changed_files: "Changed files"
git_panel.pr_created: "Pull request created"
git_panel.pr_title_required: "A pull request needs a title"
git_panel.pulls_unavailable: "Pull requests unavailable"
Expand Down Expand Up @@ -698,6 +712,11 @@ git_panel.base_branch: "Base branch"
git_panel.choose_base: "Choose base"
git_panel.commits: "Commits"
git_panel.checks: "Checks"
git_panel.review: "Überprüfen"
git_panel.review_none: "No decision yet"
git_panel.no_checks: "No checks"
git_panel.branches: "Branches"
git_panel.head_branch: "Head branch"
git_panel.files_changed: "Files changed"
git_panel.files_count: "%{count} files"
git_panel.more_files: "%{count} more files not shown"
Expand Down Expand Up @@ -1203,6 +1222,8 @@ errors.pi_timed_out: "pi %{args} hat das Zeitlimit überschritten"
errors.pi_process_error: "pi-Prozessfehler: %{error}"
errors.pi_exited_with: "pi wurde mit %{status} beendet: %{stderr}"
errors.commit_generation_timed_out: "Zeitlimit für die Commit-Nachrichtengenerierung überschritten"
errors.no_draft: "the model returned an empty draft"
errors.draft_generation_timed_out: "draft generation timed out"
explorer.files: "Files"
explorer.filter_files: "Dateien filtern…"
explorer.files_count: "%{count} files"
Expand Down
21 changes: 21 additions & 0 deletions crates/orbit-pi/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,20 @@ git_panel.pr_merged: "Merged"
git_panel.new_pull: "New pull request"
git_panel.new_pull_title: "New pull request"
git_panel.create_pull: "Create pull request"
git_panel.draft_notes_label: "Notes"
git_panel.template: "Template"
git_panel.template_blank: "Blank"
git_panel.template_none: "No template in this repository"
git_panel.draft_notes_placeholder: "Optional: describe the change, problem, or goal…"
git_panel.generate_draft: "Generate"
git_panel.generating_draft: "Generating…"
git_panel.draft_ready: "Draft ready — review before creating"
git_panel.draft_issue_fallback_title: "New issue"
git_panel.draft_pull_fallback_title: "New pull request"
git_panel.draft_what_happened: "What happened"
git_panel.draft_summary: "Summary"
git_panel.draft_placeholder: "Describe the change."
git_panel.draft_changed_files: "Changed files"
git_panel.pr_created: "Pull request created"
git_panel.pr_title_required: "A pull request needs a title"
git_panel.pulls_unavailable: "Pull requests unavailable"
Expand Down Expand Up @@ -698,6 +712,11 @@ git_panel.base_branch: "Base branch"
git_panel.choose_base: "Choose base"
git_panel.commits: "Commits"
git_panel.checks: "Checks"
git_panel.review: "Review"
git_panel.review_none: "No decision yet"
git_panel.no_checks: "No checks"
git_panel.branches: "Branches"
git_panel.head_branch: "Head branch"
git_panel.files_changed: "Files changed"
git_panel.files_count: "%{count} files"
git_panel.more_files: "%{count} more files not shown"
Expand Down Expand Up @@ -1203,6 +1222,8 @@ errors.pi_timed_out: "pi %{args} timed out"
errors.pi_process_error: "pi process error: %{error}"
errors.pi_exited_with: "pi exited with %{status}: %{stderr}"
errors.commit_generation_timed_out: "commit message generation timed out"
errors.no_draft: "the model returned an empty draft"
errors.draft_generation_timed_out: "draft generation timed out"
explorer.files: "Files"
explorer.filter_files: "Filter files…"
explorer.files_count: "%{count} files"
Expand Down
21 changes: 21 additions & 0 deletions crates/orbit-pi/locales/es.yml
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,20 @@ git_panel.pr_merged: "Fusionado"
git_panel.new_pull: "New pull request"
git_panel.new_pull_title: "New pull request"
git_panel.create_pull: "Create pull request"
git_panel.draft_notes_label: "Notes"
git_panel.template: "Template"
git_panel.template_blank: "Blank"
git_panel.template_none: "No template in this repository"
git_panel.draft_notes_placeholder: "Optional: describe the change, problem, or goal…"
git_panel.generate_draft: "Generar"
git_panel.generating_draft: "Generando…"
git_panel.draft_ready: "Draft ready — review before creating"
git_panel.draft_issue_fallback_title: "New issue"
git_panel.draft_pull_fallback_title: "New pull request"
git_panel.draft_what_happened: "What happened"
git_panel.draft_summary: "Resumen"
git_panel.draft_placeholder: "Describe the change."
git_panel.draft_changed_files: "Changed files"
git_panel.pr_created: "Pull request created"
git_panel.pr_title_required: "A pull request needs a title"
git_panel.pulls_unavailable: "Pull requests unavailable"
Expand Down Expand Up @@ -698,6 +712,11 @@ git_panel.base_branch: "Base branch"
git_panel.choose_base: "Choose base"
git_panel.commits: "Commits"
git_panel.checks: "Checks"
git_panel.review: "Revisar"
git_panel.review_none: "No decision yet"
git_panel.no_checks: "No checks"
git_panel.branches: "Ramas"
git_panel.head_branch: "Head branch"
git_panel.files_changed: "Files changed"
git_panel.files_count: "%{count} files"
git_panel.more_files: "%{count} more files not shown"
Expand Down Expand Up @@ -1203,6 +1222,8 @@ errors.pi_timed_out: "pi %{args} agotó el tiempo de espera"
errors.pi_process_error: "error del proceso pi: %{error}"
errors.pi_exited_with: "pi terminó con %{status}: %{stderr}"
errors.commit_generation_timed_out: "se agotó el tiempo de generación del mensaje de confirmación"
errors.no_draft: "the model returned an empty draft"
errors.draft_generation_timed_out: "draft generation timed out"
explorer.files: "Files"
explorer.filter_files: "Filtrar archivos…"
explorer.files_count: "%{count} files"
Expand Down
Loading
Loading