Skip to content

feat(tasks): per-member PR/CI rows + update-all for multi-repo tasks - #352

Merged
simion merged 6 commits into
simion:mainfrom
kaceper11:feat/task-delivery
Oct 1, 2026
Merged

simion merged 6 commits into
simion:mainfrom
kaceper11:feat/task-delivery

Conversation

@kaceper11

Copy link
Copy Markdown
Contributor

Summary

Multi-repo tasks only polled PR state for the host worktree — member repos' PRs/MRs were invisible on both the Git tab and the board. This adds per-member PR/CI visibility and a one-shot "update all repos" action.

Stacked on #351 — this branch is cut from azure-devops, so the diff includes that work until #351 merges, then shrinks to this feature only.

Per-member PR/CI

  • New task_member_pr_status command: polls each non-host member's checkout by its live branch (git branch --show-current), so repo_root members track what's actually checked out rather than a frozen recorded branch. Same remote→provider resolution and status vocabulary as the host lookup (github/gitlab/azure).
  • pr.refresh() now fires host + member lookups together (Promise.allSettled) — a dead remote on one side can't freeze the other, and a failed member call keeps the last snapshot.
  • Git tab: member rows under the PR card — repo · branch, state pill, #42/!42 ref, CI chip, open-in-browser. Rendered for main-checkout tasks too (host card stays hidden there, so this is the only PR surface).
  • Board: card footer shows up to 3 member mini-rows + +N more; board mount seeds discovery.
  • Poll triggers respect main-checkout semantics: prRelevant = host PR, or member PRs for main-checkout multi-repo tasks; MemberPrRows runs its own tick only when PrCard isn't mounted.
  • Staleness guards: member snapshots are dropped if the composition changed mid-flight, and a setLookup landing mid-refresh isn't clobbered by the stale response.

Update all repos

  • New task_git_update_all(id, mode): pull / merge-base / rebase-base across host + every on-disk member, each on its own repo_base_branch, via the existing git_update_repo (fetch + autostash + conflict detection). Per-repo results; one failure never aborts the batch.
  • Branch-chip dropdown gains an "All repos" section; summary toasts distinguish updated / already-current / needs-attention, localized (en + zh-CN).
  • Shared on_disk_members helper is the single contract for "which members are real checkouts" — skips missing paths and any legacy record pointing at the host — used by task_git_status, member PR lookups, and update-all.

Test plan

  • tsc -b, cargo check, cargo test — clean
  • Vitest: 177 files / 2662 tests — incl. new coverage: single-member gating, main-checkout member polling, member removal mid-flight, setLookup races, host-fail/member-ok allSettled, prFocusEligible, Rust tests for on_disk_members + live-HEAD member lookups
  • Manual: member rows verified rendering in Git tab and on board card (injected mock + real repo pills on a multi-repo task)

Out of scope (deliberate)

  • Per-member PR creation (task_pr_create stays host-only), per-check CI details, remote picker, member PR background polling on unfocused tasks.

Generated with Devin

kaceper11 and others added 6 commits September 30, 2026 22:47
Adds az/azure-devops as a third forge alongside gh and glab: remote
detection (dev.azure.com, *.visualstudio.com, ssh.dev.azure.com v3,
vs-ssh), CLI + extension + Entra/PAT auth probing, PR status/policies/
comments, Azure Boards work-item listing and issue-task seeding, PR
creation, IPC + frontend wiring, sandbox/Docker allowlisting, and docs.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…te-chip echo

Codex 0.159 TUI fires sessionStart on the FIRST prompt submit, not at
startup, so gating the seeded prompt on hook readiness guaranteed a
timeout: every codex task ended in seed-blocked. hooksOwnStartupReadiness
excludes codex from hook-owned startup readiness (work-state hooks still
gate mid-turn), so it falls back to the painted-and-quiet heuristic with
echo verification - which still refuses to submit into a picker dialog.

Two stacked delivery bugs then surfaced on that path: the echo listener
attached inside the text write's .then (an echo riding the write's own
round trip read as 'did not echo' and withheld the CR), and the literal
echo check never passes for multi-line prompts because codex renders a
bracketed paste as a '[Pasted Content N chars]' chip - the chip IS the
echo (a selection dialog can't draw one), so it is accepted for
paste-wrapped sends.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
The card's identity row is all shrink-0 except the spacer; a fully
populated row (~330px) overran the 280px default right panel and the
window clipped the rightmost 'Open on' button. ReviewChip ('Changes
requested', the widest label) now truncates with a title fallback.

forge.rs: pr_status/pr_comments/issue_list/pr_create re-probe the CLI
path instead of the startup-time cache, so a CLI installed mid-session
works without visiting Settings first.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
- az calls scope explicitly (--org/--project/--repository); --detect gone,
  so PAT remotes cannot silently resolve the wrong org
- From a PR works for azure: pr list --creator me, pr show, per-provider
  fetch refspecs, fork PRs refused instead of fetching the wrong branch
- Multi-pick issues seed ONE task; plural WORK_ISSUES_PROMPT tail with
  provider noun swap; unmodified builtins only, user edits win
- agentSend: paste chip counts as echo again for wrapped sends, failure
  diagnostics restored; cliRpc inject gets readiness + echo verification
- NewTaskDialog: stale guards on seed-object identity, pane exclusivity,
  !N ref parsing, branch latch; CreatePrDialog provider gating
- visualstudio.com org URLs drop the collection path (extension rejects
  it); legacy _ssh remotes parse; sibling-project repo guard

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Multi-repo tasks polled PR state for the host worktree only; member
repos' PRs were invisible everywhere. Member lookups now ride inside
the existing pr.refresh() cadence (same triggers, allSettled so one
dead remote can't freeze the other leg), keyed by each member's live
branch in its own checkout - repo_root members track live HEAD
instead of a frozen recorded branch. Rows render under the Git tab
PR card and as board-card mini-rows, including main-checkout tasks
where the host card stays hidden; a shared on_disk_members helper
keeps status/member-PR/update-all enumeration consistent (existing
paths, never the host twice).

The branch-chip dropdown gains an "All repos" section: pull / merge
base / rebase base across host + members in one shot via
task_git_update_all, each repo on its own base branch, failures
surfaced per repo without aborting the batch.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
# Conflicts:
#	src/components/dialogs/WelcomeDialog.tsx

@simion simion left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified locally on top of main once #351 was in: clean merge, cargo test 1216, npm test 2665, tsc -b and the e2e typecheck clean, git.e2e 75/75 on a rebuilt binary.

With #351 merged this reduces to its own single commit, which is what I reviewed.

The design calls I want to note as right, because they are the ones that would have been easy to get wrong:

Polling each member by its LIVE branch (git branch --show-current) rather than the recorded one. A repo_root member tracks whatever is checked out, and a frozen branch would have quietly reported another branch's PR as that member's.

Promise.allSettled for host + members, so one dead remote cannot freeze the other half. With a settled instead of an all, a single unreachable forge would have taken out PR status for every repo in the task.

Dropping member snapshots when the composition changed mid-flight. That is the kind of staleness nobody notices until a removed member's PR keeps rendering.

on_disk_members as one shared contract for "which members are real checkouts", used by status, member lookups and update-all alike. Three callers each deciding that separately is how they drift.

Thanks for this, and for splitting it from the forge work rather than leaving it in one branch.

@simion
simion merged commit 1973a02 into simion:main Oct 1, 2026
7 checks passed
@simion

simion commented Oct 1, 2026

Copy link
Copy Markdown
Owner

Merged, by pushing the merge commit rather than the button: GitHub had this branch as CONFLICTING/DIRTY, but the merge is clean in both directions. git merge-tree against main, and a real git merge origin/main onto the branch head, both come back with no conflicted paths. Its mergeability was computed before #351 landed and never recomputed. Nothing was resolved by hand, so what is on main is exactly what the button would have produced.

Verified on that exact main before pushing: cargo 1216, npm test 2665, git.e2e 75/75, tsc -b and the e2e typecheck clean.

Thanks for splitting this out of the forge branch rather than leaving it as one diff. With #351 in first, this reduced to a single reviewable commit, which is the difference between reading it and skimming it.

@kaceper11
kaceper11 deleted the feat/task-delivery branch October 1, 2026 10:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants