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:
gsxdsm
2026-04-23 20:44:33 -07:00
parent ed4b7380a0
commit 836089fe5f
3 changed files with 149 additions and 80 deletions

View File

@@ -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

View File

@@ -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 === */