Skip to content

feat: add cross-project run board - #32

Merged
nonlooped merged 3 commits into
mainfrom
feat/run-board
Jul 31, 2026
Merged

feat: add cross-project run board#32
nonlooped merged 3 commits into
mainfrom
feat/run-board

Conversation

@nonlooped

Copy link
Copy Markdown
Owner

Summary

  • add a run board for active and session-local settled project runs
  • show project, chat, model, elapsed time, current tool, token burn, and extension/confirmation blockers
  • retain pending Pi extension dialogs in memory across project switches

Verification

  • bun run typecheck
  • bun run test
  • bun run build
  • cd apps/web && bun run lint
  • cd apps/web && bun run typecheck
  • bun run web:build

@vercel

vercel Bot commented Jul 31, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
nativepi Ignored Ignored Preview Jul 31, 2026 10:08am

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6411d4c1f8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// Extension UI (dialogs, statuses, widgets) is chrome for the project on
// screen; an inactive project's prompts would have nothing to attach to.
if (projectDir === s.activeProjectPath) applyExtensionUi(set, get, event as ExtensionUiRequest);
applyExtensionUi(set, get, projectDir, event as ExtensionUiRequest);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Gate non-prompt extension UI by project

When project A emits an extension request while project B is active, this unconditional call now routes every method through applyExtensionUi; only dialog prompts are project-scoped there, while setStatus and setWidget overwrite B's chrome and set_editor_text writes into B's active draft. A background extension can therefore alter or replace text the user is preparing in an unrelated project; retain the inactive-project prompt capture while ignoring or separately scoping the other project-bound methods.

Useful? React with 👍 / 👎.

Comment on lines +36 to +37
case "agent_end":
return { running: false, runStartedAt: null };
return { running: false, runStartedAt: null, runEntryStart: null };

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve turn state until agent_settled

When Pi enters an automatic retry delay, compacts, or proceeds to a queued follow-up, agent_end closes only the current low-level run; apps/desktop/src/main/ipc.ts:111-116 explicitly keeps the project busy until agent_settled. Clearing the running flag, timer, and entry boundary here makes the new run board temporarily report that project as inactive, then restarts its metrics at the next agent_start, so the final elapsed time and token count omit earlier attempts in the same turn.

Useful? React with 👍 / 👎.


return (
<main className="flex h-full min-w-0 flex-col bg-background text-foreground">
<header className={`${DRAG_REGION} flex h-12 shrink-0 items-center gap-3 border-b px-4 sm:px-10`}>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Reserve space for the desktop window controls

In the desktop shell, the always-on WindowControls occupy the rightmost 132 px at z-[60], but this header does not apply WINDOW_CONTROLS_CLEARANCE. The run-board close button consequently sits underneath those controls and cannot be clicked; because selecting a row also leaves the full-screen board open, pointer users can become stuck on this screen until they reload or discover a keyboard workaround.

Useful? React with 👍 / 👎.

Comment on lines +80 to +82
<div className="overflow-hidden rounded-lg border">
<div className="grid grid-cols-[minmax(12rem,1.35fr)_minmax(10rem,1.1fr)_minmax(7rem,.8fr)] gap-x-4 border-b bg-muted/30 px-4 py-2 text-xs font-medium text-muted-foreground sm:grid-cols-[minmax(10rem,1.1fr)_minmax(10rem,1.1fr)_minmax(10rem,1fr)_5rem_7rem_6rem]">
<span>Project / chat</span><span>Model</span><span>Current work</span><span>Elapsed</span><span>Tokens</span><span>Status</span>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Allow the compact run table to fit or scroll

On a phone or other sub-640 px browser viewport, this compact grid still requires about 496 px before padding (12rem + 10rem + 7rem plus two gaps), while its parent uses overflow-hidden and provides no horizontal scrolling. The right-hand Current work and Status cells are therefore clipped and unreachable on typical 375–430 px screens; use genuinely flexible compact columns, hide secondary fields, or make the table horizontally scrollable.

Useful? React with 👍 / 👎.

<span>Project / chat</span><span>Model</span><span>Current work</span><span>Elapsed</span><span>Tokens</span><span>Status</span>
</div>
{rows.map((row) => (
<button key={row.project.path} type="button" onClick={() => void selectProject(row.project.path)} className="grid w-full grid-cols-[minmax(12rem,1.35fr)_minmax(10rem,1.1fr)_minmax(7rem,.8fr)] gap-x-4 border-b px-4 py-3 text-left last:border-b-0 hover:bg-muted/50 focus-visible:bg-muted/50 focus-visible:outline-none sm:grid-cols-[minmax(10rem,1.1fr)_minmax(10rem,1.1fr)_minmax(10rem,1fr)_5rem_7rem_6rem]">

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Open the chat represented by a settled row

After a run settles and the user switches to another chat in the same project, the board intentionally retains the settled row and labels it with the original run's chat, but clicking it calls only selectProject. Because selectProject chooses getLastChat(path) for a non-running project, closing the board then reveals the newer chat rather than the session named by the clicked row; navigate to row's recorded sessionFile as well as selecting its project.

Useful? React with 👍 / 👎.

@nonlooped
nonlooped merged commit 3e673a2 into main Jul 31, 2026
7 checks passed
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.

1 participant