fix(core): use query param instead of hash fragment for plugin cache-busting
Vite/Vitest's resolver treats `#` as part of the filesystem path in some environments, causing ERR_MODULE_NOT_FOUND on plugin reload. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -130,9 +130,81 @@ export function ClaudeCliProviderCard({
|
||||
</span>
|
||||
);
|
||||
|
||||
const actions = (
|
||||
<>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-sm"
|
||||
onClick={handleTest}
|
||||
disabled={busy !== null}
|
||||
>
|
||||
{busy === "testing" ? (
|
||||
<>
|
||||
<Loader2 size={12} className="animate-spin" />
|
||||
Testing…
|
||||
</>
|
||||
) : (
|
||||
"Test"
|
||||
)}
|
||||
</button>
|
||||
{currentlyEnabled ? (
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-sm"
|
||||
onClick={() => void handleToggle(false)}
|
||||
disabled={busy !== null}
|
||||
>
|
||||
{busy === "disabling" ? "Disabling…" : "Disable"}
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-primary btn-sm"
|
||||
onClick={() => void handleToggle(true)}
|
||||
disabled={busy !== null || !binaryAvailable}
|
||||
title={
|
||||
!binaryAvailable
|
||||
? "`claude` binary not detected on PATH — install Claude CLI first."
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{busy === "enabling" ? "Enabling…" : "Enable"}
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
// Compact layout mirrors `.auth-provider-card` so it slots cleanly into
|
||||
// the Settings > Authentication list and picks up the shared mobile rules.
|
||||
if (compact) {
|
||||
return (
|
||||
<div
|
||||
className={`auth-provider-card auth-provider-card--cli${authenticated ? " auth-provider-card--authenticated" : ""}`}
|
||||
data-testid="claude-cli-provider-card"
|
||||
>
|
||||
<div className="auth-provider-header">
|
||||
<div className="auth-provider-info">
|
||||
<ProviderIcon provider="claude-cli" size="sm" />
|
||||
<strong>Anthropic — via Claude CLI</strong>
|
||||
<ClaudeCliBadge status={status} authenticated={authenticated} />
|
||||
</div>
|
||||
<div className="auth-provider-cli-actions">{actions}</div>
|
||||
</div>
|
||||
<details className="auth-provider-cli-details">
|
||||
<summary>Details</summary>
|
||||
<div className="auth-provider-cli-details-body">
|
||||
{description}
|
||||
<ClaudeCliStatusLine status={status} authenticated={authenticated} />
|
||||
{lastAction && <ClaudeCliActionToast action={lastAction} />}
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`onboarding-provider-card${authenticated ? " onboarding-provider-card--connected" : ""}${compact ? " onboarding-provider-card--compact" : ""}`}
|
||||
className={`onboarding-provider-card${authenticated ? " onboarding-provider-card--connected" : ""}`}
|
||||
data-testid="claude-cli-provider-card"
|
||||
>
|
||||
<div className="onboarding-provider-card__icon">
|
||||
@@ -142,69 +214,33 @@ export function ClaudeCliProviderCard({
|
||||
<strong className="onboarding-provider-card__name">
|
||||
Anthropic — via Claude CLI
|
||||
</strong>
|
||||
{compact ? (
|
||||
<details className="onboarding-provider-card__details">
|
||||
<summary className="onboarding-provider-card__details-summary">
|
||||
Details
|
||||
</summary>
|
||||
{description}
|
||||
<ClaudeCliStatusLine status={status} authenticated={authenticated} />
|
||||
</details>
|
||||
) : (
|
||||
<>
|
||||
{description}
|
||||
<ClaudeCliStatusLine status={status} authenticated={authenticated} />
|
||||
</>
|
||||
)}
|
||||
{description}
|
||||
<ClaudeCliStatusLine status={status} authenticated={authenticated} />
|
||||
</div>
|
||||
<div className="onboarding-provider-card__actions">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-sm"
|
||||
onClick={handleTest}
|
||||
disabled={busy !== null}
|
||||
>
|
||||
{busy === "testing" ? (
|
||||
<>
|
||||
<Loader2 size={12} className="animate-spin" />
|
||||
Testing…
|
||||
</>
|
||||
) : (
|
||||
"Test"
|
||||
)}
|
||||
</button>
|
||||
{currentlyEnabled ? (
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-sm"
|
||||
onClick={() => void handleToggle(false)}
|
||||
disabled={busy !== null}
|
||||
>
|
||||
{busy === "disabling" ? "Disabling…" : "Disable"}
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-primary btn-sm"
|
||||
onClick={() => void handleToggle(true)}
|
||||
disabled={busy !== null || !binaryAvailable}
|
||||
title={
|
||||
!binaryAvailable
|
||||
? "`claude` binary not detected on PATH — install Claude CLI first."
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
{busy === "enabling" ? "Enabling…" : "Enable"}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{lastAction && (
|
||||
<ClaudeCliActionToast action={lastAction} />
|
||||
)}
|
||||
<div className="onboarding-provider-card__actions">{actions}</div>
|
||||
{lastAction && <ClaudeCliActionToast action={lastAction} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function ClaudeCliBadge({
|
||||
status,
|
||||
authenticated,
|
||||
}: {
|
||||
status: ClaudeCliStatus | null;
|
||||
authenticated: boolean;
|
||||
}) {
|
||||
const enabled = status?.enabled ?? authenticated;
|
||||
const available = status?.binary.available ?? false;
|
||||
if (enabled) {
|
||||
return <span className="auth-status-badge authenticated">✓ Active</span>;
|
||||
}
|
||||
if (!available && status) {
|
||||
return <span className="auth-status-badge not-authenticated">✗ Not installed</span>;
|
||||
}
|
||||
return <span className="auth-status-badge not-authenticated">✗ Not connected</span>;
|
||||
}
|
||||
|
||||
/**
|
||||
* One-line health summary. Renders different text for "binary missing"
|
||||
* vs "binary ok but disabled" vs "fully ready" so the user can quickly
|
||||
|
||||
@@ -25387,37 +25387,69 @@ html .column.drag-over * {
|
||||
width: min(calc(var(--space-2xl) * 10), 100%);
|
||||
}
|
||||
|
||||
.onboarding-provider-card--compact {
|
||||
padding: var(--space-sm) var(--space-md);
|
||||
gap: var(--space-sm);
|
||||
align-items: center;
|
||||
.auth-provider-card--cli .auth-provider-info {
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.onboarding-provider-card--compact .onboarding-provider-card__name {
|
||||
.auth-provider-card--cli .auth-provider-info strong {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.onboarding-provider-card__details {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
margin-top: 2px;
|
||||
.auth-provider-cli-actions {
|
||||
display: flex;
|
||||
gap: var(--space-xs);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.onboarding-provider-card__details-summary {
|
||||
.auth-provider-cli-details {
|
||||
border-top: 1px solid var(--border);
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.auth-provider-cli-details > summary {
|
||||
cursor: pointer;
|
||||
color: var(--text-muted);
|
||||
font-size: 12px;
|
||||
list-style: revert;
|
||||
user-select: none;
|
||||
padding: 8px 16px;
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
list-style: revert;
|
||||
}
|
||||
|
||||
.onboarding-provider-card__details[open] .onboarding-provider-card__details-summary {
|
||||
margin-bottom: var(--space-xs);
|
||||
.auth-provider-cli-details > summary:hover {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.onboarding-provider-card__details > *:not(summary) {
|
||||
display: block;
|
||||
margin-top: var(--space-xs);
|
||||
.auth-provider-cli-details-body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-xs);
|
||||
padding: 0 16px 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.auth-provider-card--cli .auth-provider-info {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.auth-provider-cli-actions {
|
||||
width: 100%;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.auth-provider-cli-actions .btn {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.auth-provider-cli-details > summary {
|
||||
padding: 8px 14px;
|
||||
}
|
||||
|
||||
.auth-provider-cli-details-body {
|
||||
padding: 0 14px 12px;
|
||||
}
|
||||
}
|
||||
|
||||
/* === Onboarding API Key Form === */
|
||||
|
||||
Reference in New Issue
Block a user