This commit is contained in:
2026-02-19 18:05:50 +00:00
parent 9870fa7ae8
commit 6a83342013
38 changed files with 1459 additions and 267 deletions
@@ -14,9 +14,10 @@ export const AIHarnessesSection = () => {
const client = useClient();
const queryClient = useQueryClient();
const { aiHarnesses, saveSettings } = useServerSettings();
const [installing, setInstalling] = useState<{ claudeCode: boolean; opencode: boolean }>({
const [installing, setInstalling] = useState<{ claudeCode: boolean; opencode: boolean; piMono: boolean }>({
claudeCode: false,
opencode: false,
piMono: false,
});
const [copied, setCopied] = useState<string | null>(null);
@@ -40,6 +41,16 @@ export const AIHarnessesSection = () => {
},
});
const { data: piMonoVersion, isLoading: piMonoLoading } = useQuery({
queryKey: ['PI_MONO_VERSION'],
queryFn: () => client.get<VersionInfo>('/server-settings/pi-mono/version'),
enabled: !!aiHarnesses?.piMono,
refetchInterval: (query) => {
const data = query.state.data;
return data?.version && !data?.globalPath ? 1000 : false;
},
});
const { data: opencodeAuth } = useQuery({
queryKey: ['OPENCODE_AUTH'],
queryFn: () => client.get<OpencodeAuthInfo>('/server-settings/opencode/auth'),
@@ -54,7 +65,7 @@ export const AIHarnessesSection = () => {
refetchInterval: (query) => (!query.state.data?.authenticated ? 2000 : false),
});
const toggleHarness = (key: 'claudeCode' | 'opencode', checked: boolean) => {
const toggleHarness = (key: 'claudeCode' | 'opencode' | 'piMono', checked: boolean) => {
const updated = { ...aiHarnesses, [key]: checked };
saveSettings({ aiHarnesses: updated });
};
@@ -79,6 +90,16 @@ export const AIHarnessesSection = () => {
}
};
const installPiMono = async () => {
setInstalling((prev) => ({ ...prev, piMono: true }));
try {
const result = await client.post<VersionInfo>('/server-settings/pi-mono/install');
queryClient.setQueryData(['PI_MONO_VERSION'], result);
} finally {
setInstalling((prev) => ({ ...prev, piMono: false }));
}
};
const copyToClipboard = (text: string) => {
navigator.clipboard.writeText(text);
setCopied(text);
@@ -210,6 +231,40 @@ export const AIHarnessesSection = () => {
</div>
)}
</div>
<div>
<label className="flex items-center gap-3 cursor-pointer">
<Checkbox
checked={!!aiHarnesses?.piMono}
onCheckedChange={(checked) => toggleHarness('piMono', !!checked)}
/>
<span className="text-sm font-medium text-duck-dark">Pi</span>
</label>
{aiHarnesses?.piMono && (
<div className="ml-7 mt-2 text-xs text-duck-dark/50">
{piMonoLoading ? (
'Checking version...'
) : piMonoVersion?.version ? (
<>
<div>{piMonoVersion.version}</div>
<div>{piMonoVersion.path}</div>
{!piMonoVersion.globalPath && piMonoVersion.path && (
<CopyCommand command={`sudo ln -s ${piMonoVersion.path} /usr/local/bin/pi`} />
)}
</>
) : (
<Button
size="sm"
className="bg-duck-teal text-duck-yellow hover:bg-duck-teal/90"
onClick={installPiMono}
disabled={installing.piMono}
>
{installing.piMono ? 'Installing...' : 'Install'}
</Button>
)}
</div>
)}
</div>
</div>
);
};