/* Copyright 2026 Marimo. All rights reserved. */ import { CheckIcon, CopyIcon } from "lucide-react"; import React, { useEffect, useState } from "react"; import { Button } from "@/components/ui/button"; import { DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { copyToClipboard } from "@/utils/copy"; import { Events } from "@/utils/events"; import { Tooltip } from "@/components/ui/tooltip"; import { assertNever } from "@/utils/assertNever"; import { asRemoteURL, useRuntimeManager } from "@/core/runtime/config"; import { API } from "@/core/network/api"; type AgentTab = "claude" | "codex" | "opencode"; function getMarimoCommand(): string { return import.meta.env.DEV ? "uv run marimo" : "uvx marimo@latest"; } function getPromptCommand( agent: AgentTab, url: string, withToken: boolean, ): string { const tokenFlag = withToken ? " --with-token" : ""; const base = `${getMarimoCommand()} pair prompt --url '${url}'${tokenFlag}`; switch (agent) { case "claude": return `claude "$(${base} --claude)"`; case "codex": return `codex "$(${base} --codex)"`; case "opencode": return `opencode --prompt "$(${base} --opencode)"`; default: assertNever(agent); } } function maskToken(token: string): string { if (token.length <= 4) { return "****"; } return `${"*".repeat(Math.min(token.length - 4, 8))}${token.slice(-4)}`; } const SKILL_INSTALL = "npx skills add marimo-team/marimo-pair"; function useAuthToken(): string | null { const [token, setToken] = useState(null); useEffect(() => { fetch(asRemoteURL("/auth/token").href, { headers: API.headers(), }) .then((res) => res.ok ? (res.json() as Promise<{ token: string | null }>) : null, ) .then((data) => setToken(data?.token ?? null)) .catch(() => setToken(null)); }, []); return token; } export const PairWithAgentModal: React.FC<{ onClose: () => void; }> = ({ onClose }) => { const [activeTab, setActiveTab] = useState("claude"); const runtimeManager = useRuntimeManager(); const authToken = useAuthToken(); const hasToken = Boolean(authToken); const remoteUrl = runtimeManager.httpURL.toString(); const promptCommand = getPromptCommand(activeTab, remoteUrl, hasToken); return ( Pair with an agent Use an AI coding agent to pair-program on this notebook.{" "} Learn more .
1. Install the skill
2. Run in your terminal setActiveTab(v as AgentTab)} > Claude Codex OpenCode
{hasToken && authToken && (
3. Paste when prompted for token
)}
); }; const CommandBlock: React.FC<{ command: string; display?: string }> = ({ command, display, }) => { const [copied, setCopied] = useState(false); const copy = Events.stopPropagation(async (e) => { e.preventDefault(); await copyToClipboard(command); setCopied(true); setTimeout(() => setCopied(false), 2000); }); return (
{display ?? command}
); };