First Release of Claw3D (#11)

Co-authored-by: iamlukethedev <iamlukethedev@users.noreply.github.com>
This commit is contained in:
Luke The Dev
2026-03-19 23:14:04 -05:00
committed by GitHub
parent 5ea96b2650
commit 4fa4f13558
431 changed files with 105438 additions and 14 deletions
@@ -0,0 +1,235 @@
"use client";
import { useEffect } from "react";
import type { SkillStatusEntry } from "@/lib/skills/types";
import {
buildSkillMissingDetails,
canRemoveSkill,
deriveSkillReadinessState,
resolvePreferredInstallOption,
} from "@/lib/skills/presentation";
type SkillSetupMessage = { kind: "success" | "error"; message: string };
type AgentSkillsSetupModalProps = {
skill: SkillStatusEntry | null;
skillsBusy: boolean;
skillsBusyKey: string | null;
skillMessage: SkillSetupMessage | null;
apiKeyDraft: string;
defaultAgentScopeWarning?: string | null;
onClose: () => void;
onInstallSkill: (skillKey: string, name: string, installId: string) => Promise<void> | void;
onSetSkillGlobalEnabled: (skillKey: string, enabled: boolean) => Promise<void> | void;
onRemoveSkill: (
skill: { skillKey: string; source: string; baseDir: string }
) => Promise<void> | void;
onSkillApiKeyChange: (skillKey: string, value: string) => Promise<void> | void;
onSaveSkillApiKey: (skillKey: string) => Promise<void> | void;
};
const READINESS_LABELS = {
ready: "Ready",
"needs-setup": "Needs setup",
unavailable: "Unavailable",
"disabled-globally": "Disabled globally",
} as const;
const READINESS_CLASSES = {
ready: "ui-badge-status-running",
"needs-setup": "ui-badge-status-error",
unavailable: "ui-badge-status-error",
"disabled-globally": "ui-badge-status-error",
} as const;
export const AgentSkillsSetupModal = ({
skill,
skillsBusy,
skillsBusyKey,
skillMessage,
apiKeyDraft,
defaultAgentScopeWarning = null,
onClose,
onInstallSkill,
onSetSkillGlobalEnabled,
onRemoveSkill,
onSkillApiKeyChange,
onSaveSkillApiKey,
}: AgentSkillsSetupModalProps) => {
useEffect(() => {
if (!skill) {
return;
}
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key !== "Escape") {
return;
}
event.preventDefault();
onClose();
};
window.addEventListener("keydown", handleKeyDown);
return () => {
window.removeEventListener("keydown", handleKeyDown);
};
}, [onClose, skill]);
if (!skill) {
return null;
}
const readiness = deriveSkillReadinessState(skill);
const readinessLabel = READINESS_LABELS[readiness];
const readinessClassName = READINESS_CLASSES[readiness];
const missingDetails = buildSkillMissingDetails(skill);
const installOption = resolvePreferredInstallOption(skill);
const canDeleteSkill = canRemoveSkill(skill);
const busyForSkill = skillsBusyKey === skill.skillKey;
const anySkillBusy = skillsBusy || Boolean(skillsBusyKey);
const trimmedApiKey = apiKeyDraft.trim();
return (
<div
className="fixed inset-0 z-[100] flex items-center justify-center bg-background/80 p-4"
role="dialog"
aria-modal="true"
aria-label={`Setup ${skill.name}`}
onClick={onClose}
>
<div
className="ui-panel w-full max-w-2xl bg-card shadow-xs"
onClick={(event) => event.stopPropagation()}
>
<div className="flex items-start justify-between gap-3 px-6 py-5">
<div className="min-w-0">
<div className="text-[11px] font-medium tracking-[0.01em] text-muted-foreground/80">
System setup
</div>
<div className="mt-1 flex flex-wrap items-center gap-2">
<span className="text-base font-semibold text-foreground">{skill.name}</span>
<span
className={`rounded border px-1.5 py-0.5 font-mono text-[10px] font-semibold ${readinessClassName}`}
>
{readinessLabel}
</span>
</div>
<div className="mt-2 text-[10px] text-muted-foreground/80">
Changes affect all agents on this gateway.
</div>
</div>
<button
type="button"
className="sidebar-btn-ghost px-3 font-mono text-[10px] font-semibold tracking-[0.06em]"
onClick={onClose}
>
Close
</button>
</div>
<div className="space-y-3 px-6 pb-3 text-[11px] text-muted-foreground">
{defaultAgentScopeWarning ? (
<div className="rounded-md border border-border/60 bg-surface-1/65 px-3 py-2 text-[10px] text-muted-foreground/80">
{defaultAgentScopeWarning}
</div>
) : null}
<div>{skill.description}</div>
{skill.blockedByAllowlist ? (
<div className="text-[10px] text-muted-foreground/80">
Blocked by bundled skills policy (`skills.allowBundled`).
</div>
) : null}
{missingDetails.map((line) => (
<div key={`${skill.skillKey}:${line}`} className="text-[10px] text-muted-foreground/80">
{line}
</div>
))}
{skillMessage ? (
<div
className={`text-[10px] ${skillMessage.kind === "error" ? "ui-text-danger" : "ui-text-success"}`}
>
{skillMessage.message}
</div>
) : null}
<div className="space-y-2 rounded-md border border-border/60 bg-surface-1/65 px-3 py-3">
{installOption ? (
<button
type="button"
className="ui-btn-secondary w-full px-3 py-2 text-[10px] font-medium disabled:cursor-not-allowed disabled:opacity-65"
disabled={anySkillBusy}
onClick={() => {
void onInstallSkill(skill.skillKey, skill.name, installOption.id);
}}
>
{busyForSkill ? "Working..." : installOption.label}
</button>
) : null}
<button
type="button"
className="ui-btn-secondary w-full px-3 py-2 text-[10px] font-medium disabled:cursor-not-allowed disabled:opacity-65"
disabled={anySkillBusy}
onClick={() => {
void onSetSkillGlobalEnabled(skill.skillKey, skill.disabled);
}}
>
{busyForSkill
? "Working..."
: skill.disabled
? "Enable globally"
: "Disable globally"}
</button>
{skill.primaryEnv ? (
<>
<input
type="password"
value={apiKeyDraft}
onChange={(event) => {
void onSkillApiKeyChange(skill.skillKey, event.target.value);
}}
disabled={anySkillBusy}
className="w-full rounded-md border border-border/60 bg-surface-1 px-3 py-2 text-[10px] text-foreground outline-none transition focus:border-border"
placeholder={`Set ${skill.primaryEnv}`}
aria-label={`API key for ${skill.name}`}
/>
<button
type="button"
className="ui-btn-secondary w-full px-3 py-2 text-[10px] font-medium disabled:cursor-not-allowed disabled:opacity-65"
disabled={anySkillBusy || trimmedApiKey.length === 0}
onClick={() => {
if (trimmedApiKey.length === 0) {
return;
}
void onSaveSkillApiKey(skill.skillKey);
}}
>
{busyForSkill ? "Working..." : `Save ${skill.primaryEnv}`}
</button>
</>
) : null}
{canDeleteSkill ? (
<button
type="button"
className="ui-btn-secondary ui-btn-danger w-full px-3 py-2 text-[10px] font-medium disabled:cursor-not-allowed disabled:opacity-65"
disabled={anySkillBusy}
onClick={() => {
const approved = window.confirm(
`Remove ${skill.name} from the gateway? This affects all agents.`
);
if (!approved) {
return;
}
void onRemoveSkill({
skillKey: skill.skillKey,
source: skill.source,
baseDir: skill.baseDir,
});
onClose();
}}
>
Remove skill from gateway
</button>
) : null}
</div>
</div>
</div>
</div>
);
};