mirror of
https://github.com/sortedcord/omnia.git
synced 2026-07-22 03:52:48 +05:30
Compare commits
3 Commits
a8b2d425a1
...
814f216ea7
| Author | SHA1 | Date | |
|---|---|---|---|
| 814f216ea7 | |||
| 7f74617077 | |||
| 264a5ea0fe |
20
.github/workflows/build-image.yml
vendored
20
.github/workflows/build-image.yml
vendored
@@ -5,19 +5,19 @@ on:
|
||||
branches: [master]
|
||||
tags: ["v*"]
|
||||
paths-ignore:
|
||||
- 'web/docs/**'
|
||||
- 'web/landing/**'
|
||||
- 'content/**'
|
||||
- 'README.md'
|
||||
- 'CONTRIBUTING.md'
|
||||
- '.github/workflows/deploy-docs.yml'
|
||||
- "web/docs/**"
|
||||
- "web/landing/**"
|
||||
- "content/**"
|
||||
- "README.md"
|
||||
- "CONTRIBUTING.md"
|
||||
- ".github/workflows/deploy-docs.yml"
|
||||
pull_request:
|
||||
branches: [master]
|
||||
paths-ignore:
|
||||
- 'web/docs/**'
|
||||
- 'web/landing/**'
|
||||
- 'content/**'
|
||||
- '*.md'
|
||||
- "web/docs/**"
|
||||
- "web/landing/**"
|
||||
- "content/**"
|
||||
- "*.md"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
FROM node:22-slim AS base
|
||||
ENV PNPM_HOME="/pnpm" \
|
||||
PATH="$PNPM_HOME:$PATH"
|
||||
RUN corepack enable && corepack prepare pnpm@11.13.0 --activate
|
||||
RUN corepack enable && corepack prepare pnpm@11.15.1 --activate
|
||||
WORKDIR /app
|
||||
|
||||
FROM base AS build-deps
|
||||
|
||||
2
apps/gui/next-env.d.ts
vendored
2
apps/gui/next-env.d.ts
vendored
@@ -1,6 +1,6 @@
|
||||
/// <reference types="next" />
|
||||
/// <reference types="next/image-types/global" />
|
||||
import "./.next/dev/types/routes.d.ts";
|
||||
import "./.next/types/routes.d.ts";
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||
|
||||
BIN
apps/gui/public/calendar_logo.png
Normal file
BIN
apps/gui/public/calendar_logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 607 B |
BIN
apps/gui/public/clock_day_icon.png
Normal file
BIN
apps/gui/public/clock_day_icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
BIN
apps/gui/public/clock_night_icon.png
Normal file
BIN
apps/gui/public/clock_night_icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
BIN
apps/gui/public/map_pointer_icon.png
Normal file
BIN
apps/gui/public/map_pointer_icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 463 B |
@@ -271,6 +271,12 @@ export async function createProviderInstance(
|
||||
);
|
||||
}
|
||||
|
||||
export async function duplicateProviderInstance(
|
||||
id: string,
|
||||
): Promise<ModelProviderInstance | null> {
|
||||
return ProviderManager.duplicate(id);
|
||||
}
|
||||
|
||||
export async function deleteProviderInstance(id: string): Promise<void> {
|
||||
ProviderManager.delete(id);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
setActiveProviderInstance,
|
||||
regenerateEmbeddings,
|
||||
deleteProviderInstance,
|
||||
duplicateProviderInstance,
|
||||
fetchAvailableModels,
|
||||
fetchAvailableModelsForInstance,
|
||||
} from "@/app/actions";
|
||||
@@ -338,6 +339,23 @@ export function ProviderInstancesConfig({
|
||||
}
|
||||
};
|
||||
|
||||
const handleDuplicate = async () => {
|
||||
if (selectedInstanceId === "new" || selectedInstanceId === null) return;
|
||||
try {
|
||||
setLoading(true);
|
||||
setError("");
|
||||
const duplicated = await duplicateProviderInstance(selectedInstanceId);
|
||||
if (duplicated) {
|
||||
setSelectedInstanceId(duplicated.id);
|
||||
await onChanged();
|
||||
}
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : String(err));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="mb-8 flex min-h-[600px] flex-col">
|
||||
{error && (
|
||||
@@ -646,16 +664,26 @@ export function ProviderInstancesConfig({
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row items-center justify-between gap-2">
|
||||
<div>
|
||||
<div className="flex flex-row gap-2">
|
||||
{selectedInstanceId !== "new" && (
|
||||
<Button
|
||||
type="button"
|
||||
variant="destructive"
|
||||
onClick={handleDelete}
|
||||
disabled={loading}
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
<>
|
||||
<Button
|
||||
type="button"
|
||||
variant="destructive"
|
||||
onClick={handleDelete}
|
||||
disabled={loading}
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
onClick={handleDuplicate}
|
||||
disabled={loading}
|
||||
>
|
||||
Duplicate
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<Button type="submit" disabled={loading}>
|
||||
|
||||
@@ -25,15 +25,8 @@ import {
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
} from "@/components/ui/dialog";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Bot, UserRound } from "lucide-react";
|
||||
|
||||
export function HomeView() {
|
||||
const router = useRouter();
|
||||
@@ -192,7 +185,7 @@ export function HomeView() {
|
||||
|
||||
return (
|
||||
<div className="flex-1 overflow-y-auto w-full relative">
|
||||
<div className="relative z-10 mx-auto max-w-[1024px] px-10 py-12">
|
||||
<div className="relative z-10 mx-auto max-w-5xl px-10 py-12">
|
||||
<div className="animate-fade-in">
|
||||
{/* Centered Big Logo */}
|
||||
<div className="flex flex-col items-center justify-center mb-10 pt-4">
|
||||
@@ -237,7 +230,7 @@ export function HomeView() {
|
||||
{Array.from({ length: 3 }).map((_, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex-shrink-0 w-72 border border-border/30 bg-card p-5 shadow-sm transition-all flex flex-col justify-between h-[148px]"
|
||||
className="shrink-0 w-72 border border-border/30 bg-card p-5 shadow-sm transition-all flex flex-col justify-between h-37"
|
||||
>
|
||||
<div className="space-y-3">
|
||||
<Skeleton className="h-5 w-2/3" />
|
||||
@@ -264,7 +257,7 @@ export function HomeView() {
|
||||
? undefined
|
||||
: () => handleResume(s.id)
|
||||
}
|
||||
className={`flex-shrink-0 w-72 border border-border/30 bg-card p-5 shadow-sm transition-all relative group ${
|
||||
className={`shrink-0 w-72 border border-border/30 bg-card p-5 shadow-sm transition-all relative group ${
|
||||
providerInstances.length === 0
|
||||
? "opacity-50 cursor-not-allowed filter grayscale"
|
||||
: "cursor-pointer hover:-translate-y-0.5 hover:shadow-md active:translate-y-0 active:shadow-sm"
|
||||
@@ -310,8 +303,8 @@ export function HomeView() {
|
||||
</h2>
|
||||
{loadingData ? (
|
||||
<div className="flex overflow-x-auto gap-6 pb-4 scrollbar-thin scrollbar-thumb-border/20">
|
||||
<Link href="/builder" className="no-underline flex-shrink-0">
|
||||
<div className="w-64 border border-border/30 bg-card p-5 cursor-pointer shadow-sm hover:-translate-y-0.5 hover:shadow-md active:translate-y-0 active:shadow-sm transition-all flex flex-col justify-between h-full min-h-[148px]">
|
||||
<Link href="/builder" className="no-underline shrink-0">
|
||||
<div className="w-64 border border-border/30 bg-card p-5 cursor-pointer shadow-sm hover:-translate-y-0.5 hover:shadow-md active:translate-y-0 active:shadow-sm transition-all flex flex-col justify-between h-full min-h-37">
|
||||
<div>
|
||||
<strong className="text-body-md text-foreground block mb-1">
|
||||
Build a scenario
|
||||
@@ -331,7 +324,7 @@ export function HomeView() {
|
||||
{Array.from({ length: 3 }).map((_, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="flex-shrink-0 w-64 border border-border/30 bg-card p-5 shadow-sm flex flex-col justify-between h-[148px]"
|
||||
className="shrink-0 w-64 border border-border/30 bg-card p-5 shadow-sm flex flex-col justify-between h-37"
|
||||
>
|
||||
<div className="space-y-3">
|
||||
<Skeleton className="h-5 w-3/4" />
|
||||
@@ -345,8 +338,8 @@ export function HomeView() {
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex overflow-x-auto gap-6 pb-4 scrollbar-thin scrollbar-thumb-border/20">
|
||||
<Link href="/builder" className="no-underline flex-shrink-0">
|
||||
<div className="w-64 border border-primary bg-primary p-5 cursor-pointer shadow-sm hover:-translate-y-0.5 hover:shadow-md active:translate-y-0 active:shadow-sm transition-all flex flex-col justify-between h-full min-h-[148px]">
|
||||
<Link href="/builder" className="no-underline shrink-0">
|
||||
<div className="w-64 border border-primary bg-primary p-5 cursor-pointer shadow-sm hover:-translate-y-0.5 hover:shadow-md active:translate-y-0 active:shadow-sm transition-all flex flex-col justify-between h-full min-h-37">
|
||||
<div>
|
||||
<strong className="text-body-md text-surface block mb-1">
|
||||
Build a scenario
|
||||
@@ -382,7 +375,7 @@ export function HomeView() {
|
||||
open={!!scenarioForModal}
|
||||
onOpenChange={(open) => !open && setScenarioForModal(null)}
|
||||
>
|
||||
<DialogContent className="max-w-[400px]">
|
||||
<DialogContent className="max-w-100">
|
||||
<DialogHeader className="border-b border-dotted border-border/20 pb-4 mb-2">
|
||||
<DialogTitle>Start Scenario</DialogTitle>
|
||||
<DialogDescription>
|
||||
@@ -412,28 +405,37 @@ export function HomeView() {
|
||||
<label className="text-xs font-semibold uppercase tracking-wider text-muted-foreground font-mono">
|
||||
Simulation Mode / Play as
|
||||
</label>
|
||||
<Select
|
||||
value={selectedEntityForModal}
|
||||
onValueChange={(val) =>
|
||||
setSelectedEntityForModal(val || "")
|
||||
}
|
||||
>
|
||||
<SelectTrigger className="w-full">
|
||||
<SelectValue placeholder="-- Run Fully Autonomously --" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
<SelectItem value="">
|
||||
-- Run Fully Autonomously --
|
||||
</SelectItem>
|
||||
{modalEntities.map((ent) => (
|
||||
<SelectItem key={ent.id} value={ent.id}>
|
||||
Play as {ent.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
<Button
|
||||
type="button"
|
||||
variant={
|
||||
selectedEntityForModal === ""
|
||||
? "default"
|
||||
: "outline"
|
||||
}
|
||||
onClick={() => setSelectedEntityForModal("")}
|
||||
className="flex-1 min-w-40"
|
||||
>
|
||||
<Bot />
|
||||
Run Fully Autonomously
|
||||
</Button>
|
||||
{modalEntities.map((ent) => (
|
||||
<Button
|
||||
key={ent.id}
|
||||
type="button"
|
||||
variant={
|
||||
selectedEntityForModal === ent.id
|
||||
? "default"
|
||||
: "outline"
|
||||
}
|
||||
onClick={() => setSelectedEntityForModal(ent.id)}
|
||||
className="flex-1 min-w-40"
|
||||
>
|
||||
<UserRound />
|
||||
Play as {ent.name}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -33,7 +33,7 @@ export function HandoffModal({ entry, onClose }: HandoffModalProps) {
|
||||
|
||||
return (
|
||||
<Dialog open onOpenChange={(open) => !open && onClose()}>
|
||||
<DialogContent className="max-w-[800px] sm:max-w-[800px] h-[85vh] overflow-hidden flex flex-col p-0 gap-0 border-2">
|
||||
<DialogContent className="max-w-200 sm:max-w-200 h-[85vh] overflow-hidden flex flex-col p-0 gap-0 border-2">
|
||||
<DialogHeader className="px-6 pt-5 pb-4 border-b">
|
||||
<DialogTitle className="text-lg font-head tracking-wide text-primary flex items-center justify-between">
|
||||
<span>Memory Handoff Details — {entry.entityName}</span>
|
||||
@@ -128,7 +128,13 @@ export function HandoffModal({ entry, onClose }: HandoffModalProps) {
|
||||
</h3>
|
||||
{chunks.map(
|
||||
(
|
||||
chunk: { content: string; importance: number },
|
||||
chunk: {
|
||||
content: string;
|
||||
importance: number;
|
||||
quotes?: string[];
|
||||
retainInBuffer?: boolean;
|
||||
involvedEntityIds?: string[];
|
||||
},
|
||||
index: number,
|
||||
) => (
|
||||
<div
|
||||
@@ -240,7 +246,7 @@ export function HandoffModal({ entry, onClose }: HandoffModalProps) {
|
||||
<h4 className="text-xs font-semibold uppercase tracking-wider text-muted-foreground font-mono">
|
||||
Raw JSON Output
|
||||
</h4>
|
||||
<pre className="p-3 bg-muted rounded text-xs font-mono whitespace-pre-wrap text-foreground border flex-1 overflow-y-auto max-h-[500px]">
|
||||
<pre className="p-3 bg-muted rounded text-xs font-mono whitespace-pre-wrap text-foreground border flex-1 overflow-y-auto max-h-125">
|
||||
{handoffResult
|
||||
? JSON.stringify(handoffResult, null, 2)
|
||||
: "No JSON Output recorded."}
|
||||
|
||||
188
apps/gui/src/components/play/InteractDock.tsx
Normal file
188
apps/gui/src/components/play/InteractDock.tsx
Normal file
@@ -0,0 +1,188 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import type { SimSnapshot } from "@/lib/simulation-types";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { formatSimDate, formatSimTimeHM, getClockIcon } from "@/lib/utils";
|
||||
|
||||
interface InteractDockProps {
|
||||
snapshot: SimSnapshot;
|
||||
loading: boolean;
|
||||
playerInput: string;
|
||||
setPlayerInput: (value: string) => void;
|
||||
onSubmitAction: (e: React.FormEvent<HTMLFormElement>) => void;
|
||||
onPauseRequested: () => void;
|
||||
onResumeRequested: () => void;
|
||||
onStopRequested: () => void;
|
||||
}
|
||||
|
||||
export function InteractDock({
|
||||
snapshot,
|
||||
loading,
|
||||
playerInput,
|
||||
setPlayerInput,
|
||||
onSubmitAction,
|
||||
onPauseRequested,
|
||||
onResumeRequested,
|
||||
onStopRequested,
|
||||
}: InteractDockProps) {
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<footer className="sticky bottom-0 px-8 py-4 z-20 shrink-0 bg-background/70 backdrop-blur-md border-t border-border/10">
|
||||
<div className="max-w-200 mx-auto relative">
|
||||
{snapshot.status === "running" ||
|
||||
snapshot.status === "waiting_player" ? (
|
||||
<div className="border border-border/30 bg-card/85 p-4 shadow-sm backdrop-blur-sm relative z-10">
|
||||
{snapshot.status === "waiting_player" && snapshot.waitingEntity && (
|
||||
<details className="mb-3">
|
||||
<summary className="cursor-pointer text-sm font-medium font-head text-primary select-none outline-none">
|
||||
<strong>Your context as {snapshot.waitingEntity.name}</strong>
|
||||
</summary>
|
||||
<pre className="text-xs whitespace-pre-wrap bg-input border border-border/20 p-2 max-h-37.5 overflow-y-auto mt-2 font-mono">
|
||||
{snapshot.waitingEntity.userContext}
|
||||
</pre>
|
||||
</details>
|
||||
)}
|
||||
|
||||
<div className="flex flex-col gap-3">
|
||||
<div className="flex justify-between items-center gap-2">
|
||||
{snapshot.worldTime ? (
|
||||
<span className="text-base font-mono text-muted-foreground font-medium">
|
||||
<img
|
||||
src="/calendar_logo.png"
|
||||
alt="Date"
|
||||
className="w-7 h-7 inline-block align-middle mr-1 opacity-70"
|
||||
/>
|
||||
{formatSimDate(snapshot.worldTime)}
|
||||
<img
|
||||
src={getClockIcon(snapshot.worldTime)}
|
||||
alt="Time"
|
||||
className="w-7 h-7 inline-block align-middle ml-2 mr-1 opacity-70"
|
||||
/>
|
||||
{formatSimTimeHM(snapshot.worldTime)}
|
||||
{snapshot.currentLocation && (
|
||||
<>
|
||||
<img
|
||||
src="/map_pointer_icon.png"
|
||||
alt="Location"
|
||||
className="w-7 h-7 inline-block align-middle ml-2 mr-1 opacity-70"
|
||||
/>
|
||||
{snapshot.currentLocation}
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
) : (
|
||||
<div />
|
||||
)}
|
||||
<div className="flex gap-2">
|
||||
{loading ? (
|
||||
<Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
onClick={onPauseRequested}
|
||||
>
|
||||
Pause
|
||||
</Button>
|
||||
) : (
|
||||
snapshot.status === "running" && (
|
||||
<Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
onClick={onResumeRequested}
|
||||
>
|
||||
Resume
|
||||
</Button>
|
||||
)
|
||||
)}
|
||||
<Button
|
||||
type="button"
|
||||
variant="destructive"
|
||||
size="sm"
|
||||
onClick={onStopRequested}
|
||||
>
|
||||
Stop
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{snapshot.status === "waiting_player" &&
|
||||
snapshot.waitingEntity && (
|
||||
<form
|
||||
onSubmit={onSubmitAction}
|
||||
className="flex flex-row gap-2 items-stretch"
|
||||
>
|
||||
<Textarea
|
||||
value={playerInput}
|
||||
onChange={(e) => setPlayerInput(e.target.value)}
|
||||
placeholder="Describe what your character does, says, or thinks..."
|
||||
rows={3}
|
||||
className="flex-1 min-h-26"
|
||||
disabled={loading}
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={loading || !playerInput.trim()}
|
||||
className="w-32 shrink-0 self-stretch"
|
||||
>
|
||||
{loading ? "Processing..." : "Submit"}
|
||||
</Button>
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
) : snapshot.status === "done" || snapshot.status === "error" ? (
|
||||
<div className="flex justify-between items-center bg-card/85 border border-border/30 p-4 shadow-sm backdrop-blur-sm">
|
||||
<div className="flex flex-col gap-1">
|
||||
<span className="text-sm font-mono text-muted-foreground">
|
||||
{snapshot.status === "error"
|
||||
? "Simulation finished with an error."
|
||||
: "Simulation complete."}
|
||||
</span>
|
||||
{snapshot.worldTime && (
|
||||
<div className="flex items-center gap-2 text-base font-mono text-muted-foreground">
|
||||
<img
|
||||
src="/calendar_logo.png"
|
||||
alt="Date"
|
||||
className="w-7 h-7 opacity-70"
|
||||
/>
|
||||
<span>{formatSimDate(snapshot.worldTime)}</span>
|
||||
<img
|
||||
src={getClockIcon(snapshot.worldTime)}
|
||||
alt="Time"
|
||||
className="w-7 h-7 opacity-70"
|
||||
/>
|
||||
<span>{formatSimTimeHM(snapshot.worldTime)}</span>
|
||||
{snapshot.currentLocation && (
|
||||
<>
|
||||
<img
|
||||
src="/map_pointer_icon.png"
|
||||
alt="Location"
|
||||
className="w-7 h-7 opacity-70"
|
||||
/>
|
||||
<span>{snapshot.currentLocation}</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<Button
|
||||
onClick={() => {
|
||||
router.push("/");
|
||||
}}
|
||||
size="sm"
|
||||
>
|
||||
{snapshot.status === "error"
|
||||
? "Back to Dashboard"
|
||||
: "New Simulation"}
|
||||
</Button>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
@@ -1,19 +1,19 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import type { SimSnapshot } from "@/lib/simulation-types";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { Spinner } from "@/components/ui/spinner";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { hydrate } from "@omnia/voice";
|
||||
import { Brain, PersonStanding, Speech } from "lucide-react";
|
||||
import {
|
||||
Alert,
|
||||
AlertAction,
|
||||
AlertDescription,
|
||||
AlertTitle,
|
||||
} from "@/components/ui/alert";
|
||||
import { InteractDock } from "./InteractDock";
|
||||
|
||||
function IntentTag({
|
||||
intent,
|
||||
@@ -26,19 +26,14 @@ function IntentTag({
|
||||
playerId: string;
|
||||
entities: SimSnapshot["entities"];
|
||||
}) {
|
||||
const labels: Record<string, string> = {
|
||||
monologue: "thought",
|
||||
thought: "thought",
|
||||
dialogue: "dialogue",
|
||||
action: "action",
|
||||
const icons: Record<string, React.ReactNode> = {
|
||||
monologue: <Brain className="size-4" />,
|
||||
thought: <Brain className="size-4" />,
|
||||
dialogue: <Speech className="size-4" />,
|
||||
action: <PersonStanding className="size-4" />,
|
||||
};
|
||||
|
||||
const label = labels[intent.type] || intent.type;
|
||||
|
||||
let outcome = "";
|
||||
if (intent.type === "action") {
|
||||
outcome = intent.isValid ? " ✅" : ` ❌ (${intent.reason})`;
|
||||
}
|
||||
const icon = icons[intent.type] || null;
|
||||
|
||||
const viewerAliasesMap = new Map<string, string>();
|
||||
if (entities) {
|
||||
@@ -69,12 +64,28 @@ function IntentTag({
|
||||
</span>
|
||||
) : null;
|
||||
|
||||
const invalidActionReason =
|
||||
intent.type === "action" && !intent.isValid && intent.reason
|
||||
? ` (${intent.reason})`
|
||||
: "";
|
||||
|
||||
const invalidActionClassName =
|
||||
intent.type === "action" && !intent.isValid ? " text-destructive" : "";
|
||||
|
||||
return (
|
||||
<span className="text-sm text-muted-foreground">
|
||||
[{label}] “{textToDisplay}”{modifiersStr}
|
||||
{outcome}
|
||||
{intent.minutesToAdvance ? ` [+${intent.minutesToAdvance}min]` : ""}
|
||||
</span>
|
||||
<>
|
||||
<span className="text-sm text-muted-foreground inline-flex items-start gap-1">
|
||||
<span className="mt-0.5 inline-flex shrink-0 items-center justify-center">
|
||||
{icon}
|
||||
</span>
|
||||
<span className={invalidActionClassName}>
|
||||
“{textToDisplay}”{modifiersStr}
|
||||
{invalidActionReason}
|
||||
{intent.minutesToAdvance ? ` [+${intent.minutesToAdvance}min]` : ""}
|
||||
</span>
|
||||
</span>
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -112,38 +123,40 @@ function LogEntryCard({
|
||||
const showMenu = !!(entry.rawPrompt || entry.decoderPrompt);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"border p-4 shadow-[2px_2px_0_0_var(--border)]",
|
||||
isPlayerCard
|
||||
? "border-primary bg-surface-container-low"
|
||||
: "border-border/30 bg-card",
|
||||
)}
|
||||
>
|
||||
<div className="flex justify-between items-center mb-2 border-b border-dotted border-border/20 pb-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<strong className="text-body-md font-bold text-foreground">
|
||||
{entry.entityName}
|
||||
</strong>
|
||||
<span className="text-xs text-muted-foreground font-mono">
|
||||
Turn {entry.turn} · {formatSimTime(entry.timestamp)}
|
||||
</span>
|
||||
</div>
|
||||
{showMenu && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => onShowPrompt(entry)}
|
||||
title="View Raw Prompts & Token Usage"
|
||||
>
|
||||
☰
|
||||
</Button>
|
||||
<div className={cn("mb-2")}>
|
||||
<div
|
||||
className={cn(
|
||||
"border p-4 shadow-sm",
|
||||
isPlayerCard
|
||||
? "border-primary bg-surface-container-low"
|
||||
: "border-border/30 bg-card",
|
||||
)}
|
||||
>
|
||||
<div className="flex justify-between items-center mb-2 border-b border-dotted border-border/20 pb-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<strong className="text-body-md font-bold text-foreground">
|
||||
{entry.entityName}
|
||||
</strong>
|
||||
<span className="text-xs text-muted-foreground font-mono">
|
||||
Turn {entry.turn} · {formatSimTime(entry.timestamp)}
|
||||
</span>
|
||||
</div>
|
||||
{showMenu && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={() => onShowPrompt(entry)}
|
||||
title="View Raw Prompts & Token Usage"
|
||||
>
|
||||
☰
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
<div className="text-body-md leading-relaxed mb-3 text-foreground/90 whitespace-pre-wrap">
|
||||
{entry.narrativeProse}
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-body-md leading-relaxed mb-3 text-foreground/90 whitespace-pre-wrap">
|
||||
{entry.narrativeProse}
|
||||
</div>
|
||||
<div className="flex flex-col gap-1.5 mt-2 border-t border-dotted border-border/10 pt-2">
|
||||
<div className={cn("mt-3 ms-3")}>
|
||||
{entry.intents.map((intent, i) => (
|
||||
<IntentTag
|
||||
key={i}
|
||||
@@ -168,6 +181,9 @@ interface InteractViewProps {
|
||||
onShowPrompt: (entry: SimSnapshot["log"][number]) => void;
|
||||
onShowHandoff: (entry: SimSnapshot["log"][number]) => void;
|
||||
logEndRef: React.RefObject<HTMLDivElement | null>;
|
||||
onPauseRequested: () => void;
|
||||
onResumeRequested: () => void;
|
||||
onStopRequested: () => void;
|
||||
}
|
||||
|
||||
export function InteractView({
|
||||
@@ -180,16 +196,17 @@ export function InteractView({
|
||||
onShowPrompt,
|
||||
onShowHandoff,
|
||||
logEndRef,
|
||||
onPauseRequested,
|
||||
onResumeRequested,
|
||||
onStopRequested,
|
||||
}: InteractViewProps) {
|
||||
const router = useRouter();
|
||||
|
||||
const playerEntity = snapshot.entities.find((e) => e.isPlayer);
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Scrollable Center Viewport */}
|
||||
<main className="flex-1 overflow-y-auto px-8 py-6">
|
||||
<div className="flex flex-col gap-4 max-w-[800px] mx-auto pb-12">
|
||||
<div className="flex flex-col gap-4 max-w-200 mx-auto pb-44 md:pb-52">
|
||||
{snapshot.log.map((entry, i) => {
|
||||
if (entry.isHandoff) {
|
||||
return (
|
||||
@@ -243,54 +260,16 @@ export function InteractView({
|
||||
</div>
|
||||
</main>
|
||||
|
||||
{/* Sticky Chat / Interaction Input Footer */}
|
||||
<footer className="sticky bottom-0 bg-background/95 backdrop-blur-xs border-t border-dotted border-border/20 px-8 py-4 z-10 shrink-0">
|
||||
<div className="max-w-[800px] mx-auto">
|
||||
{snapshot.status === "waiting_player" && snapshot.waitingEntity ? (
|
||||
<div className="border border-border/30 bg-card p-4 shadow-[2px_2px_0_0_var(--border)]">
|
||||
<details className="mb-3">
|
||||
<summary className="cursor-pointer text-sm font-medium font-head text-primary select-none outline-none">
|
||||
<strong>Your context as {snapshot.waitingEntity.name}</strong>
|
||||
</summary>
|
||||
<pre className="text-xs whitespace-pre-wrap bg-input border border-border/20 p-2 max-h-[150px] overflow-y-auto mt-2 font-mono">
|
||||
{snapshot.waitingEntity.userContext}
|
||||
</pre>
|
||||
</details>
|
||||
|
||||
<form onSubmit={onSubmitAction} className="flex flex-col gap-2">
|
||||
<Textarea
|
||||
value={playerInput}
|
||||
onChange={(e) => setPlayerInput(e.target.value)}
|
||||
placeholder="Describe what your character does, says, or thinks..."
|
||||
rows={3}
|
||||
disabled={loading}
|
||||
/>
|
||||
<Button type="submit" disabled={loading || !playerInput.trim()}>
|
||||
{loading ? "Processing..." : "Submit Action"}
|
||||
</Button>
|
||||
</form>
|
||||
</div>
|
||||
) : snapshot.status === "done" || snapshot.status === "error" ? (
|
||||
<div className="flex justify-between items-center bg-card border border-border/30 p-4 shadow-[2px_2px_0_0_var(--border)]">
|
||||
<span className="text-sm font-mono text-muted-foreground">
|
||||
{snapshot.status === "error"
|
||||
? "Simulation finished with an error."
|
||||
: "Simulation complete."}
|
||||
</span>
|
||||
<Button
|
||||
onClick={() => {
|
||||
router.push("/");
|
||||
}}
|
||||
size="sm"
|
||||
>
|
||||
{snapshot.status === "error"
|
||||
? "Back to Dashboard"
|
||||
: "New Simulation"}
|
||||
</Button>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</footer>
|
||||
<InteractDock
|
||||
snapshot={snapshot}
|
||||
loading={loading}
|
||||
playerInput={playerInput}
|
||||
setPlayerInput={setPlayerInput}
|
||||
onSubmitAction={onSubmitAction}
|
||||
onPauseRequested={onPauseRequested}
|
||||
onResumeRequested={onResumeRequested}
|
||||
onStopRequested={onStopRequested}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -319,43 +319,6 @@ export function PlayView() {
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
{/* Simulation Global Controls */}
|
||||
<div className="flex gap-2 shrink-0">
|
||||
{snapshot.status !== "done" && snapshot.status !== "error" && (
|
||||
<>
|
||||
{snapshot.status === "running" &&
|
||||
(loading ? (
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
pauseRequestedRef.current = true;
|
||||
}}
|
||||
>
|
||||
Pause
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
onClick={() => runSteps(snapshot.id)}
|
||||
>
|
||||
Resume
|
||||
</Button>
|
||||
))}
|
||||
<Button
|
||||
variant="destructive"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
pauseRequestedRef.current = true;
|
||||
router.push("/");
|
||||
}}
|
||||
>
|
||||
Stop
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-between text-xs font-mono mt-1 pt-1.5 border-t border-border/10">
|
||||
<span className="text-muted-foreground">
|
||||
@@ -390,6 +353,14 @@ export function PlayView() {
|
||||
onShowPrompt={setSelectedEntryForModal}
|
||||
onShowHandoff={setSelectedHandoffForModal}
|
||||
logEndRef={logEndRef}
|
||||
onPauseRequested={() => {
|
||||
pauseRequestedRef.current = true;
|
||||
}}
|
||||
onResumeRequested={() => runSteps(snapshot.id)}
|
||||
onStopRequested={() => {
|
||||
pauseRequestedRef.current = true;
|
||||
router.push("/");
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<ManageView snapshot={snapshot} onRename={setSnapshot} />
|
||||
|
||||
@@ -52,21 +52,26 @@ export function PromptAnalyzer({
|
||||
maxContext > 0 ? (inputTokens / maxContext) * 100 : 0;
|
||||
const isAbsolute = maxContext > 0 && usagePctOfContext >= 20;
|
||||
|
||||
const getColorClass = (type: string) => {
|
||||
switch (type) {
|
||||
case "system":
|
||||
return "bg-blue-500";
|
||||
case "world":
|
||||
return "bg-emerald-500";
|
||||
case "events":
|
||||
return "bg-purple-500";
|
||||
case "memories":
|
||||
return "bg-pink-500";
|
||||
case "input":
|
||||
return "bg-amber-500";
|
||||
default:
|
||||
return "bg-slate-500";
|
||||
}
|
||||
const legentColors = [
|
||||
"bg-blue-500",
|
||||
"bg-emerald-500",
|
||||
"bg-purple-500",
|
||||
"bg-orange-500",
|
||||
"bg-pink-500",
|
||||
"bg-amber-500",
|
||||
"bg-teal-500",
|
||||
"bg-cyan-500",
|
||||
"bg-indigo-500",
|
||||
"bg-violet-500",
|
||||
"bg-rose-500",
|
||||
"bg-sky-500",
|
||||
"bg-lime-500",
|
||||
"bg-fuchsia-500",
|
||||
"bg-red-500",
|
||||
];
|
||||
|
||||
const getColorClass = (index: number) => {
|
||||
return legentColors[index % legentColors.length];
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -106,7 +111,7 @@ export function PromptAnalyzer({
|
||||
return (
|
||||
<div
|
||||
key={idx}
|
||||
className={`h-full transition-all duration-300 ${getColorClass(item.type)}`}
|
||||
className={`h-full transition-all duration-300 ${getColorClass(idx)}`}
|
||||
style={{ width: `${widthPct}%` }}
|
||||
title={`${item.label}: ${item.tokens} tokens (${item.pct.toFixed(1)}%)`}
|
||||
/>
|
||||
@@ -129,7 +134,7 @@ export function PromptAnalyzer({
|
||||
<AccordionTrigger className="text-sm py-2.5 hover:no-underline">
|
||||
<div className="flex items-center gap-2">
|
||||
<span
|
||||
className={`inline-block w-2.5 h-2.5 rounded-sm ${getColorClass(item.type)}`}
|
||||
className={`inline-block w-2.5 h-2.5 rounded-sm ${getColorClass(idx)}`}
|
||||
/>
|
||||
<span>{item.label}:</span>
|
||||
<span className="text-muted-foreground font-normal">
|
||||
@@ -139,7 +144,7 @@ export function PromptAnalyzer({
|
||||
</div>
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<pre className="m-0 p-3 bg-muted rounded text-xs font-mono whitespace-pre-wrap text-foreground border max-h-[300px] overflow-y-auto">
|
||||
<pre className="m-0 p-3 bg-muted rounded text-xs font-mono whitespace-pre-wrap text-foreground border max-h-75 overflow-y-auto">
|
||||
{item.content}
|
||||
</pre>
|
||||
</AccordionContent>
|
||||
@@ -161,7 +166,7 @@ export function PromptAnalyzer({
|
||||
)}
|
||||
</div>
|
||||
<div className="rounded border-2">
|
||||
<pre className="m-0 p-3 bg-muted text-xs font-mono whitespace-pre-wrap text-foreground max-h-[250px] overflow-y-auto">
|
||||
<pre className="m-0 p-3 bg-muted text-xs font-mono whitespace-pre-wrap text-foreground max-h-62.5 overflow-y-auto">
|
||||
{outputText}
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
@@ -136,7 +136,7 @@ export function PromptModal({ entry, onClose }: PromptModalProps) {
|
||||
}
|
||||
modelName={validatorCall.usage?.modelName}
|
||||
providerInstanceName={validatorCall.usage?.providerInstanceName}
|
||||
outputLabel={`LLM Output (Validation for: "${validatorCall.intentContent}")`}
|
||||
outputLabel={`LLM Output`}
|
||||
outputText={JSON.stringify(validatorCall.response, null, 2)}
|
||||
outputTokens={validatorCall.usage?.outputTokens}
|
||||
/>
|
||||
|
||||
@@ -21,7 +21,7 @@ export function ScenarioCard({
|
||||
return (
|
||||
<div
|
||||
onClick={disabled ? undefined : onClick}
|
||||
className={`flex-shrink-0 w-64 border border-border/30 bg-card p-5 shadow-sm transition-all ${
|
||||
className={`shrink-0 w-64 border border-border/30 bg-card p-5 shadow-sm transition-all ${
|
||||
disabled
|
||||
? "opacity-50 cursor-not-allowed filter grayscale"
|
||||
: "cursor-pointer hover:-translate-y-0.5 hover:shadow-md active:translate-y-0 active:shadow-sm"
|
||||
|
||||
@@ -42,6 +42,9 @@ export interface HandoffResult {
|
||||
chunks: {
|
||||
content: string;
|
||||
importance: number;
|
||||
quotes?: string[];
|
||||
retainInBuffer?: boolean;
|
||||
involvedEntityIds?: string[];
|
||||
}[];
|
||||
}
|
||||
|
||||
@@ -103,4 +106,6 @@ export interface SimSnapshot {
|
||||
entityIndex: number;
|
||||
waitingEntity?: WaitingContext;
|
||||
error?: string;
|
||||
worldTime?: string;
|
||||
currentLocation?: string;
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ export async function runHandoffResolution(session: SimSession): Promise<void> {
|
||||
}
|
||||
: undefined,
|
||||
usage: lastCall?.usage,
|
||||
handoffResult: lastResult?.response || lastCall?.response,
|
||||
handoffResult: (lastResult?.response || lastCall?.response) as any,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -483,6 +483,23 @@ export class SimulationManager {
|
||||
};
|
||||
});
|
||||
|
||||
// Get current location from the waiting entity
|
||||
let currentLocation: string | undefined;
|
||||
if (
|
||||
worldState &&
|
||||
session.entityIndex >= 0 &&
|
||||
session.entityIndex < session.entities.length
|
||||
) {
|
||||
const currentEntityInfo = session.entities[session.entityIndex];
|
||||
const actualEntity = worldState.getEntity(currentEntityInfo.id);
|
||||
if (actualEntity?.locationId) {
|
||||
const location = worldState.getLocation(actualEntity.locationId);
|
||||
if (location) {
|
||||
currentLocation = location.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
id: session.worldInstanceId,
|
||||
status: session.status,
|
||||
@@ -495,6 +512,8 @@ export class SimulationManager {
|
||||
entityIndex: session.entityIndex,
|
||||
waitingEntity: session.waitingEntity,
|
||||
error: session.error,
|
||||
worldTime: worldState?.clock.get().toISOString(),
|
||||
currentLocation,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import type {
|
||||
IntentInfo,
|
||||
LogEntry,
|
||||
WaitingContext,
|
||||
ValidatorCall,
|
||||
} from "../simulation-types";
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -88,7 +89,7 @@ async function processIntents(
|
||||
prompt: {
|
||||
systemPrompt: lastResult.systemPrompt || "",
|
||||
userContext: lastResult.userContext || "",
|
||||
components: lastResult.promptComponents,
|
||||
components: lastResult.components,
|
||||
},
|
||||
response: {
|
||||
isValid: outcome.isValid,
|
||||
|
||||
@@ -4,3 +4,41 @@ import { twMerge } from "tailwind-merge";
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
|
||||
export function formatSimDate(isoString: string): string {
|
||||
try {
|
||||
const d = new Date(isoString);
|
||||
if (isNaN(d.getTime())) return isoString;
|
||||
const yyyy = d.getUTCFullYear();
|
||||
const mm = String(d.getUTCMonth() + 1).padStart(2, "0");
|
||||
const dd = String(d.getUTCDate()).padStart(2, "0");
|
||||
return `${yyyy}-${mm}-${dd}`;
|
||||
} catch {
|
||||
return isoString;
|
||||
}
|
||||
}
|
||||
|
||||
export function formatSimTimeHM(isoString: string): string {
|
||||
try {
|
||||
const d = new Date(isoString);
|
||||
if (isNaN(d.getTime())) return isoString;
|
||||
const hh = String(d.getUTCHours());
|
||||
const mm = String(d.getUTCMinutes()).padStart(2, "0");
|
||||
return `${hh}:${mm}`;
|
||||
} catch {
|
||||
return isoString;
|
||||
}
|
||||
}
|
||||
|
||||
export function getClockIcon(isoString: string): string {
|
||||
try {
|
||||
const d = new Date(isoString);
|
||||
if (isNaN(d.getTime())) return "/clock_day_icon.png";
|
||||
const hour = d.getUTCHours();
|
||||
return hour >= 6 && hour < 18
|
||||
? "/clock_day_icon.png"
|
||||
: "/clock_night_icon.png";
|
||||
} catch {
|
||||
return "/clock_day_icon.png";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
"devEngines": {
|
||||
"packageManager": {
|
||||
"name": "pnpm",
|
||||
"version": "11.13.0",
|
||||
"version": "11.15.1",
|
||||
"onFail": "download"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -62,6 +62,50 @@ export class ProviderManager {
|
||||
};
|
||||
}
|
||||
|
||||
static duplicate(id: string): ModelProviderInstance | null {
|
||||
const db = getDb();
|
||||
const source = db
|
||||
.prepare("SELECT * FROM provider_instances WHERE id = ?")
|
||||
.get(id) as DbRow | undefined;
|
||||
if (!source) return null;
|
||||
|
||||
const newId = "provider-" + Date.now();
|
||||
const newName = `${source.name} (Copy)`;
|
||||
|
||||
const activeCount = db
|
||||
.prepare(
|
||||
"SELECT COUNT(*) as count FROM provider_instances WHERE isActive = 1 AND type = ?",
|
||||
)
|
||||
.get(source.type) as { count: number };
|
||||
const isActive = activeCount.count === 0 ? 1 : 0;
|
||||
|
||||
db.prepare(
|
||||
`INSERT INTO provider_instances (id, name, providerName, apiKey, isActive, modelName, type, maxContext, endpointUrl)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
).run(
|
||||
newId,
|
||||
newName,
|
||||
source.providerName,
|
||||
source.apiKey,
|
||||
isActive,
|
||||
source.modelName,
|
||||
source.type,
|
||||
source.maxContext,
|
||||
source.endpointUrl,
|
||||
);
|
||||
|
||||
return {
|
||||
id: newId,
|
||||
name: newName,
|
||||
providerName: source.providerName,
|
||||
apiKey: source.apiKey,
|
||||
isActive: isActive === 1,
|
||||
modelName: source.modelName || undefined,
|
||||
type: source.type as "generative" | "embedding",
|
||||
maxContext: source.maxContext,
|
||||
endpointUrl: source.endpointUrl || undefined,
|
||||
};
|
||||
}
|
||||
static delete(id: string): void {
|
||||
const db = getDb();
|
||||
const provider = db
|
||||
|
||||
76
pnpm-lock.yaml
generated
76
pnpm-lock.yaml
generated
@@ -6,74 +6,74 @@ importers:
|
||||
configDependencies: {}
|
||||
packageManagerDependencies:
|
||||
"@pnpm/exe":
|
||||
specifier: 11.13.0
|
||||
version: 11.13.0
|
||||
specifier: 11.15.1
|
||||
version: 11.15.1
|
||||
pnpm:
|
||||
specifier: 11.13.0
|
||||
version: 11.13.0
|
||||
specifier: 11.15.1
|
||||
version: 11.15.1
|
||||
|
||||
packages:
|
||||
"@pnpm/exe@11.13.0":
|
||||
"@pnpm/exe@11.15.1":
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-aXsm4VW1awRuh4X4G4fl+1xdV+L9DElKrgc4Yq/3zgGQQ12ATj1n3MMeosfa68aX/i7E9VyWT42adDSg8+kEFQ==,
|
||||
integrity: sha512-+e+DQrUPtDqH+9blSre23l7od3P3lRy43HN8TOKHNvbtuTNDRQtqQ0seHk/kn7iJl+ZSKBALFrQXPvbItNgRwA==,
|
||||
}
|
||||
hasBin: true
|
||||
|
||||
"@pnpm/linux-arm64@11.13.0":
|
||||
"@pnpm/linux-arm64@11.15.1":
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-86ri9P/i3Enbv0NBAEtz27lBHHwCJqsC7YxHX56+jXPyFobGbsDVR5OUyoCCVVNz/Phs2O7c9SaDVdqKPzUFCA==,
|
||||
integrity: sha512-8QOTdBeklXcE/AY4cAR2RJ4809I38kLxtInAYW4sVDfQoWYjmEIoU/ZxpHsk78KM8VU0BehtOB+iZsMxSCyiLQ==,
|
||||
}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
"@pnpm/linux-x64@11.13.0":
|
||||
"@pnpm/linux-x64@11.15.1":
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-ZXvUMP5ew1WZllTq1f7Tm3l6sF5LK5sMesfdu9J6uxsznK/3tTi6edUeiNN6dA22mAHhjvrzVj+MeQ6X3DG0tA==,
|
||||
integrity: sha512-hbhuC2Rh5Zw9ERUsQhOSLPnwfWSRTU6phtuFdK2I2raYCXa7v5C4i+XKTH+sKLPG5vJiKPyi4Hd62UECHZoy2w==,
|
||||
}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
"@pnpm/linuxstatic-arm64@11.13.0":
|
||||
"@pnpm/linuxstatic-arm64@11.15.1":
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-elwRj0sE3W54gDECgbHu2/TerpZsHXRmLSXfzuIvReumGuOYk5zlUhD5dJqzp0B1ktetVNU4Rb1keENz5/Gb/Q==,
|
||||
integrity: sha512-xEL9kDvLXnNYAgQak9tfIhO/BaBf1R/1+/dzzntuquzSqrEaPs0x0P4qMmwq02hVBDfAGA2MAD4n9kmc6Q//tw==,
|
||||
}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
"@pnpm/linuxstatic-x64@11.13.0":
|
||||
"@pnpm/linuxstatic-x64@11.15.1":
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-PQyfFMRA6/uYB+1vqx0wSXfOirC5CUOKRlTjXNgI1q/R1Ug/NMDfKOr52qbWFllcG9pIHKV8hZTo4WyBUjS1mA==,
|
||||
integrity: sha512-SLJ4neJx649ri4qHdseQN6SnAy6nNFnsLGi7g+EH32cVux4aWX7tjMNTPHrUKJ6Oc7C6oPGXUpLmemEvAwCPOg==,
|
||||
}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
"@pnpm/macos-arm64@11.13.0":
|
||||
"@pnpm/macos-arm64@11.15.1":
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-qWf2wbvESMICLJcVfWNh4pwIsr2oK6yFwbuv1uHi0UY3OnWNt0+POmhqWtYWtDj+EPWM3pSfEAc+KFQAiaBCvg==,
|
||||
integrity: sha512-GbIUQcDZgO/i1Ql38Pk269KNYpEbSCWYcSXBHgT62y8qVTrpEbmi+TKNaLVYuUkK0k/hMibySRa5GUs7/vnNyw==,
|
||||
}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
"@pnpm/win-arm64@11.13.0":
|
||||
"@pnpm/win-arm64@11.15.1":
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-ZvbGFdjU3cX32+/sHOhV9VkkbBucJ9QyW/F6VSsqgkvmTZTXlQglYp4K1KBbKWxYKz4i6M9p5PStI6yYB+y0jA==,
|
||||
integrity: sha512-pLlcpdtoaHJxVfhWahoQg5U7Mv9b6/X/8og+dY1GX1GvsZU3Wf7Y+LlA1sfxqoPcohtQdo6MdJkWiOZ3nIFMCQ==,
|
||||
}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
"@pnpm/win-x64@11.13.0":
|
||||
"@pnpm/win-x64@11.15.1":
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-5KX2lMFbXZNvKC+gLftR5FiU25j/jMp24Zi9JB01T3r42uxrHt12GQP7CNkNjxCXdi8jioUB7e3iT1eINS8qVQ==,
|
||||
integrity: sha512-gAvQjBOrNb8zHXRQawBfZRtjDWEFe6p9aSBi8uuMtWB4XAaj0+YuzstsR93llZ/UgP67oTkbkCOITBLayRVGGQ==,
|
||||
}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
@@ -168,47 +168,47 @@ packages:
|
||||
}
|
||||
engines: { node: ">=8" }
|
||||
|
||||
pnpm@11.13.0:
|
||||
pnpm@11.15.1:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-iNlHJNjy5sGGdEpVhMblnsrIaex7oV6ctM1ijo3HBmggskgdjuO1HqjaMjpzeAaKpYxVajcg0yt8IKBR0Ig2Og==,
|
||||
integrity: sha512-gTULB+U8lTigLx8jA7QpD6LXvgTlbiqXDEzEtBfcdh3hlu2r1J1Vx9yVgNuBAHxEFD5OPX5GKzAA0jwlUSLQZQ==,
|
||||
}
|
||||
engines: { node: ">=22.13" }
|
||||
hasBin: true
|
||||
|
||||
snapshots:
|
||||
"@pnpm/exe@11.13.0":
|
||||
"@pnpm/exe@11.15.1":
|
||||
dependencies:
|
||||
"@reflink/reflink": 0.1.19
|
||||
detect-libc: 2.1.2
|
||||
optionalDependencies:
|
||||
"@pnpm/linux-arm64": 11.13.0
|
||||
"@pnpm/linux-x64": 11.13.0
|
||||
"@pnpm/linuxstatic-arm64": 11.13.0
|
||||
"@pnpm/linuxstatic-x64": 11.13.0
|
||||
"@pnpm/macos-arm64": 11.13.0
|
||||
"@pnpm/win-arm64": 11.13.0
|
||||
"@pnpm/win-x64": 11.13.0
|
||||
"@pnpm/linux-arm64": 11.15.1
|
||||
"@pnpm/linux-x64": 11.15.1
|
||||
"@pnpm/linuxstatic-arm64": 11.15.1
|
||||
"@pnpm/linuxstatic-x64": 11.15.1
|
||||
"@pnpm/macos-arm64": 11.15.1
|
||||
"@pnpm/win-arm64": 11.15.1
|
||||
"@pnpm/win-x64": 11.15.1
|
||||
|
||||
"@pnpm/linux-arm64@11.13.0":
|
||||
"@pnpm/linux-arm64@11.15.1":
|
||||
optional: true
|
||||
|
||||
"@pnpm/linux-x64@11.13.0":
|
||||
"@pnpm/linux-x64@11.15.1":
|
||||
optional: true
|
||||
|
||||
"@pnpm/linuxstatic-arm64@11.13.0":
|
||||
"@pnpm/linuxstatic-arm64@11.15.1":
|
||||
optional: true
|
||||
|
||||
"@pnpm/linuxstatic-x64@11.13.0":
|
||||
"@pnpm/linuxstatic-x64@11.15.1":
|
||||
optional: true
|
||||
|
||||
"@pnpm/macos-arm64@11.13.0":
|
||||
"@pnpm/macos-arm64@11.15.1":
|
||||
optional: true
|
||||
|
||||
"@pnpm/win-arm64@11.13.0":
|
||||
"@pnpm/win-arm64@11.15.1":
|
||||
optional: true
|
||||
|
||||
"@pnpm/win-x64@11.13.0":
|
||||
"@pnpm/win-x64@11.15.1":
|
||||
optional: true
|
||||
|
||||
"@reflink/reflink-darwin-arm64@0.1.19":
|
||||
@@ -248,7 +248,7 @@ snapshots:
|
||||
|
||||
detect-libc@2.1.2: {}
|
||||
|
||||
pnpm@11.13.0: {}
|
||||
pnpm@11.15.1: {}
|
||||
|
||||
---
|
||||
lockfileVersion: "9.0"
|
||||
|
||||
Reference in New Issue
Block a user