claude-code/components/DesktopHandoff.tsx

193 lines
19 KiB
TypeScript
Raw Normal View History

import { c as _c } from "react/compiler-runtime";
import React, { useEffect, useState } from 'react';
import type { CommandResultDisplay } from '../commands.js';
// eslint-disable-next-line custom-rules/prefer-use-keybindings -- raw input for "any key" dismiss and y/n prompt
import { Box, Text, useInput } from '../ink.js';
import { openBrowser } from '../utils/browser.js';
import { getDesktopInstallStatus, openCurrentSessionInDesktop } from '../utils/desktopDeepLink.js';
import { errorMessage } from '../utils/errors.js';
import { gracefulShutdown } from '../utils/gracefulShutdown.js';
import { flushSessionStorage } from '../utils/sessionStorage.js';
import { LoadingState } from './design-system/LoadingState.js';
const DESKTOP_DOCS_URL = 'https://clau.de/desktop';
export function getDownloadUrl(): string {
switch (process.platform) {
case 'win32':
return 'https://claude.ai/api/desktop/win32/x64/exe/latest/redirect';
default:
return 'https://claude.ai/api/desktop/darwin/universal/dmg/latest/redirect';
}
}
type DesktopHandoffState = 'checking' | 'prompt-download' | 'flushing' | 'opening' | 'success' | 'error';
type Props = {
onDone: (result?: string, options?: {
display?: CommandResultDisplay;
}) => void;
};
export function DesktopHandoff(t0) {
const $ = _c(20);
const {
onDone
} = t0;
const [state, setState] = useState("checking");
const [error, setError] = useState(null);
const [downloadMessage, setDownloadMessage] = useState("");
let t1;
if ($[0] !== error || $[1] !== onDone || $[2] !== state) {
t1 = input => {
if (state === "error") {
onDone(error ?? "Unknown error", {
display: "system"
});
return;
}
if (state === "prompt-download") {
if (input === "y" || input === "Y") {
openBrowser(getDownloadUrl()).catch(_temp);
onDone(`Starting download. Re-run /desktop once you\u2019ve installed the app.\nLearn more at ${DESKTOP_DOCS_URL}`, {
display: "system"
});
} else {
if (input === "n" || input === "N") {
onDone(`The desktop app is required for /desktop. Learn more at ${DESKTOP_DOCS_URL}`, {
display: "system"
});
}
}
}
};
$[0] = error;
$[1] = onDone;
$[2] = state;
$[3] = t1;
} else {
t1 = $[3];
}
useInput(t1);
let t2;
let t3;
if ($[4] !== onDone) {
t2 = () => {
const performHandoff = async function performHandoff() {
setState("checking");
const installStatus = await getDesktopInstallStatus();
if (installStatus.status === "not-installed") {
setDownloadMessage("Claude Desktop is not installed.");
setState("prompt-download");
return;
}
if (installStatus.status === "version-too-old") {
setDownloadMessage(`Claude Desktop needs to be updated (found v${installStatus.version}, need v1.1.2396+).`);
setState("prompt-download");
return;
}
setState("flushing");
await flushSessionStorage();
setState("opening");
const result = await openCurrentSessionInDesktop();
if (!result.success) {
setError(result.error ?? "Failed to open Claude Desktop");
setState("error");
return;
}
setState("success");
setTimeout(_temp2, 500, onDone);
};
performHandoff().catch(err => {
setError(errorMessage(err));
setState("error");
});
};
t3 = [onDone];
$[4] = onDone;
$[5] = t2;
$[6] = t3;
} else {
t2 = $[5];
t3 = $[6];
}
useEffect(t2, t3);
if (state === "error") {
let t4;
if ($[7] !== error) {
t4 = <Text color="error">Error: {error}</Text>;
$[7] = error;
$[8] = t4;
} else {
t4 = $[8];
}
let t5;
if ($[9] === Symbol.for("react.memo_cache_sentinel")) {
t5 = <Text dimColor={true}>Press any key to continue</Text>;
$[9] = t5;
} else {
t5 = $[9];
}
let t6;
if ($[10] !== t4) {
t6 = <Box flexDirection="column" paddingX={2}>{t4}{t5}</Box>;
$[10] = t4;
$[11] = t6;
} else {
t6 = $[11];
}
return t6;
}
if (state === "prompt-download") {
let t4;
if ($[12] !== downloadMessage) {
t4 = <Text>{downloadMessage}</Text>;
$[12] = downloadMessage;
$[13] = t4;
} else {
t4 = $[13];
}
let t5;
if ($[14] === Symbol.for("react.memo_cache_sentinel")) {
t5 = <Text>Download now? (y/n)</Text>;
$[14] = t5;
} else {
t5 = $[14];
}
let t6;
if ($[15] !== t4) {
t6 = <Box flexDirection="column" paddingX={2}>{t4}{t5}</Box>;
$[15] = t4;
$[16] = t6;
} else {
t6 = $[16];
}
return t6;
}
let t4;
if ($[17] === Symbol.for("react.memo_cache_sentinel")) {
t4 = {
checking: "Checking for Claude Desktop\u2026",
flushing: "Saving session\u2026",
opening: "Opening Claude Desktop\u2026",
success: "Opening in Claude Desktop\u2026"
};
$[17] = t4;
} else {
t4 = $[17];
}
const messages = t4;
const t5 = messages[state];
let t6;
if ($[18] !== t5) {
t6 = <LoadingState message={t5} />;
$[18] = t5;
$[19] = t6;
} else {
t6 = $[19];
}
return t6;
}
async function _temp2(onDone_0) {
onDone_0("Session transferred to Claude Desktop", {
display: "system"
});
await gracefulShutdown(0, "other");
}
function _temp() {}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsInVzZUVmZmVjdCIsInVzZVN0YXRlIiwiQ29tbWFuZFJlc3VsdERpc3BsYXkiLCJCb3giLCJUZXh0IiwidXNlSW5wdXQiLCJvcGVuQnJvd3NlciIsImdldERlc2t0b3BJbnN0YWxsU3RhdHVzIiwib3BlbkN1cnJlbnRTZXNzaW9uSW5EZXNrdG9wIiwiZXJyb3JNZXNzYWdlIiwiZ3JhY2VmdWxTaHV0ZG93biIsImZsdXNoU2Vzc2lvblN0b3JhZ2UiLCJMb2FkaW5nU3RhdGUiLCJERVNLVE9QX0RPQ1NfVVJMIiwiZ2V0RG93bmxvYWRVcmwiLCJwcm9jZXNzIiwicGxhdGZvcm0iLCJEZXNrdG9wSGFuZG9mZlN0YXRlIiwiUHJvcHMiLCJvbkRvbmUiLCJyZXN1bHQiLCJvcHRpb25zIiwiZGlzcGxheSIsIkRlc2t0b3BIYW5kb2ZmIiwidDAiLCIkIiwiX2MiLCJzdGF0ZSIsInNldFN0YXRlIiwiZXJyb3IiLCJzZXRFcnJvciIsImRvd25sb2FkTWVzc2FnZSIsInNldERvd25sb2FkTWVzc2FnZSIsInQxIiwiaW5wdXQiLCJjYXRjaCIsIl90ZW1wIiwidDIiLCJ0MyIsInBlcmZvcm1IYW5kb2ZmIiwiaW5zdGFsbFN0YXR1cyIsInN0YXR1cyIsInZlcnNpb24iLCJzdWNjZXNzIiwic2V0VGltZW91dCIsIl90ZW1wMiIsImVyciIsInQ0IiwidDUiLCJTeW1ib2wiLCJmb3IiLCJ0NiIsImNoZWNraW5nIiwiZmx1c2hpbmciLCJvcGVuaW5nIiwibWVzc2FnZXMiLCJvbkRvbmVfMCJdLCJzb3VyY2VzIjpbIkRlc2t0b3BIYW5kb2ZmLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgUmVhY3QsIHsgdXNlRWZmZWN0LCB1c2VTdGF0ZSB9IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHR5cGUgeyBDb21tYW5kUmVzdWx0RGlzcGxheSB9IGZyb20gJy4uL2NvbW1hbmRzLmpzJ1xuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGN1c3RvbS1ydWxlcy9wcmVmZXItdXNlLWtleWJpbmRpbmdzIC0tIHJhdyBpbnB1dCBmb3IgXCJhbnkga2V5XCIgZGlzbWlzcyBhbmQgeS9uIHByb21wdFxuaW1wb3J0IHsgQm94LCBUZXh0LCB1c2VJbnB1dCB9IGZyb20gJy4uL2luay5qcydcbmltcG9ydCB7IG9wZW5Ccm93c2VyIH0gZnJvbSAnLi4vdXRpbHMvYnJvd3Nlci5qcydcbmltcG9ydCB7XG4gIGdldERlc2t0b3BJbnN0YWxsU3RhdHVzLFxuICBvcGVuQ3VycmVudFNlc3Npb25JbkRlc2t0b3AsXG59IGZyb20gJy4uL3V0aWxzL2Rlc2t0b3BEZWVwTGluay5qcydcbmltcG9ydCB7IGVycm9yTWVzc2FnZSB9IGZyb20gJy4uL3V0aWxzL2Vycm9ycy5qcydcbmltcG9ydCB7IGdyYWNlZnVsU2h1dGRvd24gfSBmcm9tICcuLi91dGlscy9ncmFjZWZ1bFNodXRkb3duLmpzJ1xuaW1wb3J0IHsgZmx1c2hTZXNzaW9uU3RvcmFnZSB9IGZyb20gJy4uL3V0aWxzL3Nlc3Npb25TdG9yYWdlLmpzJ1xuaW1wb3J0IHsgTG9hZGluZ1N0YXRlIH0gZnJvbSAnLi9kZXNpZ24tc3lzdGVtL0xvYWRpbmdTdGF0ZS5qcydcblxuY29uc3QgREVTS1RPUF9ET0NTX1VSTCA9ICdodHRwczovL2NsYXUuZGUvZGVza3RvcCdcblxuZXhwb3J0IGZ1bmN0aW9uIGdldERvd25sb2FkVXJsKCk6IHN0cmluZyB7XG4gIHN3aXRjaCAocHJvY2Vzcy5wbGF0Zm9ybSkge1xuICAgIGNhc2UgJ3dpbjMyJzpcbiAgICAgIHJldHVybiAnaHR0cHM6Ly9jbGF1ZGUuYWkvYXBpL2Rlc2t0b3Avd2luMzIveDY0L2V4ZS9sYXRlc3QvcmVkaXJlY3QnXG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiAnaHR0cHM6Ly9jbGF1ZGUuYWkvYXBpL2Rlc2t0b3AvZGFyd2luL3VuaXZlcnNhbC9kbWcvbGF0ZXN0L3JlZGlyZWN0J1xuICB9XG59XG5cbnR5cGUgRGVza3RvcEhhbmRvZmZTdGF0ZSA9XG4gIHwgJ2NoZWNraW5nJ1xuICB8ICdwcm9tcHQtZG93bmxvYWQnXG4gIHwgJ2ZsdXNoaW5nJ1xuICB8ICdvcGVuaW5nJ1xuICB8ICdzdWNjZXNzJ1xuICB8ICdlcnJvcidcblxudHlwZSBQcm9wcyA9IHtcbiAgb25Eb25lOiAoXG4gICAgcmVzdWx0Pzogc3RyaW5nLFxuICAgIG9wdGlvbnM/OiB7IGRpc3BsYXk/OiBDb21tYW5kUmVzdWx0RGlzcGxheSB9LFxuICApID0+IHZvaWRcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIERlc2t0b3BIYW5kb2ZmKHsgb25Eb25lIH06IFByb3BzKTogUmVhY3QuUmVhY3ROb2RlIHtcbiAgY29uc3QgW3N0YXRlLCBzZXRTdGF0ZV0gPSB1c2VTdGF0ZTxEZXNrdG9wSGFuZG9mZlN0YXRlPignY2hlY2tpbmcnKVxuICBjb25zdCBbZXJyb3IsIHNldEVycm9yXSA9IHVzZVN0YXRlPHN0cmluZyB8IG51bGw+KG51bGwpXG4gIGNvbnN0IFtkb3dubG9hZE1lc3NhZ2UsIHNldERvd25sb2FkTWVzc2FnZV0gPSB1c2VTdGF0ZTxzdHJpbmc+KCcnKVxuXG4gIC8vIEhhbmRsZSBrZXlib2FyZCBpbnB1dCBmb3IgZXJyb3IgYW5kIHByb21wdC1kb3dubG9hZCBzdGF0ZXNcbiAgdXNlSW5wdXQoaW5wdXQgPT4ge1xuICAgIGlmIChzdGF0ZSA9PT0gJ2Vycm9yJykge1xuICAgICAgb25Eb25lKGVycm9yID8/ICdVbmtub3duIGVycm9yJywgeyBkaXNwbGF5OiAnc3lzdGVtJyB9KVxuICAgICAgcmV0dXJuXG4gICAgfVxuICAgIGlmIChzdGF0ZSA9PT0gJ3Byb21wdC1kb3dubG9hZCcpIHtcbiAgICAgIGlmIChpbnB1dCA9PT0gJ3knIHx8IGlucHV0ID09PSAnWScpIHtcbiAgICAgICAgb3BlbkJyb3dzZXIoZ2V0RG93bmxvYWRVcmwoKSkuY2F0Y2goKCkgPT4ge30pXG4gICAgICAgIG9uRG9uZShcbiAgICAgICAgICBgU3RhcnRpbmcgZG93bmxvYWQuIFJlLXJ1biAvZGVza3RvcCBvbmNlIHlvdVxcdTIwMTl2ZSBpbnN0YWxsZWQgdGhlIGFwcC5cXG5MZWFybiBtb3JlIGF0ICR7REVTS1RPUF9ET0NTX1VSTH1gLFxuICAgICAgICAgIHsgZGlzcGxheTogJ3N5c3RlbScgfSxcbiAgICAgICAgKVxuICAgICAgfSBlbHNlIGlmIChpbnB1dCA9PT0gJ24nIHx8IGlucHV0ID09PSAnTicpIHtcbiAgICAgICAgb25Eb25lKFxuICAgICAgICAgIGBUaGUgZGVza3RvcCBhcHAgaXMgcmVxdWlyZWQgZm9yIC9kZXNrdG9wLiBMZWFybiBtb3JlIGF0ICR7REVTS1RPUF9ET0NTX1VSTH1gLFxuICAgICAgICAgIHsgZGlzcGxheTogJ3N5c3RlbScgfSxcbiAgICAgICAgKVxuICAgICAgfVxuICAgIH1cbiA