From 5efa6aadfe3fd79ebe1def3709faf7e490827660 Mon Sep 17 00:00:00 2001
From: Michael Ramos
Date: Mon, 9 Mar 2026 22:56:26 -0700
Subject: [PATCH 1/2] feat: add Pi origin support to code review UI and update
banner
Pi users were seeing "OpenCode" badge and getting the wrong update
command. Adds 'pi' to origin types in review/annotate servers, shows
violet "Pi" badge in code review header, and copies the correct
`pi install` command in the update banner.
Co-Authored-By: Claude Opus 4.6
---
packages/review-editor/App.tsx | 18 ++++++++++--------
packages/server/annotate.ts | 2 +-
packages/server/review.ts | 2 +-
packages/ui/components/UpdateBanner.tsx | 14 +++++++++++---
4 files changed, 23 insertions(+), 13 deletions(-)
diff --git a/packages/review-editor/App.tsx b/packages/review-editor/App.tsx
index c04200cf6..ab7bad579 100644
--- a/packages/review-editor/App.tsx
+++ b/packages/review-editor/App.tsx
@@ -35,7 +35,7 @@ interface DiffData {
files: DiffFile[];
rawPatch: string;
gitRef: string;
- origin?: 'opencode' | 'claude-code';
+ origin?: 'opencode' | 'claude-code' | 'pi';
diffType?: string;
gitContext?: GitContext;
sharingEnabled?: boolean;
@@ -139,7 +139,7 @@ const ReviewApp: React.FC = () => {
const [copyFeedback, setCopyFeedback] = useState(null);
const [viewedFiles, setViewedFiles] = useState>(new Set());
const [hideViewedFiles, setHideViewedFiles] = useState(false);
- const [origin, setOrigin] = useState<'opencode' | 'claude-code' | null>(null);
+ const [origin, setOrigin] = useState<'opencode' | 'claude-code' | 'pi' | null>(null);
const [diffType, setDiffType] = useState('uncommitted');
const [gitContext, setGitContext] = useState(null);
const [isLoadingDiff, setIsLoadingDiff] = useState(false);
@@ -214,7 +214,7 @@ const ReviewApp: React.FC = () => {
.then((data: {
rawPatch: string;
gitRef: string;
- origin?: 'opencode' | 'claude-code';
+ origin?: 'opencode' | 'claude-code' | 'pi';
diffType?: string;
gitContext?: GitContext;
sharingEnabled?: boolean;
@@ -615,9 +615,11 @@ const ReviewApp: React.FC = () => {
- {origin === 'claude-code' ? 'Claude Code' : 'OpenCode'}
+ {origin === 'claude-code' ? 'Claude Code' : origin === 'pi' ? 'Pi' : 'OpenCode'}
)}
{repoInfo && (
@@ -991,10 +993,10 @@ const ReviewApp: React.FC = () => {
title={submitted === 'approved' ? 'Changes Approved' : 'Feedback Sent'}
subtitle={
submitted === 'approved'
- ? `${origin === 'claude-code' ? 'Claude Code' : 'OpenCode'} will proceed with the changes.`
- : `${origin === 'claude-code' ? 'Claude Code' : 'OpenCode'} will address your review feedback.`
+ ? `${origin === 'claude-code' ? 'Claude Code' : origin === 'pi' ? 'Pi' : 'OpenCode'} will proceed with the changes.`
+ : `${origin === 'claude-code' ? 'Claude Code' : origin === 'pi' ? 'Pi' : 'OpenCode'} will address your review feedback.`
}
- agentLabel={origin === 'claude-code' ? 'Claude Code' : 'OpenCode'}
+ agentLabel={origin === 'claude-code' ? 'Claude Code' : origin === 'pi' ? 'Pi' : 'OpenCode'}
/>
{/* Update notification */}
diff --git a/packages/server/annotate.ts b/packages/server/annotate.ts
index 1f425ad92..28a380e56 100644
--- a/packages/server/annotate.ts
+++ b/packages/server/annotate.ts
@@ -31,7 +31,7 @@ export interface AnnotateServerOptions {
/** HTML content to serve for the UI */
htmlContent: string;
/** Origin identifier for UI customization */
- origin?: "opencode" | "claude-code";
+ origin?: "opencode" | "claude-code" | "pi";
/** Whether URL sharing is enabled (default: true) */
sharingEnabled?: boolean;
/** Custom base URL for share links */
diff --git a/packages/server/review.ts b/packages/server/review.ts
index 2cc50a387..bb16c9f91 100644
--- a/packages/server/review.ts
+++ b/packages/server/review.ts
@@ -34,7 +34,7 @@ export interface ReviewServerOptions {
/** HTML content to serve for the UI */
htmlContent: string;
/** Origin identifier for UI customization */
- origin?: "opencode" | "claude-code";
+ origin?: "opencode" | "claude-code" | "pi";
/** Current diff type being displayed */
diffType?: DiffType;
/** Git context with branch info and available diff options */
diff --git a/packages/ui/components/UpdateBanner.tsx b/packages/ui/components/UpdateBanner.tsx
index 3c70ee900..4b102b4ee 100644
--- a/packages/ui/components/UpdateBanner.tsx
+++ b/packages/ui/components/UpdateBanner.tsx
@@ -1,7 +1,8 @@
import React, { useState } from 'react';
import { useUpdateCheck } from '../hooks/useUpdateCheck';
-const INSTALL_COMMAND = 'curl -fsSL https://plannotator.ai/install.sh | bash';
+const DEFAULT_INSTALL_COMMAND = 'curl -fsSL https://plannotator.ai/install.sh | bash';
+const PI_INSTALL_COMMAND = 'pi install npm:@plannotator/pi-extension';
interface UpdateBannerProps {
origin?: 'claude-code' | 'opencode' | 'pi' | null;
@@ -16,13 +17,15 @@ export const UpdateBanner: React.FC = ({ origin }) => {
const urlParams = new URLSearchParams(window.location.search);
const previewOrigin = urlParams.get('preview-origin');
const effectiveOrigin = previewOrigin || origin;
+ const isPi = effectiveOrigin === 'pi';
const isOpenCode = effectiveOrigin === 'opencode';
+ const installCommand = isPi ? PI_INSTALL_COMMAND : DEFAULT_INSTALL_COMMAND;
if (!updateInfo?.updateAvailable || dismissed) return null;
const handleCopy = async () => {
try {
- await navigator.clipboard.writeText(INSTALL_COMMAND);
+ await navigator.clipboard.writeText(installCommand);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
} catch (e) {
@@ -76,12 +79,17 @@ export const UpdateBanner: React.FC = ({ origin }) => {
You have {updateInfo.currentVersion}
- {/* OpenCode extra instructions */}
+ {/* Agent-specific extra instructions */}
{isOpenCode && (
Run the install script, then restart OpenCode.
)}
+ {isPi && (
+
+ Run the install command, then restart Pi.
+
+ )}