diff --git a/src/workspaces/helpers/clipboard.ts b/src/workspaces/helpers/clipboard.ts index dfb37c3f..6213e920 100644 --- a/src/workspaces/helpers/clipboard.ts +++ b/src/workspaces/helpers/clipboard.ts @@ -7,9 +7,12 @@ * is not localhost the whole object is undefined, so `navigator.clipboard.writeText` * throws `TypeError: Cannot read properties of undefined`. * - * Officer is reached over the tailnet — `http://officer-dev:9000` — which is - * neither https nor localhost. Twenty call sites were affected, in three states - * that all looked fine in review: + * Officer is reachable over plain http — `http://officer-dev:9000` on the tailnet — + * which is neither https nor localhost. The owner's own browsing is over https + * (`platform.officer.dev`) and was already https when this was written; the http + * origins are the other ways in, and an install with no certificate has no other + * way in at all. Twenty call sites were affected, in three states that all looked + * fine in review: * * bare `navigator.clipboard.writeText(x)` threw, killing the handler * `navigator.clipboard?.writeText(x)` did nothing, silently diff --git a/src/workspaces/officerdev/src/apps/Chat/components/ClaudeLoginDialog.tsx b/src/workspaces/officerdev/src/apps/Chat/components/ClaudeLoginDialog.tsx index 043d0294..9b7a0dc8 100644 --- a/src/workspaces/officerdev/src/apps/Chat/components/ClaudeLoginDialog.tsx +++ b/src/workspaces/officerdev/src/apps/Chat/components/ClaudeLoginDialog.tsx @@ -1,9 +1,10 @@ import { useEffect, useRef, useState } from 'react'; -import { Check, ExternalLink, Loader2 } from 'lucide-react'; +import { Check, Copy, ExternalLink, Loader2 } from 'lucide-react'; import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { Input } from '@/components/ui/input'; import { useClient } from 'hooks/useClient'; import { errorText } from 'helpers/error-text'; +import { copyToClipboard } from 'helpers/clipboard'; /* `/login` — the same flow as the terminal, without the terminal. @@ -29,6 +30,7 @@ export const ClaudeLoginDialog = ({ open, onOpenChange }: Props) => { const [busy, setBusy] = useState(false); const [error, setError] = useState(null); const [done, setDone] = useState(false); + const [copied, setCopied] = useState(false); const codeRef = useRef(null); // Start on open, and abandon on close. The server holds a live `claude` process per pending login, so a @@ -101,17 +103,38 @@ export const ClaudeLoginDialog = ({ open, onOpenChange }: Props) => {

Open this, authorise, and paste back the code it gives you.

- {/* A real anchor. Every link here opens a new tab, which is what you want for this one — - losing the dialog would lose the process holding the other half of the exchange. */} - - Authorise in claude.com - - +
+ {/* A real anchor. Every link here opens a new tab, which is what you want for this one — + losing the dialog would lose the process holding the other half of the exchange. */} + + Authorise in claude.com + + + {/* Copy, because opening here opens in THIS browser — already signed into whichever account + you are trying to move away from. Pasting into another profile or another device is how + you sign in as somebody else, and this dialog exists precisely for the machine with two + Anthropic accounts on it. */} + +