mirror of
https://github.com/0xWheatyz/handler.git
synced 2026-08-30 04:36:24 +00:00
feat(login): open the login URL in an OAuth-style popup, not an iframe
claude.com refuses to be embedded in an iframe (X-Frame-Options), so the inline frame just showed a blocked page. Replace it with a small popup window, like a "Sign in with Google" flow: the "Log in to Claude" click opens a blank popup (within the user gesture, so it isn't popup-blocked) and, once login_start returns the URL, the popup is navigated to it. Buttons to reopen the window or open the URL in a new tab remain as fallbacks, and the popup is closed on success/error. README updated to match. Rebuilt static export. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YKVyBmKvWDVgrFC9WER2f2
This commit is contained in:
@@ -243,13 +243,17 @@ pane logs it in from the browser — the same command-queue handoff every other
|
|||||||
action uses:
|
action uses:
|
||||||
|
|
||||||
1. **Log in to Claude** enqueues a `login_start` command. The worker opens `claude` in a
|
1. **Log in to Claude** enqueues a `login_start` command. The worker opens `claude` in a
|
||||||
dedicated tmux session in the control container, sends `/login`, selects the **Claude
|
dedicated (wide) tmux session in the control container, navigates whatever onboarding a
|
||||||
account with subscription** option, and scrapes the pane for the `claude.com`
|
fresh `claude` shows (theme picker, folder-trust) to the **Claude account with
|
||||||
authorization URL — returned in the command result.
|
subscription** login, and scrapes the pane for the `claude.com` authorization URL —
|
||||||
2. The UI opens that URL in an embedded frame (with a new-tab link as a fallback, since
|
returned in the command result.
|
||||||
claude.com may refuse to be framed). You authorize and Claude gives you a code.
|
2. The UI opens that URL in a small **OAuth-style popup window** (like "Sign in with …";
|
||||||
3. **Finish login** enqueues a `login_submit` command carrying the code; the worker feeds
|
claude.com refuses to be embedded in an iframe, so a popup is the right surface), with
|
||||||
it into the still-open session, waits for claude to exchange it, and reports success.
|
a new-tab link as a fallback. You authorize there and Claude gives you a code.
|
||||||
|
3. **Finish login** enqueues a `login_submit` command carrying the code; the worker pastes
|
||||||
|
it into the still-open session and presses Enter separately (a long code plus an
|
||||||
|
immediate Enter races the TUI and never submits), then confirms by watching claude write
|
||||||
|
its credentials.
|
||||||
|
|
||||||
The login session lives in the control container, and Claude's credentials land under the
|
The login session lives in the control container, and Claude's credentials land under the
|
||||||
`handler` user's home on the `/var/lib/handler` volume — so the login **persists** across
|
`handler` user's home on the `/var/lib/handler` volume — so the login **persists** across
|
||||||
|
|||||||
@@ -1,24 +1,64 @@
|
|||||||
/* Claude Login — drive the bundled `claude /login` OAuth flow on the host from the web UI.
|
/* Claude Login — drive the bundled `claude /login` OAuth flow on the host from the web UI.
|
||||||
*
|
*
|
||||||
* Click "Log in to Claude" → the worker opens `claude /login` in the control container,
|
* Click "Log in to Claude" → a small OAuth-style popup window opens (like "Sign in with
|
||||||
* selects the subscription account, and returns the claude.com authorization URL. That URL
|
* Google") and the worker drives `claude /login` in the control container, selecting the
|
||||||
* is shown in an embedded frame (and as a new-tab link, since claude.com may refuse to be
|
* subscription account and returning the claude.com authorization URL, which we point the
|
||||||
* framed); after authorizing, paste the code back to finish. All state lives in the store's
|
* popup at. (claude.com refuses to be embedded in an iframe, so a popup — not an inline
|
||||||
* `claudeLogin` machine (login_start / login_submit commands). */
|
* frame — is the right surface.) You authorize there, copy the code, and paste it back to
|
||||||
|
* finish. All state lives in the store's `claudeLogin` machine (login_start / login_submit
|
||||||
|
* commands). */
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { useDashboard } from "@/components/store";
|
import { useDashboard } from "@/components/store";
|
||||||
import { Button, Callout, Input } from "@/components/ui";
|
import { Button, Callout, Input } from "@/components/ui";
|
||||||
|
|
||||||
|
function openLoginPopup(url: string): Window | null {
|
||||||
|
const w = 520;
|
||||||
|
const h = 760;
|
||||||
|
// Center over the current window; specifying a size makes browsers open a popup window
|
||||||
|
// (the "Sign in with …" surface) rather than a new tab.
|
||||||
|
const left = window.screenX + Math.max(0, (window.outerWidth - w) / 2);
|
||||||
|
const top = window.screenY + Math.max(0, (window.outerHeight - h) / 2);
|
||||||
|
return window.open(
|
||||||
|
url,
|
||||||
|
"claude-login",
|
||||||
|
`popup=yes,width=${w},height=${h},left=${Math.round(left)},top=${Math.round(top)}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function LoginSection() {
|
export function LoginSection() {
|
||||||
const s = useDashboard();
|
const s = useDashboard();
|
||||||
const { status, url, message } = s.claudeLogin;
|
const { status, url, message } = s.claudeLogin;
|
||||||
const [code, setCode] = useState("");
|
const [code, setCode] = useState("");
|
||||||
|
const popupRef = useRef<Window | null>(null);
|
||||||
|
|
||||||
const busy = status === "starting" || status === "submitting";
|
const busy = status === "starting" || status === "submitting";
|
||||||
const awaiting = status === "awaiting" || status === "submitting";
|
const awaiting = status === "awaiting" || status === "submitting";
|
||||||
|
|
||||||
|
// Open a blank popup *within the click* (below) so browsers don't block it; once
|
||||||
|
// login_start returns the URL, navigate that same popup to it.
|
||||||
|
useEffect(() => {
|
||||||
|
if (status === "awaiting" && url && popupRef.current && !popupRef.current.closed) {
|
||||||
|
try {
|
||||||
|
popupRef.current.location.href = url;
|
||||||
|
} catch {
|
||||||
|
/* cross-origin after navigation — expected, ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (status === "done" || status === "error") {
|
||||||
|
popupRef.current?.close();
|
||||||
|
popupRef.current = null;
|
||||||
|
}
|
||||||
|
}, [status, url]);
|
||||||
|
|
||||||
|
const start = () => {
|
||||||
|
// Open the popup now, on the user gesture, to a lightweight loading page; the effect
|
||||||
|
// above redirects it to the real URL when it arrives.
|
||||||
|
popupRef.current = openLoginPopup("about:blank");
|
||||||
|
void s.startClaudeLogin();
|
||||||
|
};
|
||||||
|
|
||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
const ok = await s.submitClaudeCode(code);
|
const ok = await s.submitClaudeCode(code);
|
||||||
if (ok) setCode("");
|
if (ok) setCode("");
|
||||||
@@ -50,48 +90,42 @@ export function LoginSection() {
|
|||||||
</div>
|
</div>
|
||||||
) : !awaiting ? (
|
) : !awaiting ? (
|
||||||
<div className="hstack" style={{ gap: 10 }}>
|
<div className="hstack" style={{ gap: 10 }}>
|
||||||
<Button variant="primary" disabled={busy} onClick={s.startClaudeLogin}>
|
<Button variant="primary" disabled={busy} onClick={start}>
|
||||||
{status === "starting" ? "Starting…" : "Log in to Claude"}
|
{status === "starting" ? "Starting…" : "Log in to Claude"}
|
||||||
</Button>
|
</Button>
|
||||||
{status === "error" && (
|
{status === "error" && (
|
||||||
<Button variant="ghost" disabled={busy} onClick={s.startClaudeLogin}>
|
<Button variant="ghost" disabled={busy} onClick={start}>
|
||||||
Retry
|
Retry
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
<Callout tone="info">
|
||||||
|
A Claude sign-in window should have opened. Authorize there, copy the code
|
||||||
|
Claude shows you, and paste it below. If the window didn't open (popups
|
||||||
|
blocked), use the button.
|
||||||
|
</Callout>
|
||||||
<div className="hstack" style={{ gap: 10, flexWrap: "wrap" }}>
|
<div className="hstack" style={{ gap: 10, flexWrap: "wrap" }}>
|
||||||
<a className="btn btn-secondary" href={url} target="_blank" rel="noopener noreferrer">
|
<Button
|
||||||
Open login page in a new tab ↗
|
variant="secondary"
|
||||||
</a>
|
disabled={!url}
|
||||||
<Button variant="ghost" disabled={busy} onClick={s.startClaudeLogin}>
|
onClick={() => {
|
||||||
|
if (url) popupRef.current = openLoginPopup(url);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Open Claude sign-in window ↗
|
||||||
|
</Button>
|
||||||
|
{url && (
|
||||||
|
<a className="btn btn-ghost" href={url} target="_blank" rel="noopener noreferrer">
|
||||||
|
Open in a new tab
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
<Button variant="ghost" disabled={busy} onClick={start}>
|
||||||
Restart
|
Restart
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
border: "1px solid var(--border-default)",
|
|
||||||
borderRadius: 10,
|
|
||||||
overflow: "hidden",
|
|
||||||
height: 460,
|
|
||||||
background: "var(--surface-1, #111)",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<iframe
|
|
||||||
title="Claude login"
|
|
||||||
src={url}
|
|
||||||
style={{ width: "100%", height: "100%", border: "none" }}
|
|
||||||
sandbox="allow-forms allow-scripts allow-same-origin allow-popups"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="faint" style={{ fontSize: "var(--text-xs)" }}>
|
|
||||||
If the frame stays blank, claude.com is refusing to be embedded — use the
|
|
||||||
new-tab link above instead. The login session stays open until you submit the
|
|
||||||
code or restart.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="hstack" style={{ gap: 10, alignItems: "flex-end", flexWrap: "wrap" }}>
|
<div className="hstack" style={{ gap: 10, alignItems: "flex-end", flexWrap: "wrap" }}>
|
||||||
<div style={{ flex: "1 1 320px" }}>
|
<div style={{ flex: "1 1 320px" }}>
|
||||||
<Input
|
<Input
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
|||||||
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/css/bbd6ee1e7265be74.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-29957205745576aa.js"/><script src="/_next/static/chunks/fd9d1056-8edc3f3573e7d5e5.js" async=""></script><script src="/_next/static/chunks/117-e7bb738621b70d3f.js" async=""></script><script src="/_next/static/chunks/main-app-8321800782c5a11e.js" async=""></script><script src="/_next/static/chunks/app/page-aaee823ffe4c78c3.js" async=""></script><title>Handler · Claude Activity</title><meta name="description" content="Monitor and manage Claude Code agents across projects."/><link rel="icon" href="/icon.svg?bab509b45a421e43" type="image/svg+xml" sizes="any"/><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><div class="gate"><form class="gate-card"><div class="gate-brand"><span class="logo" style="width:26px;height:26px;border-radius:7px"></span>Claude Monitor</div><p class="muted" style="font-size:var(--text-sm);margin:0">Paste your API token to continue. Management actions require the admin token; read-only views work with the plain auth token.</p><input class="input" type="password" autoComplete="current-password" placeholder="API token" autofocus="" value=""/><button class="btn btn-primary" type="submit">Continue</button></form></div><script src="/_next/static/chunks/webpack-29957205745576aa.js" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0]);self.__next_f.push([2,null])</script><script>self.__next_f.push([1,"1:HL[\"/_next/static/css/bbd6ee1e7265be74.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"2:I[2846,[],\"\"]\n4:I[9107,[],\"ClientPageRoot\"]\n5:I[9859,[\"931\",\"static/chunks/app/page-aaee823ffe4c78c3.js\"],\"default\",1]\n6:I[4707,[],\"\"]\n7:I[6423,[],\"\"]\n9:I[1060,[],\"\"]\na:[]\n0:[\"$\",\"$L2\",null,{\"buildId\":\"J55muUx2ya8M2SQERVlYt\",\"assetPrefix\":\"\",\"urlParts\":[\"\",\"\"],\"initialTree\":[\"\",{\"children\":[\"__PAGE__\",{}]},\"$undefined\",\"$undefined\",true],\"initialSeedData\":[\"\",{\"children\":[\"__PAGE__\",{},[[\"$L3\",[\"$\",\"$L4\",null,{\"props\":{\"params\":{},\"searchParams\":{}},\"Component\":\"$5\"}],null],null],null]},[[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/bbd6ee1e7265be74.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"children\":[\"$\",\"body\",null,{\"children\":[\"$\",\"$L6\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L7\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":\"404\"}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],\"notFoundStyl"])</script><script>self.__next_f.push([1,"es\":[]}]}]}]],null],null],\"couldBeIntercepted\":false,\"initialHead\":[null,\"$L8\"],\"globalErrorComponent\":\"$9\",\"missingSlots\":\"$Wa\"}]\n"])</script><script>self.__next_f.push([1,"8:[[\"$\",\"meta\",\"0\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"1\",{\"charSet\":\"utf-8\"}],[\"$\",\"title\",\"2\",{\"children\":\"Handler · Claude Activity\"}],[\"$\",\"meta\",\"3\",{\"name\":\"description\",\"content\":\"Monitor and manage Claude Code agents across projects.\"}],[\"$\",\"link\",\"4\",{\"rel\":\"icon\",\"href\":\"/icon.svg?bab509b45a421e43\",\"type\":\"image/svg+xml\",\"sizes\":\"any\"}]]\n3:null\n"])</script></body></html>
|
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/css/bbd6ee1e7265be74.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-29957205745576aa.js"/><script src="/_next/static/chunks/fd9d1056-8edc3f3573e7d5e5.js" async=""></script><script src="/_next/static/chunks/117-e7bb738621b70d3f.js" async=""></script><script src="/_next/static/chunks/main-app-8321800782c5a11e.js" async=""></script><script src="/_next/static/chunks/app/page-5b19e394a5d5460f.js" async=""></script><title>Handler · Claude Activity</title><meta name="description" content="Monitor and manage Claude Code agents across projects."/><link rel="icon" href="/icon.svg?bab509b45a421e43" type="image/svg+xml" sizes="any"/><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body><div class="gate"><form class="gate-card"><div class="gate-brand"><span class="logo" style="width:26px;height:26px;border-radius:7px"></span>Claude Monitor</div><p class="muted" style="font-size:var(--text-sm);margin:0">Paste your API token to continue. Management actions require the admin token; read-only views work with the plain auth token.</p><input class="input" type="password" autoComplete="current-password" placeholder="API token" autofocus="" value=""/><button class="btn btn-primary" type="submit">Continue</button></form></div><script src="/_next/static/chunks/webpack-29957205745576aa.js" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0]);self.__next_f.push([2,null])</script><script>self.__next_f.push([1,"1:HL[\"/_next/static/css/bbd6ee1e7265be74.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"2:I[2846,[],\"\"]\n4:I[9107,[],\"ClientPageRoot\"]\n5:I[9859,[\"931\",\"static/chunks/app/page-5b19e394a5d5460f.js\"],\"default\",1]\n6:I[4707,[],\"\"]\n7:I[6423,[],\"\"]\n9:I[1060,[],\"\"]\na:[]\n0:[\"$\",\"$L2\",null,{\"buildId\":\"UFaQ4h6X_9jNfr8PwK2IS\",\"assetPrefix\":\"\",\"urlParts\":[\"\",\"\"],\"initialTree\":[\"\",{\"children\":[\"__PAGE__\",{}]},\"$undefined\",\"$undefined\",true],\"initialSeedData\":[\"\",{\"children\":[\"__PAGE__\",{},[[\"$L3\",[\"$\",\"$L4\",null,{\"props\":{\"params\":{},\"searchParams\":{}},\"Component\":\"$5\"}],null],null],null]},[[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/bbd6ee1e7265be74.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"children\":[\"$\",\"body\",null,{\"children\":[\"$\",\"$L6\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L7\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":\"404\"}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],\"notFoundStyl"])</script><script>self.__next_f.push([1,"es\":[]}]}]}]],null],null],\"couldBeIntercepted\":false,\"initialHead\":[null,\"$L8\"],\"globalErrorComponent\":\"$9\",\"missingSlots\":\"$Wa\"}]\n"])</script><script>self.__next_f.push([1,"8:[[\"$\",\"meta\",\"0\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"1\",{\"charSet\":\"utf-8\"}],[\"$\",\"title\",\"2\",{\"children\":\"Handler · Claude Activity\"}],[\"$\",\"meta\",\"3\",{\"name\":\"description\",\"content\":\"Monitor and manage Claude Code agents across projects.\"}],[\"$\",\"link\",\"4\",{\"rel\":\"icon\",\"href\":\"/icon.svg?bab509b45a421e43\",\"type\":\"image/svg+xml\",\"sizes\":\"any\"}]]\n3:null\n"])</script></body></html>
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
2:I[9107,[],"ClientPageRoot"]
|
2:I[9107,[],"ClientPageRoot"]
|
||||||
3:I[9859,["931","static/chunks/app/page-aaee823ffe4c78c3.js"],"default",1]
|
3:I[9859,["931","static/chunks/app/page-5b19e394a5d5460f.js"],"default",1]
|
||||||
4:I[4707,[],""]
|
4:I[4707,[],""]
|
||||||
5:I[6423,[],""]
|
5:I[6423,[],""]
|
||||||
0:["J55muUx2ya8M2SQERVlYt",[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/bbd6ee1e7265be74.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]],null],null],["$L6",null]]]]
|
0:["UFaQ4h6X_9jNfr8PwK2IS",[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",true],["",{"children":["__PAGE__",{},[["$L1",["$","$L2",null,{"props":{"params":{},"searchParams":{}},"Component":"$3"}],null],null],null]},[[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/bbd6ee1e7265be74.css","precedence":"next","crossOrigin":"$undefined"}]],["$","html",null,{"lang":"en","children":["$","body",null,{"children":["$","$L4",null,{"parallelRouterKey":"children","segmentPath":["children"],"error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L5",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"notFoundStyles":[]}]}]}]],null],null],["$L6",null]]]]
|
||||||
6:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Handler · Claude Activity"}],["$","meta","3",{"name":"description","content":"Monitor and manage Claude Code agents across projects."}],["$","link","4",{"rel":"icon","href":"/icon.svg?bab509b45a421e43","type":"image/svg+xml","sizes":"any"}]]
|
6:[["$","meta","0",{"name":"viewport","content":"width=device-width, initial-scale=1"}],["$","meta","1",{"charSet":"utf-8"}],["$","title","2",{"children":"Handler · Claude Activity"}],["$","meta","3",{"name":"description","content":"Monitor and manage Claude Code agents across projects."}],["$","link","4",{"rel":"icon","href":"/icon.svg?bab509b45a421e43","type":"image/svg+xml","sizes":"any"}]]
|
||||||
1:null
|
1:null
|
||||||
|
|||||||
Reference in New Issue
Block a user