mirror of
https://github.com/backnotprop/plannotator.git
synced 2026-09-14 14:17:26 +08:00
feat: add Pi origin support to code review UI (#263)
* 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 <noreply@anthropic.com> * feat: update Pi extension from install scripts when pi is available The install scripts now check if `pi` is on PATH and run `pi install npm:@plannotator/pi-extension` to update the extension. Silent for users without Pi installed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -35,7 +35,7 @@ interface DiffData {
|
|||||||
files: DiffFile[];
|
files: DiffFile[];
|
||||||
rawPatch: string;
|
rawPatch: string;
|
||||||
gitRef: string;
|
gitRef: string;
|
||||||
origin?: 'opencode' | 'claude-code';
|
origin?: 'opencode' | 'claude-code' | 'pi';
|
||||||
diffType?: string;
|
diffType?: string;
|
||||||
gitContext?: GitContext;
|
gitContext?: GitContext;
|
||||||
sharingEnabled?: boolean;
|
sharingEnabled?: boolean;
|
||||||
@@ -139,7 +139,7 @@ const ReviewApp: React.FC = () => {
|
|||||||
const [copyFeedback, setCopyFeedback] = useState<string | null>(null);
|
const [copyFeedback, setCopyFeedback] = useState<string | null>(null);
|
||||||
const [viewedFiles, setViewedFiles] = useState<Set<string>>(new Set());
|
const [viewedFiles, setViewedFiles] = useState<Set<string>>(new Set());
|
||||||
const [hideViewedFiles, setHideViewedFiles] = useState(false);
|
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<string>('uncommitted');
|
const [diffType, setDiffType] = useState<string>('uncommitted');
|
||||||
const [gitContext, setGitContext] = useState<GitContext | null>(null);
|
const [gitContext, setGitContext] = useState<GitContext | null>(null);
|
||||||
const [isLoadingDiff, setIsLoadingDiff] = useState(false);
|
const [isLoadingDiff, setIsLoadingDiff] = useState(false);
|
||||||
@@ -214,7 +214,7 @@ const ReviewApp: React.FC = () => {
|
|||||||
.then((data: {
|
.then((data: {
|
||||||
rawPatch: string;
|
rawPatch: string;
|
||||||
gitRef: string;
|
gitRef: string;
|
||||||
origin?: 'opencode' | 'claude-code';
|
origin?: 'opencode' | 'claude-code' | 'pi';
|
||||||
diffType?: string;
|
diffType?: string;
|
||||||
gitContext?: GitContext;
|
gitContext?: GitContext;
|
||||||
sharingEnabled?: boolean;
|
sharingEnabled?: boolean;
|
||||||
@@ -615,9 +615,11 @@ const ReviewApp: React.FC = () => {
|
|||||||
<span className={`text-[10px] px-1.5 py-0.5 rounded font-medium hidden md:inline ${
|
<span className={`text-[10px] px-1.5 py-0.5 rounded font-medium hidden md:inline ${
|
||||||
origin === 'claude-code'
|
origin === 'claude-code'
|
||||||
? 'bg-orange-500/15 text-orange-400'
|
? 'bg-orange-500/15 text-orange-400'
|
||||||
: 'bg-zinc-500/20 text-zinc-400'
|
: origin === 'pi'
|
||||||
|
? 'bg-violet-500/15 text-violet-400'
|
||||||
|
: 'bg-zinc-500/20 text-zinc-400'
|
||||||
}`}>
|
}`}>
|
||||||
{origin === 'claude-code' ? 'Claude Code' : 'OpenCode'}
|
{origin === 'claude-code' ? 'Claude Code' : origin === 'pi' ? 'Pi' : 'OpenCode'}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{repoInfo && (
|
{repoInfo && (
|
||||||
@@ -991,10 +993,10 @@ const ReviewApp: React.FC = () => {
|
|||||||
title={submitted === 'approved' ? 'Changes Approved' : 'Feedback Sent'}
|
title={submitted === 'approved' ? 'Changes Approved' : 'Feedback Sent'}
|
||||||
subtitle={
|
subtitle={
|
||||||
submitted === 'approved'
|
submitted === 'approved'
|
||||||
? `${origin === 'claude-code' ? 'Claude Code' : 'OpenCode'} will proceed with the changes.`
|
? `${origin === 'claude-code' ? 'Claude Code' : origin === 'pi' ? 'Pi' : '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 address your review feedback.`
|
||||||
}
|
}
|
||||||
agentLabel={origin === 'claude-code' ? 'Claude Code' : 'OpenCode'}
|
agentLabel={origin === 'claude-code' ? 'Claude Code' : origin === 'pi' ? 'Pi' : 'OpenCode'}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Update notification */}
|
{/* Update notification */}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export interface AnnotateServerOptions {
|
|||||||
/** HTML content to serve for the UI */
|
/** HTML content to serve for the UI */
|
||||||
htmlContent: string;
|
htmlContent: string;
|
||||||
/** Origin identifier for UI customization */
|
/** Origin identifier for UI customization */
|
||||||
origin?: "opencode" | "claude-code";
|
origin?: "opencode" | "claude-code" | "pi";
|
||||||
/** Whether URL sharing is enabled (default: true) */
|
/** Whether URL sharing is enabled (default: true) */
|
||||||
sharingEnabled?: boolean;
|
sharingEnabled?: boolean;
|
||||||
/** Custom base URL for share links */
|
/** Custom base URL for share links */
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export interface ReviewServerOptions {
|
|||||||
/** HTML content to serve for the UI */
|
/** HTML content to serve for the UI */
|
||||||
htmlContent: string;
|
htmlContent: string;
|
||||||
/** Origin identifier for UI customization */
|
/** Origin identifier for UI customization */
|
||||||
origin?: "opencode" | "claude-code";
|
origin?: "opencode" | "claude-code" | "pi";
|
||||||
/** Current diff type being displayed */
|
/** Current diff type being displayed */
|
||||||
diffType?: DiffType;
|
diffType?: DiffType;
|
||||||
/** Git context with branch info and available diff options */
|
/** Git context with branch info and available diff options */
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { useUpdateCheck } from '../hooks/useUpdateCheck';
|
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 {
|
interface UpdateBannerProps {
|
||||||
origin?: 'claude-code' | 'opencode' | 'pi' | null;
|
origin?: 'claude-code' | 'opencode' | 'pi' | null;
|
||||||
@@ -16,13 +17,15 @@ export const UpdateBanner: React.FC<UpdateBannerProps> = ({ origin }) => {
|
|||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
const previewOrigin = urlParams.get('preview-origin');
|
const previewOrigin = urlParams.get('preview-origin');
|
||||||
const effectiveOrigin = previewOrigin || origin;
|
const effectiveOrigin = previewOrigin || origin;
|
||||||
|
const isPi = effectiveOrigin === 'pi';
|
||||||
const isOpenCode = effectiveOrigin === 'opencode';
|
const isOpenCode = effectiveOrigin === 'opencode';
|
||||||
|
const installCommand = isPi ? PI_INSTALL_COMMAND : DEFAULT_INSTALL_COMMAND;
|
||||||
|
|
||||||
if (!updateInfo?.updateAvailable || dismissed) return null;
|
if (!updateInfo?.updateAvailable || dismissed) return null;
|
||||||
|
|
||||||
const handleCopy = async () => {
|
const handleCopy = async () => {
|
||||||
try {
|
try {
|
||||||
await navigator.clipboard.writeText(INSTALL_COMMAND);
|
await navigator.clipboard.writeText(installCommand);
|
||||||
setCopied(true);
|
setCopied(true);
|
||||||
setTimeout(() => setCopied(false), 2000);
|
setTimeout(() => setCopied(false), 2000);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -76,12 +79,17 @@ export const UpdateBanner: React.FC<UpdateBannerProps> = ({ origin }) => {
|
|||||||
You have {updateInfo.currentVersion}
|
You have {updateInfo.currentVersion}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{/* OpenCode extra instructions */}
|
{/* Agent-specific extra instructions */}
|
||||||
{isOpenCode && (
|
{isOpenCode && (
|
||||||
<p className="text-xs text-muted-foreground mt-3">
|
<p className="text-xs text-muted-foreground mt-3">
|
||||||
Run the install script, then restart OpenCode.
|
Run the install script, then restart OpenCode.
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
{isPi && (
|
||||||
|
<p className="text-xs text-muted-foreground mt-3">
|
||||||
|
Run the install command, then restart Pi.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="mt-4 flex items-center gap-2">
|
<div className="mt-4 flex items-center gap-2">
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -155,6 +155,14 @@ echo }
|
|||||||
echo Updated plugin hooks at !PLUGIN_HOOKS!
|
echo Updated plugin hooks at !PLUGIN_HOOKS!
|
||||||
)
|
)
|
||||||
|
|
||||||
|
REM Update Pi extension if pi is installed
|
||||||
|
where pi >nul 2>&1
|
||||||
|
if !ERRORLEVEL! equ 0 (
|
||||||
|
echo Updating Pi extension...
|
||||||
|
pi install npm:@plannotator/pi-extension
|
||||||
|
echo Pi extension updated.
|
||||||
|
)
|
||||||
|
|
||||||
REM Install /review slash command
|
REM Install /review slash command
|
||||||
if defined CLAUDE_CONFIG_DIR (
|
if defined CLAUDE_CONFIG_DIR (
|
||||||
set "CLAUDE_COMMANDS_DIR=%CLAUDE_CONFIG_DIR%\commands"
|
set "CLAUDE_COMMANDS_DIR=%CLAUDE_CONFIG_DIR%\commands"
|
||||||
|
|||||||
@@ -110,6 +110,13 @@ if (Test-Path $pluginHooks) {
|
|||||||
Remove-Item -Recurse -Force "$env:USERPROFILE\.cache\opencode\node_modules\@plannotator" -ErrorAction SilentlyContinue
|
Remove-Item -Recurse -Force "$env:USERPROFILE\.cache\opencode\node_modules\@plannotator" -ErrorAction SilentlyContinue
|
||||||
Remove-Item -Recurse -Force "$env:USERPROFILE\.bun\install\cache\@plannotator" -ErrorAction SilentlyContinue
|
Remove-Item -Recurse -Force "$env:USERPROFILE\.bun\install\cache\@plannotator" -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
# Update Pi extension if pi is installed
|
||||||
|
if (Get-Command pi -ErrorAction SilentlyContinue) {
|
||||||
|
Write-Host "Updating Pi extension..."
|
||||||
|
pi install npm:@plannotator/pi-extension
|
||||||
|
Write-Host "Pi extension updated."
|
||||||
|
}
|
||||||
|
|
||||||
# Install Claude Code slash command
|
# Install Claude Code slash command
|
||||||
$claudeCommandsDir = if ($env:CLAUDE_CONFIG_DIR) { "$env:CLAUDE_CONFIG_DIR\commands" } else { "$env:USERPROFILE\.claude\commands" }
|
$claudeCommandsDir = if ($env:CLAUDE_CONFIG_DIR) { "$env:CLAUDE_CONFIG_DIR\commands" } else { "$env:USERPROFILE\.claude\commands" }
|
||||||
New-Item -ItemType Directory -Force -Path $claudeCommandsDir | Out-Null
|
New-Item -ItemType Directory -Force -Path $claudeCommandsDir | Out-Null
|
||||||
|
|||||||
@@ -110,6 +110,13 @@ fi
|
|||||||
# Clear any cached OpenCode plugin to force fresh download on next run
|
# Clear any cached OpenCode plugin to force fresh download on next run
|
||||||
rm -rf "$HOME/.cache/opencode/node_modules/@plannotator" "$HOME/.bun/install/cache/@plannotator" 2>/dev/null || true
|
rm -rf "$HOME/.cache/opencode/node_modules/@plannotator" "$HOME/.bun/install/cache/@plannotator" 2>/dev/null || true
|
||||||
|
|
||||||
|
# Update Pi extension if pi is installed
|
||||||
|
if command -v pi &>/dev/null; then
|
||||||
|
echo "Updating Pi extension..."
|
||||||
|
pi install npm:@plannotator/pi-extension
|
||||||
|
echo "Pi extension updated."
|
||||||
|
fi
|
||||||
|
|
||||||
# Install /review slash command
|
# Install /review slash command
|
||||||
CLAUDE_COMMANDS_DIR="${CLAUDE_CONFIG_DIR:-$HOME/.claude}/commands"
|
CLAUDE_COMMANDS_DIR="${CLAUDE_CONFIG_DIR:-$HOME/.claude}/commands"
|
||||||
mkdir -p "$CLAUDE_COMMANDS_DIR"
|
mkdir -p "$CLAUDE_COMMANDS_DIR"
|
||||||
|
|||||||
Reference in New Issue
Block a user