diff --git a/PRIMITIVES.md b/PRIMITIVES.md index 6a9edea8..9c4e8e5b 100644 --- a/PRIMITIVES.md +++ b/PRIMITIVES.md @@ -127,7 +127,18 @@ MCP servers, validated against a toolspec. cookies + localStorage after each acting call and on graceful stop into a per-session Secret — the one Secret the runner is RBAC-allowed to write, never model-visible — and re-injects it when the pod wakes after a reap, so a login - survives pod churn (`pkg/agent/tool/browser/capture.go`). + survives pod churn (`pkg/agent/tool/browser/capture.go`). Phase D attaches a + **redacted** page screenshot to every browser approval/human-step card — the + acting-approval (`web_host#act`) plan-gate ask, `request_human_step`'s + confirm/code prompts, and the CAPTCHA notice — so the human deciding sees the + same page the agent does, not just its summary: credential-filled fields are + painted opaque black (`pkg/agent/tool/browser/screenshot_capture.go` resolves + each filled field's box via `dom.GetBoxModel` and fails closed on any + unresolved box; `pkg/agent/tool/browser/screenshot_redact.go` does the pixel + paint-over) before the PNG is ever stored, and the screenshot is attached to + `channelevents.InteractionRequestPayload.Screenshot` — never placed in the + model's context. Slack uploads it into the approval thread, the web chat + embeds it inline, and the local TUI links it via a signed artifact-view URL. - **Binaries:** `internal/cmd/streamclient/` (claims a streaming ToolCall via the gateway); tool execution is otherwise driven from `internal/cmd/runner/` diff --git a/pkg/agent/runner/browser_screenshot.go b/pkg/agent/runner/browser_screenshot.go new file mode 100644 index 00000000..88c790c7 --- /dev/null +++ b/pkg/agent/runner/browser_screenshot.go @@ -0,0 +1,202 @@ +package runner + +import ( + "bytes" + "context" + "fmt" + "io" + "log/slog" + + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + browsertool "github.com/authzed/openagentprimitives/pkg/agent/tool/browser" + spiceboxv1alpha1 "github.com/authzed/openagentprimitives/pkg/apis/v1alpha1" + "github.com/authzed/openagentprimitives/pkg/channels/channelevents" + "github.com/authzed/openagentprimitives/pkg/memory" + memartifact "github.com/authzed/openagentprimitives/pkg/memory/kinds/artifact" + "github.com/authzed/openagentprimitives/pkg/platform/artifacts" + "github.com/authzed/openagentprimitives/pkg/platform/artifactstore" +) + +// screenshotInlineMaxBytes is the ArtifactRenderSpec.Payload inline cap +// (pkg/apis/v1alpha1/artifactrender_types.go:57-65: "Payload inline, ≤256 +// KiB. Exactly one of Payload or PayloadRef MUST be set."). A redacted +// screenshot at or under this size is attached inline; a larger one is +// written to the artifact store first and referenced by PayloadRef. +const screenshotInlineMaxBytes = 256 << 10 + +// Fixed metadata for every screenshot artifact this package creates: one +// filename/alt-text for the whole feature, so it only needs saying once. +// The renderer kind and MIME are NOT literals here — see +// channelevents.ScreenshotRendererKind / ScreenshotMIME for why (this +// package is under mime_opinion_guard_test.go). +const ( + screenshotFilename = "page.png" + screenshotAltText = "current page (credential fields redacted)" +) + +// screenshotArtifactPutter is the subset of artifactstore.Store that +// storeScreenshotArtifact needs: Put, to store a screenshot too large to +// inline. Narrowed (mirroring secretOutputStatusWriter in loop_secretout.go +// and uiResourceStatusWriter in loop_uiresource.go) so a test can provide a +// minimal recorder without constructing a full artifactstore.Store. +type screenshotArtifactPutter interface { + Put(ctx context.Context, key string, r io.Reader) (artifactstore.Ref, error) +} + +// screenshotStoreDeps bundles the backend wiring storeScreenshotArtifact +// needs to turn redacted screenshot bytes into a durable ArtifactRender CR: +// the CR client, the artifact store (consulted only when the PNG exceeds the +// inline cap), and the session's UID for the CR's owner-ref. +// +// NewRenderName and NewArtifactID are optional id seams: nil means +// production (artifacts.RenderName and memory.NewID(memartifact.Kind{}), +// the same pair artifacts.Service itself defaults to) — mirroring +// artifacts.Service's own WithRenderNameMinter/newID seams so tests can +// assert on a deterministic CR name and artifact id instead of a random one. +type screenshotStoreDeps struct { + Client client.Client + ArtifactStore screenshotArtifactPutter + SessionUID types.UID + + NewRenderName func(session string) string + NewArtifactID func() string +} + +// storeScreenshotArtifact persists a redacted page screenshot (the PNG bytes +// Task 2 produces) as an ArtifactRender{Kind:"image"} CR and returns the +// AttachmentRef the interaction request payload's Screenshot field carries. +// +// Mirrors the CR-build shape in pkg/agent/tool/meta/artifact_prepare.go:264-274 +// and pkg/platform/artifacts.NewRender: owned by the session (by UID, as +// controller, blocking deletion), labeled with the artifact id. Unlike +// artifact_prepare / persistWidget (loop_uiresource.go) this does NOT poll the +// CR to Ready: a screenshot attaches to a live interaction request, not a +// model-facing handle, and AttachmentRef's own contract (see the doc comment +// on channelevents.AttachmentRef) is that the consumer re-Gets the CR and +// reads status.outputRef at delivery time — there is nothing for this call to +// wait on. +// +// A PNG at or under screenshotInlineMaxBytes is attached inline +// (Spec.Payload); a larger one is written to the artifact store first and +// referenced by Spec.PayloadRef. Exactly one of the two is ever set. +func storeScreenshotArtifact(ctx context.Context, deps screenshotStoreDeps, sess channelevents.SessionRef, png []byte) (*channelevents.AttachmentRef, error) { + // Fail closed on a nil Client with an ERROR, not a nil-interface panic: + // deps.Client is a plain client.Client interface field (Loop.Client), and a + // Loop built without one (a kubectl-driven session, today's e2e in-process + // harness — see Loop.screenshotStoreDeps' doc) must degrade to "ship no + // screenshot" like any other capture/store failure, never crash the + // dispatch goroutine calling it. + if deps.Client == nil { + return nil, fmt.Errorf("storeScreenshotArtifact: no k8s client wired (Loop.Client is nil)") + } + newRenderName := deps.NewRenderName + if newRenderName == nil { + newRenderName = artifacts.RenderName + } + newArtifactID := deps.NewArtifactID + if newArtifactID == nil { + newArtifactID = func() string { return memory.NewID(memartifact.Kind{}) } + } + + artifactID := newArtifactID() + renderName := newRenderName(sess.Name) + + spec := spiceboxv1alpha1.ArtifactRenderSpec{ + Kind: channelevents.ScreenshotRendererKind, + Filename: screenshotFilename, + AltText: screenshotAltText, + } + if len(png) <= screenshotInlineMaxBytes { + spec.Payload = png + } else { + if deps.ArtifactStore == nil { + return nil, fmt.Errorf("storeScreenshotArtifact: screenshot is %d bytes (> %d-byte inline cap) but no artifact store is wired", len(png), screenshotInlineMaxBytes) + } + key := fmt.Sprintf("%s/%s/%s/%s", sess.Namespace, sess.Name, artifactID, screenshotFilename) + ref, err := deps.ArtifactStore.Put(ctx, key, bytes.NewReader(png)) + if err != nil { + return nil, fmt.Errorf("storeScreenshotArtifact: store screenshot bytes: %w", err) + } + spec.PayloadRef = string(ref) + } + + cr := artifacts.NewRender(renderName, sess.Namespace, sess.Name, deps.SessionUID, artifactID, spec, nil) + if err := deps.Client.Create(ctx, cr); err != nil { + return nil, fmt.Errorf("storeScreenshotArtifact: create ArtifactRender: %w", err) + } + + return &channelevents.AttachmentRef{ + RenderName: cr.Name, + ArtifactID: artifactID, + MIME: channelevents.ScreenshotMIME, + Filename: screenshotFilename, + AltText: screenshotAltText, + }, nil +} + +// screenshotStoreDeps builds storeScreenshotArtifact's backend wiring from +// this Loop's own fields: l.Client creates the ArtifactRender CR — the same +// value applyUIResource's own CR create+poll uses (loop.go's +// uiResourceDeps{Client: l.Client, ...}) — and l.AgentSession's UID owns it +// (mirrors loop.go's own "var sessionUID types.UID; if l.AgentSession != nil +// { sessionUID = l.AgentSession.UID }" guard — empty when Loop.AgentSession is +// unset, e.g. a kubectl-driven session or a unit test). +// +// ArtifactStore is deliberately left nil: Loop carries no write-capable +// artifactstore.Store today. l.Artifacts (*artifacts.Service) manages +// ArtifactRender CR headers/revisions over memory.Memory, and l.ArtifactReader +// is read-only (modality.ArtifactReader) — neither is a screenshotArtifactPutter. +// That means only the <=screenshotInlineMaxBytes inline Payload path is +// reachable from this wiring; a screenshot over the cap makes +// storeScreenshotArtifact return an error, which the caller +// (captureBrowserScreenshotFn below) logs and treats as "ship no screenshot" — +// same as any other capture/store failure, per the best-effort/fail-closed +// contract. A single-viewport redacted PNG is well under 256 KiB in practice, +// so this degrades gracefully rather than requiring a new store seam to be +// threaded through Loop for this feature. +func (l *Loop) screenshotStoreDeps() screenshotStoreDeps { + var sessionUID types.UID + if l.AgentSession != nil { + sessionUID = l.AgentSession.UID + } + return screenshotStoreDeps{ + Client: l.Client, + SessionUID: sessionUID, + } +} + +// captureBrowserScreenshotFn builds the best-effort, fail-closed closure a +// runnerHost's captureScreenshot field carries: capture a redacted screenshot +// via cap, store it as an ArtifactRender through l, and return the +// AttachmentRef to attach to a browser interaction payload — or nil, having +// logged why, on ANY capture or store failure. A capture/store failure NEVER +// surfaces as an error to the caller; the approval publish always proceeds. +// +// Shared by BOTH places a browser-sourced ask gets published (D-R3: one +// browser session, one capturer, two publish call sites, because +// request_human_step is itself a browser tool): executeToolContained wires it +// onto the per-call host it builds for the web_host#act acting-approval +// (plan_phase ask), and humanStepRequester.Confirm/RequestCode wire it onto +// the host THEY bind for the login_human_step ask — two different *runnerHost +// values (the latter is bound fresh per round-trip via hostBinder, see its +// doc), but the SAME Loop and the SAME capturer, which is all this closure +// needs. +func (l *Loop) captureBrowserScreenshotFn(sess channelevents.SessionRef, cap browsertool.BrowserScreenshotCapturer) func(context.Context) *channelevents.AttachmentRef { + return func(ctx context.Context) *channelevents.AttachmentRef { + png, err := cap.CaptureRedacted(ctx) + if err != nil { + slog.Info("browser screenshot: capture failed; publishing text-only", + "session", sess.Namespace+"/"+sess.Name, "err", err.Error()) + return nil + } + ref, err := storeScreenshotArtifact(ctx, l.screenshotStoreDeps(), sess, png) + if err != nil { + slog.Info("browser screenshot: store failed; publishing text-only", + "session", sess.Namespace+"/"+sess.Name, "err", err.Error()) + return nil + } + return ref + } +} diff --git a/pkg/agent/runner/browser_screenshot_test.go b/pkg/agent/runner/browser_screenshot_test.go new file mode 100644 index 00000000..4c0c5927 --- /dev/null +++ b/pkg/agent/runner/browser_screenshot_test.go @@ -0,0 +1,174 @@ +package runner + +import ( + "bytes" + "context" + "errors" + "io" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + "sigs.k8s.io/controller-runtime/pkg/client/interceptor" + + spiceboxv1alpha1 "github.com/authzed/openagentprimitives/pkg/apis/v1alpha1" + "github.com/authzed/openagentprimitives/pkg/channels/channelevents" + "github.com/authzed/openagentprimitives/pkg/platform/artifactstore" +) + +// browserScreenshotTestScheme builds a scheme carrying the ArtifactRender CRD +// type. package runner (this file) cannot reuse another file's internal-test +// scheme helper across _test.go files of the same package that declare their +// own (see apptoolsGrantTestScheme's doc comment) — each file in this +// package's test suite mints its own, so this one does too. +func browserScreenshotTestScheme(t *testing.T) *runtime.Scheme { + t.Helper() + s := runtime.NewScheme() + require.NoError(t, spiceboxv1alpha1.AddToScheme(s), "AddToScheme") + return s +} + +// fakeScreenshotPutter is a minimal screenshotArtifactPutter recorder: it +// never touches real storage, just remembers the keys/bytes it was asked to +// Put and hands back a fixed Ref. +type fakeScreenshotPutter struct { + ref artifactstore.Ref + err error + calls []struct { + key string + bytes []byte + } +} + +func (f *fakeScreenshotPutter) Put(_ context.Context, key string, r io.Reader) (artifactstore.Ref, error) { + b, err := io.ReadAll(r) + if err != nil { + return "", err + } + f.calls = append(f.calls, struct { + key string + bytes []byte + }{key: key, bytes: b}) + if f.err != nil { + return "", f.err + } + return f.ref, nil +} + +func TestStoreScreenshotArtifact_InlineVsRef(t *testing.T) { + scheme := browserScreenshotTestScheme(t) + sess := channelevents.SessionRef{Namespace: "default", Name: "s1"} + + t.Run("PNG under the 256 KiB cap is stored inline", func(t *testing.T) { + c := fake.NewClientBuilder().WithScheme(scheme).Build() + putter := &fakeScreenshotPutter{ref: "mem://should-not-be-used"} + deps := screenshotStoreDeps{ + Client: c, + ArtifactStore: putter, + SessionUID: types.UID("sess-uid-1"), + } + small := bytes.Repeat([]byte{0xAB}, 1024) // < 256 KiB + + ref, err := storeScreenshotArtifact(context.Background(), deps, sess, small) + require.NoError(t, err) + require.NotNil(t, ref) + + assert.NotEmpty(t, ref.RenderName) + assert.NotEmpty(t, ref.ArtifactID) + assert.Equal(t, "image/png", ref.MIME) + assert.Equal(t, "page.png", ref.Filename) + assert.Equal(t, "current page (credential fields redacted)", ref.AltText) + + var cr spiceboxv1alpha1.ArtifactRender + require.NoError(t, c.Get(context.Background(), client.ObjectKey{Namespace: sess.Namespace, Name: ref.RenderName}, &cr), + "the created ArtifactRender must be readable back by the returned RenderName") + assert.Equal(t, ref.RenderName, cr.Name) + assert.Equal(t, "image", cr.Spec.Kind) + assert.Equal(t, small, []byte(cr.Spec.Payload), "small PNG must be inline") + assert.Empty(t, cr.Spec.PayloadRef, "small PNG must not set PayloadRef") + assert.Equal(t, ref.ArtifactID, cr.Labels["artifact.agentprimitives.authzed.com/id"]) + assert.Empty(t, putter.calls, "artifactstore.Put must not be called for an inline-sized PNG") + }) + + t.Run("PNG over the 256 KiB cap is stored by ref", func(t *testing.T) { + c := fake.NewClientBuilder().WithScheme(scheme).Build() + putter := &fakeScreenshotPutter{ref: "mem://default/s1/screenshot.png"} + deps := screenshotStoreDeps{ + Client: c, + ArtifactStore: putter, + SessionUID: types.UID("sess-uid-1"), + } + big := bytes.Repeat([]byte{0xCD}, 300*1024) // > 256 KiB + + ref, err := storeScreenshotArtifact(context.Background(), deps, sess, big) + require.NoError(t, err) + require.NotNil(t, ref) + assert.Equal(t, "image/png", ref.MIME) + + var cr spiceboxv1alpha1.ArtifactRender + require.NoError(t, c.Get(context.Background(), client.ObjectKey{Namespace: sess.Namespace, Name: ref.RenderName}, &cr)) + assert.Nil(t, cr.Spec.Payload, "big PNG must not be inlined") + assert.Equal(t, "mem://default/s1/screenshot.png", cr.Spec.PayloadRef, "big PNG must be stored by ref") + + require.Len(t, putter.calls, 1, "artifactstore.Put must be called exactly once for an oversized PNG") + assert.Equal(t, big, putter.calls[0].bytes, "the exact PNG bytes must reach the artifact store") + }) + + t.Run("artifact store Put failure is returned, not swallowed", func(t *testing.T) { + c := fake.NewClientBuilder().WithScheme(scheme).Build() + putErr := errors.New("boom: store unavailable") + putter := &fakeScreenshotPutter{err: putErr} + deps := screenshotStoreDeps{ + Client: c, + ArtifactStore: putter, + SessionUID: types.UID("sess-uid-1"), + } + big := bytes.Repeat([]byte{0xEF}, 300*1024) + + ref, err := storeScreenshotArtifact(context.Background(), deps, sess, big) + require.Error(t, err) + assert.Nil(t, ref) + assert.ErrorIs(t, err, putErr) + }) + + t.Run("CR Create failure is returned, not swallowed", func(t *testing.T) { + createErr := errors.New("boom: create refused") + c := fake.NewClientBuilder().WithScheme(scheme). + WithInterceptorFuncs(interceptor.Funcs{ + Create: func(ctx context.Context, cl client.WithWatch, obj client.Object, opts ...client.CreateOption) error { + return createErr + }, + }). + Build() + deps := screenshotStoreDeps{ + Client: c, + SessionUID: types.UID("sess-uid-1"), + } + small := bytes.Repeat([]byte{0x01}, 16) + + ref, err := storeScreenshotArtifact(context.Background(), deps, sess, small) + require.Error(t, err) + assert.Nil(t, ref) + }) + + t.Run("deterministic name/id seams are honored", func(t *testing.T) { + c := fake.NewClientBuilder().WithScheme(scheme).Build() + deps := screenshotStoreDeps{ + Client: c, + ArtifactStore: &fakeScreenshotPutter{}, + SessionUID: types.UID("sess-uid-1"), + NewRenderName: func(session string) string { return "ar-" + session + "-fixed" }, + NewArtifactID: func() string { return "artifact-fixed" }, + } + small := bytes.Repeat([]byte{0x02}, 16) + + ref, err := storeScreenshotArtifact(context.Background(), deps, sess, small) + require.NoError(t, err) + assert.Equal(t, "ar-s1-fixed", ref.RenderName) + assert.Equal(t, "artifact-fixed", ref.ArtifactID) + }) +} diff --git a/pkg/agent/runner/browser_screenshot_wiring_test.go b/pkg/agent/runner/browser_screenshot_wiring_test.go new file mode 100644 index 00000000..2c6e0f04 --- /dev/null +++ b/pkg/agent/runner/browser_screenshot_wiring_test.go @@ -0,0 +1,329 @@ +package runner + +// browser_screenshot_wiring_test.go is the TDD suite for Task 4's D-R3 wiring: +// capture + store + attach a redacted screenshot when a BROWSER interaction is +// published, best-effort and fail-closed, and NEVER for a non-browser +// interaction. It exercises both seams the wiring touches: +// +// - The HOST-BUILDER seam: buildPlanGatePending (the web_host#act acting +// approval) and buildLoginHumanStepPending (request_human_step's +// login_human_step ask) attach payload.Screenshot from h.captureScreenshot +// when it is set and returns a non-nil ref, and leave it nil otherwise. +// - The DISPATCH seam: executeToolContained sets host.captureScreenshot ONLY +// when the dispatched tool.Tool implements browser.ScreenshotProvider with +// a non-nil capturer (D-R3) — proven end to end through the real capture + +// store path (storeScreenshotArtifact over a fake k8s client), a capture +// error (Screenshot stays nil, the ask still publishes, and the failure is +// logged), and a plain tool that never captures at all. +// +// Required assertions (brief + D-R3 ruling): +// +// (i) a browser ask with a working capturer sets payload.Screenshot +// (ii) a capture error leaves Screenshot nil AND the interaction still +// publishes (never blocks the approval), with the failure logged +// (iii) a non-browser tool never invokes any capturer at all + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "log/slog" + "sync" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + + "github.com/authzed/openagentprimitives/pkg/agent/tool" + browsertool "github.com/authzed/openagentprimitives/pkg/agent/tool/browser" + "github.com/authzed/openagentprimitives/pkg/authz/guardian/approval" + "github.com/authzed/openagentprimitives/pkg/channels/channelevents" + "github.com/authzed/openagentprimitives/pkg/memory" + "github.com/authzed/openagentprimitives/pkg/platform/pipeline" +) + +// fakeCapturer is a stub browser.BrowserScreenshotCapturer: returns a scripted +// PNG or error and counts calls, so a test can prove it was (or was never) +// invoked. +type fakeCapturer struct { + mu sync.Mutex + calls int + png []byte + err error +} + +func (f *fakeCapturer) CaptureRedacted(_ context.Context) ([]byte, error) { + f.mu.Lock() + defer f.mu.Unlock() + f.calls++ + if f.err != nil { + return nil, f.err + } + return f.png, nil +} + +func (f *fakeCapturer) callCount() int { + f.mu.Lock() + defer f.mu.Unlock() + return f.calls +} + +// --------------------------------------------------------------------------- +// Host-builder seam: buildPlanGatePending / buildLoginHumanStepPending +// --------------------------------------------------------------------------- + +// TestBuildPlanGatePending_AttachesScreenshot_WhenCaptureSucceeds proves the +// web_host#act acting-approval card carries the screenshot the host's +// captureScreenshot closure returns. +func TestBuildPlanGatePending_AttachesScreenshot_WhenCaptureSucceeds(t *testing.T) { + var published channelevents.Envelope + h := planGateHost(t, &published) + ref := &channelevents.AttachmentRef{RenderName: "shot-1", ArtifactID: "art-1", MIME: "image/png", Filename: "page.png", AltText: "current page"} + var calls int + h.captureScreenshot = func(_ context.Context) *channelevents.AttachmentRef { + calls++ + return ref + } + + reqID, err := h.PublishApproval(context.Background(), planPhaseAsk()) + require.NoError(t, err) + pa, ok := h.pending().m[reqID] + require.True(t, ok) + require.NoError(t, pa.onPublish(context.Background())) + + assert.Equal(t, 1, calls, "the plan_phase builder must call captureScreenshot exactly once") + payload := decodeInteractionRequest(t, published) + require.NotNil(t, payload.Screenshot, "a working capturer must attach a screenshot") + assert.Equal(t, "shot-1", payload.Screenshot.RenderName) + assert.Equal(t, "art-1", payload.Screenshot.ArtifactID) +} + +// TestBuildPlanGatePending_NoScreenshot_WhenCaptureReturnsNil proves a capture +// that resolved to nil (the real closure already logged why) leaves +// Screenshot unset — and the card still publishes. +func TestBuildPlanGatePending_NoScreenshot_WhenCaptureReturnsNil(t *testing.T) { + var published channelevents.Envelope + h := planGateHost(t, &published) + h.captureScreenshot = func(_ context.Context) *channelevents.AttachmentRef { return nil } + + reqID, err := h.PublishApproval(context.Background(), planPhaseAsk()) + require.NoError(t, err) + pa, ok := h.pending().m[reqID] + require.True(t, ok) + require.NoError(t, pa.onPublish(context.Background()), "a nil screenshot must never block the publish") + + payload := decodeInteractionRequest(t, published) + assert.Nil(t, payload.Screenshot) +} + +// TestBuildPlanGatePending_NoScreenshot_WhenCaptureScreenshotUnset proves the +// browser-only gate at the builder: a host built for a non-browser call never +// has captureScreenshot set (executeToolContained leaves it nil), so the +// builder attempts no capture at all. +func TestBuildPlanGatePending_NoScreenshot_WhenCaptureScreenshotUnset(t *testing.T) { + var published channelevents.Envelope + h := planGateHost(t, &published) // h.captureScreenshot left nil, as for any non-browser call + + reqID, err := h.PublishApproval(context.Background(), planPhaseAsk()) + require.NoError(t, err) + pa, ok := h.pending().m[reqID] + require.True(t, ok) + require.NoError(t, pa.onPublish(context.Background())) + + payload := decodeInteractionRequest(t, published) + assert.Nil(t, payload.Screenshot) +} + +// TestBuildLoginHumanStepPending_AttachesScreenshot_WhenCaptureSucceeds mirrors +// the plan_phase case for request_human_step's login_human_step ask — the +// OTHER browser-sourced publish site D-R3 unifies via captureBrowserScreenshotFn. +func TestBuildLoginHumanStepPending_AttachesScreenshot_WhenCaptureSucceeds(t *testing.T) { + var published channelevents.Envelope + l := loginHumanStepLoop(approval.New(), func(_, _ string, env channelevents.Envelope) { published = env }) + h := newRunnerHost(l, hostSession{Namespace: "ns", Name: "s"}) + ref := &channelevents.AttachmentRef{RenderName: "shot-2", ArtifactID: "art-2", MIME: "image/png", Filename: "page.png", AltText: "current page"} + h.captureScreenshot = func(_ context.Context) *channelevents.AttachmentRef { return ref } + + reqID, err := h.PublishApproval(context.Background(), loginHumanStepAsk("approve the push")) + require.NoError(t, err) + pa, ok := h.pending().m[reqID] + require.True(t, ok) + require.NoError(t, pa.onPublish(context.Background())) + + payload := decodeInteractionRequest(t, published) + require.NotNil(t, payload.Screenshot, "a working capturer must attach a screenshot to the login_human_step card") + assert.Equal(t, "shot-2", payload.Screenshot.RenderName) +} + +// TestBuildLoginHumanStepPending_NoScreenshot_WhenCaptureScreenshotUnset proves +// the same browser-only gate for the login_human_step ask. +func TestBuildLoginHumanStepPending_NoScreenshot_WhenCaptureScreenshotUnset(t *testing.T) { + var published channelevents.Envelope + l := loginHumanStepLoop(approval.New(), func(_, _ string, env channelevents.Envelope) { published = env }) + h := newRunnerHost(l, hostSession{Namespace: "ns", Name: "s"}) + + reqID, err := h.PublishApproval(context.Background(), loginHumanStepAsk("approve the push")) + require.NoError(t, err) + pa, ok := h.pending().m[reqID] + require.True(t, ok) + require.NoError(t, pa.onPublish(context.Background())) + + payload := decodeInteractionRequest(t, published) + assert.Nil(t, payload.Screenshot) +} + +// --------------------------------------------------------------------------- +// Dispatch seam: executeToolContained's browser.ScreenshotProvider wiring +// --------------------------------------------------------------------------- + +// fakeBrowserDispatchTool is a fakeDispatchTool that ALSO implements +// browser.ScreenshotProvider, standing in for a real *browserTool (whose +// ScreenshotCapturer() returns its live *Session) without pulling in chromedp. +type fakeBrowserDispatchTool struct { + fakeDispatchTool + capturer browsertool.BrowserScreenshotCapturer +} + +func (f *fakeBrowserDispatchTool) ScreenshotCapturer() browsertool.BrowserScreenshotCapturer { + return f.capturer +} + +var _ browsertool.ScreenshotProvider = (*fakeBrowserDispatchTool)(nil) + +// screenshotAskHook publishes a fixed plan_phase ApprovalAsk at PreToolCall — +// the same host.PublishApproval → buildPlanGatePending machinery the real +// plan-gate hook drives, without reproducing its ceiling/slot logic, since +// this suite only cares whether the published payload's Screenshot field +// reflects what executeToolContained wired onto the host. The ask's own +// Timeout is set short so AwaitDecision resolves (as a fail-closed timeout) +// quickly — the test only inspects what was PUBLISHED, not the outcome. +type screenshotAskHook struct{} + +func (screenshotAskHook) Name() string { return "test_screenshot_ask_hook" } +func (screenshotAskHook) Points() []pipeline.Point { return []pipeline.Point{pipeline.PreToolCall} } +func (screenshotAskHook) Eval(_ context.Context, in pipeline.Input) pipeline.Decision { + if in.Point != pipeline.PreToolCall { + return pipeline.Decision{} + } + ask := planPhaseAsk() + ask.Timeout = 20 * time.Millisecond + return pipeline.Decision{Verdict: pipeline.Allow, Approval: &ask} +} + +// screenshotDispatchLoop builds a minimal Loop that can run executeToolContained +// through a plan_phase ask (resolving approvers and publishing), with Client +// wired to a fake k8s client so the full capture→store→attach path can +// complete (storeScreenshotArtifact creates an ArtifactRender CR). +func screenshotDispatchLoop(t *testing.T, tools []tool.Tool, published *channelevents.Envelope) *Loop { + t.Helper() + l := &Loop{ + Tools: tools, + SessionKey: memory.NamespacedName{Namespace: "ns", Name: "s"}, + Status: LocalStatusPatcher(), + Approval: approval.New(), + ChannelKind: "slack", + AgentName: "demo-agent", + Client: fake.NewClientBuilder().WithScheme(browserScreenshotTestScheme(t)).Build(), + SpiceDBLookupSubjects: func(_ context.Context, _, _ string) ([]string, error) { + return []string{"user:owner@example.com"}, nil + }, + InteractionRequestPublish: func(_ context.Context, _, _ string, env channelevents.Envelope) error { + *published = env + return nil + }, + } + reg := pipeline.NewRegistry() + reg.Register(screenshotAskHook{}, 10) + loopWithInjectedExecutor(t, l, reg) + return l +} + +// TestExecuteToolContained_AttachesScreenshot_ForScreenshotProviderToolWithWorkingCapturer +// is requirement (i): dispatching a tool that implements browser.ScreenshotProvider +// with a working capturer publishes a plan_phase ask whose payload carries the +// screenshot, through the REAL capture→store→attach path (no stubbed storage). +func TestExecuteToolContained_AttachesScreenshot_ForScreenshotProviderToolWithWorkingCapturer(t *testing.T) { + cap := &fakeCapturer{png: bytes.Repeat([]byte{0xAB}, 128)} // well under the inline cap + ft := &fakeBrowserDispatchTool{ + fakeDispatchTool: fakeDispatchTool{name: "browser_click", kind: tool.KindMCP, result: tool.Result{Content: "ok"}}, + capturer: cap, + } + var published channelevents.Envelope + l := screenshotDispatchLoop(t, []tool.Tool{ft}, &published) + sess := &tool.SessionContext{Namespace: "ns", Name: "s"} + + _, _ = l.executeToolContained(context.Background(), sess, ft, "browser_click", json.RawMessage(`{}`), "tu-1", "", containParams{}) + + assert.Equal(t, 1, cap.callCount(), "the dispatched tool's capturer must be invoked exactly once") + payload := decodeInteractionRequest(t, published) + require.NotNil(t, payload.Screenshot, "a ScreenshotProvider tool with a working capturer must attach a screenshot") + assert.Equal(t, "image/png", payload.Screenshot.MIME) +} + +// TestExecuteToolContained_NoScreenshot_WhenCaptureErrors_PublishStillHappens +// is requirement (ii): a capture error leaves Screenshot nil, the ask still +// publishes (an approval must never be blocked by a screenshot failure), and +// the failure is logged. +func TestExecuteToolContained_NoScreenshot_WhenCaptureErrors_PublishStillHappens(t *testing.T) { + logs := &guardedBuf{} + prevLogger := slog.Default() + slog.SetDefault(slog.New(slog.NewTextHandler(logs, nil))) + t.Cleanup(func() { slog.SetDefault(prevLogger) }) + + cap := &fakeCapturer{err: errors.New("cdp: target closed")} + ft := &fakeBrowserDispatchTool{ + fakeDispatchTool: fakeDispatchTool{name: "browser_click", kind: tool.KindMCP, result: tool.Result{Content: "ok"}}, + capturer: cap, + } + var published channelevents.Envelope + l := screenshotDispatchLoop(t, []tool.Tool{ft}, &published) + sess := &tool.SessionContext{Namespace: "ns", Name: "s"} + + _, _ = l.executeToolContained(context.Background(), sess, ft, "browser_click", json.RawMessage(`{}`), "tu-1", "", containParams{}) + + assert.Equal(t, 1, cap.callCount(), "the capturer must still be invoked (and fail)") + payload := decodeInteractionRequest(t, published) + assert.Nil(t, payload.Screenshot, "a capture failure must never attach a screenshot") + assert.Contains(t, logs.String(), "browser screenshot: capture failed", "a capture failure must be logged with context") + assert.Contains(t, logs.String(), "cdp: target closed") +} + +// TestExecuteToolContained_NeverCaptures_ForNonScreenshotProviderTool is +// requirement (iii): a plain tool.Tool (no browser.ScreenshotProvider) never +// gets host.captureScreenshot set, so the SAME ask-publishing hook that +// attaches a screenshot for a browser tool attaches nothing here. +func TestExecuteToolContained_NeverCaptures_ForNonScreenshotProviderTool(t *testing.T) { + ft := &fakeDispatchTool{name: "read_file", kind: tool.KindMCP, result: tool.Result{Content: "ok"}} + var published channelevents.Envelope + l := screenshotDispatchLoop(t, []tool.Tool{ft}, &published) + sess := &tool.SessionContext{Namespace: "ns", Name: "s"} + + _, _ = l.executeToolContained(context.Background(), sess, ft, "read_file", json.RawMessage(`{}`), "tu-1", "", containParams{}) + + payload := decodeInteractionRequest(t, published) + assert.Nil(t, payload.Screenshot, "a non-browser tool must never attach a screenshot") +} + +// guardedBuf is a mutex-guarded io.Writer for slog output, mirroring +// failClosedLog (loop_precondition_failclosed_test.go): slog.SetDefault makes +// the handler reachable from any goroutine still running in the package's +// suite, so a bare bytes.Buffer would race under -race. +type guardedBuf struct { + mu sync.Mutex + buf bytes.Buffer +} + +func (g *guardedBuf) Write(p []byte) (int, error) { + g.mu.Lock() + defer g.mu.Unlock() + return g.buf.Write(p) +} + +func (g *guardedBuf) String() string { + g.mu.Lock() + defer g.mu.Unlock() + return g.buf.String() +} diff --git a/pkg/agent/runner/host.go b/pkg/agent/runner/host.go index 4f9c4ed2..5d98dee5 100644 --- a/pkg/agent/runner/host.go +++ b/pkg/agent/runner/host.go @@ -9,6 +9,7 @@ import ( "time" spiceboxv1alpha1 "github.com/authzed/openagentprimitives/pkg/apis/v1alpha1" + "github.com/authzed/openagentprimitives/pkg/channels/channelevents" "github.com/authzed/openagentprimitives/pkg/memory" "github.com/authzed/openagentprimitives/pkg/memory/kinds/infoleakageaudit" "github.com/authzed/openagentprimitives/pkg/platform/pipeline" @@ -91,6 +92,18 @@ type runnerHost struct { // containParams.approvalEvent and never mutated after — fixed for the host's // lifetime, like proxyExec above. approvalEvent func(approvalObservation) + + // captureScreenshot, when non-nil, captures a redacted screenshot of the + // live browser page and stores it as an ArtifactRender, returning the + // AttachmentRef to attach to a browser interaction's payload (or nil on + // ANY capture/store failure — best-effort, never blocks the approval). + // Set once in executeToolContained ONLY when the dispatched tool + // implements browser.ScreenshotProvider with a non-nil capturer (D-R3) — + // so it is nil for every non-browser tool call, which is the browser-only + // gate: buildPlanGatePending / buildLoginHumanStepPending attach a + // screenshot only when this is set. Never mutated after being set, like + // approvalEvent above. + captureScreenshot func(context.Context) *channelevents.AttachmentRef } // setColdStartPlacement records the SessionStart hook's turn-0 placement diff --git a/pkg/agent/runner/host_approval.go b/pkg/agent/runner/host_approval.go index 213e645e..56d2b9bb 100644 --- a/pkg/agent/runner/host_approval.go +++ b/pkg/agent/runner/host_approval.go @@ -1237,6 +1237,14 @@ func (h *runnerHost) buildLoginHumanStepPending(ctx context.Context, reqID strin ExpiresAt: expiresAtPtr(hostNow().Add(h.loginHumanStepTTL())), Interruptible: true, } + // Best-effort redacted screenshot — see buildPlanGatePending's identical + // gate; request_human_step is itself a browser tool (D-R3), so the same + // host.captureScreenshot closure is set for this ask kind too. + if h.captureScreenshot != nil { + if ref := h.captureScreenshot(ctx); ref != nil { + pl.Screenshot = ref + } + } env, eerr := channelevents.BuildEnvelope(sessNS, sessName, channelevents.KindInteractionRequest, pl) if eerr != nil { return nil, fmt.Errorf("build login_human_step interaction envelope: %w", eerr) @@ -2203,6 +2211,17 @@ func (h *runnerHost) buildPlanGatePending( ExpiresAt: expiresAtPtr(hostNow().Add(h.l.resolvedApprovalTimeout())), Interruptible: false, } + // Best-effort redacted screenshot: h.captureScreenshot is set ONLY when + // THIS call's tool implements browser.ScreenshotProvider with a live + // capturer (D-R3, see executeToolContained), so a non-browser plan_phase + // ask leaves it nil and never attempts a capture. Any capture/store + // failure already returned nil (logged at the closure) — only attach when + // non-nil. + if h.captureScreenshot != nil { + if ref := h.captureScreenshot(ctx); ref != nil { + pl.Screenshot = ref + } + } env, eerr := channelevents.BuildEnvelope(sessNS, sessName, channelevents.KindInteractionRequest, pl) if eerr != nil { return nil, fmt.Errorf("build %s interaction envelope: %w", category, eerr) diff --git a/pkg/agent/runner/humanstep_deps.go b/pkg/agent/runner/humanstep_deps.go index c1ecdf0a..f011028e 100644 --- a/pkg/agent/runner/humanstep_deps.go +++ b/pkg/agent/runner/humanstep_deps.go @@ -19,6 +19,7 @@ import ( "time" browsertool "github.com/authzed/openagentprimitives/pkg/agent/tool/browser" + "github.com/authzed/openagentprimitives/pkg/channels/channelevents" "github.com/authzed/openagentprimitives/pkg/platform/pipeline" ) @@ -56,12 +57,40 @@ func NewHumanStepRequester(host approvalHost, loop *Loop, timeout time.Duration) return &humanStepRequester{binder: staticHost{h: host}, loopFn: func() *Loop { return loop }, timeout: timeout} } +// wireScreenshot attaches cap to host's captureScreenshot field, best-effort: +// if host doesn't happen to be a *runnerHost (a test fake need not implement +// it) or s.loopFn resolves no live Loop, it silently does nothing and the +// login_human_step card simply carries no screenshot — never an error, since +// nothing here can fail the round-trip. +// +// This is the SAME capturer wiring executeToolContained does for the +// web_host#act acting-approval (D-R3: request_human_step is itself a browser +// tool, so both call sites share captureBrowserScreenshotFn — one Loop +// method, two *runnerHost values, because hostBinder deliberately binds a +// FRESH host per round-trip (see its doc) rather than reusing +// executeToolContained's). +func (s *humanStepRequester) wireScreenshot(host approvalHost, cap browsertool.BrowserScreenshotCapturer) { + if cap == nil { + return + } + rh, ok := host.(*runnerHost) + if !ok { + return + } + l := s.loopFn() + if l == nil { + return + } + rh.captureScreenshot = l.captureBrowserScreenshotFn( + channelevents.SessionRef{Namespace: rh.sess.Namespace, Name: rh.sess.Name}, cap) +} + // Confirm implements browser.HumanStepRequester: bind the ONE host this // round-trip runs against, publish the login_human_step card, then block for the // decision ON THAT SAME HOST. It writes nothing — the approved bool alone tells // request_human_step whether the person completed the step. A timeout surfaces as // TimedOut (fail-closed: never a silent success). -func (s *humanStepRequester) Confirm(ctx context.Context, prompt string) (browsertool.HumanStepOutcome, error) { +func (s *humanStepRequester) Confirm(ctx context.Context, prompt string, capturer browsertool.BrowserScreenshotCapturer) (browsertool.HumanStepOutcome, error) { if s.binder == nil { return browsertool.HumanStepOutcome{}, fmt.Errorf("human step unavailable (session not ready)") } @@ -69,6 +98,7 @@ func (s *humanStepRequester) Confirm(ctx context.Context, prompt string) (browse if err != nil { return browsertool.HumanStepOutcome{}, err } + s.wireScreenshot(host, capturer) reqID, err := host.PublishApproval(ctx, pipeline.ApprovalAsk{ Kind: "login_human_step", @@ -114,7 +144,7 @@ type humanStepCodeHost interface { // expects a free-text answer back), block for the decision ON THE SAME HOST, then // read the human's typed code off that host. Writes nothing; the caller types the // code into the page. A timeout is fail-closed (TimedOut, no code). -func (s *humanStepRequester) RequestCode(ctx context.Context, prompt string) (browsertool.HumanStepCodeOutcome, error) { +func (s *humanStepRequester) RequestCode(ctx context.Context, prompt string, capturer browsertool.BrowserScreenshotCapturer) (browsertool.HumanStepCodeOutcome, error) { if s.binder == nil { return browsertool.HumanStepCodeOutcome{}, fmt.Errorf("human step unavailable (session not ready)") } @@ -122,6 +152,7 @@ func (s *humanStepRequester) RequestCode(ctx context.Context, prompt string) (br if err != nil { return browsertool.HumanStepCodeOutcome{}, err } + s.wireScreenshot(host, capturer) reqID, err := host.PublishApproval(ctx, pipeline.ApprovalAsk{ Kind: "login_human_step", @@ -167,7 +198,10 @@ func (s *humanStepRequester) RequestCode(ctx context.Context, prompt string) (br // Captcha implements browser.HumanStepRequester: surface the one-way // login_captcha notice on the live Loop. It does not block and writes nothing. -func (s *humanStepRequester) Captcha(ctx context.Context, prompt string) error { +// The capturer (the live browser session) is threaded into the notice +// publisher so the notice carries a redacted screenshot — the surface where a +// screenshot matters MOST, since a person must see the page to take over. +func (s *humanStepRequester) Captcha(ctx context.Context, prompt string, capturer browsertool.BrowserScreenshotCapturer) error { if s.loopFn == nil { return fmt.Errorf("human step captcha unavailable (session not ready)") } @@ -175,5 +209,5 @@ func (s *humanStepRequester) Captcha(ctx context.Context, prompt string) error { if l == nil { return fmt.Errorf("human step captcha unavailable (session not ready)") } - return l.publishLoginCaptchaNotice(ctx, prompt) + return l.publishLoginCaptchaNotice(ctx, prompt, capturer) } diff --git a/pkg/agent/runner/humanstep_deps_test.go b/pkg/agent/runner/humanstep_deps_test.go index c3c440d4..701d5a54 100644 --- a/pkg/agent/runner/humanstep_deps_test.go +++ b/pkg/agent/runner/humanstep_deps_test.go @@ -25,7 +25,7 @@ func TestHumanStepRequester_Confirm_PublishesLoginHumanStepAsk(t *testing.T) { host := &fakeApprovalHost{approved: true, by: "alice-canonical"} req := NewHumanStepRequester(host, nil, time.Second) - _, err := req.Confirm(context.Background(), "approve the push on your phone") + _, err := req.Confirm(context.Background(), "approve the push on your phone", nil) require.NoError(t, err) require.Equal(t, 1, host.publishCall, "Confirm must publish exactly one ask") @@ -69,7 +69,7 @@ func TestHumanStepRequester_Confirm_OutcomeMapping(t *testing.T) { host := &fakeApprovalHost{approved: tc.approved, by: tc.by, timedOut: tc.timedOut} req := NewHumanStepRequester(host, nil, time.Second) - got, err := req.Confirm(context.Background(), "approve the push") + got, err := req.Confirm(context.Background(), "approve the push", nil) require.NoError(t, err) assert.Equal(t, tc.want, got) }) @@ -83,7 +83,7 @@ func TestHumanStepRequester_RequestCode_PublishesLoginHumanStepAsk(t *testing.T) host := &fakeApprovalHost{approved: true, by: "alice-canonical", code: "123456"} req := NewHumanStepRequester(host, nil, time.Second) - _, err := req.RequestCode(context.Background(), "enter the emailed code") + _, err := req.RequestCode(context.Background(), "enter the emailed code", nil) require.NoError(t, err) require.Equal(t, 1, host.publishCall, "RequestCode must publish exactly one ask") @@ -133,7 +133,7 @@ func TestHumanStepRequester_RequestCode_OutcomeMapping(t *testing.T) { host := &fakeApprovalHost{approved: tc.approved, by: tc.by, timedOut: tc.timedOut, code: tc.hostCode} req := NewHumanStepRequester(host, nil, time.Second) - got, err := req.RequestCode(context.Background(), "enter the code") + got, err := req.RequestCode(context.Background(), "enter the code", nil) require.NoError(t, err) assert.Equal(t, tc.want, got) assert.Equal(t, tc.wantTakeCalls, host.takeCodeCall, "the code must be read off the host only on an approval") @@ -147,7 +147,7 @@ func TestHumanStepRequester_RequestCode_PublishErrorPropagates(t *testing.T) { host := &fakeApprovalHost{publishErr: errors.New("no resolvable approvers")} req := NewHumanStepRequester(host, nil, time.Second) - _, err := req.RequestCode(context.Background(), "enter the code") + _, err := req.RequestCode(context.Background(), "enter the code", nil) require.Error(t, err) assert.Contains(t, err.Error(), "no resolvable approvers") assert.Equal(t, 0, host.awaitCall, "AwaitDecision must never run after a publish error") @@ -160,7 +160,7 @@ func TestHumanStepRequester_Confirm_PublishErrorPropagates(t *testing.T) { host := &fakeApprovalHost{publishErr: errors.New("no resolvable approvers")} req := NewHumanStepRequester(host, nil, time.Second) - _, err := req.Confirm(context.Background(), "approve the push") + _, err := req.Confirm(context.Background(), "approve the push", nil) require.Error(t, err) assert.Contains(t, err.Error(), "no resolvable approvers") assert.Equal(t, 0, host.awaitCall, "AwaitDecision must never run after a publish error") @@ -176,7 +176,7 @@ func TestHumanStepRequester_Confirm_ZeroTimeout_PrefersHostResolvedTimeout(t *te } req := NewHumanStepRequester(host, nil, 0) - _, err := req.Confirm(context.Background(), "approve the push") + _, err := req.Confirm(context.Background(), "approve the push", nil) require.NoError(t, err) assert.Equal(t, 42*time.Second, host.gotTimeout) } @@ -187,7 +187,7 @@ func TestHumanStepRequester_Confirm_ZeroTimeout_FallsBackToDefault(t *testing.T) host := &fakeApprovalHost{approved: true} req := NewHumanStepRequester(host, nil, 0) - _, err := req.Confirm(context.Background(), "approve the push") + _, err := req.Confirm(context.Background(), "approve the push", nil) require.NoError(t, err) assert.Equal(t, defaultHumanStepTimeout, host.gotTimeout) } @@ -198,11 +198,11 @@ func TestHumanStepRequester_Confirm_ZeroTimeout_FallsBackToDefault(t *testing.T) func TestNewLateBoundHumanStepRequester_LoopNotReady_FailsClosed(t *testing.T) { req := NewLateBoundHumanStepRequester(func() *Loop { return nil }) - _, err := req.Confirm(context.Background(), "approve the push") + _, err := req.Confirm(context.Background(), "approve the push", nil) require.Error(t, err) assert.Contains(t, err.Error(), "not ready") - cerr := req.Captcha(context.Background(), "there is a captcha") + cerr := req.Captcha(context.Background(), "there is a captcha", nil) require.Error(t, cerr) assert.Contains(t, cerr.Error(), "not ready") } diff --git a/pkg/agent/runner/login_captcha_notice.go b/pkg/agent/runner/login_captcha_notice.go index 782d5088..69eae7c1 100644 --- a/pkg/agent/runner/login_captcha_notice.go +++ b/pkg/agent/runner/login_captcha_notice.go @@ -14,6 +14,7 @@ import ( "fmt" "strings" + browsertool "github.com/authzed/openagentprimitives/pkg/agent/tool/browser" "github.com/authzed/openagentprimitives/pkg/channels/channelevents" "github.com/authzed/openagentprimitives/pkg/channels/channelinteractions/categories" "github.com/authzed/openagentprimitives/pkg/channels/notice" @@ -30,7 +31,13 @@ const maxCaptchaPromptRunes = 500 // (kubectl-driven) has no InteractionRequestPublish wired, which is reported as // an error here and surfaced by request_human_step to the model rather than // swallowed. -func (l *Loop) publishLoginCaptchaNotice(ctx context.Context, prompt string) error { +// +// capturer is the live browser session (nil if none): the notice carries a +// redacted page screenshot so a person taking over to solve the CAPTCHA can +// see the page. Best-effort/fail-closed exactly like the acting-approval and +// login_human_step surfaces — a capture/store failure (or a nil capturer) +// yields no screenshot and the notice still publishes text-only. +func (l *Loop) publishLoginCaptchaNotice(ctx context.Context, prompt string, capturer browsertool.BrowserScreenshotCapturer) error { if l.InteractionRequestPublish == nil { return fmt.Errorf("login captcha notice unavailable (interaction publish hook not configured)") } @@ -51,6 +58,16 @@ func (l *Loop) publishLoginCaptchaNotice(ctx context.Context, prompt string) err if err != nil { return fmt.Errorf("build login captcha notice: %w", err) } + // Best-effort redacted screenshot, same closure the acting-approval and + // login_human_step surfaces use. captureBrowserScreenshotFn needs no host, + // so there is no host to thread through for this notice-only surface; a nil + // capturer or any capture/store failure resolves to nil and the notice + // publishes text-only. + if capturer != nil { + if ref := l.captureBrowserScreenshotFn(sess, capturer)(ctx); ref != nil { + pl.Screenshot = ref + } + } env, err := channelevents.BuildEnvelope(sessNS, sessName, channelevents.KindInteractionRequest, pl) if err != nil { return fmt.Errorf("build login captcha notice envelope: %w", err) diff --git a/pkg/agent/runner/login_captcha_notice_test.go b/pkg/agent/runner/login_captcha_notice_test.go index 90bf679a..5c425551 100644 --- a/pkg/agent/runner/login_captcha_notice_test.go +++ b/pkg/agent/runner/login_captcha_notice_test.go @@ -3,10 +3,12 @@ package runner import ( "context" "encoding/json" + "errors" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "sigs.k8s.io/controller-runtime/pkg/client/fake" "github.com/authzed/openagentprimitives/pkg/channels/channelevents" "github.com/authzed/openagentprimitives/pkg/channels/channelinteractions/categories" @@ -31,7 +33,7 @@ func TestPublishLoginCaptchaNotice_PublishesNotice(t *testing.T) { }, } - err := l.publishLoginCaptchaNotice(context.Background(), report) + err := l.publishLoginCaptchaNotice(context.Background(), report, nil) require.NoError(t, err) require.Equal(t, channelevents.KindInteractionRequest, published.Kind) @@ -58,7 +60,63 @@ func TestPublishLoginCaptchaNotice_NoPublisher_Errors(t *testing.T) { SessionKey: memory.NamespacedName{Namespace: "ns", Name: "s"}, // InteractionRequestPublish deliberately nil. } - err := l.publishLoginCaptchaNotice(context.Background(), "a captcha appeared") + err := l.publishLoginCaptchaNotice(context.Background(), "a captcha appeared", nil) require.Error(t, err) assert.Contains(t, err.Error(), "publish hook") } + +// TestPublishLoginCaptchaNotice_AttachesScreenshot proves that when a screenshot +// capturer succeeds, the CAPTCHA notice's payload carries the screenshot artifact ref. +func TestPublishLoginCaptchaNotice_AttachesScreenshot(t *testing.T) { + var published channelevents.Envelope + l := &Loop{ + Status: LocalStatusPatcher(), + SessionKey: memory.NamespacedName{Namespace: "ns", Name: "s"}, + Client: fake.NewClientBuilder().WithScheme(browserScreenshotTestScheme(t)).Build(), + InteractionRequestPublish: func(_ context.Context, ns, name string, env channelevents.Envelope) error { + assert.Equal(t, "ns", ns) + assert.Equal(t, "s", name) + published = env + return nil + }, + } + + err := l.publishLoginCaptchaNotice(context.Background(), "a captcha appeared", &fakeCapturer{png: []byte("fakepngbytes")}) + require.NoError(t, err) + + require.Equal(t, channelevents.KindInteractionRequest, published.Kind) + var pl channelevents.InteractionRequestPayload + require.NoError(t, json.Unmarshal(published.Payload, &pl)) + + require.NotNil(t, pl.Screenshot, "a working capturer must attach a screenshot") + assert.NotEmpty(t, pl.Screenshot.RenderName) + assert.Equal(t, "image/png", pl.Screenshot.MIME) +} + +// TestPublishLoginCaptchaNotice_CaptureError_PublishesTextOnly proves that +// when a screenshot capturer fails, the CAPTCHA notice still publishes but +// without a screenshot (best-effort capture, fail-closed publish). +func TestPublishLoginCaptchaNotice_CaptureError_PublishesTextOnly(t *testing.T) { + var published channelevents.Envelope + l := &Loop{ + Status: LocalStatusPatcher(), + SessionKey: memory.NamespacedName{Namespace: "ns", Name: "s"}, + Client: fake.NewClientBuilder().WithScheme(browserScreenshotTestScheme(t)).Build(), + InteractionRequestPublish: func(_ context.Context, ns, name string, env channelevents.Envelope) error { + assert.Equal(t, "ns", ns) + assert.Equal(t, "s", name) + published = env + return nil + }, + } + + err := l.publishLoginCaptchaNotice(context.Background(), "a captcha appeared", &fakeCapturer{err: errors.New("capture boom")}) + require.NoError(t, err, "capture error must not fail the notice publish") + + require.Equal(t, channelevents.KindInteractionRequest, published.Kind) + var pl channelevents.InteractionRequestPayload + require.NoError(t, json.Unmarshal(published.Payload, &pl)) + + assert.Nil(t, pl.Screenshot, "a capture error must leave screenshot nil") + assert.NotEmpty(t, pl.Excerpt.Content, "the text notice must still be published") +} diff --git a/pkg/agent/runner/loop_dispatch.go b/pkg/agent/runner/loop_dispatch.go index 580bf4ca..920d9518 100644 --- a/pkg/agent/runner/loop_dispatch.go +++ b/pkg/agent/runner/loop_dispatch.go @@ -14,8 +14,10 @@ import ( "github.com/authzed/openagentprimitives/pkg/agent/runner/approval/summarizer" lifecyclecore "github.com/authzed/openagentprimitives/pkg/agent/session/lifecycle" "github.com/authzed/openagentprimitives/pkg/agent/tool" + browsertool "github.com/authzed/openagentprimitives/pkg/agent/tool/browser" "github.com/authzed/openagentprimitives/pkg/agent/tool/sandbox" "github.com/authzed/openagentprimitives/pkg/authz/toolguard" + "github.com/authzed/openagentprimitives/pkg/channels/channelevents" "github.com/authzed/openagentprimitives/pkg/platform/identity" "github.com/authzed/openagentprimitives/pkg/platform/identity/credupdate" "github.com/authzed/openagentprimitives/pkg/platform/pipeline" @@ -364,6 +366,19 @@ func (l *Loop) executeToolContained( // gate in host_approval.go. host.proxyExec = p.proxyExec host.approvalEvent = p.approvalEvent + // D-R3: web_request_human_step IS a browser tool, so BOTH the acting + // approval (web_host#act, a plan_phase ask) and the human-step asks + // (login_human_step) flow through this one seam — whichever ask kind t + // ends up publishing, the SAME host carries the capturer. A non-browser + // tool doesn't implement ScreenshotProvider, so host.captureScreenshot + // stays nil and no screenshot is ever attempted for it (the browser-only + // gate, enforced here rather than in the payload builders). + if sp, ok := t.(browsertool.ScreenshotProvider); ok { + if cap := sp.ScreenshotCapturer(); cap != nil { + host.captureScreenshot = l.captureBrowserScreenshotFn( + channelevents.SessionRef{Namespace: sess.Namespace, Name: sess.Name}, cap) + } + } preIn := pipeline.Input{ Session: pipeline.SessionRef{ diff --git a/pkg/agent/tool/browser/human_step_test.go b/pkg/agent/tool/browser/human_step_test.go index e454459a..68d7fc73 100644 --- a/pkg/agent/tool/browser/human_step_test.go +++ b/pkg/agent/tool/browser/human_step_test.go @@ -29,19 +29,19 @@ type fakeHumanStep struct { captchaErr error } -func (f *fakeHumanStep) Confirm(_ context.Context, prompt string) (HumanStepOutcome, error) { +func (f *fakeHumanStep) Confirm(_ context.Context, prompt string, _ BrowserScreenshotCapturer) (HumanStepOutcome, error) { f.confirmCalls++ f.confirmPrompt = prompt return f.outcome, f.confirmErr } -func (f *fakeHumanStep) RequestCode(_ context.Context, prompt string) (HumanStepCodeOutcome, error) { +func (f *fakeHumanStep) RequestCode(_ context.Context, prompt string, _ BrowserScreenshotCapturer) (HumanStepCodeOutcome, error) { f.codeCalls++ f.codePrompt = prompt return f.codeOutcome, f.codeErr } -func (f *fakeHumanStep) Captcha(_ context.Context, prompt string) error { +func (f *fakeHumanStep) Captcha(_ context.Context, prompt string, _ BrowserScreenshotCapturer) error { f.captchaCalls++ f.captchaPrompt = prompt return f.captchaErr diff --git a/pkg/agent/tool/browser/humanstep.go b/pkg/agent/tool/browser/humanstep.go index 87789e79..d7b02350 100644 --- a/pkg/agent/tool/browser/humanstep.go +++ b/pkg/agent/tool/browser/humanstep.go @@ -17,7 +17,13 @@ type HumanStepRequester interface { // person presses it, declines, or the approval window lapses — a push approval // the person completes on their phone, say. The outcome tells the tool which // happened; it carries no secret. - Confirm(ctx context.Context, prompt string) (HumanStepOutcome, error) + // + // capturer is the SAME live session's BrowserScreenshotCapturer the caller's + // ScreenshotCapturer() returns (nil if none) — request_human_step is itself a + // browser tool (D-R3), so its login_human_step card attaches a redacted + // screenshot exactly like the web_host#act acting-approval does, best-effort + // and never blocking the ask. + Confirm(ctx context.Context, prompt string, capturer BrowserScreenshotCapturer) (HumanStepOutcome, error) // RequestCode posts a login_human_step card asking the person to type an // emailed/SMS code, and blocks until they answer, decline, or the window lapses. @@ -27,13 +33,20 @@ type HumanStepRequester interface { // credential. The code is NEVER returned as a tool result or shown to the model. // A timeout is fail-closed: TimedOut is true, Code empty, and the caller reports // a failure rather than silently succeeding. - RequestCode(ctx context.Context, prompt string) (HumanStepCodeOutcome, error) + // + // capturer: see Confirm's doc — same best-effort screenshot attachment. + RequestCode(ctx context.Context, prompt string, capturer BrowserScreenshotCapturer) (HumanStepCodeOutcome, error) // Captcha surfaces a one-way notice that a person must take over in the browser // (a CAPTCHA the agent cannot solve, or any step with no actionable kind). It // does NOT block — there is no decision leg; the agent has reported it cannot // proceed, and a human steps in out of band. - Captcha(ctx context.Context, prompt string) error + // + // capturer: see Confirm's doc. The screenshot matters MOST here — a person + // taking over to solve a CAPTCHA must see the page — so the login_captcha + // notice attaches a redacted screenshot exactly like Confirm/RequestCode, + // best-effort and never blocking the notice. + Captcha(ctx context.Context, prompt string, capturer BrowserScreenshotCapturer) error } // HumanStepCodeOutcome is the result of a RequestCode round-trip. Exactly one of diff --git a/pkg/agent/tool/browser/screenshot_capture.go b/pkg/agent/tool/browser/screenshot_capture.go new file mode 100644 index 00000000..63a77622 --- /dev/null +++ b/pkg/agent/tool/browser/screenshot_capture.go @@ -0,0 +1,137 @@ +package browser + +import ( + "context" + "encoding/json" + "fmt" + "image" + "math" + + "github.com/chromedp/cdproto/cdp" + "github.com/chromedp/cdproto/dom" + "github.com/chromedp/cdproto/page" + "github.com/chromedp/cdproto/runtime" +) + +// BrowserScreenshotCapturer captures a redacted viewport screenshot of the +// current page. Injected into the runner's interaction-publish paths; the +// browser session is the only implementation. +type BrowserScreenshotCapturer interface { + CaptureRedacted(ctx context.Context) ([]byte, error) +} + +// ScreenshotProvider is implemented by a tool whose live browser session can +// produce a redacted approval screenshot. The runner's approval-publish path +// (pkg/agent/runner) type-asserts a dispatched tool.Tool for this interface — +// the same optional-interface idiom NamedCallArgs uses (tools.go) to surface +// CurrentHost to the Permission check — rather than threading a capturer +// through a new Loop-level seam. Only *browserTool implements it; a +// non-browser tool therefore never yields a capturer and the runner never +// captures a screenshot for it. +type ScreenshotProvider interface { + // ScreenshotCapturer returns the capturer for this tool's live session, or + // nil if none is available (e.g. a browserTool synthesized without a + // session in a unit test). + ScreenshotCapturer() BrowserScreenshotCapturer +} + +// CaptureRedacted captures the viewport and paints over every credential-filled +// (blanked) field. It is FAIL-CLOSED: if any blanked field's box cannot be +// resolved it returns an error and NO bytes, so the caller ships no screenshot +// rather than one that might reveal a typed secret. +func (s *Session) CaptureRedacted(ctx context.Context) ([]byte, error) { + blanked := s.blankedNodes() + var shot []byte + var boxes []image.Rectangle + runErr := s.do(ctx, snapshotTimeout, func(c context.Context) error { + // Device pixel ratio: CaptureScreenshot pixels are DPR * CSS pixels, + // while GetBoxModel returns CSS pixels, so boxes must be scaled. + var dpr float64 = 1 + if ae := runAction(c, func(ac context.Context) error { + r, _, err := runtime.Evaluate("window.devicePixelRatio").Do(ac) + if err != nil { + // Fail closed: without a trusted DPR we could compute boxes at 1x + // against a 2x screenshot and UNDER-cover the field on a HiDPI + // display. An eval error must ship no screenshot, like a box + // resolution failure — not silently assume 1x. + return fmt.Errorf("redact: read device pixel ratio: %w", err) + } + if r != nil && r.Value != nil { + _ = json.Unmarshal(r.Value, &dpr) // best-effort; a weird value falls back below + } + if dpr <= 0 { + dpr = 1 + } + return nil + }); ae != nil { + return ae + } + for _, id := range blanked { + var box *dom.BoxModel + if ae := runAction(c, func(ac context.Context) error { + var e error + box, e = dom.GetBoxModel().WithBackendNodeID(cdp.BackendNodeID(id)).Do(ac) + return e + }); ae != nil { + // Fail closed: a blanked field we can't locate means we can't + // prove the screenshot is clean. + return fmt.Errorf("redact: box for blanked node %d: %w", id, ae) + } + // An empty rect (a non-nil box with too few quad points) is also a + // resolution failure: we cannot prove what region holds the secret, + // so fail closed rather than ship an unredacted field. + if r := boxFromModelScaled(box, dpr); r.Empty() { + return fmt.Errorf("redact: empty box for blanked node %d", id) + } else { + boxes = append(boxes, r) + } + } + if ae := runAction(c, func(ac context.Context) error { + var e error + shot, e = page.CaptureScreenshot().Do(ac) + return e + }); ae != nil { + return ae + } + return nil + }) + if runErr != nil { + return nil, runErr + } + return redactPNG(shot, boxes) +} + +// boxFromModelScaled converts a CDP content-quad box to an axis-aligned +// rectangle in screenshot pixels. The content quad is [x1,y1,x2,y2,x3,y3,x4,y4]; +// we take the bounding rect and scale by the device pixel ratio. +func boxFromModelScaled(b *dom.BoxModel, dpr float64) image.Rectangle { + if b == nil || len(b.Content) < 8 { + return image.Rectangle{} + } + xs := []float64{b.Content[0], b.Content[2], b.Content[4], b.Content[6]} + ys := []float64{b.Content[1], b.Content[3], b.Content[5], b.Content[7]} + minX, maxX, minY, maxY := xs[0], xs[0], ys[0], ys[0] + for _, x := range xs { + if x < minX { + minX = x + } + if x > maxX { + maxX = x + } + } + for _, y := range ys { + if y < minY { + minY = y + } + if y > maxY { + maxY = y + } + } + // Floor the min corners and ceil the max corners so the rect FULLY ENCLOSES + // the field after DPR scaling — a fractional scaled edge (e.g. 560.4px) must + // never leave a sub-pixel sliver of the credential field unpainted. + return image.Rect( + int(math.Floor(minX*dpr)), int(math.Floor(minY*dpr)), + int(math.Ceil(maxX*dpr)), int(math.Ceil(maxY*dpr)), + ) +} diff --git a/pkg/agent/tool/browser/screenshot_capture_chrome_test.go b/pkg/agent/tool/browser/screenshot_capture_chrome_test.go new file mode 100644 index 00000000..73b05b58 --- /dev/null +++ b/pkg/agent/tool/browser/screenshot_capture_chrome_test.go @@ -0,0 +1,168 @@ +package browser + +// screenshot_capture_chrome_test.go is the real redaction proof against a live +// Chrome (startFixture, chrome_test.go): serve a page with a solid-red text +// input, type a credential into it through the REAL fill path so the field is +// marked blanked, call CaptureRedacted, and prove the field's region is painted +// black in the returned PNG while the rest of the page is untouched. Skipped +// with a reason when no Chrome binary is present (spec §7). + +import ( + "bytes" + "context" + "encoding/json" + "image" + "image/png" + "net/http" + "testing" + "time" + + "github.com/chromedp/cdproto/cdp" + "github.com/chromedp/cdproto/dom" + "github.com/chromedp/cdproto/runtime" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + agenttool "github.com/authzed/openagentprimitives/pkg/agent/tool" + spiceboxv1alpha1 "github.com/authzed/openagentprimitives/pkg/apis/v1alpha1" +) + +// redactSecretPage serves a single text input painted solid red (both +// background and text color) and absolutely positioned at a known spot, large +// enough that its box is unambiguous. A credential typed into it is therefore a +// red rectangle in the screenshot; after redaction it must be a BLACK +// rectangle. The page background is explicit white so a control sample outside +// the field proves the redaction was targeted, not a blanket blackout. +func redactSecretPage() http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + _, _ = w.Write([]byte(`` + + `
` + + ``)) + }) +} + +// browserRedactFixture boots the chrome fixture in act mode with a one-entry +// catalog for the fixture site, returning the synthesized tools, the shared +// session (for the blanked set + box resolution), and the site base URL. +func browserRedactFixture(t *testing.T) (tools []agenttool.Tool, sess *Session, siteBase string) { + t.Helper() + fx := startFixture(t, redactSecretPage()) + fx.rt.Spec.Interaction = "act" + fx.rt.IdentityName = "site-identity" + fx.rt.Catalog = []spiceboxv1alpha1.BrowserLoginRef{{ + ID: "login-site", + Label: "Site", + Hosts: []spiceboxv1alpha1.BrowserLoginHost{{Host: "site.test"}}, + }} + ff := &fakeFetcher{} + var err error + tools, err = Synthesize(fx.rt, fx.gateURL, chromeToken, false, ff.fetch(), nil, nil) + require.NoError(t, err) + require.NotEmpty(t, tools) + sess = tools[0].(*browserTool).sess + t.Cleanup(func() { sess.Close() }) + return tools, sess, fx.siteBase +} + +// TestCaptureRedacted_CoversBlankedField is the Task 2 keystone: a credential is +// typed into a field through the real fill path (which marks it blanked), and a +// subsequent CaptureRedacted paints that field's region solid black — proving no +// typed secret survives into the screenshot bytes — while leaving the rest of the +// page untouched. +func TestCaptureRedacted_CoversBlankedField(t *testing.T) { + tools, sess, siteBase := browserRedactFixture(t) + + require.False(t, run(t, toolBy(t, tools, "navigate"), map[string]any{"url": siteBase + "/"}).IsError) + + secretRef := refByName(t, tools, "SecretField") + + // Type a credential placeholder into the field via the REAL fill path; this + // marks the field blanked exactly like any filled credential. + typed := run(t, toolBy(t, tools, "type"), map[string]any{"ref": secretRef, "text": "{{login.site.test.username}}"}) + require.False(t, typed.IsError, "type into secret field: %s", typed.Content) + require.Len(t, sess.blankedNodes(), 1, "the typed-into field must be marked blanked") + + // Resolve the field's screenshot-space rect the same way CaptureRedacted does + // (content box scaled by DPR), so the sample points land inside the redacted + // region on a HiDPI display as well. + entry, ok := sess.lookupRef(secretRef) + require.True(t, ok, "the typed ref must still resolve (no navigation)") + rect := fieldScreenshotRect(t, sess, entry.backendNodeID) + require.False(t, rect.Empty(), "the field box must resolve to a non-empty rect") + + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + shot, err := sess.CaptureRedacted(ctx) + require.NoError(t, err, "CaptureRedacted must succeed with a resolvable blanked field") + require.NotEmpty(t, shot, "a redacted screenshot must have bytes") + + img, err := png.Decode(bytes.NewReader(shot)) + require.NoError(t, err) + + // Every sampled pixel across the field's region must be opaque black — the red + // secret rectangle is gone (the brief's uniform-fill-color assertion). + for _, p := range samplePoints(rect) { + r, g, b, a := img.At(p.X, p.Y).RGBA() + assert.True(t, r == 0 && g == 0 && b == 0 && a == 0xffff, + "field pixel (%d,%d) must be redacted black, got r=%d g=%d b=%d a=%d", p.X, p.Y, r, g, b, a) + } + + // Control: a pixel at the top-left page background, well outside the field, + // must be untouched white — redaction is targeted, not a blanket blackout. + cr, cg, cb, _ := img.At(2, 2).RGBA() + assert.True(t, cr == 0xffff && cg == 0xffff && cb == 0xffff, + "the page background outside the field must be untouched, got r=%d g=%d b=%d", cr, cg, cb) +} + +// fieldScreenshotRect resolves backendNodeID's content box and scales it to +// screenshot pixels exactly as CaptureRedacted does, so a test's sample points +// match the production redacted region regardless of device pixel ratio. +func fieldScreenshotRect(t *testing.T, sess *Session, backendNodeID int64) image.Rectangle { + t.Helper() + var rect image.Rectangle + ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) + defer cancel() + require.NoError(t, sess.do(ctx, shortTimeout, func(c context.Context) error { + var dpr float64 = 1 + if err := runAction(c, func(ac context.Context) error { + r, _, e := runtime.Evaluate("window.devicePixelRatio").Do(ac) + if e == nil && r != nil && r.Value != nil { + _ = json.Unmarshal(r.Value, &dpr) + } + return nil + }); err != nil { + return err + } + var box *dom.BoxModel + if err := runAction(c, func(ac context.Context) error { + var e error + box, e = dom.GetBoxModel().WithBackendNodeID(cdp.BackendNodeID(backendNodeID)).Do(ac) + return e + }); err != nil { + return err + } + rect = boxFromModelScaled(box, dpr) + return nil + })) + return rect +} + +// samplePoints returns the center plus the four inset corners of r, staying a +// few pixels inside each edge to avoid border antialiasing. +func samplePoints(r image.Rectangle) []image.Point { + const inset = 4 + minX, minY := r.Min.X+inset, r.Min.Y+inset + maxX, maxY := r.Max.X-inset-1, r.Max.Y-inset-1 + cx, cy := (r.Min.X+r.Max.X)/2, (r.Min.Y+r.Max.Y)/2 + return []image.Point{ + {X: cx, Y: cy}, + {X: minX, Y: minY}, + {X: maxX, Y: minY}, + {X: minX, Y: maxY}, + {X: maxX, Y: maxY}, + } +} diff --git a/pkg/agent/tool/browser/screenshot_redact.go b/pkg/agent/tool/browser/screenshot_redact.go new file mode 100644 index 00000000..d948a51c --- /dev/null +++ b/pkg/agent/tool/browser/screenshot_redact.go @@ -0,0 +1,38 @@ +package browser + +import ( + "bytes" + "fmt" + "image" + "image/color" + "image/draw" + "image/png" +) + +// redactPNG decodes src (a PNG screenshot), paints each rect solid opaque +// black, and re-encodes. Rectangles are in SCREENSHOT PIXEL coordinates (the +// caller is responsible for device-pixel-ratio scaling). Returns an error on a +// decode/encode failure so the caller can fail closed (ship no screenshot) +// rather than ship a partially-redacted one. +func redactPNG(src []byte, boxes []image.Rectangle) ([]byte, error) { + img, err := png.Decode(bytes.NewReader(src)) + if err != nil { + return nil, fmt.Errorf("redact: decode screenshot: %w", err) + } + // Draw onto an RGBA copy so we can composite regardless of the source type. + out := image.NewRGBA(img.Bounds()) + draw.Draw(out, out.Bounds(), img, img.Bounds().Min, draw.Src) + black := &image.Uniform{color.RGBA{0, 0, 0, 255}} + for _, b := range boxes { + r := b.Intersect(out.Bounds()) + if r.Empty() { + continue + } + draw.Draw(out, r, black, image.Point{}, draw.Src) + } + var buf bytes.Buffer + if err := png.Encode(&buf, out); err != nil { + return nil, fmt.Errorf("redact: re-encode screenshot: %w", err) + } + return buf.Bytes(), nil +} diff --git a/pkg/agent/tool/browser/screenshot_redact_test.go b/pkg/agent/tool/browser/screenshot_redact_test.go new file mode 100644 index 00000000..fc37be74 --- /dev/null +++ b/pkg/agent/tool/browser/screenshot_redact_test.go @@ -0,0 +1,59 @@ +package browser + +import ( + "bytes" + "image" + "image/color" + "image/draw" + "image/png" + "testing" + + "github.com/chromedp/cdproto/dom" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestRedactPNG_CoversBoxesAndLeavesRest(t *testing.T) { + // 20x20 image, a 10x10 red "secret" block at (0,0), blue elsewhere. + img := image.NewRGBA(image.Rect(0, 0, 20, 20)) + red, blue := color.RGBA{255, 0, 0, 255}, color.RGBA{0, 0, 255, 255} + draw.Draw(img, img.Bounds(), &image.Uniform{blue}, image.Point{}, draw.Src) + draw.Draw(img, image.Rect(0, 0, 10, 10), &image.Uniform{red}, image.Point{}, draw.Src) + var buf bytes.Buffer + require.NoError(t, png.Encode(&buf, img)) + + out, err := redactPNG(buf.Bytes(), []image.Rectangle{image.Rect(0, 0, 10, 10)}) + require.NoError(t, err) + got, err := png.Decode(bytes.NewReader(out)) + require.NoError(t, err) + // Inside the box: NOT red anymore (covered). + r, g, b, _ := got.At(5, 5).RGBA() + assert.False(t, r == 0xffff && g == 0 && b == 0, "secret pixel must be covered, got r=%d g=%d b=%d", r, g, b) + // Outside the box: still blue (untouched). + r2, g2, b2, _ := got.At(15, 15).RGBA() + assert.True(t, r2 == 0 && g2 == 0 && b2 == 0xffff, "non-secret pixel must be untouched") +} + +func TestRedactPNG_RejectsBadInput(t *testing.T) { + _, err := redactPNG([]byte("not a png"), nil) + require.Error(t, err) +} + +// Review Focus: a device-pixel-ratio > 1 means CDP screenshot pixels are +// dpr * CSS box pixels, so the redaction rect must be scaled or it covers the +// wrong region. (boxFromModelScaled is implemented in Step 5; write this test +// alongside it.) +func TestBoxFromModelScaled_AppliesDPR(t *testing.T) { + // A CSS box at (10,20)-(30,50); at dpr=2 the screenshot rect is doubled. + b := &dom.BoxModel{Content: []float64{10, 20, 30, 20, 30, 50, 10, 50}} + got := boxFromModelScaled(b, 2) + assert.Equal(t, image.Rect(20, 40, 60, 100), got) + // dpr=1 is identity. + assert.Equal(t, image.Rect(10, 20, 30, 50), boxFromModelScaled(b, 1)) + // A fractional box must round OUTWARD (floor mins, ceil maxs) so the rect + // fully encloses the field — never one pixel short on a scaled edge. + frac := &dom.BoxModel{Content: []float64{5.4, 7.2, 10.6, 7.2, 10.6, 12.8, 5.4, 12.8}} + assert.Equal(t, image.Rect(5, 7, 11, 13), boxFromModelScaled(frac, 1)) + // A degenerate box (too few quad points) is empty → caller fails closed. + assert.True(t, boxFromModelScaled(&dom.BoxModel{}, 1).Empty()) +} diff --git a/pkg/agent/tool/browser/tools.go b/pkg/agent/tool/browser/tools.go index 8bf8d87b..906debc7 100644 --- a/pkg/agent/tool/browser/tools.go +++ b/pkg/agent/tool/browser/tools.go @@ -135,8 +135,21 @@ var ( _ agenttool.OriginTool = (*browserTool)(nil) _ agenttool.Cancellable = (*browserTool)(nil) _ agenttool.NamedCallArgs = (*browserTool)(nil) + _ ScreenshotProvider = (*browserTool)(nil) ) +// ScreenshotCapturer returns this tool's session as a BrowserScreenshotCapturer +// — every tool of a toolbox shares one *Session (see the browserTool doc +// comment), so any op's tool can hand the runner a capturer for the same live +// page. Returns nil only if the tool was synthesized without a session (a unit +// test), never in production wiring. +func (t *browserTool) ScreenshotCapturer() BrowserScreenshotCapturer { + if t.sess == nil { + return nil + } + return t.sess +} + func (t *browserTool) Name() string { return t.name } func (t *browserTool) Kind() agenttool.Kind { return agenttool.KindMCP } func (t *browserTool) Description() string { return t.description } @@ -366,7 +379,7 @@ func (t *browserTool) requestHumanStep(ctx context.Context, kind, prompt, ref st switch kind { case "confirm": - outcome, err := t.humanStep.Confirm(ctx, prompt) + outcome, err := t.humanStep.Confirm(ctx, prompt, t.ScreenshotCapturer()) if err != nil { return errResult("request_human_step failed: %v", err) } @@ -387,7 +400,7 @@ func (t *browserTool) requestHumanStep(ctx context.Context, kind, prompt, ref st case "", "captcha": // No actionable kind: a CAPTCHA, or any step the agent cannot do. Surface a // notice and tell the model a person must step in. - if err := t.humanStep.Captcha(ctx, prompt); err != nil { + if err := t.humanStep.Captcha(ctx, prompt, t.ScreenshotCapturer()); err != nil { return errResult("request_human_step: could not notify anyone that human intervention is needed: %v", err) } return errResult("request_human_step: this step needs a person and cannot be completed automatically; a notice has been sent asking someone to take over in the browser") @@ -405,7 +418,7 @@ func (t *browserTool) requestHumanStepCode(ctx context.Context, prompt, ref stri if ref == "" { return errResult("request_human_step: kind=\"code\" requires a ref naming the input to type the code into — read the page first and pass the code field's ref") } - outcome, err := t.humanStep.RequestCode(ctx, prompt) + outcome, err := t.humanStep.RequestCode(ctx, prompt, t.ScreenshotCapturer()) if err != nil { return errResult("request_human_step failed: %v", err) } diff --git a/pkg/bronzethread/bundle.go b/pkg/bronzethread/bundle.go index dd9b7adf..9bf98827 100644 --- a/pkg/bronzethread/bundle.go +++ b/pkg/bronzethread/bundle.go @@ -795,6 +795,17 @@ type Assertions struct { // pre-runner park never writes. ApprovalPrompts *int `json:"approvalPrompts,omitempty"` + // ApprovalScreenshotAttached asserts that at least one published + // interaction approval prompt carries a non-empty + // InteractionRequestPayload.Screenshot.RenderName — the redacted page + // screenshot a browser acting-approval or human-step card attaches + // (Phase D). False (the default) means "do not check"; this is the one + // place a bundle can prove the screenshot reached the published card + // rather than merely that the capture/store code compiles — a scripted + // reply says the same words whether or not the attachment rode along, so + // this has to read the recorded payload, not the transcript. + ApprovalScreenshotAttached bool `json:"approvalScreenshotAttached,omitempty"` + // AgentReplyNotContains is the negative companion, checked against the SAME // per-turn reply, in order: the reply to turn i must NOT contain // AgentReplyNotContains[i]. The only way a bundle can claim a person did not diff --git a/pkg/channels/channelevents/interaction.go b/pkg/channels/channelevents/interaction.go index d2d8e0da..e3905cc9 100644 --- a/pkg/channels/channelevents/interaction.go +++ b/pkg/channels/channelevents/interaction.go @@ -299,6 +299,16 @@ type InteractionRequestPayload struct { // Details is the category's opaque side-band payload (tool_approval puts // ToolApprovalDetails here). Never rendered as copy by a surface. Details json.RawMessage `json:"details,omitempty"` + // Screenshot, when set, is an internal artifact reference (an ArtifactRender + // CR, resolved by AssetFetcher exactly like an outbound attachment) to a + // REDACTED page screenshot the surface renders with the card. Set ONLY for + // browser-originated interactions (acting-approval, request_human_step, + // captcha); nil for every other interaction, so non-browser payloads are + // unchanged on the wire. It is human-facing only and is NEVER delivered to + // the model. The image is redacted (credential-filled fields painted over) + // in the runner before it is stored — see pkg/agent/runner/browser_screenshot.go. + // +optional + Screenshot *AttachmentRef `json:"screenshot,omitempty"` // Resources names the source resources whose #owner may decide a // DecideResourceOwners interaction (tool_call → resource#owner, info_leakage // → data#owner). Empty ⇒ the session approve-set decides. Persisted onto the diff --git a/pkg/channels/channelevents/interaction_test.go b/pkg/channels/channelevents/interaction_test.go index f1faf567..64b7cf1c 100644 --- a/pkg/channels/channelevents/interaction_test.go +++ b/pkg/channels/channelevents/interaction_test.go @@ -314,6 +314,26 @@ func TestInteractionRequestValidate_ApproversMustBeAddressable(t *testing.T) { } } +func TestInteractionRequestPayload_ScreenshotOmitEmpty(t *testing.T) { + // A payload with no screenshot must NOT serialize a "screenshot" key. + b, err := json.Marshal(InteractionRequestPayload{Category: "tool_call", RequestRef: "r1", Lead: "x"}) + require.NoError(t, err) + assert.NotContains(t, string(b), "screenshot", "non-browser interaction must not carry a screenshot key") + + // A payload WITH a screenshot round-trips the AttachmentRef. + in := InteractionRequestPayload{ + Category: "login_human_step", RequestRef: "r2", Lead: "act on aa.com", + Screenshot: &AttachmentRef{RenderName: "shot-abc", MIME: "image/png", Filename: "page.png", AltText: "page screenshot"}, + } + raw, err := json.Marshal(in) + require.NoError(t, err) + var out InteractionRequestPayload + require.NoError(t, json.Unmarshal(raw, &out)) + require.NotNil(t, out.Screenshot) + assert.Equal(t, "shot-abc", out.Screenshot.RenderName) + assert.Equal(t, "image/png", out.Screenshot.MIME) +} + // InteractionItem's three tier tones and its Hint field must survive a JSON // round trip intact, the same wire-shape guarantee every other field on this // envelope already has — a surface reads Hint from the wire, so a marshaling diff --git a/pkg/channels/channelevents/screenshot.go b/pkg/channels/channelevents/screenshot.go new file mode 100644 index 00000000..7a3368fc --- /dev/null +++ b/pkg/channels/channelevents/screenshot.go @@ -0,0 +1,25 @@ +package channelevents + +// ScreenshotRendererKind and ScreenshotMIME name the ArtifactRenderSpec.Kind +// and MIME type every redacted browser-screenshot AttachmentRef (see the +// Screenshot field on InteractionRequestPayload) is built from — +// pkg/agent/runner/browser_screenshot.go is the sole producer. +// +// Named here rather than spelled as literals in pkg/agent/runner: that +// package is under a structural guard +// (pkg/agent/runner/mime_opinion_guard_test.go) against hardcoded +// image/MIME string literals, because such a literal is normally a SECOND +// OPINION about what a model accepts that pkg/agent/llm/models/models.go +// should own exclusively. This is not that — a screenshot attachment's MIME +// is a channel-delivery concern, never carried to the model — so the fix is +// not a models.go row, it is exactly the guard's own documented escape valve: +// a named constant in the package that owns the concern, referenced by name. +// channelevents owns it because it already defines AttachmentRef and the +// Screenshot field that carries these values. +const ( + // ScreenshotRendererKind matches the registered Kind() of the raster-image + // renderer (pkg/channels/channelassets/image). + ScreenshotRendererKind = "image" + // ScreenshotMIME is the MIME type of the redacted page screenshot PNG. + ScreenshotMIME = "image/png" +) diff --git a/pkg/channels/channelinteractions/textrender.go b/pkg/channels/channelinteractions/textrender.go index bd9d9b04..aae1839a 100644 --- a/pkg/channels/channelinteractions/textrender.go +++ b/pkg/channels/channelinteractions/textrender.go @@ -19,7 +19,13 @@ import ( // decisionURL maps a decision/link_mint action ID to its hosted decision-page // URL. Nil renders those actions as plain labels plus a pointer to respond // from a connected surface. -func RenderText(p channelevents.InteractionRequestPayload, decisionURL func(actionID string) string) string { +// +// screenshotURL resolves p.Screenshot (when set) to a human-facing reference +// — a signed view link, a CLI hint, whatever the calling surface can cleanly +// produce — appended as its own line. Best-effort: a nil callback, or one +// that returns "", renders no line at all; p.Screenshot == nil never calls +// the callback. +func RenderText(p channelevents.InteractionRequestPayload, decisionURL func(actionID string) string, screenshotURL func(*channelevents.AttachmentRef) string) string { var b strings.Builder // Tone marker, for notice categories only. The floor has no colour and no @@ -59,6 +65,12 @@ func RenderText(p channelevents.InteractionRequestPayload, decisionURL func(acti fmt.Fprintf(&b, "%s\n%s\n%s\n", fence, innerText, fence) } + if p.Screenshot != nil && screenshotURL != nil { + if url := screenshotURL(p.Screenshot); url != "" { + fmt.Fprintf(&b, "\n📷 Page screenshot: %s\n", url) + } + } + if len(p.Actions) > 0 { b.WriteString("\n") unlinkable := false diff --git a/pkg/channels/channelinteractions/textrender_notice_test.go b/pkg/channels/channelinteractions/textrender_notice_test.go index 78f29b7f..e7c8690c 100644 --- a/pkg/channels/channelinteractions/textrender_notice_test.go +++ b/pkg/channels/channelinteractions/textrender_notice_test.go @@ -45,7 +45,7 @@ func TestRenderText_NoticeCarriesToneMarkerAndNextStep(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { registerNoticeFixture(t, "demo_notice", tc.tone) - out := RenderText(noticePayload("demo_notice"), nil) + out := RenderText(noticePayload("demo_notice"), nil, nil) assert.Contains(t, out, "**Agent stopped**") assert.Contains(t, out, "**Start a new thread to try again.**", @@ -70,7 +70,7 @@ func TestRenderText_NoticeCarriesToneMarkerAndNextStep(t *testing.T) { // respond to. func TestRenderText_NoticeHasNoRespondTrailer(t *testing.T) { registerNoticeFixture(t, "demo_notice", ToneRoutine) - out := RenderText(noticePayload("demo_notice"), nil) + out := RenderText(noticePayload("demo_notice"), nil, nil) assert.NotContains(t, out, "respond from a connected app") } @@ -81,7 +81,7 @@ func TestRenderText_PromptRenderingUnchanged(t *testing.T) { t.Cleanup(Reset) Register(Category{Name: "tool_approval", Deciders: DecideOwner, Tone: ToneRoutine, Resurface: ResurfaceNone}) - out := RenderText(renderableRequest(), nil) + out := RenderText(renderableRequest(), nil, nil) assert.True(t, len(out) > 0) assert.NotContains(t, out, "[!]") assert.NotContains(t, out, "[degraded]") diff --git a/pkg/channels/channelinteractions/textrender_screenshot_test.go b/pkg/channels/channelinteractions/textrender_screenshot_test.go new file mode 100644 index 00000000..0be0bafd --- /dev/null +++ b/pkg/channels/channelinteractions/textrender_screenshot_test.go @@ -0,0 +1,81 @@ +package channelinteractions + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + "github.com/authzed/openagentprimitives/pkg/channels/channelevents" +) + +// TestRenderText_Screenshot covers the four cases the browser-approval +// screenshot line must handle on the plain-text floor: a wired callback that +// resolves a URL, a wired callback that returns "" (e.g. minting failed or +// isn't configured), no Screenshot on the payload at all, and a nil callback. +// In every case but the first, no "Page screenshot:" line may appear — this +// is a best-effort addition to the card, never something that can block or +// alter the rest of it. +func TestRenderText_Screenshot(t *testing.T) { + withScreenshot := renderableRequest() + withScreenshot.Screenshot = &channelevents.AttachmentRef{ + RenderName: "shot-abc", + ArtifactID: "artifact-xyz", + MIME: channelevents.ScreenshotMIME, + Filename: "page.png", + AltText: "page screenshot", + } + withoutScreenshot := renderableRequest() + + cases := []struct { + name string + payload channelevents.InteractionRequestPayload + screenshotURL func(*channelevents.AttachmentRef) string + wantLine bool + wantURL string + }{ + { + name: "screenshot present, callback resolves a URL: line appears with the URL", + payload: withScreenshot, + screenshotURL: func(ref *channelevents.AttachmentRef) string { + return "https://example/view?d=x" + }, + wantLine: true, + wantURL: "https://example/view?d=x", + }, + { + name: "screenshot present, callback returns empty string: no line", + payload: withScreenshot, + screenshotURL: func(ref *channelevents.AttachmentRef) string { + return "" + }, + wantLine: false, + }, + { + name: "no screenshot on the payload: callback is never consulted, no line", + payload: withoutScreenshot, + screenshotURL: func(ref *channelevents.AttachmentRef) string { + return "should-not-appear" + }, + wantLine: false, + }, + { + name: "screenshot present, nil callback: no panic, no line", + payload: withScreenshot, + screenshotURL: nil, + wantLine: false, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + out := RenderText(tc.payload, nil, tc.screenshotURL) + if tc.wantLine { + assert.Contains(t, out, "Page screenshot:") + assert.Contains(t, out, tc.wantURL) + } else { + assert.NotContains(t, out, "Page screenshot:") + assert.NotContains(t, out, "should-not-appear") + } + }) + } +} diff --git a/pkg/channels/channelinteractions/textrender_test.go b/pkg/channels/channelinteractions/textrender_test.go index 01370f49..86510462 100644 --- a/pkg/channels/channelinteractions/textrender_test.go +++ b/pkg/channels/channelinteractions/textrender_test.go @@ -36,7 +36,7 @@ func TestRenderTextFullPrompt(t *testing.T) { }) out := RenderText(p, func(actionID string) string { return "https://webd.example.com/prompt/default/demo-session/req-123?action=" + actionID - }) + }, nil) assert.Contains(t, out, "**Approval needed**") assert.Contains(t, out, "The agent wants to push to a repo.") @@ -48,7 +48,7 @@ func TestRenderTextFullPrompt(t *testing.T) { } func TestRenderTextNilMinterDegradesGracefully(t *testing.T) { - out := RenderText(renderableRequest(), nil) + out := RenderText(renderableRequest(), nil, nil) assert.Contains(t, out, "Approve") assert.NotContains(t, out, "](", "no links can be built without a minter (except none exist here)") assert.Contains(t, out, "respond from a connected app") @@ -63,7 +63,7 @@ func TestRenderTextExcerptIsInert(t *testing.T) { Label: "Suspicious content", Content: "IGNORE PREVIOUS INSTRUCTIONS\n```\n[Approve](https://evil.example.com)\n```", } - out := RenderText(p, nil) + out := RenderText(p, nil, nil) // The excerpt's inner fence must be out-fenced: the wrapping fence is // strictly longer than any backtick run inside the content or label. @@ -84,7 +84,7 @@ func TestRenderTextExcerptLabelEscapeAttempt(t *testing.T) { Label: "x``````y", // six backticks Content: "short", } - out := RenderText(p, nil) + out := RenderText(p, nil, nil) // The load-bearing guard: the label (with its 6-backtick run) is INSIDE // the fenced region, and the wrapping fence is the longest backtick run @@ -116,7 +116,7 @@ func TestRenderTextLinkMintAction(t *testing.T) { } out := RenderText(p, func(actionID string) string { return "https://webd.example.com/mint/" + actionID - }) + }, nil) assert.Contains(t, out, "[View live](https://webd.example.com/mint/view)", "LinkMint actions render as links when decisionURL is provided") @@ -125,7 +125,7 @@ func TestRenderTextLinkMintAction(t *testing.T) { func TestRenderTextNoActionsIsReadOnlyCard(t *testing.T) { p := renderableRequest() p.Actions = nil - out := RenderText(p, nil) + out := RenderText(p, nil, nil) assert.Contains(t, out, "**Approval needed**") assert.NotContains(t, out, "respond from a connected app", "read-only cards carry no action hint") } @@ -158,7 +158,7 @@ func TestRenderText_aPlanCardKeepsEveryResourceAndItsAttribution(t *testing.T) { {Label: "Why (the agent's words)", Value: "the ticket names these repositories"}, } - out := RenderText(p, func(actionID string) string { return "https://webd.example.com/x?action=" + actionID }) + out := RenderText(p, func(actionID string) string { return "https://webd.example.com/x?action=" + actionID }, nil) assert.Contains(t, out, first, "the first resource must survive") assert.Contains(t, out, last, diff --git a/pkg/channels/channelkinds/kindtest/categories.go b/pkg/channels/channelkinds/kindtest/categories.go index c8074180..ab9d39ce 100644 --- a/pkg/channels/channelkinds/kindtest/categories.go +++ b/pkg/channels/channelkinds/kindtest/categories.go @@ -54,7 +54,7 @@ func AssertCategoryConformance(t *testing.T, c channelinteractions.Category) { require.NoError(t, c.Validate(), "category %q must validate", c.Name) req := SampleRequest(c) require.NoError(t, req.Validate(), "category %q sample payload must be wire-valid", c.Name) - out := channelinteractions.RenderText(req, nil) + out := channelinteractions.RenderText(req, nil, nil) assert.NotEmpty(t, out, "category %q must render on the text floor", c.Name) assert.Contains(t, out, req.Lead, "text floor must carry the lead") } diff --git a/pkg/channels/channelkinds/kindtest/excerpt_inertness_test.go b/pkg/channels/channelkinds/kindtest/excerpt_inertness_test.go index d39333f9..0f5b6320 100644 --- a/pkg/channels/channelkinds/kindtest/excerpt_inertness_test.go +++ b/pkg/channels/channelkinds/kindtest/excerpt_inertness_test.go @@ -33,7 +33,7 @@ func TestExcerptInertness_TextFloor(t *testing.T) { if req.Excerpt == nil { t.Skip("category has no excerpt") } - out := channelinteractions.RenderText(req, nil) + out := channelinteractions.RenderText(req, nil, nil) // Find the longest backtick run in the whole rendered output — that // run is the wrapping fence. It must exist, and its opening/closing diff --git a/pkg/channels/channelkinds/local/host.go b/pkg/channels/channelkinds/local/host.go index 5e694268..a0d640eb 100644 --- a/pkg/channels/channelkinds/local/host.go +++ b/pkg/channels/channelkinds/local/host.go @@ -188,7 +188,11 @@ func (h *Host) SubChannelSenderFor(_ context.Context, sess *spiceboxv1alpha1.Age minter: h.deps.AgentUIMinter, }, nil case "interaction": - return &interactionSender{sink: h.sink}, nil + return &interactionSender{ + sink: h.sink, + minter: h.deps.ArtifactViewMinter, + principal: h.principal, + }, nil default: return nil, nil } diff --git a/pkg/channels/channelkinds/local/interaction.go b/pkg/channels/channelkinds/local/interaction.go index 21512e2e..e779a620 100644 --- a/pkg/channels/channelkinds/local/interaction.go +++ b/pkg/channels/channelkinds/local/interaction.go @@ -5,9 +5,12 @@ import ( "encoding/json" "fmt" + "sigs.k8s.io/controller-runtime/pkg/log" + "github.com/authzed/openagentprimitives/pkg/channels/channelevents" "github.com/authzed/openagentprimitives/pkg/channels/channelinteractions" "github.com/authzed/openagentprimitives/pkg/channels/channelkinds" + "github.com/authzed/openagentprimitives/pkg/platform/identity" ) // interactionSender is the host-side "interaction" sub-channel sender: @@ -18,6 +21,15 @@ import ( // floor is used for the read-only (link / notice) path where no modal opens. type interactionSender struct { sink *inertSink + // minter and principal mint the screenshot reference link RenderText + // appends for a browser-originated interaction (see screenshotURL below). + // Both are the same ArtifactViewMinter/Principal pair host.go already wires + // into liveViewOfferSender for the sibling "live_view_offer" sub-channel — + // nil minter (no webd base URL configured) degrades to no line, never an + // error: unlike a live-view offer, the screenshot line is a side note on a + // card whose Lead/Actions must still be delivered. + minter channelkinds.ArtifactViewMinter + principal identity.Principal } func (s *interactionSender) emitErr(sess channelkinds.SessionInfo, k channelevents.Kind, err error) (channelkinds.SubChannelSendResult, error) { @@ -25,7 +37,7 @@ func (s *interactionSender) emitErr(sess channelkinds.SessionInfo, k channeleven return channelkinds.SubChannelSendResult{}, fmt.Errorf("local interaction sender (%s): %w", k, err) } -func (s *interactionSender) Send(_ context.Context, sess channelkinds.SessionInfo, env channelevents.Envelope) (channelkinds.SubChannelSendResult, error) { +func (s *interactionSender) Send(ctx context.Context, sess channelkinds.SessionInfo, env channelevents.Envelope) (channelkinds.SubChannelSendResult, error) { switch env.Kind { case channelevents.KindInteractionRequest: var pl channelevents.InteractionRequestPayload @@ -42,7 +54,7 @@ func (s *interactionSender) Send(_ context.Context, sess channelkinds.SessionInf // render as plain labels plus a note to respond from a connected app. // The rendered Text is the read-only timeline floor; Payload carries the // structured actions the TUI's decision modal binds keys to. - text := channelinteractions.RenderText(pl, nil) + text := channelinteractions.RenderText(pl, nil, s.screenshotURL(ctx, sess)) s.sink.Emit(MsgInteractionRequest{Session: refOf(sess), Payload: pl, Text: text}) return channelkinds.SubChannelSendResult{}, nil @@ -77,3 +89,25 @@ func (s *interactionSender) Send(_ context.Context, sess channelkinds.SessionInf return s.emitErr(sess, env.Kind, fmt.Errorf("unsupported envelope kind for the interaction sender")) } } + +// screenshotURL returns the per-call closure RenderText consults to resolve a +// browser-originated interaction's redacted screenshot to a human-facing +// link. Best-effort, matching the AGENTS.md "never silently drop errors" +// rule with a log line rather than a failure: the TUI's decision modal and +// the rest of the card must still render if minting fails or is unconfigured, +// so a mint error here is a skipped line, never a dropped card. +func (s *interactionSender) screenshotURL(ctx context.Context, sess channelkinds.SessionInfo) func(*channelevents.AttachmentRef) string { + return func(ref *channelevents.AttachmentRef) string { + if s.minter == nil || ref == nil || ref.ArtifactID == "" { + return "" + } + sessionRef := sess.Namespace + "/" + sess.Name + url, err := s.minter.MintArtifactViewLink(ref.ArtifactID, sessionRef, s.principal, "") + if err != nil { + log.FromContext(ctx).Info("local interaction sender: mint screenshot view link failed (best-effort, card still delivered)", + "session", sessionRef, "artifactID", ref.ArtifactID, "err", err.Error()) + return "" + } + return url + } +} diff --git a/pkg/channels/channelkinds/local/interaction_screenshot_test.go b/pkg/channels/channelkinds/local/interaction_screenshot_test.go new file mode 100644 index 00000000..55d92a6d --- /dev/null +++ b/pkg/channels/channelkinds/local/interaction_screenshot_test.go @@ -0,0 +1,91 @@ +package local + +import ( + "context" + "errors" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/authzed/openagentprimitives/pkg/channels/channelevents" + "github.com/authzed/openagentprimitives/pkg/platform/identity" +) + +func screenshotRequestEnv(t *testing.T) channelevents.Envelope { + t.Helper() + return mustEnv(t, channelevents.KindInteractionRequest, + channelevents.InteractionRequestPayload{ + AgentSessionRef: channelevents.SessionRef{Namespace: "default", Name: "s1"}, + Category: "acting_approval", + RequestRef: "act-1", + Lead: "Approve this browser action?", + Screenshot: &channelevents.AttachmentRef{ + RenderName: "shot-abc", + ArtifactID: "artifact-xyz", + MIME: channelevents.ScreenshotMIME, + Filename: "page.png", + }, + Audience: channelevents.InteractionAudience{ + Scope: channelevents.AudienceRequester, + Requester: &channelevents.ExternalIdentity{Kind: "user", ExternalID: "user-1"}, + }, + }) +} + +// TestInteractionSender_Screenshot_WiredMinter_EmitsLinkLine verifies that +// when a browser-originated interaction carries a Screenshot and the sender +// has a working ArtifactViewMinter + principal wired (as host.go wires for +// the "interaction" sub-channel, mirroring live_view_offer's), the rendered +// Text includes the screenshot reference line with the minted URL. +func TestInteractionSender_Screenshot_WiredMinter_EmitsLinkLine(t *testing.T) { + sink := &RecordingSink{} + s := &interactionSender{ + sink: newInertSink(sink), + minter: &fakeMinter{url: "https://webd.example.com/artifact-view?d=abc&sig=def"}, + principal: identity.RawSubject("user:alice"), + } + + _, err := s.Send(context.Background(), sessInfo(), screenshotRequestEnv(t)) + require.NoError(t, err) + require.Len(t, sink.Events(), 1) + m, ok := sink.Events()[0].(MsgInteractionRequest) + require.True(t, ok, "want MsgInteractionRequest, got %T", sink.Events()[0]) + assert.Contains(t, m.Text, "Page screenshot:") + assert.Contains(t, m.Text, "https://webd.example.com/artifact-view?d=abc&sig=def") +} + +// TestInteractionSender_Screenshot_NilMinter_NoLineNoError verifies the +// best-effort contract: an unwired minter must never block or error the +// card — it only means no screenshot line, exactly like a text payload with +// no Screenshot at all. +func TestInteractionSender_Screenshot_NilMinter_NoLineNoError(t *testing.T) { + sink := &RecordingSink{} + s := &interactionSender{sink: newInertSink(sink)} + + _, err := s.Send(context.Background(), sessInfo(), screenshotRequestEnv(t)) + require.NoError(t, err, "a nil minter must never fail the card") + require.Len(t, sink.Events(), 1) + m, ok := sink.Events()[0].(MsgInteractionRequest) + require.True(t, ok, "want MsgInteractionRequest, got %T", sink.Events()[0]) + assert.NotContains(t, m.Text, "Page screenshot:") +} + +// TestInteractionSender_Screenshot_MinterErrors_NoLineNoError verifies that a +// minting error is swallowed into "no line" rather than propagated as a +// Send error — the card (Lead/Body/Actions) must still be delivered. +func TestInteractionSender_Screenshot_MinterErrors_NoLineNoError(t *testing.T) { + sink := &RecordingSink{} + s := &interactionSender{ + sink: newInertSink(sink), + minter: &fakeMinter{err: errors.New("mint failed")}, + principal: identity.RawSubject("user:alice"), + } + + _, err := s.Send(context.Background(), sessInfo(), screenshotRequestEnv(t)) + require.NoError(t, err, "a minter error must never fail the card") + require.Len(t, sink.Events(), 1) + m, ok := sink.Events()[0].(MsgInteractionRequest) + require.True(t, ok, "want MsgInteractionRequest, got %T", sink.Events()[0]) + assert.NotContains(t, m.Text, "Page screenshot:") +} diff --git a/pkg/channels/channelkinds/slack/interaction.go b/pkg/channels/channelkinds/slack/interaction.go index 1334e1a4..c35e7fb1 100644 --- a/pkg/channels/channelkinds/slack/interaction.go +++ b/pkg/channels/channelkinds/slack/interaction.go @@ -14,7 +14,10 @@ // ephemeral-with-DM-fallback) to every identity in Audience.Requester or // Audience.Approvers depending on Scope. The delivery lands in s.delivery, // keyed by RequestRef, whenever deliveryEditable(p) says a later -// interaction_applied will need to edit it in place. +// interaction_applied will need to edit it in place. When the payload +// carries a Screenshot (browser-originated interactions only), the +// resolved PNG is uploaded as a threaded file under each recipient's +// card right after it posts — best-effort, see uploadScreenshot. // - KindInteractionApplied{Category: credential_link, Outcome: resolved}: // posts a "connected" notice at the resolved tone. credential_link resolves // out-of-band (an OAuth callback, not a click), so there is no response_url @@ -40,6 +43,7 @@ package slack import ( + "bytes" "context" "encoding/json" "fmt" @@ -344,6 +348,13 @@ func (s *interactionSender) sendRequest(ctx context.Context, sess channelkinds.S } lastRef = ref delivered = true + // Screenshot upload is threaded under THIS recipient's card, posted + // immediately after it so a fan-out to multiple approvers gives each + // their own in-thread picture rather than racing to attach to + // whichever card landed last. Best-effort: the card already carries + // the full approval text, so a fetch/upload failure must not fail the + // interaction send (see uploadScreenshot). + s.uploadScreenshot(ctx, sess, p, ref, logger) } // Nothing reached anybody. This is a FAILURE, not a benign skip: the // session parks awaiting a decision no one was asked for, and without a @@ -423,6 +434,58 @@ func (s *interactionSender) sendRequest(ctx context.Context, sess channelkinds.S return nil } +// uploadScreenshot resolves p.Screenshot's bytes via the AssetFetcher and +// uploads the redacted page image as a PNG file threaded under ref — the +// card's own (channelID, ts) that deliverPrompt / postBroadcast just +// returned. Mirrors sendWithAttachments' fetch+upload shape (sender.go), not +// its fallback-text behavior: there is nothing to fall back to here, since +// the card already landed carrying the full approval text — a missing +// picture is a cosmetic loss, not a delivery failure. +// +// Every exit here is a silent-but-logged skip, never an error returned to +// the caller (sendRequest): a nil Screenshot is the common case (every +// non-browser interaction) and logs nothing; a nil AssetFetcher (a surface +// that never configured one) or ref.TS == "" (nothing was actually posted to +// thread under, e.g. a delivery that errored before reaching here — though +// callers only reach this after a successful deliverPrompt/postBroadcast) +// logs once and returns; a Fetch or UploadFileContext failure logs the +// session + renderName + error per the repo's no-silent-errors rule and +// returns, leaving the card as the complete approval surface. +func (s *interactionSender) uploadScreenshot(ctx context.Context, sess channelkinds.SessionInfo, p channelevents.InteractionRequestPayload, ref deliveryRef, logger logr.Logger) { + if p.Screenshot == nil || ref.TS == "" { + return + } + if s.deps.AssetFetcher == nil { + logger.Info("interaction sender: no AssetFetcher configured; screenshot upload skipped", + "session", sess.Namespace+"/"+sess.Name, "requestRef", p.RequestRef, "render", p.Screenshot.RenderName) + return + } + ab, err := s.deps.AssetFetcher.Fetch(ctx, sess.Namespace, sess.Name, p.Screenshot.RenderName) + if err != nil { + logger.Info("interaction sender: fetch screenshot failed (best-effort, card already delivered)", + "session", sess.Namespace+"/"+sess.Name, "requestRef", p.RequestRef, "render", p.Screenshot.RenderName, "err", err.Error()) + return + } + filename := p.Screenshot.Filename + if filename == "" { + filename = ab.Filename + } + if filename == "" { + filename = "page.png" + } + if _, err := s.client.UploadFileContext(ctx, slackapi.UploadFileParameters{ + Reader: bytes.NewReader(ab.Bytes), + FileSize: len(ab.Bytes), + Filename: filename, + Channel: ref.ChannelID, + ThreadTimestamp: ref.TS, + AltTxt: p.Screenshot.AltText, + }); err != nil { + logger.Info("interaction sender: upload screenshot failed (best-effort, card already delivered)", + "session", sess.Namespace+"/"+sess.Name, "requestRef", p.RequestRef, "render", p.Screenshot.RenderName, "err", err.Error()) + } +} + // sendApplied renders a resolved interaction outcome. credential_link is a // special case (out-of-band "✅ connected" notice, see the file-top comment // for why the recipient comes from sess.SessionInitiator rather than the diff --git a/pkg/channels/channelkinds/slack/interaction_screenshot_test.go b/pkg/channels/channelkinds/slack/interaction_screenshot_test.go new file mode 100644 index 00000000..ff5c9948 --- /dev/null +++ b/pkg/channels/channelkinds/slack/interaction_screenshot_test.go @@ -0,0 +1,174 @@ +// pkg/channels/channelkinds/slack/interaction_screenshot_test.go +// +// Task 5 (browser approval screenshots): after an interaction_request card +// posts, a payload carrying Screenshot must have the resolved PNG uploaded +// as a file threaded under that SAME card — see interaction.go's +// uploadScreenshot. These tests pin the three contract points: the happy +// path threads the upload under the card's own ts, a nil Screenshot is a +// complete no-op (no Fetch, no upload — the common case for every +// non-browser interaction), and a Fetch failure must not fail the card send +// (best-effort; the card already carries the full approval). +package slack + +import ( + "context" + "errors" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/authzed/openagentprimitives/pkg/channels/channelevents" + "github.com/authzed/openagentprimitives/pkg/channels/channelkinds" + "github.com/authzed/openagentprimitives/pkg/platform/identity" +) + +// screenshotRequestPayload returns a wire-valid AudienceRequester +// InteractionRequestPayload carrying the given Screenshot ref — the shape a +// browser-originated interaction (acting-approval, login_human_step, +// captcha) publishes. nil is legal (every non-browser category's zero +// value). +func screenshotRequestPayload(rawExternalID string, screenshot *channelevents.AttachmentRef) channelevents.InteractionRequestPayload { + return channelevents.InteractionRequestPayload{ + Category: "login_human_step", + RequestRef: "req-shot-1", + Lead: "Finish signing in", + Screenshot: screenshot, + Actions: []channelevents.InteractionAction{ + {ID: "done", Label: "Done", Kind: channelevents.ActionKindDecision, Style: channelevents.ActionStylePrimary}, + }, + Audience: channelevents.InteractionAudience{ + Scope: channelevents.AudienceRequester, + Requester: &channelevents.ExternalIdentity{ + Kind: "slack", + ExternalID: identity.RawExternalID(rawExternalID), + }, + }, + } +} + +// TestInteractionSender_Request_Screenshot_UploadsThreadedUnderCard verifies +// the happy path end to end: the card posts first (via PostEphemeralContext, +// since the session carries channel context), and the Screenshot is then +// resolved via AssetFetcher.Fetch(ns, sess, RenderName) and uploaded via +// UploadFileContext with ThreadTimestamp equal to the card's own ts — the +// card establishes the thread root; the upload never can (see sender.go's +// sendWithAttachments note on files.uploadV2 returning no ts). +func TestInteractionSender_Request_Screenshot_UploadsThreadedUnderCard(t *testing.T) { + const ( + slackID = "U_SHOT" + chanID = "C01CHAN" + threadTS = "1700000000.000001" + ) + pngBytes := []byte("\x89PNG-fake-bytes") + af := &stubAssetFetcher{bytes: pngBytes, mime: "image/png", filename: "page.png"} + c := &fakeSlackClient{} + s := &interactionSender{client: c, deps: channelkinds.Deps{AssetFetcher: af}} + + screenshot := &channelevents.AttachmentRef{ + RenderName: "shot-1", + MIME: "image/png", + Filename: "page.png", + AltText: "redacted page screenshot", + } + pl := screenshotRequestPayload(slackID, screenshot) + env := interactionEnvelope(t, channelevents.KindInteractionRequest, pl) + sess := sessionWithChannel(chanID, threadTS) + + _, err := s.Send(context.Background(), sess, env) + require.NoError(t, err, "Send") + + // The card itself landed via PostEphemeral (channel context present). + require.Len(t, c.postEphemeralCalls, 1, "expected 1 card post") + cardTS := "1614191050.013301" // fakeSlackClient's fixed PostEphemeralContext ts + + require.Len(t, af.calls, 1, "expected exactly one asset fetch") + assert.Equal(t, stubFetchCall{ns: "default", sess: "sess-1", render: "shot-1"}, af.calls[0], + "AssetFetcher.Fetch must be called with the ref's RenderName") + + require.Len(t, c.uploadFileCalls, 1, "expected exactly one file upload") + up := c.uploadFileCalls[0] + assert.Equal(t, chanID, up.channelID, "upload must target the card's channel") + assert.Equal(t, cardTS, up.threadTS, "upload must be threaded under the card's own ts") + assert.Equal(t, pngBytes, up.contents, "uploaded bytes must be the fetched PNG bytes") + assert.Equal(t, "page.png", up.filename) + assert.Equal(t, "redacted page screenshot", up.altTxt) +} + +// TestInteractionSender_Request_NilScreenshot_NoUploadAttempt verifies the +// common case (every non-browser interaction): a nil Screenshot means no +// Fetch call and no UploadFileContext call, while the card itself still +// sends normally. +func TestInteractionSender_Request_NilScreenshot_NoUploadAttempt(t *testing.T) { + const ( + slackID = "U_NOSHOT" + chanID = "C01CHAN" + threadTS = "1700000000.000002" + ) + af := &stubAssetFetcher{bytes: []byte("should never be fetched"), mime: "image/png", filename: "page.png"} + c := &fakeSlackClient{} + s := &interactionSender{client: c, deps: channelkinds.Deps{AssetFetcher: af}} + + pl := screenshotRequestPayload(slackID, nil) + env := interactionEnvelope(t, channelevents.KindInteractionRequest, pl) + sess := sessionWithChannel(chanID, threadTS) + + _, err := s.Send(context.Background(), sess, env) + require.NoError(t, err, "Send") + + require.Len(t, c.postEphemeralCalls, 1, "the card must still send") + assert.Empty(t, af.calls, "no Screenshot ⇒ AssetFetcher.Fetch must never be called") + assert.Empty(t, c.uploadFileCalls, "no Screenshot ⇒ UploadFileContext must never be called") +} + +// TestInteractionSender_Request_ScreenshotFetchError_CardStillSucceeds +// verifies the best-effort contract: an AssetFetcher.Fetch error must not +// fail sendRequest (the card already carries the full approval text) and +// must not attempt an upload with no bytes. +func TestInteractionSender_Request_ScreenshotFetchError_CardStillSucceeds(t *testing.T) { + const ( + slackID = "U_FETCHFAIL" + chanID = "C01CHAN" + threadTS = "1700000000.000003" + ) + af := &stubAssetFetcher{err: errors.New("operator says no")} + c := &fakeSlackClient{} + s := &interactionSender{client: c, deps: channelkinds.Deps{AssetFetcher: af}} + + screenshot := &channelevents.AttachmentRef{RenderName: "shot-err", MIME: "image/png", Filename: "page.png"} + pl := screenshotRequestPayload(slackID, screenshot) + env := interactionEnvelope(t, channelevents.KindInteractionRequest, pl) + sess := sessionWithChannel(chanID, threadTS) + + _, err := s.Send(context.Background(), sess, env) + require.NoError(t, err, "a screenshot fetch failure must not fail the card send") + + require.Len(t, c.postEphemeralCalls, 1, "the card must still have landed") + require.Len(t, af.calls, 1, "the fetch must still have been attempted") + assert.Empty(t, c.uploadFileCalls, "no bytes to upload after a fetch failure") +} + +// TestInteractionSender_Request_ScreenshotNoAssetFetcher_SkipsUpload verifies +// the AssetFetcher-nil guard: a surface that never configured an +// AssetFetcher (some surfaces don't) must skip the upload entirely — +// no panic, no error, the card still sends. +func TestInteractionSender_Request_ScreenshotNoAssetFetcher_SkipsUpload(t *testing.T) { + const ( + slackID = "U_NOFETCHER" + chanID = "C01CHAN" + threadTS = "1700000000.000004" + ) + c := &fakeSlackClient{} + s := &interactionSender{client: c} // deps.AssetFetcher left nil + + screenshot := &channelevents.AttachmentRef{RenderName: "shot-nofetcher", MIME: "image/png", Filename: "page.png"} + pl := screenshotRequestPayload(slackID, screenshot) + env := interactionEnvelope(t, channelevents.KindInteractionRequest, pl) + sess := sessionWithChannel(chanID, threadTS) + + _, err := s.Send(context.Background(), sess, env) + require.NoError(t, err, "a nil AssetFetcher must not fail the card send") + + require.Len(t, c.postEphemeralCalls, 1, "the card must still have landed") + assert.Empty(t, c.uploadFileCalls, "no AssetFetcher ⇒ no upload attempted") +} diff --git a/pkg/web/webui/chat/sink_screenshot_test.go b/pkg/web/webui/chat/sink_screenshot_test.go new file mode 100644 index 00000000..1d436206 --- /dev/null +++ b/pkg/web/webui/chat/sink_screenshot_test.go @@ -0,0 +1,88 @@ +package chat + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/authzed/openagentprimitives/pkg/channels/channelevents" + "github.com/authzed/openagentprimitives/pkg/channels/channelkinds/browser" +) + +// TestToFrame_InteractionRequest_CarriesScreenshotRef pins the claim Task 6 +// of the browser-approval-screenshots feature depends on: toFrame's +// MsgInteractionRequest branch maps the WHOLE channelevents. +// InteractionRequestPayload (Payload: m) onto the wire frame, so +// InteractionRequestPayload.Screenshot — Task 1's redacted-screenshot +// AttachmentRef — rides along with no change to toFrame itself. This test +// exists to catch a future refactor that narrows the frame's payload to a +// hand-picked field set (the same mistake would silently drop Screenshot +// again) rather than to prove any code was written here. +func TestToFrame_InteractionRequest_CarriesScreenshotRef(t *testing.T) { + ref := browser.SessionRef{Namespace: "default", Name: "s1"} + shot := &channelevents.AttachmentRef{ + RenderName: "shot-1", + ArtifactID: "art-1", + MIME: "image/png", + Filename: "page.png", + AltText: "the page", + } + msg := browser.MsgInteractionRequest{ + Session: ref, + Payload: channelevents.InteractionRequestPayload{ + Category: "tool_approval", + RequestRef: "req-1", + Lead: "Approve this tool call?", + Screenshot: shot, + }, + } + + frame, ok := toFrame(msg) + require.True(t, ok, "toFrame must map browser.MsgInteractionRequest") + assert.Equal(t, "interaction_request", frame.Type) + + // Round-trip through JSON the same way the wire frame actually travels to + // the browser, rather than reaching into frame.Payload's concrete type — + // that is the only way to catch a regression in the json tag itself. + raw, err := json.Marshal(frame) + require.NoError(t, err) + var decoded struct { + Payload struct { + Payload struct { + Screenshot *channelevents.AttachmentRef `json:"screenshot"` + } `json:"payload"` + } `json:"payload"` + } + require.NoError(t, json.Unmarshal(raw, &decoded)) + require.NotNil(t, decoded.Payload.Payload.Screenshot, "screenshot ref must survive the frame round-trip") + assert.Equal(t, "shot-1", decoded.Payload.Payload.Screenshot.RenderName) + assert.Equal(t, "art-1", decoded.Payload.Payload.Screenshot.ArtifactID) + assert.Equal(t, "page.png", decoded.Payload.Payload.Screenshot.Filename) + assert.Equal(t, "the page", decoded.Payload.Payload.Screenshot.AltText) +} + +// TestToFrame_InteractionRequest_NilScreenshotOmitted covers the inverse: a +// non-browser (or best-effort-failed) interaction request carries no +// screenshot, and omitempty keeps it absent from the wire frame entirely +// rather than serializing an explicit null the TS side would have to special +// case. +func TestToFrame_InteractionRequest_NilScreenshotOmitted(t *testing.T) { + ref := browser.SessionRef{Namespace: "default", Name: "s1"} + msg := browser.MsgInteractionRequest{ + Session: ref, + Payload: channelevents.InteractionRequestPayload{ + Category: "credential_link", + RequestRef: "req-2", + Lead: "Connect your account", + }, + } + + frame, ok := toFrame(msg) + require.True(t, ok) + + raw, err := json.Marshal(frame) + require.NoError(t, err) + assert.NotContains(t, string(raw), `"screenshot"`, "a nil Screenshot must be omitted, not sent as null") +} diff --git a/pkg/web/webui/chat/ui/InteractionCard.test.tsx b/pkg/web/webui/chat/ui/InteractionCard.test.tsx index 731d25a0..4590a35d 100644 --- a/pkg/web/webui/chat/ui/InteractionCard.test.tsx +++ b/pkg/web/webui/chat/ui/InteractionCard.test.tsx @@ -612,4 +612,35 @@ describe("InteractionCard resolved-state collapsing", () => { expect(container.querySelector("details")).toBeNull(); expect(screen.getByText("Phase 1")).toBeTruthy(); }); + + it("renders the screenshot as an inline img built from the same-origin artifact-download URL", () => { + const { container } = render( + , + ); + const img = container.querySelector("img") as HTMLImageElement | null; + expect(img).toBeTruthy(); + const src = img?.getAttribute("src") ?? ""; + expect(src).toContain("/artifact-download?"); + expect(src).toContain("artifactId=art-1"); + expect(src).toContain(`sessionRef=${baseRequest.agentSessionRef.namespace}%2F${baseRequest.agentSessionRef.name}`); + expect(src).toContain("fn=page.png"); + expect(img?.getAttribute("alt")).toBe("the page"); + }); + + it("renders no img when the request carries no screenshot (the common case)", () => { + const { container } = render(); + expect(container.querySelector("img")).toBeNull(); + }); }); diff --git a/pkg/web/webui/chat/ui/InteractionCard.tsx b/pkg/web/webui/chat/ui/InteractionCard.tsx index a331c12f..ff8b03d8 100644 --- a/pkg/web/webui/chat/ui/InteractionCard.tsx +++ b/pkg/web/webui/chat/ui/InteractionCard.tsx @@ -20,8 +20,27 @@ import type { InteractionField, InteractionItem, InteractionRequestInner, + InteractionScreenshot, + SessionRef, } from "./types"; +// screenshotDownloadURL builds the same-origin download link for the +// interaction's screenshot attachment — same shape as ChatView's +// artifactDownloadURL (not exported from there, so replicated here rather +// than reached across files): gated by the logged-in session + the viewer's +// CheckView, no signed link needed. /artifact-download sets +// Content-Disposition: attachment, but that only affects a top-level +// navigation/click, not an sub-resource load, so it still renders +// inline here. +function screenshotDownloadURL(session: SessionRef, shot: InteractionScreenshot): string { + const params = new URLSearchParams({ + artifactId: shot.artifactId ?? "", + sessionRef: `${session.namespace}/${session.name}`, + fn: shot.filename || shot.renderName, + }); + return `/artifact-download?${params.toString()}`; +} + // outcomeIcon maps an InteractionAppliedInner.outcome (channelevents.Outcome*) // to its resolved-state glyph, mirroring MessageList's planItemIcon. Unknown // outcomes fall back to a neutral check — a resolved card always reads as @@ -386,6 +405,19 @@ export function InteractionCard(props: { {request.body &&
{request.body}
} + {request.screenshot && ( + // The screenshot is a visual aid for the approver's judgment call — a + // redacted snapshot of the page at the moment the interaction was + // raised. Capped at max-height so a tall page can't blow out the + // card's layout; a bad/missing src just shows a broken-image glyph + // (acceptable — a best-effort render, never worth throwing over). + {request.screenshot.altText + )} + {footer} {request.fields && request.fields.length > 0 && ( diff --git a/pkg/web/webui/chat/ui/types.ts b/pkg/web/webui/chat/ui/types.ts index 40c29106..29d5aacd 100644 --- a/pkg/web/webui/chat/ui/types.ts +++ b/pkg/web/webui/chat/ui/types.ts @@ -420,6 +420,21 @@ export interface InteractionAction { url?: string; } +// InteractionScreenshot mirrors channelevents.AttachmentRef as carried on +// InteractionRequestPayload.Screenshot: a redacted page screenshot taken at +// the moment a browser interaction (e.g. a tool approval) was raised. Refs +// only — the bytes are fetched same-origin via /artifact-download, gated by +// the viewer's CheckView, same as an outbound message's attachments +// (ChatView's artifactDownloadURL). artifactId/filename are the fields that +// URL needs; mime/altText are display hints only. +export interface InteractionScreenshot { + renderName: string; + artifactId?: string; + mime: string; + filename: string; + altText?: string; +} + // InteractionRequestInner mirrors channelevents.InteractionRequestPayload — // the semantic request body (Lead/Body/Fields/Excerpt/Actions/Audience) that // replaced the per-prompt-type kind families (tool approval, credential @@ -438,6 +453,12 @@ export interface InteractionRequestInner { audience: { scope: string }; expiresAt?: string; interruptible?: boolean; + // screenshot, when set, is a redacted page screenshot taken when a browser + // interaction was raised (a tool approval's "what does the page look like + // right now"). Absent for every non-browser category and for a browser + // interaction whose capture failed (best-effort — see + // channelevents.InteractionRequestPayload.Screenshot). + screenshot?: InteractionScreenshot; } // InteractionRequestPayload mirrors builtin.MsgInteractionRequest diff --git a/pkg/web/webui/webassets/dist/IdentityShell.D-zSSgc9.js b/pkg/web/webui/webassets/dist/IdentityShell.DBeEfGP6.js similarity index 86% rename from pkg/web/webui/webassets/dist/IdentityShell.D-zSSgc9.js rename to pkg/web/webui/webassets/dist/IdentityShell.DBeEfGP6.js index 2db5e899..0f9031ea 100644 --- a/pkg/web/webui/webassets/dist/IdentityShell.D-zSSgc9.js +++ b/pkg/web/webui/webassets/dist/IdentityShell.DBeEfGP6.js @@ -1 +1 @@ -import{j as e}from"./vendor.C5MRNvUt.js";import{C as a,b as n,d,e as m}from"./mount.BOEH1oNx.js";function l({title:s,subtitle:r,children:t}){return e.jsx("div",{className:"min-h-screen flex items-start justify-center p-6 bg-background text-foreground",children:e.jsxs(a,{className:"max-w-xl w-full mt-[8vh]",children:[e.jsxs(n,{children:[e.jsx(d,{children:s}),r&&e.jsx("p",{className:"text-sm text-muted-foreground mt-1",children:r})]}),e.jsx(m,{children:t})]})})}export{l as I}; +import{j as e}from"./vendor.C5MRNvUt.js";import{C as a,b as n,d,e as m}from"./mount.D4ypHaeQ.js";function l({title:s,subtitle:r,children:t}){return e.jsx("div",{className:"min-h-screen flex items-start justify-center p-6 bg-background text-foreground",children:e.jsxs(a,{className:"max-w-xl w-full mt-[8vh]",children:[e.jsxs(n,{children:[e.jsx(d,{children:s}),r&&e.jsx("p",{className:"text-sm text-muted-foreground mt-1",children:r})]}),e.jsx(m,{children:t})]})})}export{l as I}; diff --git a/pkg/web/webui/webassets/dist/NoticeBanner.lKrMgKCy.js b/pkg/web/webui/webassets/dist/NoticeBanner.C_F8xF59.js similarity index 91% rename from pkg/web/webui/webassets/dist/NoticeBanner.lKrMgKCy.js rename to pkg/web/webui/webassets/dist/NoticeBanner.C_F8xF59.js index 8149e316..5bf0d78a 100644 --- a/pkg/web/webui/webassets/dist/NoticeBanner.lKrMgKCy.js +++ b/pkg/web/webui/webassets/dist/NoticeBanner.C_F8xF59.js @@ -1 +1 @@ -import{r as o,j as c}from"./vendor.C5MRNvUt.js";import{A as u,a as d,c as a}from"./mount.BOEH1oNx.js";function k(t){const e=new URLSearchParams(t),i=e.get("error");if(i)return{kind:"error",text:i};const n=e.get("notice");if(n){const[s,r]=n.split(":");return s==="linked"&&r?{kind:"success",text:`Linked ${r}.`}:s==="revoked"&&r?{kind:"success",text:`Revoked ${r}.`}:s==="linkedunverified"&&r?{kind:"error",text:`Linked ${r} — but the token could not be verified. It may not work.`}:{kind:"success",text:n}}return null}function f({search:t}){const[e]=o.useState(()=>k(t));return e?c.jsx(u,{className:a("mb-4",e.kind==="error"?"border-destructive text-destructive":"border-success text-success"),children:c.jsx(d,{children:e.text})}):null}export{f as N}; +import{r as o,j as c}from"./vendor.C5MRNvUt.js";import{A as u,a as d,c as a}from"./mount.D4ypHaeQ.js";function k(t){const e=new URLSearchParams(t),i=e.get("error");if(i)return{kind:"error",text:i};const n=e.get("notice");if(n){const[s,r]=n.split(":");return s==="linked"&&r?{kind:"success",text:`Linked ${r}.`}:s==="revoked"&&r?{kind:"success",text:`Revoked ${r}.`}:s==="linkedunverified"&&r?{kind:"error",text:`Linked ${r} — but the token could not be verified. It may not work.`}:{kind:"success",text:n}}return null}function f({search:t}){const[e]=o.useState(()=>k(t));return e?c.jsx(u,{className:a("mb-4",e.kind==="error"?"border-destructive text-destructive":"border-success text-success"),children:c.jsx(d,{children:e.text})}):null}export{f as N}; diff --git a/pkg/web/webui/webassets/dist/PatForm.BuKUBhkS.js b/pkg/web/webui/webassets/dist/PatForm.BrJ1dS20.js similarity index 92% rename from pkg/web/webui/webassets/dist/PatForm.BuKUBhkS.js rename to pkg/web/webui/webassets/dist/PatForm.BrJ1dS20.js index c5ede216..2cc4f59f 100644 --- a/pkg/web/webui/webassets/dist/PatForm.BuKUBhkS.js +++ b/pkg/web/webui/webassets/dist/PatForm.BrJ1dS20.js @@ -1 +1 @@ -import{j as e}from"./vendor.C5MRNvUt.js";import{B as m}from"./mount.BOEH1oNx.js";function p({action:o,hidden:r,submitLabel:a,instructions:t,docsUrl:n}){return e.jsxs(e.Fragment,{children:[t&&e.jsxs("div",{className:"text-xs text-muted-foreground mb-3 whitespace-pre-line",children:[t,n&&e.jsxs(e.Fragment,{children:[" ",e.jsx("a",{href:n,target:"_blank",rel:"noreferrer",className:"underline",children:"How to get this token"})]})]}),e.jsxs("form",{method:"POST",action:o,autoComplete:"off",className:"flex gap-2 items-center",children:[r&&Object.entries(r).map(([s,i])=>e.jsx("input",{type:"hidden",name:s,value:i},s)),e.jsx("input",{type:"password",name:"token",placeholder:"Token",required:!0,className:"flex-1 rounded-md bg-background border border-input px-2.5 py-1.5 text-sm outline-none focus:ring-2 focus:ring-ring"}),e.jsx(m,{type:"submit",size:"sm",children:a})]})]})}export{p as P}; +import{j as e}from"./vendor.C5MRNvUt.js";import{B as m}from"./mount.D4ypHaeQ.js";function p({action:o,hidden:r,submitLabel:a,instructions:t,docsUrl:n}){return e.jsxs(e.Fragment,{children:[t&&e.jsxs("div",{className:"text-xs text-muted-foreground mb-3 whitespace-pre-line",children:[t,n&&e.jsxs(e.Fragment,{children:[" ",e.jsx("a",{href:n,target:"_blank",rel:"noreferrer",className:"underline",children:"How to get this token"})]})]}),e.jsxs("form",{method:"POST",action:o,autoComplete:"off",className:"flex gap-2 items-center",children:[r&&Object.entries(r).map(([s,i])=>e.jsx("input",{type:"hidden",name:s,value:i},s)),e.jsx("input",{type:"password",name:"token",placeholder:"Token",required:!0,className:"flex-1 rounded-md bg-background border border-input px-2.5 py-1.5 text-sm outline-none focus:ring-2 focus:ring-ring"}),e.jsx(m,{type:"submit",size:"sm",children:a})]})]})}export{p as P}; diff --git a/pkg/web/webui/webassets/dist/StartupLine.D55RHpak.js b/pkg/web/webui/webassets/dist/StartupLine.o9MnUGnk.js similarity index 73% rename from pkg/web/webui/webassets/dist/StartupLine.D55RHpak.js rename to pkg/web/webui/webassets/dist/StartupLine.o9MnUGnk.js index 381780d9..0fed1b1e 100644 --- a/pkg/web/webui/webassets/dist/StartupLine.D55RHpak.js +++ b/pkg/web/webui/webassets/dist/StartupLine.o9MnUGnk.js @@ -1,3 +1,3 @@ -import{ad as nt,r as l,j as n,x as rt,y as J,z as st,ae as ue,K as at,af as fe,ag as xe,ah as Se,ai as ot,aj as it,ak as lt,al as ct,am as Te,an as ce,ao as _e,c as dt,ap as ut,C as ft,O as xt,T as pt,aa as mt,aq as ht,E as gt,ar as yt,as as bt,at as jt}from"./vendor.C5MRNvUt.js";import{I as vt,J as wt,K as Nt,c as b,B as X,H as kt}from"./mount.BOEH1oNx.js";import{M as Ct}from"./markdown.FOTo-3Mz.js";function ye(e){return e.toFixed(1).replace(/\.0$/,"")}function be(e){return(!Number.isFinite(e)||e<0)&&(e=0),e<1e3?String(Math.round(e)):e<1e6?`${ye(e/1e3)}K`:`${ye(e/1e6)}M`}function pe(e){if((!Number.isFinite(e)||e<0)&&(e=0),e=Math.floor(e),e<60)return`${e}s`;const t=Math.floor(e/60),r=e%60;return r===0?`${t}m`:`${t}m${r}s`}function It(e){return e?`working · ${pe(e.elapsedSeconds)} · ${be(e.inputTokens)} in · ${be(e.outputTokens)} out`:"working"}const je=500,Z=new Uint8Array(0);function Rt(e){return{ref:e,outerTool:"",reason:"",lines:[],elided:0,pending:{stdout:Z,stderr:Z},done:!1,ok:!1}}function St(e){try{const t=atob(e),r=new Uint8Array(t.length);for(let s=0;s{const r={text:t.content};t.fg&&(r.fg=`rgb(${t.fg})`),t.bg&&(r.bg=`rgb(${t.bg})`);const s=t.decoration??void 0,d=Array.isArray(t.decorations)?t.decorations:s?[s]:[];return d.includes("bold")&&(r.bold=!0),d.includes("italic")&&(r.italic=!0),d.includes("underline")&&(r.underline=!0),d.includes("dim")&&(r.dim=!0),r})}function F(e,t){if(e.lines.push(t),e.lines.length>je){const r=e.lines.length-je;e.lines.splice(0,r),e.elided+=r}}function _t(e,t,r){let s=Tt(e.pending[t],r),d=0;for(let u=0;ud&&s[c-1]===13&&c--,F(e,{kind:t,spans:M($e.decode(s.subarray(d,c)))}),d=u+1}e.pending[t]=d===0?s:s.subarray(d)}function qe(e){for(const t of["stdout","stderr"]){const r=e.pending[t];r.length!==0&&(F(e,{kind:t,spans:M($e.decode(r))}),e.pending[t]=Z)}}function ve(e,t){const r=e??Rt(t);return{...r,lines:r.lines.slice(),pending:{...r.pending}}}function we(e){const t=e.payload;return t==null?void 0:t.payload}function $t(e,t){switch(t.outerTool&&(e.outerTool=t.outerTool),t.reason&&(e.reason=t.reason),t.eventType){case"result":qe(e),e.done=!0,e.ok=t.ok??!1,t.durationMs!==void 0&&(e.durationMs=t.durationMs),t.costUsd!==void 0&&(e.costUsd=t.costUsd),t.summary&&F(e,{kind:"event",spans:M(t.summary)});return;case"tool_use_start":F(e,{kind:"event",spans:M(t.summary??""),toolName:t.toolName});return;case"tool_use_stop":F(e,{kind:"event",spans:M(" "+[t.ok?"✓":"✗",t.summary].filter(Boolean).join(" "))});return;default:t.text&&F(e,{kind:"event",spans:M(t.text)})}}function qt(e,t){const r=t.stream==="stderr"?"stderr":"stdout";t.data&&_t(e,r,St(t.data)),t.terminal&&(qe(e),e.done=!0,e.ok=(t.exitCode??0)===0&&t.exitReason!=="failed",t.exitCode!==void 0&&(e.exitCode=t.exitCode),t.exitReason&&(e.exitReason=t.exitReason))}function Et(e,t){if(t.type==="tool_session_event"){const r=we(t);if(!(r!=null&&r.toolCallRef))return e;const s=ve(e[r.toolCallRef],r.toolCallRef);return $t(s,r),{...e,[r.toolCallRef]:s}}if(t.type==="tool_session_delta"){const r=we(t);if(!(r!=null&&r.toolCallRef))return e;const s=ve(e[r.toolCallRef],r.toolCallRef);return qt(s,r),{...e,[r.toolCallRef]:s}}return e}function At(e){try{const t=JSON.parse(e);return!t||typeof t.type!="string"?null:t}catch{return null}}function Ot(e,t,r){return`${e.protocol==="https:"?"wss:":"ws:"}//${e.host}/sessions/api/${encodeURIComponent(t)}/${encodeURIComponent(r)}/ws`}const oe=3;function Lt(e,t,r){const[s,d]=l.useState("connecting"),u=l.useRef(r);return u.current=r,l.useEffect(()=>{if(!e||!t){console.error("chat: no live socket opened; this view was given no session to address",{ns:e,name:t}),d("offline");return}let c=null,a,m=!1,p=0;const N=()=>{m||(p+=1,d(p>=oe?"offline":"reconnecting"),a=window.setTimeout(j,2e3))},j=()=>{if(!m){d(p===0?"connecting":p>=oe?"offline":"reconnecting");try{c=new WebSocket(Ot(window.location,e,t))}catch{N();return}c.onopen=()=>{p=0,d("connected")},c.onmessage=S=>{const _=At(S.data);_&&u.current(_)},c.onerror=()=>{m||d(p>=oe?"offline":"reconnecting")},c.onclose=N}};return j(),()=>{m=!0,a&&window.clearTimeout(a),c&&c.close()}},[e,t]),{state:s}}const Ee={turnActive:!1,awaitingReply:!1,pausedIdle:!1,lastAgentReply:null,replySeq:0,composingUpdate:!1,activity:null,plan:null,notice:null,ended:!1,startup:null,pendingInteractions:[]};function Ut(e,t){return e===t?!0:e===null||t===null?!1:e.text===t.text&&e.seq===t.seq}function ie(e,t){return e===t?!0:e===null||t===null?!1:JSON.stringify(e)===JSON.stringify(t)}function Dt(e,t){return e===t?!0:e.length!==t.length?!1:e.every((r,s)=>r===t[s])}function Pt(e,t){return e.turnActive===t.turnActive&&e.awaitingReply===t.awaitingReply&&e.pausedIdle===t.pausedIdle&&Ut(e.lastAgentReply,t.lastAgentReply)&&e.replySeq===t.replySeq&&e.composingUpdate===t.composingUpdate&&ie(e.activity,t.activity)&&ie(e.plan,t.plan)&&e.notice===t.notice&&e.ended===t.ended&&ie(e.startup,t.startup)&&Dt(e.pendingInteractions,t.pendingInteractions)}const Mt={type:"__reconnect"};function Ft(e,t){const r=Bt(e,t);return r===e||Pt(e,r)?e:r}function Bt(e,t){var r,s,d,u,c;switch(t.type){case"turn_activity":{const a=t.payload;return a!=null&&a.active?{...e,turnActive:!0,awaitingReply:!1,pausedIdle:!1,composingUpdate:!1,lastAgentReply:null,notice:null}:{...e,turnActive:!1,awaitingReply:(a==null?void 0:a.cause)==="awaiting_reply",pausedIdle:(a==null?void 0:a.cause)==="idle",composingUpdate:!1}}case"user_message":{const a=t.payload,m=e.replySeq+1;return{...e,lastAgentReply:{text:(a==null?void 0:a.text)??"",seq:m},replySeq:m}}case"user_echo":return{...e,lastAgentReply:null,awaitingReply:!1};case"stream_delta":{const a=(r=t.payload)==null?void 0:r.payload;return(a==null?void 0:a.eventType)==="tool_use_start"&&a.toolName==="update_view"?{...e,composingUpdate:!0}:(a==null?void 0:a.eventType)==="tool_use_stop"||(a==null?void 0:a.eventType)==="stop"?{...e,composingUpdate:!1}:e}case"operation_activity":{const a=(s=t.payload)==null?void 0:s.payload;return{...e,activity:a!=null&&a.cleared?null:a??null}}case"plan_update":{const a=(d=t.payload)==null?void 0:d.payload;return{...e,plan:a??null}}case"notification":{const a=t.payload;return{...e,notice:(a==null?void 0:a.text)??null}}case"interaction_request":{const a=(u=t.payload)==null?void 0:u.payload;if(!(a!=null&&a.requestRef))return e;const m=e.pendingInteractions.findIndex(N=>N.requestRef===a.requestRef),p=m>=0?e.pendingInteractions.map((N,j)=>j===m?a:N):[...e.pendingInteractions,a];return{...e,pendingInteractions:p}}case"interaction_applied":{const a=(c=t.payload)==null?void 0:c.payload;return a!=null&&a.requestRef?{...e,pendingInteractions:e.pendingInteractions.filter(m=>m.requestRef!==a.requestRef)}:e}case"__reconnect":return{...e,turnActive:!1,pausedIdle:!1,composingUpdate:!1,activity:null,startup:null,pendingInteractions:[]};case"session_startup":{const a=t.payload;return!a||a.started||!a.text?{...e,startup:null}:{...e,startup:{text:a.text??"",short:a.short??null,stillTrying:!!a.stillTrying}}}case"session_ended":return{...e,ended:!0,turnActive:!1,awaitingReply:!1,pausedIdle:!1,composingUpdate:!1,startup:null,pendingInteractions:[]};default:return e}}const Ae=l.createContext(Ee);function Oe(){return l.useContext(Ae)}const me=l.createContext({state:"offline",subscribe:()=>(console.error("chat: useSessionFrames outside a SessionSocketProvider; no frames will arrive"),()=>{})});function Ln({ns:e,name:t,children:r}){const s=l.useRef(null);s.current===null&&(s.current=new Set);const[d,u]=l.useReducer(Ft,Ee),c=l.useCallback(j=>{u(j);for(const S of s.current)S(j)},[]),{state:a}=Lt(e,t,c),m=l.useCallback(j=>(s.current.add(j),()=>{s.current.delete(j)}),[]),p=l.useRef(a);l.useEffect(()=>{const j=p.current;p.current=a,a==="connected"&&(j==="reconnecting"||j==="offline")&&u(Mt)},[a]);const N=l.useMemo(()=>({state:a,subscribe:m}),[a,m]);return n.jsx(me.Provider,{value:N,children:n.jsx(Ae.Provider,{value:d,children:r})})}function Ht(e){const{subscribe:t}=l.useContext(me),r=l.useRef(e);r.current=e,l.useEffect(()=>t(s=>r.current(s)),[t])}function Jt(){return l.useContext(me).state}const Vt={connected:{Icon:st,color:"text-success",spin:!1,tip:"Live — connected"},connecting:{Icon:J,color:"text-warning",spin:!0,tip:"Connecting…"},reconnecting:{Icon:J,color:"text-warning",spin:!0,tip:"Reconnecting…"},offline:{Icon:rt,color:"text-destructive",spin:!1,tip:"Offline — retrying"}};function Yt({state:e}){const t=Vt[e],{Icon:r}=t;return n.jsxs(vt,{children:[n.jsx(wt,{asChild:!0,children:n.jsx("div",{className:`flex h-7 w-7 items-center justify-center rounded-md cursor-default ${t.color}`,children:n.jsx(r,{className:`h-[18px] w-[18px] ${t.spin?"animate-spin":""}`,"aria-hidden":"true"})})}),n.jsx(Nt,{children:t.tip})]})}function Kt({call:e}){return n.jsxs("div",{className:b("flex items-center gap-1.5 pl-4 text-[11px]",e.active?"text-muted-foreground animate-pulse":"text-muted-foreground/60"),children:[n.jsx("span",{className:"truncate",children:e.reason}),n.jsxs("span",{className:"shrink-0",children:["· ",pe(e.elapsedSeconds)]})]})}function zt({op:e}){return n.jsxs("div",{className:"flex flex-col gap-0.5",children:[n.jsxs("div",{className:b("flex items-center gap-1.5 text-[11px]",e.active?"text-muted-foreground animate-pulse":"text-muted-foreground/60"),children:[n.jsx("span",{className:"truncate",children:e.description}),n.jsxs("span",{className:"shrink-0",children:["· ",pe(e.elapsedSeconds)]})]}),(e.calls??[]).map((t,r)=>n.jsx(Kt,{call:t},r))]})}function Wt({nodes:e}){return e.length===0?null:n.jsx("div",{className:"flex flex-col gap-1 items-start","data-testid":"operation-tree",children:e.map(t=>n.jsx(zt,{op:t},t.id))})}function Gt({fields:e}){return!e||e.length===0?null:n.jsx("div",{className:"flex flex-col gap-0.5",children:e.map((t,r)=>n.jsxs("div",{className:"text-xs leading-snug",children:[n.jsxs("span",{className:"font-medium text-card-foreground",children:[t.label,":"]})," ",n.jsx("span",{className:"text-muted-foreground",children:t.value})]},`${t.label}:${r}`))})}function Le({excerpt:e}){return e?n.jsx("pre",{className:"max-h-48 overflow-auto whitespace-pre-wrap break-words rounded-md border border-border bg-background px-2 py-1.5 text-[11px] leading-snug text-card-foreground",children:n.jsxs("code",{children:[e.label?`${e.label}: -`:"",e.content]})}):null}function Qt(e){switch(e){case"denied":return n.jsx(Se,{className:"h-3.5 w-3.5 shrink-0 text-destructive","aria-hidden":"true"});case"expired":return n.jsx(xe,{className:"h-3.5 w-3.5 shrink-0 text-muted-foreground","aria-hidden":"true"});default:return n.jsx(fe,{className:"h-3.5 w-3.5 shrink-0 text-success","aria-hidden":"true"})}}const Xt={agent:"Running as the agent",userPassthrough:"Running as you",cancel:"Cancelled"},Zt={approved:"Approved",denied:"Denied",expired:"Expired",resolved:"Resolved"};function en(e){if(e.category==="identity_choice"){const r=Xt[e.outcomeText??""];if(r)return r}const t=(e.outcomeText??"").trim();return t!==""?t:Zt[e.outcome]??e.outcome}function tn(e){return e==="primary"?"default":e==="danger"?"destructive":"secondary"}function nn({action:e,pending:t,onClick:r}){const s=tn(e.style);return e.kind==="link"||e.kind==="link_mint"?e.url?n.jsx(X,{asChild:!0,variant:s,size:"sm",children:n.jsxs("a",{href:e.url,target:"_blank",rel:"noopener noreferrer",children:[e.label,n.jsx(Te,{className:"h-3.5 w-3.5","aria-hidden":"true"})]})}):null:n.jsx(X,{variant:s,size:"sm",disabled:t,onClick:r,children:e.label})}const rn={readonly:{Icon:it,textClass:"text-success"},readwrite:{Icon:ot,textClass:"text-primary"},external:{Icon:ue,textClass:"text-warning"}},sn={repository:ct,github:lt};function de({items:e,depth:t=0}){let r=0;return n.jsx("div",{className:b("flex flex-col",t===0?"gap-1.5":t===1?"gap-1":"gap-0.5 pl-2"),children:e.map((s,d)=>{var m;const u=t===0&&!!((m=s.items)!=null&&m.length);u&&(r+=1);const c=s.tone?rn[s.tone]:void 0,a=s.icon?sn[s.icon]:void 0;return n.jsxs("div",{className:b(u&&"rounded-md border border-border/60 bg-muted/30 px-3 py-2.5"),children:[n.jsxs("div",{className:"flex flex-wrap items-baseline gap-x-1.5",children:[u&&n.jsx("span",{className:"rounded bg-state/15 px-1 py-px font-mono text-[10px] font-medium text-state",children:r}),c&&n.jsx(c.Icon,{"data-testid":`tier-${s.tone}`,className:b("h-3 w-3 shrink-0",c.textClass),"aria-hidden":"true"}),a&&n.jsx(a,{"data-testid":`resource-icon-${s.icon}`,className:"h-3 w-3 shrink-0 text-muted-foreground","aria-hidden":"true"}),n.jsx("span",{title:s.hint||void 0,className:b(u&&"font-medium",s.hint&&"cursor-help underline decoration-dotted decoration-muted-foreground/60 underline-offset-2",s.tone==="muted"?"text-muted-foreground":c?b("font-medium",c.textClass):"text-card-foreground"),children:s.text}),s.detail&&s.href?n.jsx("a",{href:s.href,target:"_blank",rel:"noopener noreferrer",className:"break-all font-mono text-[11px] text-link underline decoration-link/40 underline-offset-2 hover:decoration-link",children:s.href}):s.detail&&n.jsx("span",{className:b("break-all",s.tone==="external"?"rounded bg-warning/15 px-1.5 py-px text-[10px] font-semibold uppercase tracking-wide text-warning ring-1 ring-inset ring-warning/30":"font-mono text-[11px] text-muted-foreground"),children:s.detail})]}),s.items&&s.items.length>0&&n.jsx("div",{className:b(t===0&&"mt-2"),children:n.jsx(de,{items:s.items,depth:t+1})})]},`${s.text}:${d}`)})})}function an(e){const t=r=>(r??[]).some(s=>s.tone==="external"||t(s.items));return(e??[]).some(r=>t(r.items))}function on(e){const{request:t,applied:r,onDecision:s,footer:d}=e,u=an(t.fields),[c,a]=l.useState(!1),m=!!r;return n.jsxs("div",{className:b("mx-auto flex w-full max-w-[85%] flex-col gap-2 rounded-lg border bg-card/60 px-3 py-2.5",m?"border-border":u?"border-l-2 border-border border-l-warning":"border-l-2 border-border border-l-primary"),"data-testid":"interaction-card","data-request-ref":t.requestRef,"data-external":u?"true":void 0,children:[n.jsxs("div",{className:"flex items-start gap-1.5",children:[n.jsx("span",{className:"mt-0.5",children:m?Qt(r.outcome):u?n.jsx(ue,{className:"h-3.5 w-3.5 shrink-0 text-warning","aria-hidden":"true"}):n.jsx(at,{className:"h-3.5 w-3.5 shrink-0 text-primary","aria-hidden":"true"})}),n.jsx("span",{className:b("break-words text-sm font-semibold leading-snug",m?"text-muted-foreground":"text-card-foreground"),children:t.lead})]}),t.body&&n.jsx("div",{className:"text-xs leading-snug text-muted-foreground",children:t.body}),d,t.fields&&t.fields.length>0&&n.jsx("div",{className:"flex flex-col gap-2.5",children:t.fields.map((p,N)=>{if(p.items&&p.items.length>0){const S="text-[10px] font-medium uppercase tracking-wide text-muted-foreground";return m?n.jsxs("details",{className:"text-xs leading-snug",children:[n.jsxs("summary",{className:b(S,"cursor-pointer hover:text-foreground"),children:[p.label," ",n.jsxs("span",{className:"font-normal normal-case tracking-normal text-muted-foreground/70",children:["(",p.items.length,")"]})]}),n.jsx("div",{className:"mt-2",children:n.jsx(de,{items:p.items})})]},`${p.label}:${N}`):n.jsxs("div",{className:"flex flex-col gap-1 text-xs leading-snug",children:[n.jsx("div",{className:S,children:p.label}),n.jsx(de,{items:p.items})]},`${p.label}:${N}`)}const j=p.value.includes(` -`);return n.jsxs("div",{className:"flex flex-col gap-0.5 text-xs leading-snug",children:[n.jsx("div",{className:"text-[10px] font-medium uppercase tracking-wide text-muted-foreground",children:p.label}),n.jsx("span",{className:b("text-card-foreground",j&&"whitespace-pre-wrap break-words"),children:p.value})]},`${p.label}:${N}`)})}),n.jsx(Le,{excerpt:t.excerpt}),m?n.jsx("div",{className:b("text-xs",r.outcome==="denied"?"text-destructive":"text-muted-foreground"),children:en(r)}):t.actions&&t.actions.length>0&&n.jsx("div",{className:"mt-0.5 flex flex-wrap justify-end gap-1.5 border-t border-border/60 pt-2",children:t.actions.map(p=>n.jsx(nn,{action:p,pending:c,onClick:()=>{a(!0),s(t.requestRef,t.category,p.id)}},p.id))})]})}const ln={critical:{Icon:ue,color:"text-destructive"},privacy:{Icon:dt,color:"text-warning"},degraded:{Icon:_e,color:"text-warning"},waiting:{Icon:xe,color:"text-muted-foreground"},routine:{Icon:ce,color:"text-muted-foreground"},housekeeping:{Icon:ce,color:"text-muted-foreground"},resolved:{Icon:fe,color:"text-success"}},cn={Icon:ce,color:"text-muted-foreground"},dn={money:ut,clock:xe};function un({notice:e}){const t=ln[e.tone??""]??cn,r=dn[e.glyph??""]??t.Icon;return n.jsxs("div",{className:"mx-auto flex w-full max-w-[85%] flex-col gap-2 rounded-lg border border-border bg-card/60 px-3 py-2.5","data-testid":"notice-card","data-tone":e.tone||"",children:[n.jsxs("div",{className:b("flex items-center gap-1.5 text-xs font-medium",t.color),children:[n.jsx(r,{className:"h-3.5 w-3.5 shrink-0","aria-hidden":"true"}),n.jsx("span",{className:"break-words text-card-foreground",children:e.lead})]}),e.body&&n.jsx("div",{className:"text-xs text-muted-foreground",children:e.body}),n.jsx(Gt,{fields:e.fields}),n.jsx(Le,{excerpt:e.excerpt}),e.nextStep&&n.jsx("div",{className:"text-xs font-medium text-card-foreground",children:e.nextStep})]})}function fn({spans:e}){return n.jsx(n.Fragment,{children:e.map((t,r)=>{const s={};return t.fg&&(s.color=t.fg),t.bg&&(s.backgroundColor=t.bg),t.dim&&(s.opacity=.6),n.jsx("span",{style:s,className:b(t.bold&&"font-semibold",t.italic&&"italic",t.underline&&"underline"),children:t.text},r)})})}function xn({line:e}){return n.jsxs("div",{"data-stream":e.kind,className:b("whitespace-pre-wrap break-all font-mono text-[11px] leading-[1.45]",e.kind==="stderr"&&"text-red-300/90",e.kind==="event"&&"text-foreground/80"),children:[e.toolName&&n.jsxs("span",{className:"mr-1.5 inline-flex items-center gap-1 text-[10px] text-muted-foreground",children:[n.jsx(mt,{className:"h-2.5 w-2.5"}),e.toolName]}),n.jsx(fn,{spans:e.spans})]})}function pn(e){const t=e/1e3;if(t<60)return`${t.toFixed(1)}s`;const r=Math.floor(t/60);return`${r}m${Math.round(t-r*60)}s`}function mn(e){const t=[e.ok?"done":"failed"];return!e.ok&&e.exitCode!==void 0&&t.push(`exit ${e.exitCode}`),!e.ok&&e.exitReason&&e.exitReason!=="failed"&&t.push(e.exitReason),e.durationMs!==void 0&&t.push(pn(e.durationMs)),e.costUsd!==void 0&&t.push(`$${e.costUsd.toFixed(2)}`),t.join(" · ")}function hn({state:e}){const[t,r]=l.useState(void 0),s=t??!(e.done&&e.ok),d=[e.outerTool||"tool",e.reason].filter(Boolean).join(" · ");return n.jsxs("div",{className:"my-1 w-full overflow-hidden rounded-md border border-border/60 bg-background/40",children:[n.jsxs("button",{type:"button","data-testid":"tool-session-toggle",onClick:()=>r(!s),className:"flex w-full items-center gap-1.5 px-2 py-1.5 text-left text-[11px] text-muted-foreground hover:bg-foreground/5",children:[s?n.jsx(ft,{className:"h-3 w-3 shrink-0"}):n.jsx(xt,{className:"h-3 w-3 shrink-0"}),n.jsx(pt,{className:"h-3 w-3 shrink-0"}),n.jsx("span",{className:b("truncate",!e.done&&"animate-pulse"),children:d})]}),s&&n.jsxs("div",{"data-testid":"tool-session-body",className:"max-h-80 overflow-auto border-t border-border/60 px-2 py-1.5",children:[e.elided>0&&n.jsxs("div",{className:"mb-1 text-[10px] italic text-muted-foreground/70",children:["… ",e.elided," earlier ",e.elided===1?"line":"lines"," elided"]}),e.lines.map((u,c)=>n.jsx(xn,{line:u},c))]}),e.done&&n.jsx("div",{"data-testid":"tool-session-footer",className:b("border-t border-border/60 px-2 py-1 text-[10px]",e.ok?"text-muted-foreground":"text-red-300/90"),children:mn(e)})]})}const G=l.memo(function({text:t}){return n.jsx(Ct,{children:t})});function Ue({text:e}){return n.jsx("span",{className:"whitespace-pre-wrap break-words",children:e})}function De(e){return e==="done"||e==="complete"||e==="completed"||e==="skipped"}function gn(e,t){if(De(e))return n.jsx(fe,{className:"h-3.5 w-3.5 shrink-0 text-success","aria-hidden":"true"});switch(e){case"in_progress":case"active":case"running":return n.jsx(J,{className:b("h-3.5 w-3.5 shrink-0 text-primary",t&&"animate-spin"),"aria-hidden":"true"});case"blocked":case"failed":case"error":return n.jsx(Se,{className:"h-3.5 w-3.5 shrink-0 text-destructive","aria-hidden":"true"});default:return n.jsx(bt,{className:"h-3.5 w-3.5 shrink-0 text-muted-foreground","aria-hidden":"true"})}}function le({items:e,live:t}){return n.jsx("ul",{className:"flex flex-col gap-1",children:e.map(r=>{const s=De(r.status);return n.jsxs("li",{className:"flex items-start gap-1.5 text-xs leading-snug",children:[n.jsx("span",{className:"mt-0.5",children:gn(r.status,t)}),n.jsx("span",{className:b("break-words",s?"text-muted-foreground":"text-card-foreground"),children:r.label})]},r.id)})})}function Pe({plan:e,live:t}){const r=e.items??[],s=e.phases??[];if(s.length===0)return n.jsx(le,{items:r,live:t});const d=s.map(a=>({phase:a,steps:r.filter(m=>m.phase===a.id)})).filter(a=>a.steps.length>0),u=new Set(s.map(a=>a.id)),c=r.filter(a=>!a.phase||!u.has(a.phase));return n.jsxs("div",{className:"flex flex-col gap-2",children:[d.map((a,m)=>n.jsxs("div",{className:"flex flex-col gap-1",children:[n.jsx("div",{className:"break-words text-xs font-medium text-card-foreground",children:a.phase.label}),n.jsx("div",{className:"border-l border-border/60 pl-2",children:n.jsx(le,{items:a.steps,live:t})})]},a.phase.id||m)),c.length>0&&n.jsxs("div",{className:"flex flex-col gap-1",children:[d.length>0&&n.jsx("span",{className:"text-[10px] font-medium uppercase tracking-wide text-muted-foreground",children:"Other steps"}),n.jsx("div",{className:b(d.length>0&&"border-l border-border/60 pl-2"),children:n.jsx(le,{items:c,live:t})})]})]})}function yn({plan:e,live:t}){const r=e.items??[];return n.jsxs("div",{className:"mx-auto w-full max-w-[85%] rounded-lg border border-border bg-card/60 px-3 py-2",children:[n.jsxs("div",{className:"flex items-center gap-1.5 text-xs font-medium text-muted-foreground mb-1.5",children:[n.jsx(yt,{className:"h-3.5 w-3.5","aria-hidden":"true"}),n.jsxs("span",{children:["Plan",r.length>0?` · ${r.length} step${r.length===1?"":"s"}`:""]})]}),r.length===0?n.jsx("div",{className:"text-xs text-muted-foreground",children:"Plan updated."}):n.jsx(Pe,{plan:e,live:t})]})}function D({isUser:e,className:t,children:r}){return n.jsx("div",{className:b("flex",e?"justify-end":"justify-start"),children:n.jsx("div",{className:b("max-w-[75%] rounded-2xl px-3.5 py-2 text-sm leading-relaxed",e?"bg-primary text-primary-foreground rounded-br-sm":"bg-card border border-border text-card-foreground rounded-bl-sm",t),children:r})})}const bn=l.memo(function({line:t,toolSession:r,onRetry:s,onDecision:d,live:u,absorbedPlan:c}){return t.role==="toolSession"?r?n.jsx(hn,{state:r}):null:t.liveViewUrl?n.jsx("div",{className:"flex justify-center py-1",children:n.jsxs("a",{href:t.liveViewUrl,target:"_blank",rel:"noopener noreferrer",className:"inline-flex items-center gap-1.5 rounded-lg border border-border bg-card px-3 py-1.5 text-xs font-medium text-card-foreground hover:bg-accent hover:text-accent-foreground",children:[n.jsx(Te,{className:"h-3.5 w-3.5 shrink-0","aria-hidden":"true"}),"View live"]})}):t.role==="plan"&&t.plan?n.jsx(yn,{plan:t.plan,live:u}):t.role==="interaction"&&t.interactionRequest?n.jsx(on,{request:t.interactionRequest,applied:t.interactionApplied,onDecision:d??(()=>{}),footer:c?n.jsxs("div",{className:"flex flex-col gap-1 border-t border-border/60 pt-2",children:[n.jsx("span",{className:"text-[10px] font-medium uppercase tracking-wide text-muted-foreground",children:"The plan this covers"}),n.jsx(Pe,{plan:c,live:u})]}):void 0}):t.role==="notice"&&t.notice?n.jsx(un,{notice:t.notice}):t.role==="system"||t.role==="error"?n.jsx("div",{className:b("mx-auto max-w-[85%] text-center text-xs py-1",t.role==="error"?"text-destructive":"text-muted-foreground"),children:n.jsx(Ue,{text:t.text})}):t.role==="user"&&t.sendStatus==="failed"?n.jsxs("div",{className:"flex flex-col items-end gap-1","data-testid":"failed-message",children:[n.jsx(D,{isUser:!0,className:"border border-destructive bg-destructive/10 text-foreground",children:n.jsx(G,{text:t.text})}),n.jsxs("div",{className:"flex items-center gap-2 text-[11px] text-destructive",children:[n.jsx(_e,{className:"h-3.5 w-3.5 shrink-0","aria-hidden":"true"}),n.jsx("span",{className:"break-words",children:t.sendError||"Failed to send."}),s&&n.jsxs("button",{type:"button",onClick:()=>s(t.id,t.text,t.requestId??""),className:"inline-flex items-center gap-1 font-medium underline underline-offset-2 hover:no-underline",children:[n.jsx(ht,{className:"h-3 w-3","aria-hidden":"true"}),"Retry"]})]})]}):t.role==="user"&&t.sendStatus==="pending"?n.jsx("div",{"data-testid":"pending-message",children:n.jsx(D,{isUser:!0,className:"opacity-60 animate-pulse",children:n.jsx(G,{text:t.text})})}):t.role==="user"&&t.queued?n.jsx("div",{"data-testid":"queued-message",children:n.jsxs(D,{isUser:!0,children:[n.jsx("div",{className:"mb-0.5 text-[10px] font-medium uppercase tracking-wide text-muted-foreground",children:"Queued"}),n.jsx("span",{className:"whitespace-pre-wrap break-words text-muted-foreground",children:t.text})]})}):t.attachments&&t.attachments.length>0?n.jsxs("div",{className:b("flex flex-col gap-1",t.role==="user"?"items-end":"items-start"),children:[n.jsx(D,{isUser:t.role==="user",children:n.jsx(G,{text:t.text})}),n.jsx(jn,{attachments:t.attachments})]}):n.jsx(D,{isUser:t.role==="user",children:n.jsx(G,{text:t.text})})});function jn({attachments:e}){return n.jsx("div",{className:"flex flex-wrap gap-1.5","data-testid":"attachment-chips",children:e.map((t,r)=>n.jsxs("a",{href:t.url,download:t.filename,className:"inline-flex items-center gap-1.5 rounded-lg border border-border bg-card px-2.5 py-1 text-xs text-card-foreground hover:bg-accent hover:text-accent-foreground",children:[n.jsx(gt,{className:"h-3.5 w-3.5 shrink-0","aria-hidden":"true"}),n.jsx("span",{className:"break-all",children:t.filename})]},r))})}function vn({text:e}){return n.jsxs(D,{isUser:!1,children:[n.jsx(Ue,{text:e}),n.jsx("span",{className:"ml-0.5 inline-block h-4 w-[2px] translate-y-0.5 bg-current animate-pulse","aria-hidden":"true"})]})}function wn(){return n.jsx("div",{className:"flex justify-start",role:"status","aria-label":"Agent is working",children:n.jsx("div",{className:"flex items-center gap-2 rounded-2xl rounded-bl-sm border border-border bg-card px-3.5 py-2.5",children:n.jsx("div",{className:"flex items-center gap-1",children:[0,150,300].map(e=>n.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-muted-foreground animate-bounce",style:{animationDelay:`${e}ms`}},e))})})})}function Nn({text:e}){return n.jsx("div",{className:"flex items-center justify-center text-[11px] text-muted-foreground py-0.5",children:n.jsx("span",{className:"animate-pulse",children:e})})}function kn({text:e}){return n.jsxs("div",{className:"flex items-center justify-center gap-1.5 text-[11px] text-muted-foreground py-0.5",children:[n.jsx(J,{className:"h-3 w-3 animate-spin","aria-hidden":"true"}),n.jsx("span",{children:e})]})}function Cn({lines:e,streamingText:t,working:r,statusText:s,notice:d,opTree:u,toolSessions:c,onRetry:a,onDecision:m}){const p=l.useRef(null),N=l.useRef(null),j=l.useRef(null);l.useEffect(()=>{var w,O;const g=N.current;if(!(!g||!(g.scrollHeight-g.scrollTop-g.clientHeight<120))){if(typeof requestAnimationFrame!="function"){(O=(w=p.current)==null?void 0:w.scrollIntoView)==null||O.call(w,{block:"end"});return}return j.current!=null&&cancelAnimationFrame(j.current),j.current=requestAnimationFrame(()=>{var k,L;j.current=null,(L=(k=p.current)==null?void 0:k.scrollIntoView)==null||L.call(k,{block:"end"})}),()=>{j.current!=null&&(cancelAnimationFrame(j.current),j.current=null)}}},[e.length,t,r,s,d,u]);const{absorbedPlanByLine:S,suppressedPlanLines:_}=l.useMemo(()=>{var O;const g={},$=new Set;let w;for(const k of e){if(k.role==="plan"&&k.plan){w=k;continue}const L=(O=k.interactionRequest)==null?void 0:O.category;k.role==="interaction"&&(L==="plan_phase"||L==="plan_amendment")&&w!=null&&w.plan&&(g[k.id]=w.plan,$.add(w.id))}return{absorbedPlanByLine:g,suppressedPlanLines:$}},[e]),A=t.length>0,V=r&&!A;return n.jsx("div",{ref:N,className:"flex-1 min-h-0 overflow-y-auto px-4 py-4",children:n.jsxs("div",{className:"flex flex-col gap-2.5 max-w-3xl mx-auto",children:[e.map(g=>_.has(g.id)?null:n.jsx("div",{"data-testid":"chat-line","data-role":g.role,children:n.jsx(bn,{line:g,toolSession:g.toolSessionRef?c[g.toolSessionRef]:void 0,onRetry:a,onDecision:m,live:r,absorbedPlan:S[g.id]})},g.id)),A&&n.jsx(vn,{text:t}),V&&n.jsx(wn,{}),r&&d&&n.jsx(Nn,{text:d}),r&&u.length>0&&n.jsx(Wt,{nodes:u}),r&&s&&n.jsx(kn,{text:s}),n.jsx("div",{ref:p})]})})}function In({disabled:e,placeholder:t,onSend:r}){const[s,d]=l.useState(""),u=()=>{const a=s.trim();!a||e||(r(a),d(""))},c=a=>{a.key==="Enter"&&!a.shiftKey&&(a.preventDefault(),u())};return n.jsxs("div",{className:"flex items-end gap-2 px-4 py-3 border-t border-border bg-card",children:[n.jsx("textarea",{rows:1,value:s,disabled:e,placeholder:t,onChange:a=>d(a.target.value),onKeyDown:c,className:b("flex-1 resize-none max-h-40 rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm","placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring","disabled:cursor-not-allowed disabled:opacity-50")}),n.jsx(X,{size:"icon",className:"h-9 w-9 shrink-0",disabled:e||!s.trim(),onClick:u,title:"Send",children:n.jsx(jt,{className:"h-4 w-4"})})]})}function P(e,t){return`/sessions/api/${encodeURIComponent(e)}/${encodeURIComponent(t)}`}async function Q(e,t){if((e.headers.get("content-type")??"").includes("application/json"))try{const r=await e.json(),s=r==null?void 0:r.error;if(typeof s=="string"&&s.trim()!=="")return s}catch{}switch(e.status){case 401:return"You are no longer signed in. Reload the page to continue.";case 403:return"You do not have access to this conversation.";case 503:return"That could not be checked right now. Try again in a moment.";default:return t}}async function Un(e,t,r){const s=await fetch(`/sessions/api/${encodeURIComponent(e)}/${encodeURIComponent(t)}/message`,{method:"POST",credentials:"same-origin",headers:{"Content-Type":"application/json"},body:JSON.stringify({text:r})});if(!s.ok)throw new Error(`send session message: request failed (${s.status})`)}function Rn(e,t,r){const s=l.useCallback(async(d,u,c)=>{try{const a=await fetch(`${P(e,t)}/decision`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({category:u,requestRef:d,actionId:c})});if(!a.ok){console.error("interaction decision: request failed",{ns:e,name:t,status:a.status});const m=await Q(a,`Failed to submit decision (${a.status}).`);r(m)}}catch(a){console.error("interaction decision: request errored",{ns:e,name:t,err:a}),r("Network error while trying to submit decision.")}},[e,t,r]);return l.useCallback((d,u,c)=>{s(d,u,c)},[s])}function Sn(e){if(e.class==="already_resolved"){let r="someone else";e.originalDecider&&(r=e.originalDecider.email||e.originalDecider.externalId||r);let s=`This request was already resolved by ${r}`;return e.originalOutcome&&(s+=` (${e.originalOutcome})`),s+"."}return((e.reason||"").trim()||"your click could not be applied")+"."}function Tn(e){switch(e.reason){case"succeeded":return"Conversation ended.";case"failed":return`Conversation ended: ${e.failureMessage||e.failureReason||"the agent failed"}.`;case"idle_timeout":return"Conversation ended after being idle too long.";case"server_shutdown":return"Conversation ended: the server is restarting.";default:return"Conversation ended."}}function Ne(e,t){return e.map(r=>r.kind==="plan"?{id:`plan:${r.plan.planName}`,role:"plan",text:"",plan:r.plan}:{id:t(),role:r.role,text:r.text})}const ke="Earlier messages could not be loaded. The live conversation still works.",_n="Starting…",Ce="Working…",Ie={text:"",ephemeral:!1};function Re(e){return e.ephemeral&&e.text!==Ce?{text:Ce,ephemeral:!0}:e}function $n(e,t){return`/artifact-download?${new URLSearchParams({artifactId:t.artifactId,sessionRef:`${e.namespace}/${e.name}`,fn:t.filename||t.artifactId}).toString()}`}const qn=new Set(["startup","scheduling"]);function Dn({ns:e,name:t,readOnly:r,onUserSend:s,onSessionEnded:d}){const[u,c]=l.useState([]),[a,m]=l.useState(!1),[p,N]=l.useState([]),{startup:j}=Oe(),S=j===null?p:p.filter(o=>!qn.has(o.kind)),_=r||a,A=l.useCallback(()=>{m(!0),d==null||d()},[d]),V=l.useRef(`${e}/${t}`),g=l.useCallback(o=>o===V.current,[]),[$,w]=l.useState(!1),[O,k]=l.useState(Ie),[L,Me]=l.useState(""),[Fe,ee]=l.useState(null),[Be,te]=l.useState([]),[He,Je]=l.useState({}),ne=l.useRef(""),U=l.useCallback(o=>{const f=o(ne.current);ne.current=f,Me(f)},[]),[Ve,Ye]=l.useState(null),re=l.useRef(null),q=l.useCallback(o=>{re.current=o,Ye(o)},[]),Ke=l.useRef(0),I=l.useCallback(()=>`l${Ke.current++}`,[]),C=l.useCallback((o,f,h)=>{c(i=>[...i,{id:I(),role:o,text:f,queued:h==null?void 0:h.queued,attachments:h==null?void 0:h.attachments}])},[I]),he=l.useCallback(o=>{o.lead&&c(f=>[...f,{id:I(),role:"notice",text:"",notice:o}])},[I]),Y=l.useRef(!1),E=l.useRef(!1),K=l.useCallback(()=>{E.current=!0,w(!0),ee(null),k({text:_n,ephemeral:!0}),U(()=>"")},[U]),R=l.useCallback(()=>{E.current=!1,w(!1),ee(null),te([]),k(Ie),U(()=>"")},[U]),se=l.useCallback(()=>{const o=ne.current;o&&C("agent",o)},[C]),ae=l.useCallback(()=>{c(o=>o.map(f=>f.queued?{...f,queued:!1}:f))},[]),ge=l.useCallback(async()=>{const o=P(e,t),f=`${e}/${t}`;try{const[h,i]=await Promise.all([fetch(`${o}/messages`),fetch(`${o}/detail`)]);if(!h.ok)console.error("chat: resync transcript failed",{ns:e,name:t,status:h.status});else{const y=await h.json();if(!g(f))return;c(Ne(y.timeline??[],I))}if(!i.ok){console.error("chat: resync session detail failed",{ns:e,name:t,status:i.status});return}const x=await i.json();if(!g(f))return;x.phase!=="Running"&&R(),N(x.notices??[])}catch(h){console.error("chat: resync after reconnect errored",{ns:e,name:t,err:h})}},[e,t,I,R,g]);l.useEffect(()=>{let o=!1;return V.current=`${e}/${t}`,c([]),m(!1),R(),q(null),Y.current=!1,(async()=>{try{(async()=>{try{const i=await fetch(`${P(e,t)}/detail`);if(o||!i.ok)return;const x=await i.json();o||N(x.notices??[])}catch(i){console.error("chat: load session detail errored",{ns:e,name:t,err:i})}})();const f=await fetch(`${P(e,t)}/messages`);if(o)return;if(f.ok){const i=await f.json();if(o)return;c(Ne(i.timeline??[],I));return}console.error("chat: load transcript failed",{ns:e,name:t,status:f.status});const h=f.status===501?"History replay is unavailable here; resuming live.":await Q(f,ke);if(o)return;c([{id:I(),role:f.status===501?"system":"error",text:h}])}catch(f){if(console.error("chat: load transcript errored",{ns:e,name:t,err:f}),o)return;c([{id:I(),role:"error",text:ke}])}})(),()=>{o=!0}},[e,t,I,R,q]);const ze=l.useCallback(o=>{var f,h;switch(o.type){case"user_message":{const i=o.payload,x=i.text;U(()=>"");const y=(i.attachments??[]).filter(v=>v.artifactId).map(v=>({filename:v.filename||v.artifactId,mime:v.mime,url:$n(i.session,v)}));C("agent",x,y.length?{attachments:y}:void 0);break}case"user_echo":{const i=o.payload;c(x=>i.requestID&&x.some(y=>y.requestId===i.requestID)?x:[...x,{id:I(),role:"user",text:i.text}]);break}case"notification":{if(!E.current)break;const i=o.payload;w(!0),k({text:i.text,ephemeral:i.ephemeral===!0});break}case"plan_update":{const i=o.payload.payload;E.current&&w(!0);const x=`plan:${i.planName}`;c(y=>{const v=y.findIndex(T=>T.role==="plan"&&T.id===x);if(v>=0){const T=y.slice();return T[v]={...y[v],plan:i},T}return[...y,{id:x,role:"plan",text:"",plan:i}]});break}case"stream_delta":{if(!E.current)break;const i=o.payload.payload;(i==null?void 0:i.eventType)==="text_delta"&&i.text&&(w(!0),k(Re),U(x=>x+i.text));break}case"turn_progress":if(!E.current)break;w(!0),k(Re),ee(o.payload.payload);break;case"operation_activity":{if(!E.current){te([]);break}const i=o.payload.payload;te(i.cleared?[]:i.operations??[]);break}case"turn_activity":{o.payload.active?(E.current=!0,w(!0)):(se(),R(),ae());break}case"interrupt_applied":{const i=o.payload;if(i.requestID!==re.current)break;q(null),i.outcome==="interrupted"?(C("system","Interrupting — sending your message(s) now."),ae()):C("system","Couldn't interrupt — "+(i.reason||"the runner declined."));break}case"send_error":R(),C("error",o.payload.err||"The agent failed to process a message.");break;case"session_ended":{A(),se(),R(),C("system",Tn(o.payload));break}case"live_view_offer":{const i=o.payload.url;i&&c(x=>[...x,{id:I(),role:"system",text:"",liveViewUrl:i}]);break}case"tool_session_event":case"tool_session_delta":{Je(y=>Et(y,o));const i=(h=(f=o.payload)==null?void 0:f.payload)==null?void 0:h.toolCallRef;if(!i)break;const x=`toolsession:${i}`;c(y=>y.some(v=>v.id===x)?y:[...y,{id:x,role:"toolSession",text:"",toolSessionRef:i}]);break}case"interaction_request":{const i=o.payload.payload,x=`interaction:${i.requestRef}`;c(y=>{const v=y.findIndex(T=>T.role==="interaction"&&T.id===x);if(v>=0){const T=y.slice();return T[v]={...y[v],interactionRequest:i},T}return[...y,{id:x,role:"interaction",text:"",interactionRequest:i}]});break}case"interaction_applied":{const i=o.payload.payload,x=`interaction:${i.requestRef}`;c(y=>y.map(v=>v.id===x?{...v,interactionApplied:i}:v));break}case"interaction_decision_rejected":{const i=o.payload.payload;C(i.class==="already_resolved"?"system":"error",Sn(i));break}}},[C,I,U,q,A,R,se,ae]);Ht(ze);const B=Jt(),z=l.useRef(!1);l.useEffect(()=>{if(B==="connected"){z.current=!1,Y.current&&(Y.current=!1,ge());return}if(B==="connecting"){z.current=!1;return}Y.current=!0,B==="offline"&&!_&&!z.current&&(z.current=!0,R(),C("error","Connection lost — reload the page to reconnect."))},[B,_,C,ge,R]);const H=l.useCallback((o,f,h)=>{c(i=>i.map(x=>x.id===o?{...x,sendStatus:f,sendError:h}:x))},[]),W=l.useCallback(async(o,f,h)=>{const i=`${e}/${t}`;H(o,"pending");try{const x=await fetch(`${P(e,t)}/message`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({text:f,requestId:h})});if(!g(i))return;if(!x.ok){console.error("chat: send failed",{ns:e,name:t,status:x.status});const v=await Q(x,`Failed to send (${x.status}).`);if(!g(i))return;H(o,"failed",v),R();return}const y=await x.json();if(!g(i))return;H(o,"sent"),y.notice&&he(y.notice),y.ended&&(A(),R())}catch(x){if(console.error("chat: send errored",{ns:e,name:t,err:x}),!g(i))return;H(o,"failed","Network error while sending your message."),R()}},[e,t,H,he,A,R,g]),We=l.useCallback(o=>{s==null||s();const f=I(),h=crypto.randomUUID();c(i=>[...i,{id:f,role:"user",text:o,queued:$,sendStatus:"pending",requestId:h}]),K(),W(f,o,h)},[$,I,K,s,W]),Ge=l.useCallback((o,f,h)=>{K(),W(o,f,h)},[K,W]),Qe=l.useCallback(async()=>{if(re.current)return;const o=`${e}/${t}`,f=crypto.randomUUID();q(f);try{const h=await fetch(`${P(e,t)}/interrupt`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({requestId:f})});if(!h.ok){console.error("chat: interrupt failed",{ns:e,name:t,status:h.status});const i=await Q(h,`Failed to interrupt (${h.status}).`);if(!g(o))return;C("error",i),q(null)}}catch(h){if(console.error("chat: interrupt errored",{ns:e,name:t,err:h}),!g(o))return;C("error","Network error while trying to interrupt."),q(null)}},[e,t,C,q,g]),Xe=l.useCallback(o=>{g(`${e}/${t}`)&&C("error",o)},[e,t,g,C]),Ze=Rn(e,t,Xe),et=$?It(Fe):null,tt=_?"This conversation has ended.":"Message the agent…";return n.jsx(kt,{delayDuration:200,children:n.jsxs("div",{className:"flex min-h-0 flex-1 flex-col bg-background text-foreground","data-testid":"chat-view",children:[n.jsx("div",{className:"flex items-center justify-end px-3 py-1 border-b border-border bg-card/40",children:n.jsx(Yt,{state:B})}),n.jsx(Cn,{lines:u,streamingText:L,working:$,statusText:et,notice:O.text,opTree:Be,toolSessions:He,onRetry:Ge,onDecision:Ze}),$&&u.some(o=>o.queued)&&n.jsx("div",{className:"flex justify-center px-4 pt-2 bg-card",children:n.jsx(X,{variant:"secondary",size:"sm",disabled:Ve!==null,onClick:Qe,children:"Interrupt & Send Now"})}),S.length>0&&n.jsx("div",{className:"mx-4 mb-2 flex flex-col gap-1.5",children:S.map((o,f)=>n.jsxs("div",{"data-testid":`session-notice-${o.kind}`,className:b("rounded-md border px-3 py-2 text-xs leading-snug",o.tone==="degraded"?"border-warning/30 bg-warning/10 text-warning":"border-border/60 bg-muted/40 text-muted-foreground"),children:[n.jsx("div",{children:o.lead}),o.nextStep&&n.jsx("div",{className:"mt-0.5 font-medium",children:o.nextStep}),o.body&&n.jsx("div",{className:"mt-1 break-all font-mono text-[10px] opacity-70",children:o.body})]},`${o.kind}:${f}`))}),n.jsx(In,{disabled:_,placeholder:tt,onSend:We})]})})}function Pn(){const{startup:e}=Oe();return e===null?null:n.jsxs("div",{"data-testid":"session-shell-startup",role:"status",className:"flex items-center gap-2 border-b border-border bg-card/60 px-4 py-2 text-sm text-muted-foreground",children:[n.jsx(J,{className:"h-4 w-4 shrink-0 animate-spin","aria-hidden":"true"}),n.jsxs("span",{children:[e.short!==null?n.jsxs(n.Fragment,{children:[n.jsx("span",{className:"hidden sm:inline",children:e.text}),n.jsx("span",{className:"sm:hidden",children:e.short})]}):e.text,e.stillTrying&&n.jsx("span",{"data-testid":"session-shell-startup-still-trying",children:" — still trying"})]})]})}export{Dn as C,on as I,Ln as S,Pn as a,Rn as b,Ht as c,Sn as i,Un as s,Oe as u}; +import{ad as nt,r as l,j as n,x as rt,y as J,z as st,ae as ue,K as at,af as fe,ag as xe,ah as Se,ai as ot,aj as it,ak as lt,al as ct,am as Te,an as ce,ao as _e,c as dt,ap as ut,C as ft,O as xt,T as pt,aa as mt,aq as ht,E as gt,ar as yt,as as bt,at as jt}from"./vendor.C5MRNvUt.js";import{I as vt,J as wt,K as Nt,c as b,B as X,H as kt}from"./mount.D4ypHaeQ.js";import{M as Ct}from"./markdown.DHnzytkE.js";function ye(e){return e.toFixed(1).replace(/\.0$/,"")}function be(e){return(!Number.isFinite(e)||e<0)&&(e=0),e<1e3?String(Math.round(e)):e<1e6?`${ye(e/1e3)}K`:`${ye(e/1e6)}M`}function pe(e){if((!Number.isFinite(e)||e<0)&&(e=0),e=Math.floor(e),e<60)return`${e}s`;const t=Math.floor(e/60),r=e%60;return r===0?`${t}m`:`${t}m${r}s`}function Rt(e){return e?`working · ${pe(e.elapsedSeconds)} · ${be(e.inputTokens)} in · ${be(e.outputTokens)} out`:"working"}const je=500,Z=new Uint8Array(0);function It(e){return{ref:e,outerTool:"",reason:"",lines:[],elided:0,pending:{stdout:Z,stderr:Z},done:!1,ok:!1}}function St(e){try{const t=atob(e),r=new Uint8Array(t.length);for(let s=0;s{const r={text:t.content};t.fg&&(r.fg=`rgb(${t.fg})`),t.bg&&(r.bg=`rgb(${t.bg})`);const s=t.decoration??void 0,d=Array.isArray(t.decorations)?t.decorations:s?[s]:[];return d.includes("bold")&&(r.bold=!0),d.includes("italic")&&(r.italic=!0),d.includes("underline")&&(r.underline=!0),d.includes("dim")&&(r.dim=!0),r})}function F(e,t){if(e.lines.push(t),e.lines.length>je){const r=e.lines.length-je;e.lines.splice(0,r),e.elided+=r}}function _t(e,t,r){let s=Tt(e.pending[t],r),d=0;for(let u=0;ud&&s[c-1]===13&&c--,F(e,{kind:t,spans:M($e.decode(s.subarray(d,c)))}),d=u+1}e.pending[t]=d===0?s:s.subarray(d)}function qe(e){for(const t of["stdout","stderr"]){const r=e.pending[t];r.length!==0&&(F(e,{kind:t,spans:M($e.decode(r))}),e.pending[t]=Z)}}function ve(e,t){const r=e??It(t);return{...r,lines:r.lines.slice(),pending:{...r.pending}}}function we(e){const t=e.payload;return t==null?void 0:t.payload}function $t(e,t){switch(t.outerTool&&(e.outerTool=t.outerTool),t.reason&&(e.reason=t.reason),t.eventType){case"result":qe(e),e.done=!0,e.ok=t.ok??!1,t.durationMs!==void 0&&(e.durationMs=t.durationMs),t.costUsd!==void 0&&(e.costUsd=t.costUsd),t.summary&&F(e,{kind:"event",spans:M(t.summary)});return;case"tool_use_start":F(e,{kind:"event",spans:M(t.summary??""),toolName:t.toolName});return;case"tool_use_stop":F(e,{kind:"event",spans:M(" "+[t.ok?"✓":"✗",t.summary].filter(Boolean).join(" "))});return;default:t.text&&F(e,{kind:"event",spans:M(t.text)})}}function qt(e,t){const r=t.stream==="stderr"?"stderr":"stdout";t.data&&_t(e,r,St(t.data)),t.terminal&&(qe(e),e.done=!0,e.ok=(t.exitCode??0)===0&&t.exitReason!=="failed",t.exitCode!==void 0&&(e.exitCode=t.exitCode),t.exitReason&&(e.exitReason=t.exitReason))}function Et(e,t){if(t.type==="tool_session_event"){const r=we(t);if(!(r!=null&&r.toolCallRef))return e;const s=ve(e[r.toolCallRef],r.toolCallRef);return $t(s,r),{...e,[r.toolCallRef]:s}}if(t.type==="tool_session_delta"){const r=we(t);if(!(r!=null&&r.toolCallRef))return e;const s=ve(e[r.toolCallRef],r.toolCallRef);return qt(s,r),{...e,[r.toolCallRef]:s}}return e}function At(e){try{const t=JSON.parse(e);return!t||typeof t.type!="string"?null:t}catch{return null}}function Lt(e,t,r){return`${e.protocol==="https:"?"wss:":"ws:"}//${e.host}/sessions/api/${encodeURIComponent(t)}/${encodeURIComponent(r)}/ws`}const oe=3;function Ot(e,t,r){const[s,d]=l.useState("connecting"),u=l.useRef(r);return u.current=r,l.useEffect(()=>{if(!e||!t){console.error("chat: no live socket opened; this view was given no session to address",{ns:e,name:t}),d("offline");return}let c=null,a,m=!1,p=0;const N=()=>{m||(p+=1,d(p>=oe?"offline":"reconnecting"),a=window.setTimeout(j,2e3))},j=()=>{if(!m){d(p===0?"connecting":p>=oe?"offline":"reconnecting");try{c=new WebSocket(Lt(window.location,e,t))}catch{N();return}c.onopen=()=>{p=0,d("connected")},c.onmessage=S=>{const _=At(S.data);_&&u.current(_)},c.onerror=()=>{m||d(p>=oe?"offline":"reconnecting")},c.onclose=N}};return j(),()=>{m=!0,a&&window.clearTimeout(a),c&&c.close()}},[e,t]),{state:s}}const Ee={turnActive:!1,awaitingReply:!1,pausedIdle:!1,lastAgentReply:null,replySeq:0,composingUpdate:!1,activity:null,plan:null,notice:null,ended:!1,startup:null,pendingInteractions:[]};function Ut(e,t){return e===t?!0:e===null||t===null?!1:e.text===t.text&&e.seq===t.seq}function ie(e,t){return e===t?!0:e===null||t===null?!1:JSON.stringify(e)===JSON.stringify(t)}function Dt(e,t){return e===t?!0:e.length!==t.length?!1:e.every((r,s)=>r===t[s])}function Pt(e,t){return e.turnActive===t.turnActive&&e.awaitingReply===t.awaitingReply&&e.pausedIdle===t.pausedIdle&&Ut(e.lastAgentReply,t.lastAgentReply)&&e.replySeq===t.replySeq&&e.composingUpdate===t.composingUpdate&&ie(e.activity,t.activity)&&ie(e.plan,t.plan)&&e.notice===t.notice&&e.ended===t.ended&&ie(e.startup,t.startup)&&Dt(e.pendingInteractions,t.pendingInteractions)}const Mt={type:"__reconnect"};function Ft(e,t){const r=Bt(e,t);return r===e||Pt(e,r)?e:r}function Bt(e,t){var r,s,d,u,c;switch(t.type){case"turn_activity":{const a=t.payload;return a!=null&&a.active?{...e,turnActive:!0,awaitingReply:!1,pausedIdle:!1,composingUpdate:!1,lastAgentReply:null,notice:null}:{...e,turnActive:!1,awaitingReply:(a==null?void 0:a.cause)==="awaiting_reply",pausedIdle:(a==null?void 0:a.cause)==="idle",composingUpdate:!1}}case"user_message":{const a=t.payload,m=e.replySeq+1;return{...e,lastAgentReply:{text:(a==null?void 0:a.text)??"",seq:m},replySeq:m}}case"user_echo":return{...e,lastAgentReply:null,awaitingReply:!1};case"stream_delta":{const a=(r=t.payload)==null?void 0:r.payload;return(a==null?void 0:a.eventType)==="tool_use_start"&&a.toolName==="update_view"?{...e,composingUpdate:!0}:(a==null?void 0:a.eventType)==="tool_use_stop"||(a==null?void 0:a.eventType)==="stop"?{...e,composingUpdate:!1}:e}case"operation_activity":{const a=(s=t.payload)==null?void 0:s.payload;return{...e,activity:a!=null&&a.cleared?null:a??null}}case"plan_update":{const a=(d=t.payload)==null?void 0:d.payload;return{...e,plan:a??null}}case"notification":{const a=t.payload;return{...e,notice:(a==null?void 0:a.text)??null}}case"interaction_request":{const a=(u=t.payload)==null?void 0:u.payload;if(!(a!=null&&a.requestRef))return e;const m=e.pendingInteractions.findIndex(N=>N.requestRef===a.requestRef),p=m>=0?e.pendingInteractions.map((N,j)=>j===m?a:N):[...e.pendingInteractions,a];return{...e,pendingInteractions:p}}case"interaction_applied":{const a=(c=t.payload)==null?void 0:c.payload;return a!=null&&a.requestRef?{...e,pendingInteractions:e.pendingInteractions.filter(m=>m.requestRef!==a.requestRef)}:e}case"__reconnect":return{...e,turnActive:!1,pausedIdle:!1,composingUpdate:!1,activity:null,startup:null,pendingInteractions:[]};case"session_startup":{const a=t.payload;return!a||a.started||!a.text?{...e,startup:null}:{...e,startup:{text:a.text??"",short:a.short??null,stillTrying:!!a.stillTrying}}}case"session_ended":return{...e,ended:!0,turnActive:!1,awaitingReply:!1,pausedIdle:!1,composingUpdate:!1,startup:null,pendingInteractions:[]};default:return e}}const Ae=l.createContext(Ee);function Le(){return l.useContext(Ae)}const me=l.createContext({state:"offline",subscribe:()=>(console.error("chat: useSessionFrames outside a SessionSocketProvider; no frames will arrive"),()=>{})});function Un({ns:e,name:t,children:r}){const s=l.useRef(null);s.current===null&&(s.current=new Set);const[d,u]=l.useReducer(Ft,Ee),c=l.useCallback(j=>{u(j);for(const S of s.current)S(j)},[]),{state:a}=Ot(e,t,c),m=l.useCallback(j=>(s.current.add(j),()=>{s.current.delete(j)}),[]),p=l.useRef(a);l.useEffect(()=>{const j=p.current;p.current=a,a==="connected"&&(j==="reconnecting"||j==="offline")&&u(Mt)},[a]);const N=l.useMemo(()=>({state:a,subscribe:m}),[a,m]);return n.jsx(me.Provider,{value:N,children:n.jsx(Ae.Provider,{value:d,children:r})})}function Ht(e){const{subscribe:t}=l.useContext(me),r=l.useRef(e);r.current=e,l.useEffect(()=>t(s=>r.current(s)),[t])}function Jt(){return l.useContext(me).state}const Vt={connected:{Icon:st,color:"text-success",spin:!1,tip:"Live — connected"},connecting:{Icon:J,color:"text-warning",spin:!0,tip:"Connecting…"},reconnecting:{Icon:J,color:"text-warning",spin:!0,tip:"Reconnecting…"},offline:{Icon:rt,color:"text-destructive",spin:!1,tip:"Offline — retrying"}};function Yt({state:e}){const t=Vt[e],{Icon:r}=t;return n.jsxs(vt,{children:[n.jsx(wt,{asChild:!0,children:n.jsx("div",{className:`flex h-7 w-7 items-center justify-center rounded-md cursor-default ${t.color}`,children:n.jsx(r,{className:`h-[18px] w-[18px] ${t.spin?"animate-spin":""}`,"aria-hidden":"true"})})}),n.jsx(Nt,{children:t.tip})]})}function Kt({call:e}){return n.jsxs("div",{className:b("flex items-center gap-1.5 pl-4 text-[11px]",e.active?"text-muted-foreground animate-pulse":"text-muted-foreground/60"),children:[n.jsx("span",{className:"truncate",children:e.reason}),n.jsxs("span",{className:"shrink-0",children:["· ",pe(e.elapsedSeconds)]})]})}function zt({op:e}){return n.jsxs("div",{className:"flex flex-col gap-0.5",children:[n.jsxs("div",{className:b("flex items-center gap-1.5 text-[11px]",e.active?"text-muted-foreground animate-pulse":"text-muted-foreground/60"),children:[n.jsx("span",{className:"truncate",children:e.description}),n.jsxs("span",{className:"shrink-0",children:["· ",pe(e.elapsedSeconds)]})]}),(e.calls??[]).map((t,r)=>n.jsx(Kt,{call:t},r))]})}function Wt({nodes:e}){return e.length===0?null:n.jsx("div",{className:"flex flex-col gap-1 items-start","data-testid":"operation-tree",children:e.map(t=>n.jsx(zt,{op:t},t.id))})}function Gt({fields:e}){return!e||e.length===0?null:n.jsx("div",{className:"flex flex-col gap-0.5",children:e.map((t,r)=>n.jsxs("div",{className:"text-xs leading-snug",children:[n.jsxs("span",{className:"font-medium text-card-foreground",children:[t.label,":"]})," ",n.jsx("span",{className:"text-muted-foreground",children:t.value})]},`${t.label}:${r}`))})}function Oe({excerpt:e}){return e?n.jsx("pre",{className:"max-h-48 overflow-auto whitespace-pre-wrap break-words rounded-md border border-border bg-background px-2 py-1.5 text-[11px] leading-snug text-card-foreground",children:n.jsxs("code",{children:[e.label?`${e.label}: +`:"",e.content]})}):null}function Qt(e,t){return`/artifact-download?${new URLSearchParams({artifactId:t.artifactId??"",sessionRef:`${e.namespace}/${e.name}`,fn:t.filename||t.renderName}).toString()}`}function Xt(e){switch(e){case"denied":return n.jsx(Se,{className:"h-3.5 w-3.5 shrink-0 text-destructive","aria-hidden":"true"});case"expired":return n.jsx(xe,{className:"h-3.5 w-3.5 shrink-0 text-muted-foreground","aria-hidden":"true"});default:return n.jsx(fe,{className:"h-3.5 w-3.5 shrink-0 text-success","aria-hidden":"true"})}}const Zt={agent:"Running as the agent",userPassthrough:"Running as you",cancel:"Cancelled"},en={approved:"Approved",denied:"Denied",expired:"Expired",resolved:"Resolved"};function tn(e){if(e.category==="identity_choice"){const r=Zt[e.outcomeText??""];if(r)return r}const t=(e.outcomeText??"").trim();return t!==""?t:en[e.outcome]??e.outcome}function nn(e){return e==="primary"?"default":e==="danger"?"destructive":"secondary"}function rn({action:e,pending:t,onClick:r}){const s=nn(e.style);return e.kind==="link"||e.kind==="link_mint"?e.url?n.jsx(X,{asChild:!0,variant:s,size:"sm",children:n.jsxs("a",{href:e.url,target:"_blank",rel:"noopener noreferrer",children:[e.label,n.jsx(Te,{className:"h-3.5 w-3.5","aria-hidden":"true"})]})}):null:n.jsx(X,{variant:s,size:"sm",disabled:t,onClick:r,children:e.label})}const sn={readonly:{Icon:it,textClass:"text-success"},readwrite:{Icon:ot,textClass:"text-primary"},external:{Icon:ue,textClass:"text-warning"}},an={repository:ct,github:lt};function de({items:e,depth:t=0}){let r=0;return n.jsx("div",{className:b("flex flex-col",t===0?"gap-1.5":t===1?"gap-1":"gap-0.5 pl-2"),children:e.map((s,d)=>{var m;const u=t===0&&!!((m=s.items)!=null&&m.length);u&&(r+=1);const c=s.tone?sn[s.tone]:void 0,a=s.icon?an[s.icon]:void 0;return n.jsxs("div",{className:b(u&&"rounded-md border border-border/60 bg-muted/30 px-3 py-2.5"),children:[n.jsxs("div",{className:"flex flex-wrap items-baseline gap-x-1.5",children:[u&&n.jsx("span",{className:"rounded bg-state/15 px-1 py-px font-mono text-[10px] font-medium text-state",children:r}),c&&n.jsx(c.Icon,{"data-testid":`tier-${s.tone}`,className:b("h-3 w-3 shrink-0",c.textClass),"aria-hidden":"true"}),a&&n.jsx(a,{"data-testid":`resource-icon-${s.icon}`,className:"h-3 w-3 shrink-0 text-muted-foreground","aria-hidden":"true"}),n.jsx("span",{title:s.hint||void 0,className:b(u&&"font-medium",s.hint&&"cursor-help underline decoration-dotted decoration-muted-foreground/60 underline-offset-2",s.tone==="muted"?"text-muted-foreground":c?b("font-medium",c.textClass):"text-card-foreground"),children:s.text}),s.detail&&s.href?n.jsx("a",{href:s.href,target:"_blank",rel:"noopener noreferrer",className:"break-all font-mono text-[11px] text-link underline decoration-link/40 underline-offset-2 hover:decoration-link",children:s.href}):s.detail&&n.jsx("span",{className:b("break-all",s.tone==="external"?"rounded bg-warning/15 px-1.5 py-px text-[10px] font-semibold uppercase tracking-wide text-warning ring-1 ring-inset ring-warning/30":"font-mono text-[11px] text-muted-foreground"),children:s.detail})]}),s.items&&s.items.length>0&&n.jsx("div",{className:b(t===0&&"mt-2"),children:n.jsx(de,{items:s.items,depth:t+1})})]},`${s.text}:${d}`)})})}function on(e){const t=r=>(r??[]).some(s=>s.tone==="external"||t(s.items));return(e??[]).some(r=>t(r.items))}function ln(e){const{request:t,applied:r,onDecision:s,footer:d}=e,u=on(t.fields),[c,a]=l.useState(!1),m=!!r;return n.jsxs("div",{className:b("mx-auto flex w-full max-w-[85%] flex-col gap-2 rounded-lg border bg-card/60 px-3 py-2.5",m?"border-border":u?"border-l-2 border-border border-l-warning":"border-l-2 border-border border-l-primary"),"data-testid":"interaction-card","data-request-ref":t.requestRef,"data-external":u?"true":void 0,children:[n.jsxs("div",{className:"flex items-start gap-1.5",children:[n.jsx("span",{className:"mt-0.5",children:m?Xt(r.outcome):u?n.jsx(ue,{className:"h-3.5 w-3.5 shrink-0 text-warning","aria-hidden":"true"}):n.jsx(at,{className:"h-3.5 w-3.5 shrink-0 text-primary","aria-hidden":"true"})}),n.jsx("span",{className:b("break-words text-sm font-semibold leading-snug",m?"text-muted-foreground":"text-card-foreground"),children:t.lead})]}),t.body&&n.jsx("div",{className:"text-xs leading-snug text-muted-foreground",children:t.body}),t.screenshot&&n.jsx("img",{src:Qt(t.agentSessionRef,t.screenshot),alt:t.screenshot.altText||"current page screenshot",className:"max-h-64 w-full rounded-md border border-border/60 object-contain object-top"}),d,t.fields&&t.fields.length>0&&n.jsx("div",{className:"flex flex-col gap-2.5",children:t.fields.map((p,N)=>{if(p.items&&p.items.length>0){const S="text-[10px] font-medium uppercase tracking-wide text-muted-foreground";return m?n.jsxs("details",{className:"text-xs leading-snug",children:[n.jsxs("summary",{className:b(S,"cursor-pointer hover:text-foreground"),children:[p.label," ",n.jsxs("span",{className:"font-normal normal-case tracking-normal text-muted-foreground/70",children:["(",p.items.length,")"]})]}),n.jsx("div",{className:"mt-2",children:n.jsx(de,{items:p.items})})]},`${p.label}:${N}`):n.jsxs("div",{className:"flex flex-col gap-1 text-xs leading-snug",children:[n.jsx("div",{className:S,children:p.label}),n.jsx(de,{items:p.items})]},`${p.label}:${N}`)}const j=p.value.includes(` +`);return n.jsxs("div",{className:"flex flex-col gap-0.5 text-xs leading-snug",children:[n.jsx("div",{className:"text-[10px] font-medium uppercase tracking-wide text-muted-foreground",children:p.label}),n.jsx("span",{className:b("text-card-foreground",j&&"whitespace-pre-wrap break-words"),children:p.value})]},`${p.label}:${N}`)})}),n.jsx(Oe,{excerpt:t.excerpt}),m?n.jsx("div",{className:b("text-xs",r.outcome==="denied"?"text-destructive":"text-muted-foreground"),children:tn(r)}):t.actions&&t.actions.length>0&&n.jsx("div",{className:"mt-0.5 flex flex-wrap justify-end gap-1.5 border-t border-border/60 pt-2",children:t.actions.map(p=>n.jsx(rn,{action:p,pending:c,onClick:()=>{a(!0),s(t.requestRef,t.category,p.id)}},p.id))})]})}const cn={critical:{Icon:ue,color:"text-destructive"},privacy:{Icon:dt,color:"text-warning"},degraded:{Icon:_e,color:"text-warning"},waiting:{Icon:xe,color:"text-muted-foreground"},routine:{Icon:ce,color:"text-muted-foreground"},housekeeping:{Icon:ce,color:"text-muted-foreground"},resolved:{Icon:fe,color:"text-success"}},dn={Icon:ce,color:"text-muted-foreground"},un={money:ut,clock:xe};function fn({notice:e}){const t=cn[e.tone??""]??dn,r=un[e.glyph??""]??t.Icon;return n.jsxs("div",{className:"mx-auto flex w-full max-w-[85%] flex-col gap-2 rounded-lg border border-border bg-card/60 px-3 py-2.5","data-testid":"notice-card","data-tone":e.tone||"",children:[n.jsxs("div",{className:b("flex items-center gap-1.5 text-xs font-medium",t.color),children:[n.jsx(r,{className:"h-3.5 w-3.5 shrink-0","aria-hidden":"true"}),n.jsx("span",{className:"break-words text-card-foreground",children:e.lead})]}),e.body&&n.jsx("div",{className:"text-xs text-muted-foreground",children:e.body}),n.jsx(Gt,{fields:e.fields}),n.jsx(Oe,{excerpt:e.excerpt}),e.nextStep&&n.jsx("div",{className:"text-xs font-medium text-card-foreground",children:e.nextStep})]})}function xn({spans:e}){return n.jsx(n.Fragment,{children:e.map((t,r)=>{const s={};return t.fg&&(s.color=t.fg),t.bg&&(s.backgroundColor=t.bg),t.dim&&(s.opacity=.6),n.jsx("span",{style:s,className:b(t.bold&&"font-semibold",t.italic&&"italic",t.underline&&"underline"),children:t.text},r)})})}function pn({line:e}){return n.jsxs("div",{"data-stream":e.kind,className:b("whitespace-pre-wrap break-all font-mono text-[11px] leading-[1.45]",e.kind==="stderr"&&"text-red-300/90",e.kind==="event"&&"text-foreground/80"),children:[e.toolName&&n.jsxs("span",{className:"mr-1.5 inline-flex items-center gap-1 text-[10px] text-muted-foreground",children:[n.jsx(mt,{className:"h-2.5 w-2.5"}),e.toolName]}),n.jsx(xn,{spans:e.spans})]})}function mn(e){const t=e/1e3;if(t<60)return`${t.toFixed(1)}s`;const r=Math.floor(t/60);return`${r}m${Math.round(t-r*60)}s`}function hn(e){const t=[e.ok?"done":"failed"];return!e.ok&&e.exitCode!==void 0&&t.push(`exit ${e.exitCode}`),!e.ok&&e.exitReason&&e.exitReason!=="failed"&&t.push(e.exitReason),e.durationMs!==void 0&&t.push(mn(e.durationMs)),e.costUsd!==void 0&&t.push(`$${e.costUsd.toFixed(2)}`),t.join(" · ")}function gn({state:e}){const[t,r]=l.useState(void 0),s=t??!(e.done&&e.ok),d=[e.outerTool||"tool",e.reason].filter(Boolean).join(" · ");return n.jsxs("div",{className:"my-1 w-full overflow-hidden rounded-md border border-border/60 bg-background/40",children:[n.jsxs("button",{type:"button","data-testid":"tool-session-toggle",onClick:()=>r(!s),className:"flex w-full items-center gap-1.5 px-2 py-1.5 text-left text-[11px] text-muted-foreground hover:bg-foreground/5",children:[s?n.jsx(ft,{className:"h-3 w-3 shrink-0"}):n.jsx(xt,{className:"h-3 w-3 shrink-0"}),n.jsx(pt,{className:"h-3 w-3 shrink-0"}),n.jsx("span",{className:b("truncate",!e.done&&"animate-pulse"),children:d})]}),s&&n.jsxs("div",{"data-testid":"tool-session-body",className:"max-h-80 overflow-auto border-t border-border/60 px-2 py-1.5",children:[e.elided>0&&n.jsxs("div",{className:"mb-1 text-[10px] italic text-muted-foreground/70",children:["… ",e.elided," earlier ",e.elided===1?"line":"lines"," elided"]}),e.lines.map((u,c)=>n.jsx(pn,{line:u},c))]}),e.done&&n.jsx("div",{"data-testid":"tool-session-footer",className:b("border-t border-border/60 px-2 py-1 text-[10px]",e.ok?"text-muted-foreground":"text-red-300/90"),children:hn(e)})]})}const G=l.memo(function({text:t}){return n.jsx(Ct,{children:t})});function Ue({text:e}){return n.jsx("span",{className:"whitespace-pre-wrap break-words",children:e})}function De(e){return e==="done"||e==="complete"||e==="completed"||e==="skipped"}function yn(e,t){if(De(e))return n.jsx(fe,{className:"h-3.5 w-3.5 shrink-0 text-success","aria-hidden":"true"});switch(e){case"in_progress":case"active":case"running":return n.jsx(J,{className:b("h-3.5 w-3.5 shrink-0 text-primary",t&&"animate-spin"),"aria-hidden":"true"});case"blocked":case"failed":case"error":return n.jsx(Se,{className:"h-3.5 w-3.5 shrink-0 text-destructive","aria-hidden":"true"});default:return n.jsx(bt,{className:"h-3.5 w-3.5 shrink-0 text-muted-foreground","aria-hidden":"true"})}}function le({items:e,live:t}){return n.jsx("ul",{className:"flex flex-col gap-1",children:e.map(r=>{const s=De(r.status);return n.jsxs("li",{className:"flex items-start gap-1.5 text-xs leading-snug",children:[n.jsx("span",{className:"mt-0.5",children:yn(r.status,t)}),n.jsx("span",{className:b("break-words",s?"text-muted-foreground":"text-card-foreground"),children:r.label})]},r.id)})})}function Pe({plan:e,live:t}){const r=e.items??[],s=e.phases??[];if(s.length===0)return n.jsx(le,{items:r,live:t});const d=s.map(a=>({phase:a,steps:r.filter(m=>m.phase===a.id)})).filter(a=>a.steps.length>0),u=new Set(s.map(a=>a.id)),c=r.filter(a=>!a.phase||!u.has(a.phase));return n.jsxs("div",{className:"flex flex-col gap-2",children:[d.map((a,m)=>n.jsxs("div",{className:"flex flex-col gap-1",children:[n.jsx("div",{className:"break-words text-xs font-medium text-card-foreground",children:a.phase.label}),n.jsx("div",{className:"border-l border-border/60 pl-2",children:n.jsx(le,{items:a.steps,live:t})})]},a.phase.id||m)),c.length>0&&n.jsxs("div",{className:"flex flex-col gap-1",children:[d.length>0&&n.jsx("span",{className:"text-[10px] font-medium uppercase tracking-wide text-muted-foreground",children:"Other steps"}),n.jsx("div",{className:b(d.length>0&&"border-l border-border/60 pl-2"),children:n.jsx(le,{items:c,live:t})})]})]})}function bn({plan:e,live:t}){const r=e.items??[];return n.jsxs("div",{className:"mx-auto w-full max-w-[85%] rounded-lg border border-border bg-card/60 px-3 py-2",children:[n.jsxs("div",{className:"flex items-center gap-1.5 text-xs font-medium text-muted-foreground mb-1.5",children:[n.jsx(yt,{className:"h-3.5 w-3.5","aria-hidden":"true"}),n.jsxs("span",{children:["Plan",r.length>0?` · ${r.length} step${r.length===1?"":"s"}`:""]})]}),r.length===0?n.jsx("div",{className:"text-xs text-muted-foreground",children:"Plan updated."}):n.jsx(Pe,{plan:e,live:t})]})}function D({isUser:e,className:t,children:r}){return n.jsx("div",{className:b("flex",e?"justify-end":"justify-start"),children:n.jsx("div",{className:b("max-w-[75%] rounded-2xl px-3.5 py-2 text-sm leading-relaxed",e?"bg-primary text-primary-foreground rounded-br-sm":"bg-card border border-border text-card-foreground rounded-bl-sm",t),children:r})})}const jn=l.memo(function({line:t,toolSession:r,onRetry:s,onDecision:d,live:u,absorbedPlan:c}){return t.role==="toolSession"?r?n.jsx(gn,{state:r}):null:t.liveViewUrl?n.jsx("div",{className:"flex justify-center py-1",children:n.jsxs("a",{href:t.liveViewUrl,target:"_blank",rel:"noopener noreferrer",className:"inline-flex items-center gap-1.5 rounded-lg border border-border bg-card px-3 py-1.5 text-xs font-medium text-card-foreground hover:bg-accent hover:text-accent-foreground",children:[n.jsx(Te,{className:"h-3.5 w-3.5 shrink-0","aria-hidden":"true"}),"View live"]})}):t.role==="plan"&&t.plan?n.jsx(bn,{plan:t.plan,live:u}):t.role==="interaction"&&t.interactionRequest?n.jsx(ln,{request:t.interactionRequest,applied:t.interactionApplied,onDecision:d??(()=>{}),footer:c?n.jsxs("div",{className:"flex flex-col gap-1 border-t border-border/60 pt-2",children:[n.jsx("span",{className:"text-[10px] font-medium uppercase tracking-wide text-muted-foreground",children:"The plan this covers"}),n.jsx(Pe,{plan:c,live:u})]}):void 0}):t.role==="notice"&&t.notice?n.jsx(fn,{notice:t.notice}):t.role==="system"||t.role==="error"?n.jsx("div",{className:b("mx-auto max-w-[85%] text-center text-xs py-1",t.role==="error"?"text-destructive":"text-muted-foreground"),children:n.jsx(Ue,{text:t.text})}):t.role==="user"&&t.sendStatus==="failed"?n.jsxs("div",{className:"flex flex-col items-end gap-1","data-testid":"failed-message",children:[n.jsx(D,{isUser:!0,className:"border border-destructive bg-destructive/10 text-foreground",children:n.jsx(G,{text:t.text})}),n.jsxs("div",{className:"flex items-center gap-2 text-[11px] text-destructive",children:[n.jsx(_e,{className:"h-3.5 w-3.5 shrink-0","aria-hidden":"true"}),n.jsx("span",{className:"break-words",children:t.sendError||"Failed to send."}),s&&n.jsxs("button",{type:"button",onClick:()=>s(t.id,t.text,t.requestId??""),className:"inline-flex items-center gap-1 font-medium underline underline-offset-2 hover:no-underline",children:[n.jsx(ht,{className:"h-3 w-3","aria-hidden":"true"}),"Retry"]})]})]}):t.role==="user"&&t.sendStatus==="pending"?n.jsx("div",{"data-testid":"pending-message",children:n.jsx(D,{isUser:!0,className:"opacity-60 animate-pulse",children:n.jsx(G,{text:t.text})})}):t.role==="user"&&t.queued?n.jsx("div",{"data-testid":"queued-message",children:n.jsxs(D,{isUser:!0,children:[n.jsx("div",{className:"mb-0.5 text-[10px] font-medium uppercase tracking-wide text-muted-foreground",children:"Queued"}),n.jsx("span",{className:"whitespace-pre-wrap break-words text-muted-foreground",children:t.text})]})}):t.attachments&&t.attachments.length>0?n.jsxs("div",{className:b("flex flex-col gap-1",t.role==="user"?"items-end":"items-start"),children:[n.jsx(D,{isUser:t.role==="user",children:n.jsx(G,{text:t.text})}),n.jsx(vn,{attachments:t.attachments})]}):n.jsx(D,{isUser:t.role==="user",children:n.jsx(G,{text:t.text})})});function vn({attachments:e}){return n.jsx("div",{className:"flex flex-wrap gap-1.5","data-testid":"attachment-chips",children:e.map((t,r)=>n.jsxs("a",{href:t.url,download:t.filename,className:"inline-flex items-center gap-1.5 rounded-lg border border-border bg-card px-2.5 py-1 text-xs text-card-foreground hover:bg-accent hover:text-accent-foreground",children:[n.jsx(gt,{className:"h-3.5 w-3.5 shrink-0","aria-hidden":"true"}),n.jsx("span",{className:"break-all",children:t.filename})]},r))})}function wn({text:e}){return n.jsxs(D,{isUser:!1,children:[n.jsx(Ue,{text:e}),n.jsx("span",{className:"ml-0.5 inline-block h-4 w-[2px] translate-y-0.5 bg-current animate-pulse","aria-hidden":"true"})]})}function Nn(){return n.jsx("div",{className:"flex justify-start",role:"status","aria-label":"Agent is working",children:n.jsx("div",{className:"flex items-center gap-2 rounded-2xl rounded-bl-sm border border-border bg-card px-3.5 py-2.5",children:n.jsx("div",{className:"flex items-center gap-1",children:[0,150,300].map(e=>n.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-muted-foreground animate-bounce",style:{animationDelay:`${e}ms`}},e))})})})}function kn({text:e}){return n.jsx("div",{className:"flex items-center justify-center text-[11px] text-muted-foreground py-0.5",children:n.jsx("span",{className:"animate-pulse",children:e})})}function Cn({text:e}){return n.jsxs("div",{className:"flex items-center justify-center gap-1.5 text-[11px] text-muted-foreground py-0.5",children:[n.jsx(J,{className:"h-3 w-3 animate-spin","aria-hidden":"true"}),n.jsx("span",{children:e})]})}function Rn({lines:e,streamingText:t,working:r,statusText:s,notice:d,opTree:u,toolSessions:c,onRetry:a,onDecision:m}){const p=l.useRef(null),N=l.useRef(null),j=l.useRef(null);l.useEffect(()=>{var w,L;const g=N.current;if(!(!g||!(g.scrollHeight-g.scrollTop-g.clientHeight<120))){if(typeof requestAnimationFrame!="function"){(L=(w=p.current)==null?void 0:w.scrollIntoView)==null||L.call(w,{block:"end"});return}return j.current!=null&&cancelAnimationFrame(j.current),j.current=requestAnimationFrame(()=>{var k,O;j.current=null,(O=(k=p.current)==null?void 0:k.scrollIntoView)==null||O.call(k,{block:"end"})}),()=>{j.current!=null&&(cancelAnimationFrame(j.current),j.current=null)}}},[e.length,t,r,s,d,u]);const{absorbedPlanByLine:S,suppressedPlanLines:_}=l.useMemo(()=>{var L;const g={},$=new Set;let w;for(const k of e){if(k.role==="plan"&&k.plan){w=k;continue}const O=(L=k.interactionRequest)==null?void 0:L.category;k.role==="interaction"&&(O==="plan_phase"||O==="plan_amendment")&&w!=null&&w.plan&&(g[k.id]=w.plan,$.add(w.id))}return{absorbedPlanByLine:g,suppressedPlanLines:$}},[e]),A=t.length>0,V=r&&!A;return n.jsx("div",{ref:N,className:"flex-1 min-h-0 overflow-y-auto px-4 py-4",children:n.jsxs("div",{className:"flex flex-col gap-2.5 max-w-3xl mx-auto",children:[e.map(g=>_.has(g.id)?null:n.jsx("div",{"data-testid":"chat-line","data-role":g.role,children:n.jsx(jn,{line:g,toolSession:g.toolSessionRef?c[g.toolSessionRef]:void 0,onRetry:a,onDecision:m,live:r,absorbedPlan:S[g.id]})},g.id)),A&&n.jsx(wn,{text:t}),V&&n.jsx(Nn,{}),r&&d&&n.jsx(kn,{text:d}),r&&u.length>0&&n.jsx(Wt,{nodes:u}),r&&s&&n.jsx(Cn,{text:s}),n.jsx("div",{ref:p})]})})}function In({disabled:e,placeholder:t,onSend:r}){const[s,d]=l.useState(""),u=()=>{const a=s.trim();!a||e||(r(a),d(""))},c=a=>{a.key==="Enter"&&!a.shiftKey&&(a.preventDefault(),u())};return n.jsxs("div",{className:"flex items-end gap-2 px-4 py-3 border-t border-border bg-card",children:[n.jsx("textarea",{rows:1,value:s,disabled:e,placeholder:t,onChange:a=>d(a.target.value),onKeyDown:c,className:b("flex-1 resize-none max-h-40 rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm","placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring","disabled:cursor-not-allowed disabled:opacity-50")}),n.jsx(X,{size:"icon",className:"h-9 w-9 shrink-0",disabled:e||!s.trim(),onClick:u,title:"Send",children:n.jsx(jt,{className:"h-4 w-4"})})]})}function P(e,t){return`/sessions/api/${encodeURIComponent(e)}/${encodeURIComponent(t)}`}async function Q(e,t){if((e.headers.get("content-type")??"").includes("application/json"))try{const r=await e.json(),s=r==null?void 0:r.error;if(typeof s=="string"&&s.trim()!=="")return s}catch{}switch(e.status){case 401:return"You are no longer signed in. Reload the page to continue.";case 403:return"You do not have access to this conversation.";case 503:return"That could not be checked right now. Try again in a moment.";default:return t}}async function Dn(e,t,r){const s=await fetch(`/sessions/api/${encodeURIComponent(e)}/${encodeURIComponent(t)}/message`,{method:"POST",credentials:"same-origin",headers:{"Content-Type":"application/json"},body:JSON.stringify({text:r})});if(!s.ok)throw new Error(`send session message: request failed (${s.status})`)}function Sn(e,t,r){const s=l.useCallback(async(d,u,c)=>{try{const a=await fetch(`${P(e,t)}/decision`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({category:u,requestRef:d,actionId:c})});if(!a.ok){console.error("interaction decision: request failed",{ns:e,name:t,status:a.status});const m=await Q(a,`Failed to submit decision (${a.status}).`);r(m)}}catch(a){console.error("interaction decision: request errored",{ns:e,name:t,err:a}),r("Network error while trying to submit decision.")}},[e,t,r]);return l.useCallback((d,u,c)=>{s(d,u,c)},[s])}function Tn(e){if(e.class==="already_resolved"){let r="someone else";e.originalDecider&&(r=e.originalDecider.email||e.originalDecider.externalId||r);let s=`This request was already resolved by ${r}`;return e.originalOutcome&&(s+=` (${e.originalOutcome})`),s+"."}return((e.reason||"").trim()||"your click could not be applied")+"."}function _n(e){switch(e.reason){case"succeeded":return"Conversation ended.";case"failed":return`Conversation ended: ${e.failureMessage||e.failureReason||"the agent failed"}.`;case"idle_timeout":return"Conversation ended after being idle too long.";case"server_shutdown":return"Conversation ended: the server is restarting.";default:return"Conversation ended."}}function Ne(e,t){return e.map(r=>r.kind==="plan"?{id:`plan:${r.plan.planName}`,role:"plan",text:"",plan:r.plan}:{id:t(),role:r.role,text:r.text})}const ke="Earlier messages could not be loaded. The live conversation still works.",$n="Starting…",Ce="Working…",Re={text:"",ephemeral:!1};function Ie(e){return e.ephemeral&&e.text!==Ce?{text:Ce,ephemeral:!0}:e}function qn(e,t){return`/artifact-download?${new URLSearchParams({artifactId:t.artifactId,sessionRef:`${e.namespace}/${e.name}`,fn:t.filename||t.artifactId}).toString()}`}const En=new Set(["startup","scheduling"]);function Pn({ns:e,name:t,readOnly:r,onUserSend:s,onSessionEnded:d}){const[u,c]=l.useState([]),[a,m]=l.useState(!1),[p,N]=l.useState([]),{startup:j}=Le(),S=j===null?p:p.filter(o=>!En.has(o.kind)),_=r||a,A=l.useCallback(()=>{m(!0),d==null||d()},[d]),V=l.useRef(`${e}/${t}`),g=l.useCallback(o=>o===V.current,[]),[$,w]=l.useState(!1),[L,k]=l.useState(Re),[O,Me]=l.useState(""),[Fe,ee]=l.useState(null),[Be,te]=l.useState([]),[He,Je]=l.useState({}),ne=l.useRef(""),U=l.useCallback(o=>{const f=o(ne.current);ne.current=f,Me(f)},[]),[Ve,Ye]=l.useState(null),re=l.useRef(null),q=l.useCallback(o=>{re.current=o,Ye(o)},[]),Ke=l.useRef(0),R=l.useCallback(()=>`l${Ke.current++}`,[]),C=l.useCallback((o,f,h)=>{c(i=>[...i,{id:R(),role:o,text:f,queued:h==null?void 0:h.queued,attachments:h==null?void 0:h.attachments}])},[R]),he=l.useCallback(o=>{o.lead&&c(f=>[...f,{id:R(),role:"notice",text:"",notice:o}])},[R]),Y=l.useRef(!1),E=l.useRef(!1),K=l.useCallback(()=>{E.current=!0,w(!0),ee(null),k({text:$n,ephemeral:!0}),U(()=>"")},[U]),I=l.useCallback(()=>{E.current=!1,w(!1),ee(null),te([]),k(Re),U(()=>"")},[U]),se=l.useCallback(()=>{const o=ne.current;o&&C("agent",o)},[C]),ae=l.useCallback(()=>{c(o=>o.map(f=>f.queued?{...f,queued:!1}:f))},[]),ge=l.useCallback(async()=>{const o=P(e,t),f=`${e}/${t}`;try{const[h,i]=await Promise.all([fetch(`${o}/messages`),fetch(`${o}/detail`)]);if(!h.ok)console.error("chat: resync transcript failed",{ns:e,name:t,status:h.status});else{const y=await h.json();if(!g(f))return;c(Ne(y.timeline??[],R))}if(!i.ok){console.error("chat: resync session detail failed",{ns:e,name:t,status:i.status});return}const x=await i.json();if(!g(f))return;x.phase!=="Running"&&I(),N(x.notices??[])}catch(h){console.error("chat: resync after reconnect errored",{ns:e,name:t,err:h})}},[e,t,R,I,g]);l.useEffect(()=>{let o=!1;return V.current=`${e}/${t}`,c([]),m(!1),I(),q(null),Y.current=!1,(async()=>{try{(async()=>{try{const i=await fetch(`${P(e,t)}/detail`);if(o||!i.ok)return;const x=await i.json();o||N(x.notices??[])}catch(i){console.error("chat: load session detail errored",{ns:e,name:t,err:i})}})();const f=await fetch(`${P(e,t)}/messages`);if(o)return;if(f.ok){const i=await f.json();if(o)return;c(Ne(i.timeline??[],R));return}console.error("chat: load transcript failed",{ns:e,name:t,status:f.status});const h=f.status===501?"History replay is unavailable here; resuming live.":await Q(f,ke);if(o)return;c([{id:R(),role:f.status===501?"system":"error",text:h}])}catch(f){if(console.error("chat: load transcript errored",{ns:e,name:t,err:f}),o)return;c([{id:R(),role:"error",text:ke}])}})(),()=>{o=!0}},[e,t,R,I,q]);const ze=l.useCallback(o=>{var f,h;switch(o.type){case"user_message":{const i=o.payload,x=i.text;U(()=>"");const y=(i.attachments??[]).filter(v=>v.artifactId).map(v=>({filename:v.filename||v.artifactId,mime:v.mime,url:qn(i.session,v)}));C("agent",x,y.length?{attachments:y}:void 0);break}case"user_echo":{const i=o.payload;c(x=>i.requestID&&x.some(y=>y.requestId===i.requestID)?x:[...x,{id:R(),role:"user",text:i.text}]);break}case"notification":{if(!E.current)break;const i=o.payload;w(!0),k({text:i.text,ephemeral:i.ephemeral===!0});break}case"plan_update":{const i=o.payload.payload;E.current&&w(!0);const x=`plan:${i.planName}`;c(y=>{const v=y.findIndex(T=>T.role==="plan"&&T.id===x);if(v>=0){const T=y.slice();return T[v]={...y[v],plan:i},T}return[...y,{id:x,role:"plan",text:"",plan:i}]});break}case"stream_delta":{if(!E.current)break;const i=o.payload.payload;(i==null?void 0:i.eventType)==="text_delta"&&i.text&&(w(!0),k(Ie),U(x=>x+i.text));break}case"turn_progress":if(!E.current)break;w(!0),k(Ie),ee(o.payload.payload);break;case"operation_activity":{if(!E.current){te([]);break}const i=o.payload.payload;te(i.cleared?[]:i.operations??[]);break}case"turn_activity":{o.payload.active?(E.current=!0,w(!0)):(se(),I(),ae());break}case"interrupt_applied":{const i=o.payload;if(i.requestID!==re.current)break;q(null),i.outcome==="interrupted"?(C("system","Interrupting — sending your message(s) now."),ae()):C("system","Couldn't interrupt — "+(i.reason||"the runner declined."));break}case"send_error":I(),C("error",o.payload.err||"The agent failed to process a message.");break;case"session_ended":{A(),se(),I(),C("system",_n(o.payload));break}case"live_view_offer":{const i=o.payload.url;i&&c(x=>[...x,{id:R(),role:"system",text:"",liveViewUrl:i}]);break}case"tool_session_event":case"tool_session_delta":{Je(y=>Et(y,o));const i=(h=(f=o.payload)==null?void 0:f.payload)==null?void 0:h.toolCallRef;if(!i)break;const x=`toolsession:${i}`;c(y=>y.some(v=>v.id===x)?y:[...y,{id:x,role:"toolSession",text:"",toolSessionRef:i}]);break}case"interaction_request":{const i=o.payload.payload,x=`interaction:${i.requestRef}`;c(y=>{const v=y.findIndex(T=>T.role==="interaction"&&T.id===x);if(v>=0){const T=y.slice();return T[v]={...y[v],interactionRequest:i},T}return[...y,{id:x,role:"interaction",text:"",interactionRequest:i}]});break}case"interaction_applied":{const i=o.payload.payload,x=`interaction:${i.requestRef}`;c(y=>y.map(v=>v.id===x?{...v,interactionApplied:i}:v));break}case"interaction_decision_rejected":{const i=o.payload.payload;C(i.class==="already_resolved"?"system":"error",Tn(i));break}}},[C,R,U,q,A,I,se,ae]);Ht(ze);const B=Jt(),z=l.useRef(!1);l.useEffect(()=>{if(B==="connected"){z.current=!1,Y.current&&(Y.current=!1,ge());return}if(B==="connecting"){z.current=!1;return}Y.current=!0,B==="offline"&&!_&&!z.current&&(z.current=!0,I(),C("error","Connection lost — reload the page to reconnect."))},[B,_,C,ge,I]);const H=l.useCallback((o,f,h)=>{c(i=>i.map(x=>x.id===o?{...x,sendStatus:f,sendError:h}:x))},[]),W=l.useCallback(async(o,f,h)=>{const i=`${e}/${t}`;H(o,"pending");try{const x=await fetch(`${P(e,t)}/message`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({text:f,requestId:h})});if(!g(i))return;if(!x.ok){console.error("chat: send failed",{ns:e,name:t,status:x.status});const v=await Q(x,`Failed to send (${x.status}).`);if(!g(i))return;H(o,"failed",v),I();return}const y=await x.json();if(!g(i))return;H(o,"sent"),y.notice&&he(y.notice),y.ended&&(A(),I())}catch(x){if(console.error("chat: send errored",{ns:e,name:t,err:x}),!g(i))return;H(o,"failed","Network error while sending your message."),I()}},[e,t,H,he,A,I,g]),We=l.useCallback(o=>{s==null||s();const f=R(),h=crypto.randomUUID();c(i=>[...i,{id:f,role:"user",text:o,queued:$,sendStatus:"pending",requestId:h}]),K(),W(f,o,h)},[$,R,K,s,W]),Ge=l.useCallback((o,f,h)=>{K(),W(o,f,h)},[K,W]),Qe=l.useCallback(async()=>{if(re.current)return;const o=`${e}/${t}`,f=crypto.randomUUID();q(f);try{const h=await fetch(`${P(e,t)}/interrupt`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({requestId:f})});if(!h.ok){console.error("chat: interrupt failed",{ns:e,name:t,status:h.status});const i=await Q(h,`Failed to interrupt (${h.status}).`);if(!g(o))return;C("error",i),q(null)}}catch(h){if(console.error("chat: interrupt errored",{ns:e,name:t,err:h}),!g(o))return;C("error","Network error while trying to interrupt."),q(null)}},[e,t,C,q,g]),Xe=l.useCallback(o=>{g(`${e}/${t}`)&&C("error",o)},[e,t,g,C]),Ze=Sn(e,t,Xe),et=$?Rt(Fe):null,tt=_?"This conversation has ended.":"Message the agent…";return n.jsx(kt,{delayDuration:200,children:n.jsxs("div",{className:"flex min-h-0 flex-1 flex-col bg-background text-foreground","data-testid":"chat-view",children:[n.jsx("div",{className:"flex items-center justify-end px-3 py-1 border-b border-border bg-card/40",children:n.jsx(Yt,{state:B})}),n.jsx(Rn,{lines:u,streamingText:O,working:$,statusText:et,notice:L.text,opTree:Be,toolSessions:He,onRetry:Ge,onDecision:Ze}),$&&u.some(o=>o.queued)&&n.jsx("div",{className:"flex justify-center px-4 pt-2 bg-card",children:n.jsx(X,{variant:"secondary",size:"sm",disabled:Ve!==null,onClick:Qe,children:"Interrupt & Send Now"})}),S.length>0&&n.jsx("div",{className:"mx-4 mb-2 flex flex-col gap-1.5",children:S.map((o,f)=>n.jsxs("div",{"data-testid":`session-notice-${o.kind}`,className:b("rounded-md border px-3 py-2 text-xs leading-snug",o.tone==="degraded"?"border-warning/30 bg-warning/10 text-warning":"border-border/60 bg-muted/40 text-muted-foreground"),children:[n.jsx("div",{children:o.lead}),o.nextStep&&n.jsx("div",{className:"mt-0.5 font-medium",children:o.nextStep}),o.body&&n.jsx("div",{className:"mt-1 break-all font-mono text-[10px] opacity-70",children:o.body})]},`${o.kind}:${f}`))}),n.jsx(In,{disabled:_,placeholder:tt,onSend:We})]})})}function Mn(){const{startup:e}=Le();return e===null?null:n.jsxs("div",{"data-testid":"session-shell-startup",role:"status",className:"flex items-center gap-2 border-b border-border bg-card/60 px-4 py-2 text-sm text-muted-foreground",children:[n.jsx(J,{className:"h-4 w-4 shrink-0 animate-spin","aria-hidden":"true"}),n.jsxs("span",{children:[e.short!==null?n.jsxs(n.Fragment,{children:[n.jsx("span",{className:"hidden sm:inline",children:e.text}),n.jsx("span",{className:"sm:hidden",children:e.short})]}):e.text,e.stillTrying&&n.jsx("span",{"data-testid":"session-shell-startup-still-trying",children:" — still trying"})]})]})}export{Pn as C,ln as I,Un as S,Mn as a,Sn as b,Ht as c,Tn as i,Dn as s,Le as u}; diff --git a/pkg/web/webui/webassets/dist/admin.C9jbAoMt.js b/pkg/web/webui/webassets/dist/admin.D8BEorQ0.js similarity index 99% rename from pkg/web/webui/webassets/dist/admin.C9jbAoMt.js rename to pkg/web/webui/webassets/dist/admin.D8BEorQ0.js index aa4ce28a..964fe176 100644 --- a/pkg/web/webui/webassets/dist/admin.C9jbAoMt.js +++ b/pkg/web/webui/webassets/dist/admin.D8BEorQ0.js @@ -1 +1 @@ -import{c as Ge,r as en,f as Pe,s as _t,C as me,b as he,d as fe,e as pe,T as tn,g as sn,h as nn,i as rn,A as I,a as F,j as Y,k as Q,l as M,n as y,o as X,p as v,B as U,D as Je,q as Ye,t as Qe,u as Xe,v as Ze,w as Be,x as et,y as wt,S as an,z as on,E as ln,F as cn,G as dn,H as un,I as xn,J as mn,K as hn,L as fn,m as pn}from"./mount.BOEH1oNx.js";import{r as d,j as e,L as gn,A as jn,T as bn,S as vn,H as yn,B as Nn,W as wn,a as kn,G as Sn,F as Cn,b as $n,K as Tn,U as ms,c as Ln,d as An,e as En,f as Dn,g as Rn,h as On,D as In,N as hs,i as Fn,k as Mn,l as Pn,M as Kn,C as _n,m as Un,n as Vn,o as Wn,p as Hn,q as fs,X as zn,s as qn,t as Gn,u as Jn}from"./vendor.C5MRNvUt.js";import{B as z}from"./badge.CIlGQKPh.js";import{M as kt}from"./model-name.DtAiu0oG.js";const Ke="M159.186 7.59677C164.993 -2.53226 179.604 -2.53226 185.411 7.59677L342.572 281.702C348.349 291.779 341.075 304.335 329.459 304.335H15.138C3.52262 304.335 -3.75273 291.779 2.02468 281.702L159.186 7.59677Z",Yn="M178.855 133.226C175.951 128.161 168.646 128.161 165.742 133.226L117.254 217.794C114.366 222.832 118.003 229.11 123.811 229.11H220.786C226.594 229.11 230.232 222.832 227.343 217.794L178.855 133.226Z",Te=[1,2,3,4,5].map(t=>`hsl(var(--chart-${t}))`),_e=12,Qn=3.2,Xn=.55,Zn=.35;function Bn(){return typeof window<"u"&&typeof window.matchMedia=="function"?window.matchMedia("(prefers-reduced-motion: reduce)").matches:!1}function Le(t,s,n,r){if(t){if(n<=.05){t.style.opacity="0";return}t.style.opacity="1",t.style.stroke=r,t.style.strokeDasharray=`${n} ${100-n}`,t.style.strokeDashoffset=`${-s}`}}function er({className:t,title:s,active:n=!1,lapMs:r=2400,band:a=12,bandWidth:o=12,handoverEvery:i=2,...l}){const c=d.useRef(null),u=d.useRef(null),h=d.useRef([]),N=n&&!Bn();d.useEffect(()=>{if(!N)return;const b=performance.now();let x=0;const j=$=>{const C=($-b)/r,E=C*100%100,m=(E-a+100)%100,w=Math.floor(C*3),R=Math.floor(w/i),O=Te[R%Te.length],L=Te[(R-1+Te.length)%Te.length],k=w/3*100%100,g=(E-k+100)%100,T=w%i===0&&gcancelAnimationFrame(x)},[N,r,a,i]);const p={opacity:0};return e.jsxs("svg",{viewBox:"0 0 345 305",fill:"currentColor","aria-hidden":s?void 0:!0,role:s?"img":void 0,className:Ge("shrink-0 overflow-visible",t),"data-relay":N?"on":"off",...l,children:[s?e.jsx("title",{children:s}):null,e.jsx("path",{d:Ke+Yn,style:{opacity:N?Zn:1,transition:"opacity 240ms ease-out"},"data-ink":!0}),e.jsxs("g",{fill:"none",strokeWidth:o,strokeLinecap:"round",strokeLinejoin:"round",style:{opacity:N?1:0,transition:"opacity 240ms ease-out"},children:[Array.from({length:_e},(b,x)=>e.jsx("path",{ref:j=>{h.current[x]=j},d:Ke,pathLength:100,style:p,strokeLinecap:"butt","data-seg":"tail"},x)),e.jsx("path",{ref:c,d:Ke,pathLength:100,style:p,"data-seg":"a"}),e.jsx("path",{ref:u,d:Ke,pathLength:100,style:p,"data-seg":"b"})]})]})}const ps=[{group:"",items:[{id:"overview",label:"Overview",icon:gn}]},{group:"Live",items:[{id:"sessions",label:"Agent sessions",icon:jn},{id:"toolcalls",label:"Live tool calls",icon:bn},{id:"approvals",label:"Approvals",icon:vn},{id:"workshops",label:"Workshops",icon:yn}]},{group:"Config",items:[{id:"agents",label:"Agents",icon:Nn},{id:"tools",label:"Tools",icon:wn},{id:"skills",label:"Skills",icon:kn},{id:"sources",label:"Sources",icon:Sn},{id:"directory",label:"Directory",icon:Cn},{id:"channels",label:"Channels",icon:$n},{id:"identity",label:"Identity",icon:Tn},{id:"users",label:"Users",icon:ms},{id:"access",label:"Access",icon:Ln},{id:"settings",label:"Settings",icon:An}]},{group:"Audit",items:[{id:"logs",label:"Logs",icon:En},{id:"sessionsAudit",label:"Sessions",icon:Dn},{id:"budget",label:"Budget",icon:Rn},{id:"artifacts",label:"Artifacts",icon:On},{id:"memory",label:"Memory",icon:In},{id:"knowledge",label:"Knowledge",icon:hs}]}],gs={overview:{title:"Overview",sub:"Platform at a glance — usage, spend, and health"},sessions:{title:"Agent sessions",sub:"Live agent sessions across the platform"},toolcalls:{title:"Live tool calls",sub:"Tool invocations as they happen, across every session"},approvals:{title:"Approvals",sub:"Tool calls & leakage gates awaiting a decision"},workshops:{title:"Workshops",sub:"Agent-builder sessions' drafted bundles — install, decline, or kill"},agents:{title:"Agents",sub:"Configured AgentClasses and their readiness · oap class / kubectl agentclass"},tools:{title:"Tools",sub:"MCP servers, sandboxed CLIs, sidecars, toolkits · oap tools"},skills:{title:"Skills",sub:"Instruction & executable skills available to agents · oap skill"},sources:{title:"Sources",sub:"Skill sources synced from git · oap skill source"},directory:{title:"Directory",sub:"Directory syncs feeding SpiceDB — Slack, GitHub, 1Password · oap directory"},channels:{title:"Channels",sub:"Where agents are reachable · oap channel / kubectl channel"},identity:{title:"Identity",sub:"Agent identities, credentials, and login providers · oap identity / oap idp"},users:{title:"Users",sub:"People linked to the platform · oap user-identity"},access:{title:"Access",sub:"Platform admins & the SpiceDB authorization schema · oap platform / oap spicedb"},settings:{title:"Settings",sub:"Cluster configuration — defaults, ceilings, security · oap settings"},logs:{title:"Logs",sub:"Cross-session audit — approvals, authz, tool calls, scope changes · oap audit"},sessionsAudit:{title:"Sessions",sub:"Every agent session, current and historical"},budget:{title:"Budget",sub:"Estimated spend by model, agent, session, user"},artifacts:{title:"Artifacts",sub:"Rendered outputs agents produced · oap artifact"},memory:{title:"Memory",sub:"The searchable, authorized memory store · oap memory"},knowledge:{title:"Knowledge",sub:"The knowledge graph — entities, facts, communities · oap kg"}};class J extends Error{constructor(s,n){super(s),this.status=n}}class tt extends J{constructor(s,n,r=[],a=[],o=[],i=[]){super(s,400),this.questions=n,this.skillClones=r,this.warnings=a,this.channels=o,this.conflicts=i}}class st extends J{constructor(s,n,r=[],a=[],o=[],i=[]){super(s,409),this.conflicts=n,this.skillClones=r,this.channels=a,this.warnings=o,this.questions=i}}async function js(t,s){var a,o,i;const n=await fetch(`${t}/agents/oap-install`,s);if(n.ok)return await n.json();let r={};try{r=await n.json()}catch{}throw n.status===400&&((((a=r.questions)==null?void 0:a.length)??0)>0||(((o=r.channels)==null?void 0:o.length)??0)>0||(((i=r.conflicts)==null?void 0:i.length)??0)>0)?new tt(r.error||"missing required question(s)",r.questions??[],r.skillClones??[],r.warnings??[],r.channels??[],r.conflicts??[]):n.status===409&&r.conflicts&&r.conflicts.length>0?new st(r.error||"install would overwrite pre-existing object(s)",r.conflicts,r.skillClones??[],r.channels??[],r.warnings??[],r.questions??[]):new J(r.error||`request failed (${n.status})`,n.status)}class ht extends J{constructor(s,n){super(s,400),this.questions=n}}async function bs(t,s,n){var o;const r=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({setupToken:s,answers:n})});if(r.ok)return await r.json();let a={};try{a=await r.json()}catch{}throw r.status===400&&(((o=a.questions)==null?void 0:o.length)??0)>0?new ht(a.error||"missing required channel answer(s)",a.questions??[]):new J(a.error||`request failed (${r.status})`,r.status)}const Ut=(t,s,n)=>bs(`${t}/agents/channel-setup`,s,n),tr=(t,s,n)=>bs(`${t}/agents/channel-handoff`,s,n),sr=(t,s)=>js(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)}),nr=(t,s,n)=>{var a;const r=new FormData;return r.append("file",s),r.append("namespace",n.namespace),n.name&&r.append("name",n.name),n.values&&r.append("values",JSON.stringify(n.values)),(a=n.adopt)!=null&&a.length&&r.append("adopt",JSON.stringify(n.adopt)),js(t,{method:"POST",body:r})};async function rr(t,s){const n=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(n.ok)return await n.json();let r={};try{r=await n.json()}catch{}throw n.status===400&&r.questions&&r.questions.length>0?new tt(r.error||"missing required question(s)",r.questions,r.skillClones??[],r.warnings??[]):n.status===409&&r.conflicts&&r.conflicts.length>0?new st(r.error||"install would overwrite pre-existing object(s)",r.conflicts,r.skillClones??[]):new J(r.error||`request failed (${n.status})`,n.status)}const ar=(t,s,n,r)=>rr(`${t}/workshops/${s}/${n}/install`,r);async function St(t){if(!t.ok){let s=`request failed (${t.status})`;try{const n=await t.json();n.error&&(s=n.error)}catch{}throw new J(s,t.status)}return await t.json()}const _=async t=>St(await fetch(t)),or=t=>_(`${t}/overview`),lr=t=>_(`${t}/health`),ir=t=>_(`${t}/cluster`),cr=t=>_(`${t}/budget`),dr=t=>_(`${t}/toolcalls`),ur=(t,s,n)=>_(`${t}/sessions/${s}/${n}/logs`),xr=t=>_(`${t}/approvals`),Ct=async(t,s)=>await _(`${t}/config/${s}`)??[],Vt=(t,s,n)=>_(`${t}/config/${s}/${n}`),mr=t=>_(`${t}/access`),hr=t=>_(`${t}/artifacts`),fr=(t,s,n)=>_(`${t}/artifacts/${s}/${n}`),pr=t=>_(`${t}/workshops`),gr=(t,s={})=>{const n=new URLSearchParams;s.q&&n.set("q",s.q),s.kind&&n.set("kind",s.kind);const r=n.toString();return _(`${t}/memory${r?`?${r}`:""}`)},jr=t=>_(`${t}/config/settings`),Fe=(t,s,n={})=>{const r=new URLSearchParams(n).toString();return`${t}/kg/${s}${r?`?${r}`:""}`},br=(t,s)=>_(Fe(t,"search",s?{q:s}:{})),vr=(t,s)=>_(Fe(t,"entity",{uuid:s})),yr=(t,s)=>_(Fe(t,"facts",{uuid:s})),Nr=(t,s)=>_(Fe(t,"related",{uuid:s})),wr=t=>_(Fe(t,"communities")),ft=async(t,s)=>St(await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)})),vs=async t=>{const s=await fetch(t,{method:"DELETE"});!s.ok&&s.status!==404&&await St(s)};function kr(t,s){const n=new EventSource(`${t}/sessions/stream`);let r;const a=()=>{r&&clearTimeout(r),s.onStale(!1),r=setTimeout(()=>s.onStale(!0),15e3)};return n.addEventListener("session",o=>{a(),s.onSession(JSON.parse(o.data))}),n.addEventListener("remove",o=>{a(),s.onRemove(JSON.parse(o.data))}),n.addEventListener("heartbeat",a),n.onerror=()=>s.onStale(!0),a(),()=>{r&&clearTimeout(r),n.close()}}const ee=t=>`${t.namespace}/${t.name}`;function Se(t){try{const s=new URL(t);return s.protocol==="http:"||s.protocol==="https:"?t:null}catch{return null}}const Sr={gke:"GKE",eks:"EKS",aks:"AKS",local:"Local",unknown:"Cluster"},Ie="h-3.5 w-3.5 shrink-0";function Cr(){return e.jsxs("svg",{viewBox:"0 0 24 24",className:Ie,"aria-hidden":"true",fill:"none",children:[e.jsx("path",{d:"M12 2.5 L20.16 7.25 V16.75 L12 21.5 L3.84 16.75 V7.25 Z",fill:"#4285F4",fillOpacity:"0.16",stroke:"#4285F4",strokeWidth:"1.5",strokeLinejoin:"round"}),e.jsx("circle",{cx:"12",cy:"12",r:"3",stroke:"#4285F4",strokeWidth:"1.5"})]})}function $r(){return e.jsxs("svg",{viewBox:"0 0 24 24",className:Ie,"aria-hidden":"true",fill:"none",children:[e.jsx("path",{d:"M4 12.5 C 8 16.2, 16 16.2, 20 12.5",stroke:"#FF9900",strokeWidth:"2",strokeLinecap:"round"}),e.jsx("path",{d:"M16.6 12.2 L20.4 12.4 L18.9 15.6 Z",fill:"#FF9900"})]})}function Tr(){return e.jsxs("svg",{viewBox:"0 0 24 24",className:Ie,"aria-hidden":"true",children:[e.jsx("path",{d:"M12.8 3 L21 20 H14.8 L12.4 13.6 Z",fill:"#0078D4"}),e.jsx("path",{d:"M10.8 8 L3.2 20 H15 L12.8 15.4 H9 Z",fill:"#0078D4",fillOpacity:"0.7"})]})}function Lr({type:t}){switch(t){case"gke":return e.jsx(Cr,{});case"eks":return e.jsx($r,{});case"aks":return e.jsx(Tr,{});case"local":return e.jsx(Mn,{"aria-hidden":"true",className:`${Ie} text-muted-foreground`});default:return e.jsx(Fn,{"aria-hidden":"true",className:`${Ie} text-muted-foreground`})}}function Ar({apiBase:t}){const[s,n]=d.useState(null);if(d.useEffect(()=>{let u=!0;return ir(t).then(h=>{u&&n(h)}).catch(h=>{console.warn("cluster info fetch failed",h)}),()=>{u=!1}},[t]),!s)return null;const r=Sr[s.type]??"Cluster",a=s.name||r||"cluster",o=!!s.name,i=s.consoleURL?Se(s.consoleURL):null,l=e.jsxs(e.Fragment,{children:[e.jsx(Lr,{type:s.type}),e.jsx("span",{className:"max-w-[16rem] truncate font-medium text-foreground",children:a}),o&&e.jsx("span",{className:"font-mono text-[10px] uppercase tracking-wide text-muted-foreground",children:r})]}),c="flex items-center gap-1.5 rounded-full border bg-card/60 px-2 py-0.5 text-xs";return i?e.jsx("a",{href:i,target:"_blank",rel:"noopener noreferrer",title:`Open ${a} in the cloud console`,className:`${c} transition-colors hover:border-primary/50 hover:bg-accent/40`,children:l}):e.jsx("span",{className:c,title:a,children:l})}const Er={email:"admin@example.com"};function Dr(){typeof window>"u"||window.location.assign("/admin/logout")}function Rr({view:t,onNavigate:s,currentUser:n=Er,apiBase:r="/admin/api",onSignOut:a=Dr,children:o}){const i=gs[t],[l,c]=d.useState(!1),[u,h]=d.useState(!1),[N,p]=d.useState(()=>en()),b=d.useRef(null);return d.useEffect(()=>{if(!l)return;function x($){b.current&&!b.current.contains($.target)&&c(!1)}function j($){$.key==="Escape"&&c(!1)}return document.addEventListener("mousedown",x),document.addEventListener("keydown",j),()=>{document.removeEventListener("mousedown",x),document.removeEventListener("keydown",j)}},[l]),e.jsxs("div",{className:"flex h-screen flex-col bg-background text-foreground",children:[e.jsxs("header",{className:"flex shrink-0 items-center border-b bg-card/30 px-5 py-2.5",children:[e.jsxs("div",{className:"mr-auto flex items-center gap-2.5",onPointerEnter:()=>h(!0),onPointerLeave:()=>h(!1),children:[e.jsx(er,{active:u,bandWidth:32,band:14,className:"h-5 w-5 text-foreground"}),e.jsx("span",{className:"text-sm font-semibold",children:"Open Agent Primitives"}),e.jsx(Ar,{apiBase:r})]}),e.jsx("button",{type:"button","aria-label":Pe(N)==="dark"?"Switch to light theme":"Switch to dark theme",title:Pe(N)==="dark"?"Light theme":"Dark theme",onClick:()=>{const x=Pe(N)==="dark"?"light":"dark";_t(x),p(x)},className:"mr-2 grid h-7 w-7 place-items-center rounded-md border text-muted-foreground transition-colors hover:bg-surface-2 hover:text-foreground",children:Pe(N)==="dark"?e.jsx(Pn,{className:"h-3.5 w-3.5","aria-hidden":"true"}):e.jsx(Kn,{className:"h-3.5 w-3.5","aria-hidden":"true"})}),e.jsxs("div",{ref:b,className:"relative",children:[e.jsxs("button",{type:"button","aria-haspopup":"menu","aria-expanded":l,"aria-label":"User menu",onClick:()=>c(x=>!x),className:"flex items-center gap-2 rounded-md border bg-card px-2 py-1 transition-colors hover:bg-accent/50",children:[e.jsx("div",{"aria-hidden":"true",className:"grid h-6 w-6 shrink-0 place-items-center rounded-full border border-border bg-surface-3 font-mono text-[11px] font-medium uppercase leading-none text-foreground",children:n.email.trim()[0]||"?"}),e.jsx("div",{className:"text-left leading-tight",children:e.jsx("div",{className:"font-mono text-xs",children:n.email})}),e.jsx(_n,{className:`h-3.5 w-3.5 text-muted-foreground transition-transform ${l?"rotate-180":""}`})]}),l&&e.jsxs("div",{role:"menu",className:"absolute right-0 z-50 mt-1 w-44 overflow-hidden rounded-md border bg-card shadow-lg",children:[e.jsx("div",{className:"px-3 pt-2 pb-1 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground",children:"Appearance"}),e.jsx("div",{role:"group","aria-label":"Appearance",className:"flex gap-1 px-2 pb-2",children:["dark","light","system"].map(x=>e.jsx("button",{type:"button",role:"menuitemradio","aria-checked":N===x,onClick:()=>{_t(x),p(x)},className:["flex-1 rounded px-2 py-1 text-xs capitalize transition-colors",N===x?"bg-surface-active text-foreground":"text-muted-foreground hover:bg-surface-2 hover:text-foreground"].join(" "),children:x},x))}),e.jsx("div",{className:"border-t"}),e.jsxs("button",{type:"button",role:"menuitem",onClick:()=>{c(!1),a()},className:"flex w-full items-center gap-2 px-3 py-2 text-left text-sm text-foreground transition-colors hover:bg-accent",children:[e.jsx(Un,{"aria-hidden":"true",className:"h-4 w-4 text-muted-foreground"}),"Sign Out"]})]})]})]}),e.jsxs("div",{className:"flex min-h-0 flex-1",children:[e.jsx("aside",{className:"flex w-48 shrink-0 flex-col border-r bg-card/20 lg:w-60",children:e.jsx("nav",{className:"flex-1 overflow-y-auto px-2 py-1",children:ps.map(x=>e.jsxs("div",{children:[x.group&&e.jsx("p",{className:"mt-3 mb-0.5 px-2 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground",children:x.group}),x.items.map(j=>{const $=j.icon,C=t===j.id;return e.jsxs("button",{type:"button","aria-current":C?"page":void 0,onClick:()=>s(j.id),className:["flex w-full items-center gap-2 py-1.5 text-left text-sm transition-colors",C?"-ml-2 rounded-r-md bg-surface-active pl-4 pr-2 font-medium text-foreground shadow-[inset_3px_0_0_hsl(var(--state))]":"rounded-md px-2 text-foreground/80 hover:bg-surface-2 hover:text-foreground"].join(" "),children:[e.jsx($,{className:"h-4 w-4 shrink-0"}),j.label]},j.id)})]},x.group||"__root__"))})}),e.jsxs("div",{className:"flex min-w-0 flex-1 flex-col",children:[e.jsx("header",{className:"flex shrink-0 items-center justify-between border-b bg-card/10 px-6 py-3.5",children:e.jsxs("div",{children:[e.jsx("h1",{className:"text-base font-semibold",children:i.title}),e.jsx("p",{className:"text-xs text-muted-foreground",children:i.sub})]})}),e.jsx("main",{className:"flex-1 overflow-y-auto px-4 py-4 lg:px-6 lg:py-5",children:o})]})]})]})}function Or({view:t}){const s=gs[t];return e.jsxs(me,{className:"mt-2 border-dashed",children:[e.jsx(he,{children:e.jsx(fe,{className:"text-sm font-medium text-muted-foreground",children:s.title})}),e.jsx(pe,{children:e.jsx("p",{className:"text-xs text-muted-foreground",children:"This surface lands in a later Part 7 task."})})]})}const ve="/admin",Ir=new Set(ps.flatMap(t=>t.items.map(s=>s.id))),ys={session:"sessions",agent:"agents",tool:"tools",skill:"skills",source:"sources",directory:"directory",channel:"channels",identity:"identity",provider:"identity",artifact:"artifacts",user:"users"},Fr=Object.keys(ys),Mr=new Set(Fr);function Ns(t){return Mr.has(t)}const Wt={type:"view",view:"overview"};function Pr(t,s=""){const r=(t.startsWith(ve)?t.slice(ve.length):t).split("/").filter(Boolean);if(r.length===0)return Wt;const[a,...o]=r;if(r.length===1&&Ir.has(a)){const i=a,l=new URLSearchParams(s);return[...l].length>0?{type:"view",view:i,query:l}:{type:"view",view:i}}if(Ns(a)&&o.length>0){const i=o.join("/"),l=new URLSearchParams(s).get("tab")??void 0;return l?{type:"detail",entity:a,id:i,tab:l}:{type:"detail",entity:a,id:i}}return Wt}function ws(t){if(t.type==="detail"){const r=`${ve}/${t.entity}/${t.id}`;return t.tab?`${r}?tab=${encodeURIComponent(t.tab)}`:r}const s=t.query?t.query.toString():"";if(t.view==="overview"&&s==="")return ve;const n=`${ve}/${t.view}`;return s?`${n}?${s}`:n}function Kr(t){return t.type==="view"?t.view:ys[t.entity]}const pt=new Set;function _r(){for(const t of pt)t()}function Ur(t){return pt.add(t),typeof window<"u"&&window.addEventListener("popstate",t),()=>{pt.delete(t),typeof window<"u"&&window.removeEventListener("popstate",t)}}function Vr(){return typeof window>"u"?ve:window.location.pathname+window.location.search}function Wr(){return ve}function te(t){typeof window>"u"||(window.history.pushState({},"",ws(t)),_r())}function ks(){const t=d.useSyncExternalStore(Ur,Vr,Wr),s=t.indexOf("?"),n=s>=0?t.slice(0,s):t,r=s>=0?t.slice(s):"";return Pr(n,r)}function nt({title:t,subtitle:s,backLabel:n="Back",backRoute:r,tabs:a,activeTab:o,onTab:i,children:l,headerRight:c}){return e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{children:[e.jsxs("button",{type:"button",onClick:()=>{r?te(r):typeof window<"u"&&window.history.back()},className:"mb-2 inline-flex items-center gap-1 text-xs text-muted-foreground transition-colors hover:text-foreground",children:[e.jsx(Vn,{className:"h-3.5 w-3.5"}),n]}),e.jsxs("div",{className:"flex items-start justify-between gap-4",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("h2",{className:"truncate text-lg font-semibold",children:t}),s&&e.jsx("p",{className:"text-sm text-muted-foreground",children:s})]}),c&&e.jsx("div",{className:"shrink-0",children:c})]})]}),e.jsxs(tn,{value:o,onValueChange:i,children:[e.jsx(sn,{children:a.map(u=>e.jsx(nn,{value:u.id,children:u.label},u.id))}),a.map(u=>e.jsx(rn,{value:u.id,className:"mt-4",forceMount:!0,hidden:u.id!==o,children:u.id===o?l:null},u.id))]})]})}const Ss="ap_admin_";function Cs(){return typeof document<"u"}function Hr(t){if(!Cs())return null;const s=Ss+t+"=";for(const n of document.cookie.split(";")){const r=n.trimStart();if(r.startsWith(s))return decodeURIComponent(r.slice(s.length))}return null}function zr(t,s,n){if(!Cs())return;let r=`${Ss+t}=${encodeURIComponent(s)}; path=/; SameSite=Lax`;const a=365;r+=`; Expires=${new Date(Date.now()+a*864e5).toUTCString()}`,document.cookie=r}function qr(t){if(t.length>0&&t[0]==='"')try{const s=JSON.parse(t);if(typeof s=="string")return s}catch{}return t}function $t(t,s){const[n,r]=d.useState(()=>{const o=Hr(t);return o===null?s:qr(o)}),a=d.useCallback(o=>{r(o),zr(t,o)},[t]);return[n,a]}function $s({value:t,onChange:s}){return e.jsxs("div",{className:"inline-flex items-center rounded-md border bg-background p-0.5",children:[e.jsx(Ht,{label:"Grid view",active:t==="grid",onClick:()=>s("grid"),children:e.jsx(Wn,{className:"h-3.5 w-3.5"})}),e.jsx(Ht,{label:"Table view",active:t==="table",onClick:()=>s("table"),children:e.jsx(Hn,{className:"h-3.5 w-3.5"})})]})}function Ht({label:t,active:s,onClick:n,children:r}){return e.jsx("button",{type:"button","aria-label":t,"aria-pressed":s,onClick:n,className:`inline-flex h-6 w-6 items-center justify-center rounded ${s?"bg-accent text-primary":"text-muted-foreground hover:text-foreground"}`,children:r})}function Gr(t){const s=t.indexOf("/");return s<0?{ns:"",name:t}:{ns:t.slice(0,s),name:t.slice(s+1)}}function Jr(t){return t===""||t==="default"}function Z({id:t,ns:s,name:n,className:r}){const a=t!=null?Gr(t):{ns:s??"",name:n??""};return e.jsxs("span",{className:r,children:[!Jr(a.ns)&&e.jsx("span",{className:"text-muted-foreground",children:`${a.ns}/`}),a.name]})}function Yr(t){return t.button===0&&!t.metaKey&&!t.ctrlKey&&!t.shiftKey&&!t.altKey}function Ts({route:t,className:s,onClick:n,children:r}){const a=ws(t);return e.jsx("a",{href:a,className:s,onClick:o=>{n==null||n(o),Yr(o)&&(o.preventDefault(),te(t))},children:r})}function W({entity:t,id:s,tab:n,className:r,onClick:a,children:o}){return e.jsx(Ts,{route:{type:"detail",entity:t,id:s,...n?{tab:n}:{}},className:r,onClick:a,children:o})}function zt({view:t,query:s,className:n,children:r}){return e.jsx(Ts,{route:{type:"view",view:t,...s?{query:s}:{}},className:n,children:r})}const He=["hsl(var(--chart-1))","hsl(var(--chart-2))","hsl(var(--chart-3))","hsl(var(--chart-4))","hsl(var(--chart-5))"];function Ls(t){const s=Array.from(new Set(t.filter(r=>r!==""))).sort(),n=new Map;return s.forEach((r,a)=>n.set(r,He[a%He.length])),n}function As(t){if(t==="")return;let s=0;for(let n=0;n>>0)%He.length]}function rt({kind:t,className:s}){return t?e.jsxs("span",{className:`inline-flex items-center gap-1.5 rounded-full border bg-background px-2 py-0.5 font-mono text-[10px] text-muted-foreground${s?` ${s}`:""}`,children:[e.jsx(Tt,{kind:t}),t]}):null}function Tt({kind:t}){const s=As(t);return s?e.jsx("span",{"aria-hidden":"true",className:"inline-block h-2 w-2 shrink-0 rounded-full",style:{backgroundColor:s}}):null}function Qr(t){const s=t.replace(/-/g,"+").replace(/_/g,"/"),n=s.length%4===0?"":"=".repeat(4-s.length%4),r=atob(s+n),a=new Uint8Array(r.length);for(let o=0;o=1e3?`${(t/1e3).toFixed(1)}K`:`${t}`}function xe(t){return t>=1e6?`${(t/1e6).toFixed(2)}M`:t>=1e3?`${Math.round(t/1e3)}K`:`${t}`}function Lt(t,s=Date.now()){if(!t)return"—";const n=new Date(t).getTime();if(Number.isNaN(n))return"—";const r=Math.round((s-n)/1e3);if(r<45)return"just now";const a=Math.round(r/60);if(a<60)return`${a}m ago`;const o=Math.round(a/60);if(o<24)return`${o}h ago`;const i=Math.round(o/24);return i<7?`${i}d ago`:new Date(n).toLocaleDateString()}const Xr={Valid:"success",Ready:"success",Connected:"success",Reachable:"success",Synced:"success",Healthy:"success",Active:"success",Degraded:"warning",Syncing:"warning",Pending:"warning",Progressing:"warning",Failed:"destructive",Invalid:"destructive",Error:"destructive",Down:"destructive",Running:"primary",Deferred:"primary"},Zr={success:"border-success/40 bg-success/10 text-success",warning:"border-warning/40 bg-warning/10 text-warning",destructive:"border-destructive/40 bg-destructive/10 text-destructive",primary:"border-primary/40 bg-primary/10 text-primary",muted:"border-border bg-background text-muted-foreground"};function Es(t){return Xr[t]??"muted"}function Ds(t){return Zr[t]}function at(t){return Ds(Es(t))}function At({phase:t}){return e.jsx("span",{className:`inline-flex items-center rounded-full border px-2 py-0.5 text-[10px] ${at(t??"")}`,children:t||"—"})}function Br({s:t,onOpen:s}){const n=t.active?"bg-primary":t.phase==="Failed"?"bg-destructive":"bg-success",r=t.pendingToolGrants+t.pendingLeakageApprovals;return e.jsxs(me,{className:"cursor-pointer transition-colors hover:border-primary/50",onClick:s,children:[e.jsx(he,{className:"pb-2",children:e.jsxs(fe,{className:"flex items-center justify-between text-sm font-medium",children:[e.jsxs("span",{className:"flex items-center gap-2",children:[e.jsx("span",{className:Ge("inline-block h-2 w-2 rounded-full",n,t.active&&"animate-ap-pulse-dot")}),e.jsxs("span",{className:"font-mono",children:[t.class??"?"," / ",e.jsx(Z,{ns:t.namespace,name:t.name})]})]}),e.jsx(At,{phase:t.phase})]})}),e.jsxs(pe,{className:"space-y-2 text-xs text-muted-foreground",children:[t.statusText&&e.jsx("p",{className:"truncate font-mono",children:t.statusText}),e.jsxs("p",{className:"font-mono",children:[ge(t.inputTokens)," in · ",ge(t.outputTokens)," out · ",t.elapsedSeconds,"s · ",t.toolCallCount," tools"]}),e.jsxs("div",{className:"flex gap-2",children:[t.channelKind&&e.jsx(z,{variant:"outline",children:t.channelKind}),r>0&&e.jsxs(z,{variant:"destructive",children:[r," approval",r>1?"s":""," pending"]})]}),t.active&&e.jsx("div",{className:"h-0.5 rounded bg-gradient-to-r from-primary via-state to-primary bg-[length:200%_100%] animate-ap-flow"})]})]})}function qt(t){te({type:"detail",entity:"session",id:`${t.namespace}/${t.name}`})}function ea({kinds:t,value:s,onChange:n}){const r="rounded-full border px-2 py-0.5 text-[10px] transition-colors",a="border-border bg-background text-muted-foreground hover:bg-accent/50",o="border-primary/40 bg-primary/10 text-primary";return e.jsxs("div",{className:"flex flex-wrap items-center gap-1.5",children:[e.jsx("button",{type:"button","aria-pressed":s==="",onClick:()=>n(""),className:`${r} ${s===""?o:a}`,children:"All"}),t.map(i=>{const l=s===i;return e.jsx("button",{type:"button","aria-pressed":l,onClick:()=>n(l?"":i),className:`${r} ${l?o:a}`,children:i},i)})]})}function ta({apiBase:t}){const[s,n]=d.useState(new Map),[r,a]=d.useState(!1),[o,i]=d.useState(null),[l,c]=d.useState(""),[u,h]=$t("sessions_view","grid");d.useEffect(()=>{let x=!1;const j=new Map;let $=0;const C=()=>{const w=++$;j.clear(),_(`${t}/sessions`).then(R=>{if(x||w!==$)return;const O=new Map(R.map(L=>[ee(L),L]));for(const[L,k]of j)k?O.set(L,k):O.delete(L);j.clear(),n(O),i(null)}).catch(R=>{x||i(R.message)})};C();let E=!1;const m=kr(t,{onSession:w=>{j.set(ee(w),w),n(R=>new Map(R).set(ee(w),w))},onRemove:w=>{j.set(ee(w),null),n(R=>{const O=new Map(R);return O.delete(ee(w)),O})},onStale:w=>{a(w),!w&&E&&C(),E=w}});return()=>{x=!0,m()}},[t]);const N=[...s.values()].sort((x,j)=>(j.startedAt??"").localeCompare(x.startedAt??"")),p=[...new Set(N.map(x=>x.channelKind).filter(x=>!!x))].sort(),b=l?N.filter(x=>x.channelKind===l):N;return e.jsxs("div",{className:"space-y-4",children:[o&&e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load sessions: ",o]})}),r&&e.jsx(I,{children:e.jsx(F,{children:"Live feed stalled — showing last known state."})}),e.jsxs("div",{className:"flex items-center justify-between gap-4",children:[p.length>0?e.jsx(ea,{kinds:p,value:l,onChange:c}):e.jsx("span",{}),e.jsx($s,{value:u,onChange:h})]}),b.length===0&&!o&&e.jsx("p",{className:"text-sm text-muted-foreground",children:N.length===0?"No sessions.":"No sessions match this filter."}),b.length>0&&u==="grid"&&e.jsx("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3",children:b.map(x=>e.jsx(Br,{s:x,onOpen:()=>qt(x)},ee(x)))}),b.length>0&&u==="table"&&e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{children:"Session"}),e.jsx(y,{children:"Class"}),e.jsx(y,{children:"Channel"}),e.jsx(y,{children:"Phase"}),e.jsx(y,{children:"Tokens"}),e.jsx(y,{children:"Started"})]})}),e.jsx(X,{children:b.map(x=>e.jsxs(M,{className:"cursor-pointer",onClick:()=>qt(x),children:[e.jsx(v,{className:"font-mono text-xs text-foreground",children:e.jsx(Z,{id:ee(x)})}),e.jsx(v,{className:"font-mono text-xs",children:x.class?e.jsx(W,{entity:"agent",id:`${x.namespace}/${x.class}`,className:"text-link hover:underline",onClick:j=>j.stopPropagation(),children:x.class}):e.jsx("span",{className:"text-muted-foreground",children:"—"})}),e.jsxs(v,{className:"text-xs",children:[x.channelName?e.jsx(W,{entity:"channel",id:`${x.namespace}/${x.channelName}`,className:"font-mono text-link hover:underline",onClick:j=>j.stopPropagation(),children:e.jsx(Z,{ns:x.namespace,name:x.channelName})}):!x.channelKind&&e.jsx("span",{className:"font-mono text-muted-foreground",children:"—"}),x.channelKind&&e.jsx(rt,{kind:x.channelKind,className:x.channelName?"ml-1.5":""})]}),e.jsx(v,{children:e.jsx(At,{phase:x.phase})}),e.jsxs(v,{className:"whitespace-nowrap font-mono text-xs text-muted-foreground",children:[ge(x.inputTokens)," in · ",ge(x.outputTokens)," out"]}),e.jsxs(v,{className:"whitespace-nowrap text-xs text-muted-foreground",children:[Lt(x.startedAt),x.startedBy&&e.jsxs("span",{className:"mt-0.5 flex items-center gap-1.5 text-[10px] text-muted-foreground/70",children:[e.jsx(Tt,{kind:x.startedBy}),e.jsx(W,{entity:"user",id:x.startedBy,className:"font-mono text-link hover:underline",children:ae(x.startedBy)})]})]})]},ee(x)))})]})]})}function sa(t){const s=new Date(t);return Number.isNaN(s.getTime())?t:s.toLocaleTimeString()}const na=4e3;function ra({apiBase:t}){const[s,n]=d.useState([]),[r,a]=d.useState(null),[o,i]=d.useState(!1);return d.useEffect(()=>{let l=!0;const c=()=>{dr(t).then(h=>{l&&(n(h),a(null),i(!0))}).catch(h=>{l&&(a(h.message),i(!0))})};c();const u=setInterval(c,na);return()=>{l=!1,clearInterval(u)}},[t]),e.jsxs("div",{className:"space-y-3",children:[r&&e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load tool calls: ",r]})}),o&&s.length===0&&!r&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"No tool calls yet — they appear here as agents dispatch them."}),s.length>0&&e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{children:"When"}),e.jsx(y,{children:"Session"}),e.jsx(y,{children:"Agent"}),e.jsx(y,{children:"Tool"})]})}),e.jsx(X,{children:s.map((l,c)=>e.jsxs(M,{children:[e.jsx(v,{className:"whitespace-nowrap font-mono text-xs text-muted-foreground",children:sa(l.t)}),e.jsx(v,{className:"font-mono text-xs",children:e.jsx(W,{entity:"session",id:ee(l),className:"text-link hover:underline",children:e.jsx(Z,{id:ee(l)})})}),e.jsx(v,{className:"text-xs",children:l.agentClass?e.jsx(W,{entity:"agent",id:`${l.namespace}/${l.agentClass}`,className:"text-link hover:underline",children:l.agentClass}):"(unknown)"}),e.jsx(v,{className:"font-mono text-xs text-foreground",children:l.tool||"(tool)"})]},`${ee(l)}-${l.t}-${c}`))})]})]})}const aa=4e3,oa={tool_call:{label:"Tool call",cls:"border-warning/40 text-warning"},leakage:{label:"Leakage",cls:"border-state/40 text-state"},content_inspection:{label:"Content",cls:"border-warning/40 text-warning"}};function la(t){const s=new Date(t).getTime();if(Number.isNaN(s)||s{let c=!0;const u=()=>{xr(t).then(N=>{c&&(r(N),o(null),l(!0))}).catch(N=>{c&&(o(N.message),l(!0))})};u();const h=setInterval(u,aa);return()=>{c=!1,clearInterval(h)}},[t]),e.jsxs("div",{className:"space-y-3",children:[a&&e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load approvals: ",a]})}),i&&n.length===0&&!a&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"Nothing awaiting a decision — pending approvals appear here as agents request them."}),n.length>0&&e.jsx("div",{className:"grid grid-cols-1 gap-3 lg:grid-cols-2",children:n.map((c,u)=>{const h=oa[c.kind]??{label:c.kind,cls:"border-input text-muted-foreground"},N=la(c.requestedAt);return e.jsxs(me,{className:"ring-1 ring-warning/20",children:[e.jsx(he,{className:"pb-2",children:e.jsxs(fe,{className:"flex items-center justify-between text-sm font-medium",children:[e.jsx("span",{className:"font-mono",children:c.tool||h.label}),e.jsx(z,{variant:"outline",className:Ge(h.cls),children:h.label})]})}),e.jsxs(pe,{className:"space-y-3 text-xs text-muted-foreground",children:[e.jsxs("p",{className:"font-mono",children:[c.agentClass||"(unknown)"," / ",ee(c)]}),e.jsxs("div",{className:"flex items-center justify-between",children:[c.requester?e.jsxs("span",{children:["requested by ",e.jsx("span",{className:"text-foreground",children:c.requester})]}):e.jsx("span",{}),N&&e.jsxs("span",{className:"rounded-full border border-warning/40 bg-warning/10 px-2 py-0.5 text-[10px] text-warning",children:["waiting ",N]})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(U,{variant:"outline",size:"sm",disabled:!s,onClick:()=>s==null?void 0:s(c.namespace,c.name),children:"Open session"}),e.jsx("span",{className:"text-[11px] text-muted-foreground",children:"decide in the channel thread"})]})]})]},`${ee(c)}-${c.kind}-${c.requestedAt}-${u}`)})}),n.length>0&&e.jsx("p",{className:"text-[11px] text-muted-foreground",children:"Read-only — decisions happen in the originating channel thread. Open the session to watch it."})]})}const ze="w-full rounded-md border border-border bg-background px-2 py-1.5 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:opacity-50";function gt({label:t,children:s}){return e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx("span",{className:"text-[10px] font-medium uppercase tracking-wide text-muted-foreground",children:t}),e.jsx("div",{className:"text-sm text-foreground",children:s})]})}function Gt(t){return t==null?"":typeof t=="string"?t:Array.isArray(t)?t.join(","):String(t)}function ca({q:t,value:s,onChange:n}){const r=t.required!==!1,a=`${t.prompt||t.name}${r?" *":""}`;return e.jsxs(gt,{label:a,children:[t.type==="bool"?e.jsx("input",{type:"checkbox",checked:s==="true",onChange:o=>n(o.target.checked?"true":"false"),"aria-label":a,className:"h-4 w-4 rounded border-border"}):t.type==="enum"?e.jsxs("select",{value:s,onChange:o=>n(o.target.value),"aria-label":a,className:ze,children:[e.jsx("option",{value:"",disabled:!0,children:"Select…"}),(t.enum??[]).map((o,i)=>{var u;const l=(u=t.enumLabels)==null?void 0:u[i],c=l!==void 0&&l.trim()!==""?l:o;return e.jsx("option",{value:o,children:c},o)})]}):e.jsx("input",{type:t.type==="secret"?"password":t.type==="int"?"number":"text",value:s,onChange:o=>n(o.target.value),"aria-label":a,placeholder:t.type==="resourceList"?"comma-separated":void 0,autoComplete:t.type==="secret"?"new-password":"off",className:ze}),t.description&&e.jsx("p",{className:"text-[11px] text-muted-foreground",children:t.description})]})}function da({apiBase:t,row:s,onDone:n}){const[r,a]=d.useState(!1),[o,i]=d.useState(s.namespace),[l,c]=d.useState(s.suggestedName??""),[u,h]=d.useState({}),[N,p]=d.useState(null),[b,x]=d.useState([]),[j,$]=d.useState([]),[C,E]=d.useState(null),[m,w]=d.useState(!1),R=()=>{x([]),$([])},O=(g,T)=>{h(P=>({...P,[g]:T})),R()},L=()=>{E(null),p(null),R()},k=async()=>{E(null),w(!0);try{await ar(t,s.namespace,s.name,{namespace:o,name:l,values:u,adopt:j}),a(!1),L(),n()}catch(g){g instanceof tt?(p(g.questions),h(T=>{const P={...T};for(const V of g.questions)P[V.name]===void 0&&V.default!==void 0&&V.default!==null&&(P[V.name]=Gt(V.default));return P})):g instanceof st?x(g.conflicts):(g instanceof J,E(g.message))}finally{w(!1)}};return e.jsxs(Je,{open:r,onOpenChange:g=>{a(g),g||L()},children:[e.jsx(Ye,{asChild:!0,children:e.jsx(U,{size:"sm",children:"Install"})}),e.jsxs(Qe,{children:[e.jsxs(Xe,{children:[e.jsxs(Ze,{children:["Install ",s.suggestedName||s.name]}),e.jsx(Be,{children:"Installs this workshop's drafted bundle under the operator identity. No secret answer is ever pre-filled — type it below."})]}),e.jsxs("div",{className:"flex flex-col gap-3",children:[C&&e.jsx(I,{variant:"destructive",children:e.jsx(F,{children:C})}),e.jsxs("div",{className:"grid grid-cols-1 gap-3 sm:grid-cols-2",children:[e.jsx(gt,{label:"Namespace *",children:e.jsx("input",{type:"text",value:o,onChange:g=>{i(g.target.value),R()},"aria-label":"Namespace",className:ze})}),e.jsx(gt,{label:"Name (optional)",children:e.jsx("input",{type:"text",value:l,onChange:g=>{c(g.target.value),R()},placeholder:"defaults to the bundle's own name","aria-label":"Name",className:ze})})]}),b.length>0&&e.jsxs("div",{className:"flex flex-col gap-2 rounded-md border border-destructive/50 p-3",children:[e.jsx("p",{className:"text-xs font-medium text-foreground",children:"These objects already exist and were not created by this install. Adopting one overwrites its spec with this bundle's."}),b.map(g=>{const T=`${g.kind}/${g.name}`,P=g.namespace?`${g.kind} ${g.namespace}/${g.name}`:T;return e.jsxs("label",{className:"flex items-center gap-2 text-xs text-foreground",children:[e.jsx("input",{type:"checkbox",checked:j.includes(T),"aria-label":P,onChange:V=>$(q=>V.target.checked?[...q,T]:q.filter(ie=>ie!==T)),className:"h-4 w-4 rounded border-border"}),e.jsx("span",{children:P}),g.secret&&e.jsx("span",{className:"text-destructive",children:"overwrites this Secret's data"})]},T)})]}),N&&N.length>0&&e.jsxs("div",{className:"flex flex-col gap-3 rounded-md border border-dashed border-border p-3",children:[e.jsxs("p",{className:"text-xs text-muted-foreground",children:["This bundle needs ",N.length===1?"an answer":"answers"," before it can install:"]}),N.map(g=>e.jsx(ca,{q:g,value:u[g.name]??Gt(g.default),onChange:T=>O(g.name,T)},g.name))]})]}),e.jsxs(et,{children:[e.jsx(wt,{asChild:!0,children:e.jsx(U,{variant:"outline",children:"Cancel"})}),e.jsx(U,{onClick:k,disabled:m||o.trim()==="",children:m?"Installing…":b.length>0&&j.length>0?"Adopt and install":N?"Submit answers":"Confirm install"})]})]})]})}function ua({apiBase:t,row:s,onDone:n}){const[r,a]=d.useState(!1),[o,i]=d.useState(null),l=async()=>{i(null),a(!0);try{await ft(`${t}/workshops/${s.namespace}/${s.name}/decline`,{}),n()}catch(c){i(c.message)}finally{a(!1)}};return e.jsxs("span",{className:"flex flex-col items-end gap-1",children:[e.jsx(U,{variant:"outline",size:"sm",onClick:l,disabled:r,children:r?"Declining…":"Decline"}),o&&e.jsx("span",{className:"text-[11px] text-destructive",children:o})]})}function xa({apiBase:t,row:s,onDone:n}){const[r,a]=d.useState(!1),[o,i]=d.useState(null),[l,c]=d.useState(!1),u=async()=>{i(null),c(!0);try{await vs(`${t}/workshops/${s.namespace}/${s.name}`),a(!1),n()}catch(h){i(h.message)}finally{c(!1)}};return e.jsxs(Je,{open:r,onOpenChange:a,children:[e.jsx(Ye,{asChild:!0,children:e.jsx(U,{variant:"destructive",size:"sm",children:"Kill"})}),e.jsxs(Qe,{children:[e.jsxs(Xe,{children:[e.jsxs(Ze,{children:["Kill workshop ",s.name,"?"]}),e.jsx(Be,{children:"Deletes the Workshop — its provisioned builder namespace is torn down. This cannot be undone."})]}),o&&e.jsx(I,{variant:"destructive",children:e.jsx(F,{children:o})}),e.jsxs(et,{children:[e.jsx(wt,{asChild:!0,children:e.jsx(U,{variant:"outline",children:"Cancel"})}),e.jsx(U,{variant:"destructive",onClick:u,disabled:l,children:l?"Killing…":"Kill it"})]})]})]})}function ma({apiBase:t}){const[s,n]=d.useState([]),[r,a]=d.useState(null),[o,i]=d.useState(!1),l=d.useCallback(()=>{pr(t).then(c=>{n(c),a(null),i(!0)}).catch(c=>{a(c.message),i(!0)})},[t]);return d.useEffect(()=>{l()},[l]),r?e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load workshops: ",r]})}):e.jsxs("div",{className:"space-y-3",children:[o&&s.length===0&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"No workshops yet."}),s.length>0&&e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{children:"Workshop"}),e.jsx(y,{children:"Session"}),e.jsx(y,{children:"Starter"}),e.jsx(y,{children:"Phase"}),e.jsx(y,{children:"Install"}),e.jsx(y,{className:"text-right",children:"Actions"})]})}),e.jsx(X,{children:s.map(c=>{const u=`${c.namespace}/${c.name}`;return e.jsxs(M,{children:[e.jsxs(v,{className:"font-mono text-xs",children:[u,c.exported&&e.jsx(z,{variant:"outline",className:"ml-2",children:"exported"})]}),e.jsx(v,{className:"font-mono text-xs text-muted-foreground",children:c.session}),e.jsx(v,{className:"font-mono text-xs text-muted-foreground",children:c.starter}),e.jsx(v,{children:e.jsx(z,{variant:"outline",children:c.phase||"—"})}),e.jsx(v,{className:"font-mono text-xs text-muted-foreground",children:c.installPhase?e.jsxs("span",{className:"flex items-center gap-2",children:[e.jsx(z,{variant:c.installPhase==="Failed"?"destructive":"outline",children:c.installPhase}),c.installedRef&&e.jsx("span",{children:c.installedRef})]}):c.pendingCapability?"capability requested":"—"}),e.jsx(v,{className:"text-right",children:e.jsxs("div",{className:"flex justify-end gap-2",children:[c.pendingInstall&&e.jsxs(e.Fragment,{children:[e.jsx(da,{apiBase:t,row:c,onDone:l}),e.jsx(ua,{apiBase:t,row:c,onDone:l})]}),e.jsx(xa,{apiBase:t,row:c,onDone:l})]})})]},u)})})]}),e.jsx("p",{className:"text-[11px] text-muted-foreground",children:"Workshop — an agent-builder session's drafted bundle, awaiting an admin's install/decline/kill decision."})]})}function qe({value:t,className:s}){const[n,r]=d.useState(!1);return e.jsxs("div",{className:Ge("rounded border border-border bg-background/40 text-xs",s),children:[e.jsx("div",{className:"flex justify-end border-b border-border/50 px-1.5 py-0.5",children:e.jsx("button",{type:"button",onClick:()=>r(a=>!a),className:"font-mono text-[10px] uppercase tracking-wide text-muted-foreground hover:text-foreground","aria-pressed":n,children:n?"tree":"raw"})}),e.jsx("div",{className:"overflow-x-auto p-2 font-mono leading-relaxed",children:n?e.jsx("pre",{className:"whitespace-pre-wrap break-words text-foreground",children:ha(t)}):e.jsx(Os,{value:t})})]})}function ha(t){const s=JSON.stringify(t,null,2);return s===void 0?String(t):s}function Rs(t){const s=t.trim();if(!(!s.startsWith("{")&&!s.startsWith("[")))try{return JSON.parse(s)}catch{return}}function Os({value:t,label:s}){return t===null||typeof t!="object"?e.jsxs("div",{className:"flex flex-wrap items-start gap-1.5",children:[s!==void 0&&e.jsxs("span",{className:"shrink-0 text-foreground/70",children:[s,":"]}),e.jsx(pa,{value:t})]}):e.jsx(ga,{value:t,label:s})}function fa(t){switch(typeof t){case"string":return"text-success";case"number":return"text-primary";case"boolean":return"text-state";default:return"text-muted-foreground"}}function pa({value:t}){const s=typeof t=="string"?JSON.stringify(t):String(t);return e.jsx("span",{className:fa(t),children:s})}function ga({value:t,label:s}){const[n,r]=d.useState(!0),a=Array.isArray(t),o=a?t.map((u,h)=>[String(h),u]):Object.entries(t),[i,l]=a?["[","]"]:["{","}"],c=s!==void 0?e.jsxs("span",{className:"text-foreground/70",children:[s,": "]}):null;return o.length===0?e.jsxs("div",{children:[c,e.jsxs("span",{className:"text-muted-foreground",children:[i,l]})]}):e.jsxs("div",{children:[e.jsxs("button",{type:"button",onClick:()=>r(u=>!u),"aria-expanded":n,className:"text-muted-foreground hover:text-foreground",children:[c,e.jsx("span",{"aria-hidden":"true",children:n?"▾":"▸"})," ",i,!n&&e.jsxs("span",{className:"text-muted-foreground",children:[" ","…",o.length," ",l]})]}),n&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"ml-2 border-l border-border/40 pl-2",children:o.map(([u,h])=>e.jsx(Os,{value:h,label:a?void 0:u},u))}),e.jsx("div",{className:"text-muted-foreground",children:l})]})]})}const ja=560,De=28,be={channel:60,agent:260,tools:470};function dt({x:t,y:s,label:n,stroke:r}){return e.jsxs("g",{children:[e.jsx("circle",{cx:t,cy:s,r:De,fill:"hsl(var(--card))",stroke:r,strokeWidth:1.5}),e.jsx("text",{x:t,y:s+4,textAnchor:"middle",fontSize:10,fill:"hsl(var(--foreground))",fontFamily:"monospace",children:n.length>11?n.slice(0,10)+"…":n})]})}function Jt({x1:t,y1:s,x2:n,y2:r,active:a}){return e.jsx("path",{className:a?"ap-edge-active":void 0,d:`M ${t} ${s} C ${(t+n)/2} ${s}, ${(t+n)/2} ${r}, ${n} ${r}`,fill:"none",stroke:a?"hsl(var(--primary))":"hsl(var(--border))",strokeWidth:1.5,strokeDasharray:a?"6 6":void 0,children:a&&e.jsx("animate",{attributeName:"stroke-dashoffset",from:"24",to:"0",dur:"0.9s",repeatCount:"indefinite"})})}function ba({channelKind:t,agentClass:s,tools:n,active:r}){const a=n.slice(0,8),o=Math.max(160,a.length*64+40),i=o/2;return e.jsxs("svg",{viewBox:`0 0 ${ja} ${o}`,className:"w-full",role:"img","aria-label":"session flow graph",children:[e.jsx(Jt,{x1:be.channel+De,y1:i,x2:be.agent-De,y2:i,active:r}),a.map((l,c)=>{const u=40+c*64+12;return e.jsxs(d.Fragment,{children:[e.jsx(Jt,{x1:be.agent+De,y1:i,x2:be.tools-De,y2:u,active:r}),e.jsx(dt,{x:be.tools,y:u,label:l,stroke:"hsl(var(--state))"})]},l)}),e.jsx(dt,{x:be.channel,y:i,label:t??"channel",stroke:"hsl(var(--success))"}),e.jsx(dt,{x:be.agent,y:i,label:s??"agent",stroke:"hsl(var(--primary))"})]})}const va=[{id:"overview",label:"Overview"},{id:"activity",label:"Recent Activity"},{id:"logs",label:"Full Logs"}];function ya(t){const s=t.indexOf("/");return s<0?{ns:"",name:t}:{ns:t.slice(0,s),name:t.slice(s+1)}}function Na(t){var n;const s=new Set;for(const r of t.recentEvents)if(r.kind==="tool_activity"){const a=(n=r.payload)==null?void 0:n.tool;a&&s.add(a)}return[...s]}function wa({apiBase:t,id:s,tab:n}){const{ns:r,name:a}=ya(s),o=n??"overview",i=`${t}/sessions/${r}/${a}`,[l,c]=d.useState(null),[u,h]=d.useState(null),[N,p]=d.useState(!1),[b,x]=d.useState(null),[j,$]=d.useState(null),[C,E]=d.useState(!1),m=d.useRef(null);d.useEffect(()=>()=>{m.current!==null&&clearTimeout(m.current)},[]),d.useEffect(()=>{let O=!0;return c(null),h(null),p(!1),_(i).then(L=>{O&&c(L)}).catch(L=>{O&&(L instanceof J&&L.status===404?p(!0):h(L.message))}),()=>{O=!1}},[i]);const w=async()=>{$(null);try{await vs(i),E(!1),x("Session terminated."),m.current=setTimeout(()=>te({type:"view",view:"sessions"}),800)}catch(O){E(!1),$(O.message)}},R=O=>te({type:"detail",entity:"session",id:s,tab:O});return e.jsx(nt,{title:e.jsxs("span",{className:"font-mono",children:[l&&`${l.class??"?"} / `,e.jsx(Z,{ns:r,name:a})]}),backRoute:{type:"view",view:"sessions"},tabs:va,activeTab:o,onTab:R,headerRight:l!=null&&l.phase?e.jsx(z,{variant:"outline",children:l.phase}):void 0,children:o==="logs"?e.jsx($a,{apiBase:t,ns:r,name:a}):u?e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load session: ",u]})}):N?e.jsxs("p",{className:"text-sm text-muted-foreground",children:["Session ",s," is not tracked — it may have completed or never started."]}):l?o==="activity"?e.jsx(Ca,{detail:l}):e.jsx(ka,{detail:l,name:a,killNote:b,killError:j,killOpen:C,onKillOpenChange:E,onKill:w}):e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading…"})})}function ka({detail:t,name:s,killNote:n,killError:r,killOpen:a,onKillOpenChange:o,onKill:i}){return e.jsxs("div",{className:"flex flex-col gap-4",children:[n&&e.jsx("p",{className:"text-sm text-success",children:n}),r&&e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not kill session: ",r]})}),e.jsx("div",{className:"rounded-lg border border-border bg-card p-4",children:e.jsx(ba,{channelKind:t.channelKind,agentClass:t.class,tools:Na(t),active:t.active})}),t.statusText&&e.jsx("p",{className:"font-mono text-sm text-muted-foreground",children:t.statusText}),e.jsxs("p",{className:"font-mono text-xs text-muted-foreground",children:[ge(t.inputTokens)," in · ",ge(t.outputTokens)," out · ",t.toolCallCount," tool calls · turn ",t.turnCount]}),e.jsxs("dl",{className:"grid grid-cols-2 gap-x-6 gap-y-2 text-xs sm:grid-cols-3",children:[e.jsx(Ae,{label:"Phase",value:t.phase??"—"}),e.jsx(Ae,{label:"Model",children:t.model?e.jsx(kt,{model:t.model}):"—"}),e.jsx(Ae,{label:"Elapsed",value:`${t.elapsedSeconds}s`}),t.startedAt&&e.jsx(Ae,{label:"Started",value:new Date(t.startedAt).toLocaleString()}),t.activityCause&&e.jsx(Ae,{label:"Activity",value:t.activityCause})]}),t.bundles&&t.bundles.length>0&&e.jsx(Sa,{bundles:t.bundles}),e.jsxs(Je,{open:a,onOpenChange:o,children:[e.jsx(Ye,{asChild:!0,children:e.jsx(U,{variant:"destructive",className:"mt-2 self-start",children:"Kill session"})}),e.jsxs(Qe,{children:[e.jsxs(Xe,{children:[e.jsxs(Ze,{children:["Kill ",s,"?"]}),e.jsx(Be,{children:"Deletes the AgentSession — the runner pod is torn down immediately. This cannot be undone."})]}),e.jsxs(et,{children:[e.jsx(wt,{asChild:!0,children:e.jsx(U,{variant:"outline",children:"Cancel"})}),e.jsx(U,{variant:"destructive",onClick:i,children:"Kill it"})]})]})]})]})}function Ae({label:t,value:s,children:n}){return e.jsxs("div",{className:"flex flex-col",children:[e.jsx("dt",{className:"text-[10px] uppercase tracking-wide text-muted-foreground",children:t}),e.jsx("dd",{className:"font-mono text-foreground",children:n??s})]})}function Sa({bundles:t}){return e.jsxs("div",{className:"rounded-lg border border-border bg-card p-4",children:[e.jsx("h3",{className:"mb-2 text-[10px] uppercase tracking-wide text-muted-foreground",children:"Bundles"}),e.jsx("ul",{className:"space-y-2",children:t.map(s=>e.jsxs("li",{className:"flex flex-wrap items-center gap-2 font-mono text-xs",children:[e.jsx("span",{className:"font-semibold text-foreground",children:s.name}),e.jsx("span",{className:"text-muted-foreground",children:s.spiceboxSessionName}),s.sandboxKind?e.jsxs(e.Fragment,{children:[e.jsx(z,{variant:"outline",children:s.sandboxKind}),e.jsx("span",{className:"break-all text-muted-foreground",children:s.sandboxRef}),s.prewarmed&&e.jsx(z,{variant:"outline",children:"warm"})]}):e.jsx("span",{className:"text-muted-foreground",children:"sandbox not yet resolved"}),s.workspaceMode&&e.jsxs(z,{variant:"outline",children:[s.workspaceMode," workspace"]}),s.phase&&e.jsx(z,{variant:s.phase==="Failed"?"destructive":"outline",children:s.phase}),s.reason&&e.jsx("span",{className:"text-muted-foreground",children:s.reason})]},s.name))})]})}function Ca({detail:t}){return t.recentEvents.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No recent activity."}):e.jsx("ul",{className:"space-y-1 font-mono text-xs text-muted-foreground",children:t.recentEvents.slice().reverse().map((s,n)=>e.jsxs("li",{children:[new Date(s.at).toLocaleTimeString()," · ",s.kind]},n))})}function $a({apiBase:t,ns:s,name:n}){const[r,a]=d.useState(null),[o,i]=d.useState(null);return d.useEffect(()=>{let l=!0;return a(null),i(null),ur(t,s,n).then(c=>{l&&a(c)}).catch(c=>{l&&i(c.message)}),()=>{l=!1}},[t,s,n]),o?e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load logs: ",o]})}):r?r.entries.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No transcript entries yet."}):e.jsxs("div",{className:"space-y-3",children:[r.truncated&&e.jsxs("p",{className:"text-xs text-warning",children:["Showing the latest ",r.entries.length," entries — older turns were truncated."]}),e.jsx("ul",{className:"space-y-2",children:r.entries.map(l=>e.jsx(La,{entry:l},l.id))})]}):e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading logs…"})}function Ta(t){switch(t){case"user":case"inbox":return{container:"border-state/40 bg-state/5",badge:"bg-state/15 text-state"};case"assistant":return{container:"border-primary/40 bg-primary/5",badge:"bg-primary/15 text-primary"};case"tool":return{container:"border-warning/40 bg-warning/5",badge:"bg-warning/15 text-warning"};default:return{container:"border-border bg-card",badge:"bg-muted text-muted-foreground"}}}function La({entry:t}){const s=t.role||t.kind,n=Ta(t.role??"");return e.jsxs("li",{className:`rounded-md border p-3 ${n.container}`,children:[e.jsxs("div",{className:"mb-2 flex items-center justify-between gap-2 font-mono text-[11px] text-muted-foreground",children:[e.jsxs("span",{className:"flex items-center gap-2",children:[e.jsx("span",{className:`rounded px-1.5 py-0.5 text-[10px] uppercase tracking-wide ${n.badge}`,children:s}),t.actor&&e.jsxs("span",{className:"flex items-center gap-1",children:[t.actorInferred?"requested by":"by"," ",e.jsx(W,{entity:"user",id:t.actor,className:"text-link hover:underline",children:ae(t.actor)}),t.actorInferred&&e.jsxs("span",{className:"text-muted-foreground/60",title:"Session initiator — this legacy turn predates per-turn authorship.",children:[" ","(session initiator)"]})]})]}),e.jsx("span",{children:new Date(t.createdAt).toLocaleString()})]}),t.blocks&&t.blocks.length>0?e.jsx("div",{className:"space-y-2",children:t.blocks.map((r,a)=>e.jsx(Aa,{block:r,role:t.role??""},a))}):e.jsx(jt,{text:t.content,className:"text-foreground"})]})}function Aa({block:t,role:s}){if(t.type==="tool_use")return e.jsxs("div",{className:"rounded border border-warning/40 bg-warning/5 p-2",children:[e.jsxs("div",{className:"mb-1 font-mono text-[11px] text-warning",children:["→ ",t.name||"tool"]}),e.jsx(qe,{value:t.input??{}})]});if(t.type==="tool_result"){const r=t.isError,a=r?"border-destructive/50 bg-destructive/10":"border-success/40 bg-success/5",o=r?"text-destructive":"text-success",i=Ea(t.content);return e.jsxs("div",{className:`rounded border p-2 ${a}`,children:[e.jsxs("div",{className:`mb-1 font-mono text-[11px] ${o}`,children:["← ",r?"error":"result"]}),i!==null?e.jsx(jt,{text:i,className:"text-foreground/90"}):e.jsx(qe,{value:t.content??""})]})}const n=s==="assistant"?"text-foreground":"text-foreground/90";return e.jsx(jt,{text:t.text??"",className:n})}function Ea(t){if(typeof t!="string")return null;let s=t;if(s.length>=2&&s.startsWith('"')&&s.endsWith('"'))try{const n=JSON.parse(s);typeof n=="string"&&(s=n)}catch{}return s.includes("]*)?>/g;function Yt({chunk:t}){const s=Rs(t);return s!==void 0?e.jsx(qe,{value:s,className:"my-1"}):e.jsx("span",{className:"rounded-sm bg-muted/40 text-muted-foreground",children:t})}function jt({text:t,className:s}){const n=`whitespace-pre-wrap break-words font-mono text-xs ${s??""}`;if(!t.includes("t.stopPropagation(),Ra=t=>t==="denied"||t==="read_denied"||t==="failed"?"destructive":t==="pending"?"secondary":"outline",Is=[{key:"kind",label:"Kind",value:t=>t.kind},{key:"outcome",label:"Outcome",value:t=>t.outcome},{key:"agent",label:"Agent",value:t=>t.agentClass??""},{key:"tool",label:"Tool",value:t=>t.tool??""},{key:"actor",label:"Actor",value:t=>t.actor?ae(t.actor):""}];function Oa(t){return{kind:t.kind,outcome:t.outcome,agent:t.agentClass??"",tool:t.tool??"",actor:t.actor?ae(t.actor):""}}function Ee({color:t}){return t?e.jsx("span",{className:"mr-1.5 inline-block h-2 w-2 shrink-0 rounded-full align-middle",style:{backgroundColor:t}}):null}function Ia({colorMaps:t}){return e.jsx("div",{role:"group","aria-label":"Color legends",className:"grid gap-2 rounded-md border border-border bg-card p-2 text-xs sm:grid-cols-2 lg:grid-cols-3",children:Is.map(s=>{const n=[...t[s.key].entries()];return e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground",children:s.label}),n.length===0?e.jsx("span",{className:"text-muted-foreground",children:"—"}):e.jsx("div",{className:"flex flex-wrap gap-1",children:n.map(([r,a])=>e.jsxs("span",{className:"inline-flex max-w-full items-center gap-1 rounded border border-border bg-background px-1.5 py-0.5 font-mono",children:[e.jsx("span",{className:"h-2 w-2 shrink-0 rounded-full",style:{backgroundColor:a}}),e.jsx("span",{className:"truncate",children:r})]},r))})]},s.key)})})}function Fa({events:t,onRow:s,colorMaps:n}){const r=(a,o)=>n==null?void 0:n[a].get(o);return e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{children:"When"}),e.jsx(y,{children:"Kind"}),e.jsx(y,{children:"Outcome"}),e.jsx(y,{children:"Agent"}),e.jsx(y,{children:"Tool"}),e.jsx(y,{children:"Actor"}),e.jsx(y,{children:"Session"}),e.jsx(y,{children:"Event"})]})}),e.jsx(X,{children:t.map(a=>{const o=Oa(a);return e.jsxs(M,{className:`cursor-pointer${a.outcome==="denied"||a.outcome==="read_denied"?" bg-destructive/5":""}`,onClick:()=>s(a),children:[e.jsx(v,{className:"whitespace-nowrap font-mono text-xs",children:new Date(a.time).toLocaleString()}),e.jsxs(v,{className:"whitespace-nowrap",children:[e.jsx(Ee,{color:r("kind",o.kind)}),e.jsx(z,{variant:"outline",children:a.kind})]}),e.jsxs(v,{className:"whitespace-nowrap",children:[e.jsx(Ee,{color:r("outcome",o.outcome)}),e.jsx(z,{variant:Ra(a.outcome),children:a.outcome})]}),e.jsxs(v,{className:"font-mono text-xs",children:[e.jsx(Ee,{color:r("agent",o.agent)}),a.agentClass?e.jsx(W,{entity:"agent",id:`${a.sessionNamespace}/${a.agentClass}`,className:"text-link hover:underline",onClick:Qt,children:a.agentClass}):"—"]}),e.jsxs(v,{className:"font-mono text-xs",children:[e.jsx(Ee,{color:r("tool",o.tool)}),a.tool||"—"]}),e.jsxs(v,{className:"font-mono text-xs",title:a.actor||void 0,children:[e.jsx(Ee,{color:r("actor",o.actor)}),o.actor||"—"]}),e.jsx(v,{className:"font-mono text-xs",children:e.jsxs(W,{entity:"session",id:`${a.sessionNamespace}/${a.sessionName}`,className:"text-link hover:underline",onClick:Qt,children:[a.sessionNamespace,"/",a.sessionName]})}),e.jsx(v,{className:"max-w-md truncate text-xs",children:a.summary})]},a.entryId)})})]})}function Ma({event:t,onClose:s}){return e.jsx(an,{open:!0,onOpenChange:n=>!n&&s(),children:e.jsxs(on,{side:"right",className:"w-full overflow-y-auto sm:max-w-xl",children:[e.jsx(ln,{children:e.jsx(cn,{className:"text-sm",children:t.summary})}),e.jsxs("dl",{className:"mt-4 space-y-1 font-mono text-xs",children:[e.jsxs("div",{children:[e.jsx("dt",{className:"inline text-muted-foreground",children:"when:"})," ",e.jsx("dd",{className:"inline",children:t.time})]}),e.jsxs("div",{children:[e.jsx("dt",{className:"inline text-muted-foreground",children:"session:"})," ",e.jsxs("dd",{className:"inline",children:[t.sessionNamespace,"/",t.sessionName]})]}),e.jsxs("div",{children:[e.jsx("dt",{className:"inline text-muted-foreground",children:"agent:"})," ",e.jsx("dd",{className:"inline",children:t.agentClass})]}),e.jsxs("div",{children:[e.jsx("dt",{className:"inline text-muted-foreground",children:"actor:"})," ",e.jsx("dd",{className:"inline",children:t.actor})]}),e.jsxs("div",{children:[e.jsx("dt",{className:"inline text-muted-foreground",children:"tool:"})," ",e.jsx("dd",{className:"inline",children:t.tool})]}),e.jsxs("div",{children:[e.jsx("dt",{className:"inline text-muted-foreground",children:"entry:"})," ",e.jsx("dd",{className:"inline",children:t.entryId})]})]}),e.jsx("h3",{className:"mt-4 text-xs font-semibold uppercase text-muted-foreground",children:"Raw"}),e.jsx("pre",{className:"mt-1 overflow-x-auto rounded bg-card p-3 font-mono text-xs",children:JSON.stringify(t.raw??{},null,2)})]})})}const Xt=50,Zt=[{facet:"kind",field:"kinds",label:"Kind"},{facet:"outcome",field:"outcome",label:"Outcome"},{facet:"agentClass",field:"agentClass",label:"Agent"},{facet:"tool",field:"tool",label:"Tool"},{facet:"actor",field:"actor",label:"Actor"}];function Pa(t,s){const n=s.trim().toLowerCase();return n?[t.kind,t.agentClass,t.sessionNamespace,t.sessionName,`${t.sessionNamespace}/${t.sessionName}`,t.outcome,t.tool,t.actor,t.actor?ae(t.actor):"",t.summary].filter(Boolean).join(" ").toLowerCase().includes(n):!0}function Ka({apiBase:t,initialFilter:s}){const[n,r]=d.useState(s),[a,o]=d.useState(0),[i,l]=d.useState(null),[c,u]=d.useState(null),[h,N]=d.useState(null),[p,b]=d.useState(null),[x,j]=d.useState(""),[$,C]=d.useState(!0);d.useEffect(()=>{let k=!0;const g={...n,limit:Xt,offset:a*Xt};return Promise.all([ft(`${t}/audit/query`,g),ft(`${t}/audit/facets`,n)]).then(([T,P])=>{k&&(l(T),u(P),b(null))}).catch(T=>{k&&b(T.message)}),()=>{k=!1}},[t,n,a]);const E=(k,g)=>{o(0),r(T=>({...T,[k]:k==="kinds"?[g]:g}))},m=k=>{o(0),r(g=>{const T={...g};return delete T[k],T})},w=Zt.filter(({field:k})=>n[k]).map(({field:k,label:g})=>({field:k,label:g,value:k==="kinds"?(n.kinds??[]).join(","):String(n[k])})),R=(i==null?void 0:i.events)??[],O=d.useMemo(()=>R.filter(k=>Pa(k,x)),[R,x]),L=d.useMemo(()=>{const k={};for(const g of Is)k[g.key]=Ls(O.map(g.value));return k},[O]);return e.jsxs("div",{className:"flex flex-col gap-4 lg:flex-row lg:gap-6",children:[e.jsx("aside",{className:"grid grid-cols-2 gap-4 sm:grid-cols-3 lg:block lg:w-48 lg:shrink-0 lg:space-y-4",children:Zt.map(({facet:k,field:g,label:T})=>e.jsxs("div",{children:[e.jsx("h4",{className:"text-xs font-semibold uppercase text-muted-foreground",children:T}),e.jsx("ul",{className:"mt-1 space-y-0.5 text-xs",children:Object.entries((c==null?void 0:c.counts[k])??{}).sort(([,P],[,V])=>V-P).slice(0,8).map(([P,V])=>e.jsx("li",{children:e.jsxs("button",{className:"hover:text-primary",onClick:()=>E(g,P),children:[P," (",V,")"]})},P))})]},k))}),e.jsxs("div",{className:"min-w-0 flex-1 space-y-3",children:[p&&e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Audit query failed: ",p]})}),(i==null?void 0:i.truncated)&&e.jsx(I,{children:e.jsx(F,{children:"Results truncated — narrow the time range or filters for complete counts."})}),e.jsx("div",{className:"flex flex-wrap gap-2",children:w.map(k=>e.jsxs(z,{variant:"secondary",className:"cursor-pointer",onClick:()=>m(k.field),children:[k.label.toLowerCase(),": ",k.value," ✕"]},k.field))}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("div",{className:"relative min-w-0 flex-1",children:e.jsx("input",{type:"search",value:x,onChange:k=>j(k.target.value),placeholder:"Filter loaded events…","aria-label":"Filter loaded events",className:"w-full rounded-md border border-border bg-background px-2 py-1 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring"})}),x&&e.jsx(U,{variant:"ghost",size:"sm",onClick:()=>j(""),children:"Clear"}),e.jsx(U,{variant:"outline",size:"sm",onClick:()=>C(k=>!k),children:$?"Hide legend":"Show legend"}),e.jsxs("span",{className:"whitespace-nowrap text-xs text-muted-foreground",children:[O.length,x?` of ${R.length}`:""," shown"]})]}),$&&e.jsx(Ia,{colorMaps:L}),e.jsx(Fa,{events:O,onRow:N,colorMaps:L}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(U,{variant:"outline",size:"sm",disabled:a===0,onClick:()=>o(k=>k-1),children:"Prev"}),e.jsx(U,{variant:"outline",size:"sm",disabled:!(i!=null&&i.hasMore),onClick:()=>o(k=>k+1),children:"Next"}),e.jsxs("span",{className:"text-xs text-muted-foreground",children:["page ",a+1]})]})]}),h&&e.jsx(Ma,{event:h,onClose:()=>N(null)})]})}const _a={agents:"agent",sessions:"session",tools:"tool",users:"user"};function Ua(t,s){switch(t){case"agents":return{agentClass:s};case"sessions":{const n=s.indexOf("/");return n<0?{sessionName:s}:{sessionNamespace:s.slice(0,n),sessionName:s.slice(n+1)}}case"tools":return{tool:s};case"users":return{actor:s}}}function Va(t,s){return t==="users"?ae(s):s}function Wa({status:t}){return t?e.jsx("span",{className:`inline-flex rounded-full border px-2 py-0.5 text-[10px] font-medium ${at(t)}`,children:t}):e.jsx("span",{className:"text-muted-foreground",children:"—"})}function Ha({apiBase:t,axis:s,onDrill:n}){const[r,a]=d.useState([]),[o,i]=d.useState(null);d.useEffect(()=>{let u=!0;return _(`${t}/audit/entities/${s}`).then(h=>{u&&(a(h),i(null))}).catch(h=>{u&&i(h.message)}),()=>{u=!1}},[t,s]);const l=s==="sessions",c=_a[s];return e.jsxs("div",{className:"space-y-3",children:[o&&e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load rollups: ",o]})}),e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{className:"capitalize",children:s}),l&&e.jsx(y,{children:"Status"}),l&&e.jsx(y,{className:"text-right",children:"Est. tokens"}),l&&e.jsx(y,{children:"Started"}),l&&e.jsx(y,{children:"Started by"}),e.jsx(y,{className:"text-right",children:"Events"}),e.jsx(y,{className:"text-right",children:"Denied"}),e.jsx(y,{className:"text-right",children:"Logs"})]})}),e.jsx(X,{children:r.map(u=>e.jsxs(M,{children:[e.jsx(v,{className:"font-mono text-xs",children:e.jsx(W,{entity:c,id:u.key,className:"text-link hover:underline",children:l?e.jsx(Z,{id:u.key}):Va(s,u.key)})}),l&&e.jsx(v,{children:e.jsx(Wa,{status:u.status})}),l&&e.jsx(v,{className:"text-right font-mono text-xs text-muted-foreground",title:u.estimatedCostUSD?`~$${u.estimatedCostUSD.toFixed(2)} (est.)`:void 0,children:u.inputTokens||u.outputTokens?`${ge(u.inputTokens??0)} in · ${ge(u.outputTokens??0)} out`:"—"}),l&&e.jsx(v,{className:"whitespace-nowrap text-xs text-muted-foreground",children:Lt(u.startedAt)}),l&&e.jsx(v,{className:"text-xs",children:u.startedBy?e.jsxs("span",{className:"inline-flex items-center gap-1.5",children:[e.jsx(Tt,{kind:u.startedBy}),e.jsx(W,{entity:"user",id:u.startedBy,className:"font-mono text-link hover:underline",children:ae(u.startedBy)})]}):e.jsx("span",{className:"font-mono text-muted-foreground",children:"—"})}),e.jsx(v,{className:"text-right font-mono text-xs",children:u.events}),e.jsx(v,{className:"text-right font-mono text-xs text-destructive",children:u.denied||""}),e.jsx(v,{className:"text-right",children:e.jsx("button",{type:"button",className:"text-xs text-muted-foreground hover:text-link hover:underline",onClick:()=>n(Ua(s,u.key)),children:"filter logs"})})]},u.key))})]}),e.jsxs("p",{className:"text-[11px] text-muted-foreground",children:["Row → ",c," detail · “filter logs” → the audit log scoped to that ",c]})]})}const bt=14,Bt=8,ut=4;function Fs(t){return`${t.namespace}/${t.artifactId||t.name}`}function Re(t){return`${t.namespace}/${t.name}`}function za(t){const s=new Map;for(const n of t){const r=Fs(n),a=s.get(r);if(a===void 0){s.set(r,n);continue}const o=new Date(n.created).getTime(),i=new Date(a.created).getTime();(o>i||o===i&&Re(n){const x=Fs(p);a.push(x),s.has(x)||(s.set(x,b),r.set(x,As(x)??"#888")),n.set(x,b)});const o=[...s.keys()],i=[],l=new Map;for(const p of o){const b=s.get(p);let x=i.findIndex(j=>jnew Array(t.length).fill(void 0));for(const p of o){const b=l.get(p);for(let x=s.get(p);x<=n.get(p);x++)u[b][x]===void 0&&(u[b][x]=p)}const h=za(t),N=t.map((p,b)=>{const x=a[b],j=l.get(x),$=[];for(let C=0;Cs.get(E),R=E!==void 0&&b{const r=es(n.lane);return e.jsxs("g",{children:[n.up&&e.jsx("line",{x1:r,y1:0,x2:r,y2:5,stroke:n.color,strokeWidth:1.5,strokeOpacity:.7}),n.down&&e.jsx("line",{x1:r,y1:5,x2:r,y2:10,stroke:n.color,strokeWidth:1.5,strokeOpacity:.7})]},n.lane)})}),e.jsx("div",{className:"absolute inset-0 flex items-center",children:t.segments.filter(n=>n.dot).map(n=>e.jsx("span",{className:"absolute rounded-full border",style:{left:es(n.lane)-ut,width:ut*2,height:ut*2,backgroundColor:n.color,borderColor:"hsl(var(--card))",opacity:t.isLatest?1:.55},"data-lane":n.lane,"data-testid":"track-dot"},n.lane))})]})}const Ja={Ready:"border-success/40 bg-success/10 text-success",Failed:"border-destructive/40 bg-destructive/10 text-destructive",Rendering:"border-primary/40 bg-primary/10 text-primary",Pending:"border-border bg-muted text-muted-foreground"};function ot({phase:t}){const s=Ja[t]??"border-border bg-background text-muted-foreground";return e.jsx("span",{className:`inline-flex rounded-full border px-2 py-0.5 text-[10px] font-medium ${s}`,children:t||"—"})}function Et(t){if(!t)return"—";const s=["B","KB","MB","GB"];let n=0,r=t;for(;r>=1024&&n{let u=!0;return hr(t).then(h=>{u&&(r(h),o(null),l(!0))}).catch(h=>{u&&(o(h.message),l(!0))}),()=>{u=!1}},[t]);const c=d.useMemo(()=>qa(n),[n]);return a?e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load artifacts: ",a]})}):e.jsxs("div",{className:"space-y-3",children:[i&&n.length===0&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"No artifacts rendered yet."}),n.length>0&&e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{children:"When"}),e.jsx(y,{children:"Artifact"}),e.jsx(y,{children:"Session"}),e.jsx(y,{children:"Kind"}),e.jsx(y,{children:"MIME"}),e.jsx(y,{className:"text-right",children:"Size"}),e.jsx(y,{className:"text-right",children:"Revisions"}),e.jsx(y,{children:"Phase"}),e.jsx(y,{className:"text-right",children:"Tracks"})]})}),e.jsx(X,{children:n.map((u,h)=>{const N=!!(u.session&&s),p=c.rows[h],b=p.isLatest;return e.jsxs(M,{children:[e.jsx(v,{className:"whitespace-nowrap font-mono text-xs text-muted-foreground",children:new Date(u.created).toLocaleString()}),e.jsx(v,{className:"font-mono text-xs",children:e.jsx(W,{entity:"artifact",id:`${u.namespace}/${u.name}`,className:b?"text-link hover:underline":"text-muted-foreground hover:underline",children:u.name})}),e.jsx(v,{className:"font-mono text-xs text-muted-foreground",children:u.session?N?e.jsx("button",{type:"button",className:"hover:text-link hover:underline",onClick:()=>s(Ya(u.session)),children:e.jsx(Z,{id:u.session})}):e.jsx(Z,{id:u.session}):"—"}),e.jsx(v,{children:e.jsx(z,{variant:"outline",children:u.kind})}),e.jsx(v,{className:"font-mono text-xs text-muted-foreground",children:u.mime||"—"}),e.jsx(v,{className:"text-right font-mono text-xs text-muted-foreground",children:Et(u.size)}),e.jsx(v,{className:"text-right font-mono text-xs text-muted-foreground",children:u.revisions||""}),e.jsx(v,{children:e.jsx(ot,{phase:u.phase})}),e.jsx(v,{className:"p-0 pl-2 align-middle",children:e.jsx(Ga,{row:p,width:c.width})})]},p.uid)})})]}),e.jsx("p",{className:"text-[11px] text-muted-foreground",children:"ArtifactRender — versioned, sanitized agent outputs · click the name → artifact detail · the session → its Logs · Tracks = git-graph of revisions per logical artifact · oap artifact"})]})}const Xa=[{id:"overview",label:"Overview"},{id:"revisions",label:"Revisions"}];function Za(t){const s=t.indexOf("/");return s<0?{ns:"",name:t}:{ns:t.slice(0,s),name:t.slice(s+1)}}function Ba(t){try{return new URL(t,"http://placeholder.invalid").searchParams.has("artifactId")}catch{return!1}}function ke({label:t,children:s}){return e.jsxs("div",{className:"flex flex-col gap-0.5",children:[e.jsx("dt",{className:"text-[10px] uppercase tracking-wide text-muted-foreground",children:t}),e.jsx("dd",{className:"font-mono text-xs text-foreground",children:s})]})}function eo({apiBase:t,id:s,tab:n}){const{ns:r,name:a}=Za(s),o=n??"overview",[i,l]=d.useState(null),[c,u]=d.useState(null),[h,N]=d.useState(!1);d.useEffect(()=>{let b=!0;return l(null),u(null),N(!1),fr(t,r,a).then(x=>{b&&l(x)}).catch(x=>{b&&(x instanceof J&&x.status===404?N(!0):u(x.message))}),()=>{b=!1}},[t,r,a]);const p=b=>te({type:"detail",entity:"artifact",id:s,tab:b});return e.jsx(nt,{title:e.jsx("span",{className:"font-mono",children:e.jsx(Z,{ns:r,name:a})}),backRoute:{type:"view",view:"artifacts"},tabs:Xa,activeTab:o,onTab:p,headerRight:i?e.jsx(ot,{phase:i.phase}):void 0,children:c?e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load artifact: ",c]})}):h?e.jsxs("p",{className:"text-sm text-muted-foreground",children:["Artifact ",s," not found — it may have been garbage-collected."]}):i?o==="revisions"?e.jsx(so,{detail:i}):e.jsx(to,{detail:i}):e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading…"})})}function to({detail:t}){const s=Ba(t.viewPath);return e.jsxs("div",{className:"flex flex-col gap-5",children:[e.jsxs("dl",{className:"grid grid-cols-2 gap-x-6 gap-y-3 sm:grid-cols-3",children:[e.jsx(ke,{label:"Kind",children:t.kind||"—"}),e.jsx(ke,{label:"Phase",children:e.jsx(ot,{phase:t.phase})}),e.jsx(ke,{label:"MIME",children:t.mime||"—"}),e.jsx(ke,{label:"Size",children:Et(t.size)}),e.jsx(ke,{label:"Created",children:new Date(t.created).toLocaleString()}),e.jsx(ke,{label:"Session",children:t.session?e.jsx(W,{entity:"session",id:t.session,className:"text-link hover:underline",children:e.jsx(Z,{id:t.session})}):"—"})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("span",{className:"text-[10px] font-semibold uppercase tracking-wide text-muted-foreground",children:"Viewer"}),s?e.jsx("a",{href:t.viewPath,target:"_blank",rel:"noopener noreferrer",className:"w-fit text-sm text-link hover:underline",children:"Open viewer"}):e.jsx("span",{className:"text-[11px] text-muted-foreground",children:"No viewer available for this artifact."})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("span",{className:"text-[10px] font-semibold uppercase tracking-wide text-muted-foreground",children:"Download"}),t.outputRef?e.jsx("code",{className:"w-fit break-all rounded border border-border bg-background px-2 py-1 font-mono text-xs text-foreground",children:t.outputRef}):e.jsx("span",{className:"text-sm text-muted-foreground",children:"No content ref yet — the render has not reached Ready."})]})]})}function so({detail:t}){return t.revisions.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No revisions."}):e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{children:"Name"}),e.jsx(y,{children:"Phase"}),e.jsx(y,{children:"MIME"}),e.jsx(y,{className:"text-right",children:"Size"}),e.jsx(y,{children:"Created"})]})}),e.jsx(X,{children:t.revisions.map(s=>e.jsxs(M,{className:s.name===t.name?"bg-muted/40":void 0,children:[e.jsx(v,{className:"font-mono text-xs",children:e.jsx(W,{entity:"artifact",id:`${t.namespace}/${s.name}`,className:"text-link hover:underline",children:s.name})}),e.jsx(v,{children:e.jsx(ot,{phase:s.phase})}),e.jsx(v,{className:"font-mono text-xs text-muted-foreground",children:s.mime||"—"}),e.jsx(v,{className:"text-right font-mono text-xs text-muted-foreground",children:Et(s.size)}),e.jsx(v,{className:"whitespace-nowrap font-mono text-xs text-muted-foreground",children:new Date(s.created).toLocaleString()})]},s.name))})]})}const Ms=t=>t==null||Number.isNaN(t)?"NaN":`$${t.toFixed(2)}`,ue=[{id:"byModel",label:"By model",keyLabel:"Model"},{id:"byAgentClass",label:"By agent",keyLabel:"Agent class",keyEntity:"agent"},{id:"bySession",label:"By session",keyLabel:"Session",keyEntity:"session"},{id:"byUser",label:"By user",keyLabel:"User",decode:!0}];function no({color:t}){return t?e.jsx("span",{"aria-hidden":"true",className:"inline-block h-2.5 w-2.5 shrink-0 rounded-sm",style:{backgroundColor:t}}):null}function ro({rows:t,keyLabel:s,highlightKey:n,keyEntity:r,decode:a,isModel:o}){if(t.length===0)return e.jsx("p",{className:"px-1 py-6 text-center text-xs text-muted-foreground",children:"No usage recorded."});const i=Ls(t.map(l=>l.key));return e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{children:s}),e.jsx(y,{className:"text-right",children:"Input tokens"}),e.jsx(y,{className:"text-right",children:"Output tokens"}),e.jsx(y,{className:"text-right",children:"Est. cost"})]})}),e.jsx(X,{children:t.map(l=>{const c=n!=null&&l.key===n,u=r==="session"?e.jsx(Z,{id:l.key}):a?ae(l.key):l.key;return e.jsxs(M,{className:c?"bg-accent/60":void 0,children:[e.jsx(v,{className:"font-mono text-xs",children:e.jsxs("span",{className:"flex items-center gap-2",children:[e.jsx(no,{color:i.get(l.key)}),l.key&&r?e.jsx(W,{entity:r,id:l.key,className:"text-link hover:underline",children:u}):o&&l.key?e.jsx(kt,{model:l.key}):e.jsx("span",{children:l.key?u:"(unknown)"}),c&&e.jsx(z,{variant:"secondary",className:"align-middle text-[10px]",children:"from Overview"})]})}),e.jsx(v,{className:"text-right font-mono text-xs text-muted-foreground",children:xe(l.inputTokens)}),e.jsx(v,{className:"text-right font-mono text-xs text-muted-foreground",children:xe(l.outputTokens)}),e.jsx(v,{className:"text-right font-mono text-xs",children:Ms(l.estimatedCostUSD)})]},l.key)})})]})}function ao({apiBase:t}){const s=ks(),n=s.type==="view"&&s.query?s.query.get("model")??void 0:void 0,[r,a]=d.useState(null),[o,i]=d.useState(null);d.useEffect(()=>{let p=!0;return cr(t).then(b=>{p&&(a(b),i(null))}).catch(b=>{p&&i(b.message)}),()=>{p=!1}},[t]);const[l,c]=d.useState("byModel"),u=d.useRef(null),h=p=>{var C,E;if(!["ArrowRight","ArrowLeft","Home","End"].includes(p.key))return;p.preventDefault();const x=ue.findIndex(m=>m.id===l),j=p.key==="ArrowRight"?(x+1)%ue.length:p.key==="ArrowLeft"?(x-1+ue.length)%ue.length:p.key==="Home"?0:ue.length-1,$=ue[j].id;c($),(E=(C=u.current)==null?void 0:C.querySelector(`#budget-tab-${$}`))==null||E.focus()};if(o)return e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load budget: ",o]})});if(!r)return e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading budget…"});const N=r.byModel.reduce((p,b)=>p+(b.estimatedCostUSD??NaN),0);return e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-2 rounded-xl border bg-card p-4 shadow",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-[11px] text-muted-foreground",children:"Total estimated spend"}),e.jsx("div",{className:"mt-0.5 text-2xl font-semibold tracking-tight",children:Ms(N)})]}),e.jsx("p",{className:"max-w-md text-[11px] text-muted-foreground",children:"Estimated from list prices — not a metered bill. Same live-session scope as the Overview budget panel."})]}),e.jsx("div",{ref:u,role:"tablist","aria-label":"Budget breakdown axes",onKeyDown:h,className:"inline-flex h-9 items-center gap-1 rounded-lg bg-muted p-1 text-muted-foreground",children:ue.map(p=>{const b=l===p.id;return e.jsx("button",{id:`budget-tab-${p.id}`,type:"button",role:"tab","aria-selected":b,"aria-controls":`budget-panel-${p.id}`,tabIndex:b?0:-1,onClick:()=>c(p.id),className:["inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium transition-all",b?"bg-background text-foreground shadow":"hover:text-foreground"].join(" "),children:p.label},p.id)})}),ue.filter(p=>p.id===l).map(p=>e.jsx("div",{id:`budget-panel-${p.id}`,role:"tabpanel","aria-labelledby":`budget-tab-${p.id}`,tabIndex:0,className:"rounded-xl border bg-card p-2 shadow",children:e.jsx(ro,{rows:r[p.id],keyLabel:p.keyLabel,highlightKey:p.id==="byModel"?n:void 0,keyEntity:p.keyEntity,decode:p.decode,isModel:p.id==="byModel"})},p.id))]})}function oo({apiBase:t}){const[s,n]=d.useState(""),[r,a]=d.useState(""),[o,i]=d.useState(null),[l,c]=d.useState(null),[u,h]=d.useState(!1);d.useEffect(()=>{let j=!0;return gr(t,r?{q:r}:{}).then($=>{j&&(i($),c(null),h(!0))}).catch($=>{j&&(c($.message),h(!0))}),()=>{j=!1}},[t,r]);const N=j=>{j.preventDefault(),a(s.trim())},p=(o==null?void 0:o.rollups)??[],b=(o==null?void 0:o.entries)??[],x=r!=="";return e.jsxs("div",{className:"space-y-3",children:[e.jsx("form",{onSubmit:N,className:"flex items-center gap-2",children:e.jsxs("label",{className:"flex h-9 flex-1 items-center gap-2 rounded-md border border-input bg-background px-3 text-xs",children:[e.jsx(fs,{className:"h-3.5 w-3.5 text-muted-foreground"}),e.jsx("input",{type:"search",value:s,onChange:j=>n(j.target.value),placeholder:"search memory — text, tags, vectors…","aria-label":"Search memory",className:"flex-1 bg-transparent text-xs text-foreground outline-none placeholder:text-muted-foreground"})]})}),l&&e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load memory: ",l]})}),(o==null?void 0:o.truncated)&&e.jsx(I,{children:e.jsx(F,{children:"Results truncated — narrow the scan for complete rollup counts."})}),x?b.length===0?e.jsxs("p",{className:"text-sm text-muted-foreground",children:["No matches for “",r,"”."]}):e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{children:"Kind"}),e.jsx(y,{children:"Scope"}),e.jsx(y,{children:"Entry"}),e.jsx(y,{children:"When"}),e.jsx(y,{className:"text-right",children:"Score"})]})}),e.jsx(X,{children:b.map(j=>e.jsxs(M,{children:[e.jsx(v,{children:e.jsx(z,{variant:"outline",children:j.kind})}),e.jsx(v,{className:"font-mono text-xs text-muted-foreground",children:j.scope}),e.jsx(v,{className:"font-mono text-xs text-foreground",children:j.id}),e.jsx(v,{className:"whitespace-nowrap font-mono text-xs text-muted-foreground",children:j.created?new Date(j.created).toLocaleString():"—"}),e.jsx(v,{className:"text-right font-mono text-xs text-muted-foreground",children:j.score!=null?j.score.toFixed(2):""})]},`${j.scope}/${j.kind}/${j.id}`))})]}):p.length===0?u&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"No memory entries yet."}):e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{children:"Kind"}),e.jsx(y,{className:"text-right",children:"Entries"}),e.jsx(y,{className:"text-right",children:"Scopes"}),e.jsx(y,{children:"Last write"}),e.jsx(y,{})]})}),e.jsx(X,{children:p.map(j=>e.jsxs(M,{children:[e.jsx(v,{className:"font-mono text-xs text-foreground",children:j.kind}),e.jsx(v,{className:"text-right font-mono text-xs text-muted-foreground",children:j.entries}),e.jsx(v,{className:"text-right font-mono text-xs text-muted-foreground",children:j.scopes}),e.jsx(v,{className:"whitespace-nowrap font-mono text-xs text-muted-foreground",children:j.lastWrite?new Date(j.lastWrite).toLocaleString():"—"}),e.jsx(v,{children:j.appendOnly&&e.jsx(z,{children:"append-only"})})]},j.kind))})]}),e.jsxs("p",{className:"text-[11px] text-muted-foreground",children:["Append-only kinds are tamper-evident (Ed25519 hash chains) — verify with"," ",e.jsx("span",{className:"font-mono",children:"oap audit verify"})," · oap memory list / search / query"]})]})}function vt({uuid:t,label:s,onOpen:n}){return t?e.jsxs("button",{type:"button",onClick:()=>n(t),className:"inline-flex items-center gap-2 rounded-full border bg-background px-3 py-1 font-mono text-xs hover:bg-accent hover:text-accent-foreground",children:[e.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-state"}),s||t]}):e.jsx("span",{className:"font-mono text-xs text-muted-foreground",children:s||"—"})}function ts({facts:t,onOpen:s}){return t.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No facts."}):e.jsx("ul",{className:"space-y-2",children:t.map(n=>e.jsxs("li",{className:"rounded-md border bg-background p-3",children:[e.jsx("div",{className:"text-sm text-foreground",children:n.fact||n.name}),e.jsxs("div",{className:"mt-1.5 flex flex-wrap items-center gap-1.5",children:[e.jsx(vt,{uuid:n.fromEntity,label:n.fromEntity,onOpen:s}),e.jsx("span",{className:"text-muted-foreground",children:"→"}),e.jsx(vt,{uuid:n.toEntity,label:n.toEntity,onOpen:s}),n.validAt&&e.jsx("span",{className:"ml-1 font-mono text-[11px] text-muted-foreground",children:new Date(n.validAt).toLocaleDateString()})]})]},n.uuid))})}function lo({apiBase:t}){var L,k;const[s,n]=d.useState(null),[r,a]=d.useState(""),[o,i]=d.useState(null),[l,c]=d.useState([]),[u,h]=d.useState(""),[N,p]=d.useState(""),[b,x]=d.useState(null),[j,$]=d.useState(null),[C,E]=d.useState(null),m=d.useRef(null);d.useEffect(()=>{let g=!0;return wr(t).then(T=>{g&&(n(T.available),a(T.note??""),c(T.communities??[]),i(T.error??null))}).catch(T=>{g&&(n(!0),i(T.message))}),()=>{g=!1}},[t]),d.useEffect(()=>{if(!N){x(null),$(null);return}let g=!0;return br(t,N).then(T=>{g&&(x(T.facts??[]),$(T.error??null))}).catch(T=>{g&&(x([]),$(T.message))}),()=>{g=!1}},[t,N]);const w=d.useCallback(g=>{g&&(m.current=g,E({uuid:g,loading:!0,entity:null,facts:[],related:[]}),Promise.all([vr(t,g),yr(t,g),Nr(t,g)]).then(([T,P,V])=>{m.current===g&&E({uuid:g,loading:!1,entity:T.entity??null,facts:P.facts??[],related:V.entities??[],error:T.error||P.error||V.error||void 0})}).catch(T=>{m.current===g&&E({uuid:g,loading:!1,entity:null,facts:[],related:[],error:T.message})}))},[t]),R=g=>{g.preventDefault(),p(u.trim())};if(s===!1)return e.jsxs("div",{className:"rounded-xl border border-dashed bg-card p-6 shadow",children:[e.jsxs("div",{className:"flex items-center gap-2 text-sm font-semibold text-foreground",children:[e.jsx(hs,{className:"h-4 w-4 text-muted-foreground"})," Knowledge graph not configured"]}),e.jsxs("p",{className:"mt-2 text-sm text-muted-foreground",children:[r||"The knowledge graph is not available."," Set"," ",e.jsx("span",{className:"font-mono",children:"--graphiti-endpoint"})," on the operator to enable graph-aware entity, fact, and community search."]}),e.jsx("p",{className:"mt-3 text-[11px] text-muted-foreground",children:"oap kg search / entity / facts / related / communities"})]});if(s===null&&!o)return e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading knowledge graph…"});const O=N!=="";return e.jsxs("div",{className:"space-y-4",children:[o&&e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load knowledge graph: ",o]})}),e.jsx("form",{onSubmit:R,className:"flex items-center gap-2",children:e.jsxs("label",{className:"flex h-9 flex-1 items-center gap-2 rounded-md border border-input bg-background px-3 text-xs",children:[e.jsx(fs,{className:"h-3.5 w-3.5 text-muted-foreground"}),e.jsx("input",{type:"search",value:u,onChange:g=>h(g.target.value),placeholder:"search facts — graph-aware…","aria-label":"Search facts",className:"flex-1 bg-transparent text-xs text-foreground outline-none placeholder:text-muted-foreground"})]})}),j&&e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Fact search degraded: ",j]})}),O&&e.jsxs("div",{className:"rounded-xl border bg-card p-4 shadow",children:[e.jsxs("div",{className:"text-sm font-semibold text-foreground",children:["Facts matching “",N,"”"]}),e.jsx("div",{className:"mt-3",children:b===null?e.jsx("p",{className:"text-sm text-muted-foreground",children:"Searching…"}):e.jsx(ts,{facts:b,onOpen:w})})]}),C&&e.jsxs("div",{className:"rounded-xl border bg-card p-4 shadow",children:[e.jsxs("div",{className:"flex items-start justify-between",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-semibold text-foreground",children:((L=C.entity)==null?void 0:L.name)||C.uuid}),((k=C.entity)==null?void 0:k.summary)&&e.jsx("div",{className:"mt-0.5 text-xs text-muted-foreground",children:C.entity.summary})]}),e.jsx("button",{type:"button","aria-label":"Close entity",onClick:()=>E(null),className:"inline-flex h-6 w-6 items-center justify-center rounded border border-input bg-background text-muted-foreground hover:bg-accent hover:text-accent-foreground",children:e.jsx(zn,{className:"h-3 w-3"})})]}),C.error&&e.jsx(I,{variant:"destructive",className:"mt-3",children:e.jsxs(F,{children:["Entity lookup degraded: ",C.error]})}),C.loading?e.jsx("p",{className:"mt-3 text-sm text-muted-foreground",children:"Loading entity…"}):e.jsxs("div",{className:"mt-3 space-y-4",children:[e.jsxs("div",{children:[e.jsx("div",{className:"mb-2 text-xs font-semibold text-muted-foreground",children:"Facts"}),e.jsx(ts,{facts:C.facts,onOpen:w})]}),e.jsxs("div",{children:[e.jsx("div",{className:"mb-2 text-xs font-semibold text-muted-foreground",children:"Related entities"}),C.related.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No related entities."}):e.jsx("div",{className:"flex flex-wrap gap-2",children:C.related.map(g=>e.jsx(vt,{uuid:g.uuid,label:g.name||g.uuid,onOpen:w},g.uuid))})]})]})]}),e.jsxs("div",{className:"rounded-xl border bg-card p-4 shadow",children:[e.jsx("div",{className:"text-sm font-semibold text-foreground",children:"Communities"}),l.length===0?e.jsx("p",{className:"mt-2 text-sm text-muted-foreground",children:"No communities yet."}):e.jsx("ul",{className:"mt-3 space-y-2",children:l.map(g=>e.jsxs("li",{className:"rounded-md border bg-background p-3",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"font-mono text-xs text-foreground",children:g.name||g.uuid}),e.jsxs(z,{variant:"outline",children:[g.members.length," members"]})]}),g.summary&&e.jsx("div",{className:"mt-1 text-xs text-muted-foreground",children:g.summary})]},g.uuid))}),e.jsx("p",{className:"mt-3 text-[11px] text-muted-foreground",children:"Graphiti knowledge graph — entities, facts, communities · oap kg search / entity / facts / related"})]})]})}const ss=t=>new URLSearchParams({model:t}),io=t=>t==null||Number.isNaN(t)?"NaN":`$${t.toFixed(2)}`,Ue=["bg-chart-1","bg-chart-2","bg-chart-3","bg-chart-4","bg-chart-5"],co={Healthy:"bg-success",Degraded:"bg-warning",Down:"bg-destructive",NotConfigured:"bg-muted-foreground"},uo={Healthy:"text-success",Degraded:"text-warning",Down:"text-destructive",NotConfigured:"text-muted-foreground"};function xo({values:t,width:s=600,height:n=150}){const r=Math.max(1,...t)*1.12,a=6,o=t.length,i=h=>a+(o<=1?0:h*(s-2*a)/(o-1)),l=h=>n-a-h/r*(n-2*a),c=t.map((h,N)=>`${N?"L":"M"} ${i(N).toFixed(1)} ${l(h).toFixed(1)}`).join(" "),u=`${c} L ${i(o-1).toFixed(1)} ${(n-a).toFixed(1)} L ${i(0).toFixed(1)} ${(n-a).toFixed(1)} Z`;return e.jsxs("svg",{viewBox:`0 0 ${s} ${n}`,className:"h-40 w-full",preserveAspectRatio:"none",role:"img","aria-label":"Tokens over time",children:[e.jsx("defs",{children:e.jsxs("linearGradient",{id:"ap-overview-area",x1:"0",x2:"0",y1:"0",y2:"1",children:[e.jsx("stop",{offset:"0%",stopColor:"hsl(var(--chart-1))",stopOpacity:"0.35"}),e.jsx("stop",{offset:"100%",stopColor:"hsl(var(--chart-1))",stopOpacity:"0"})]})}),e.jsx("path",{d:u,fill:"url(#ap-overview-area)"}),e.jsx("path",{d:c,fill:"none",stroke:"hsl(var(--chart-1))",strokeWidth:"1.5",vectorEffect:"non-scaling-stroke"})]})}function mo({label:t,value:s,sub:n}){return e.jsxs("div",{className:"rounded-xl border bg-card p-4 shadow",children:[e.jsx("div",{className:"text-[11px] text-muted-foreground",children:t}),e.jsx("div",{className:"mt-1 text-2xl font-semibold tracking-tight",children:s}),n&&e.jsx("div",{className:"mt-0.5 font-mono text-[11px] text-muted-foreground",children:n})]})}function ho({apiBase:t}){const[s,n]=d.useState(null),[r,a]=d.useState(null),[o,i]=d.useState(null),[l,c]=d.useState(null);if(d.useEffect(()=>{let m=!0;return or(t).then(w=>{m&&(n(w),i(null))}).catch(w=>{m&&i(w.message)}),lr(t).then(w=>{m&&(a(w),c(null))}).catch(w=>{m&&c(w.message)}),()=>{m=!1}},[t]),o)return e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load overview: ",o]})});if(!s)return e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading overview…"});const u=s.kpis,h=s.budget,N=s.series24h.map(m=>m.inputTokens+m.outputTokens),p=N.reduce((m,w)=>m+w,0),b=h.tokenCeiling&&h.tokenCeiling>0?h.tokensSpent/h.tokenCeiling*100:null,x=b!=null?`${b.toFixed(0)}%`:xe(h.tokensSpent),j=[{label:"Active sessions",value:`${u.activeSessions}`},{label:"Tokens today",value:xe(u.tokensToday)},{label:"Tool calls (24h)",value:`${u.toolCalls24h}`},{label:"Approvals pending",value:`${u.approvalsPending}`},{label:"Denials (24h)",value:`${u.denials24h}`}],$=s.byModel.reduce((m,w)=>m+w.inputTokens+w.outputTokens,0)||1,C=Math.max(1,...s.byAgentClass.map(m=>m.inputTokens+m.outputTokens)),E=((r==null?void 0:r.components)??[]).filter(m=>m.status==="Degraded"||m.status==="Down").length;return e.jsxs("div",{className:"space-y-4",children:[e.jsx("div",{className:"grid grid-cols-2 gap-3 md:grid-cols-3 xl:grid-cols-5",children:j.map(m=>e.jsx(mo,{label:m.label,value:m.value},m.label))}),e.jsxs("div",{className:"grid grid-cols-1 gap-4 lg:grid-cols-3",children:[e.jsxs(me,{className:"lg:col-span-2",children:[e.jsxs(he,{className:"flex-row items-center justify-between pb-2",children:[e.jsxs("div",{children:[e.jsx(fe,{className:"text-sm",children:"Tokens over time"}),e.jsx("div",{className:"text-[11px] text-muted-foreground",children:"last 24 hours · all models"})]}),e.jsxs("div",{className:"font-mono text-xs text-muted-foreground",children:[xe(p)," total"]})]}),e.jsx(pe,{children:e.jsx(xo,{values:N})})]}),e.jsx(zt,{view:"budget",className:"block h-full rounded-xl",children:e.jsxs(me,{className:"h-full transition-colors hover:border-primary/50 hover:bg-accent/20",children:[e.jsxs(he,{className:"flex-row items-center justify-between pb-2",children:[e.jsx(fe,{className:"text-sm",children:"Budget"}),e.jsx("span",{className:"text-[11px] text-link",children:"View breakdown →"})]}),e.jsxs(pe,{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-end gap-2",children:[e.jsx("div",{className:"text-3xl font-semibold tracking-tight",children:x}),e.jsx("div",{className:"mb-1 font-mono text-xs text-muted-foreground",children:b!=null?`${xe(h.tokensSpent)} tokens`:"tokens spent"})]}),e.jsxs("div",{className:"font-mono text-sm text-muted-foreground",children:["est. ",io(h.estimatedCostUSD)]}),e.jsxs("div",{className:"text-[11px] text-muted-foreground",children:[h.estimated?"estimated · list-price":"metered"," · daily budget resets 00:00 UTC"]})]})]})})]}),e.jsxs("div",{className:"grid grid-cols-1 gap-4 lg:grid-cols-2",children:[e.jsxs(me,{children:[e.jsx(he,{className:"pb-2",children:e.jsx(fe,{className:"text-sm",children:"Tokens by model"})}),e.jsxs(pe,{className:"space-y-3",children:[e.jsx("div",{"aria-hidden":"true",className:"flex h-3 w-full overflow-hidden rounded",children:s.byModel.map((m,w)=>e.jsx("div",{onClick:()=>te({type:"view",view:"budget",query:ss(m.model)}),title:`${m.model||"(unknown)"} — view budget`,className:`h-full cursor-pointer ${Ue[w%Ue.length]}`,style:{width:`${((m.inputTokens+m.outputTokens)/$*100).toFixed(1)}%`}},m.model))}),e.jsxs("div",{className:"space-y-2",children:[s.byModel.length===0&&e.jsx("p",{className:"text-xs text-muted-foreground",children:"No live model usage."}),s.byModel.map((m,w)=>e.jsxs(zt,{view:"budget",query:ss(m.model),className:"-mx-1 flex items-center justify-between rounded px-1 py-0.5 text-xs transition-colors hover:bg-accent/40",children:[e.jsxs("span",{className:"flex items-center gap-2",children:[e.jsx("span",{"aria-hidden":"true",className:`h-2.5 w-2.5 rounded-sm ${Ue[w%Ue.length]}`}),m.model?e.jsx(kt,{model:m.model}):e.jsx("span",{className:"font-mono",children:"(unknown)"})]}),e.jsxs("span",{className:"font-mono text-muted-foreground",children:[xe(m.inputTokens+m.outputTokens)," · ",m.sessions," sess"]})]},m.model))]})]})]}),e.jsxs(me,{children:[e.jsx(he,{className:"pb-2",children:e.jsx(fe,{className:"text-sm",children:"Tokens by agent class"})}),e.jsxs(pe,{className:"space-y-2.5",children:[s.byAgentClass.length===0&&e.jsx("p",{className:"text-xs text-muted-foreground",children:"No live agent-class usage."}),s.byAgentClass.map(m=>{const w=m.inputTokens+m.outputTokens,R=e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"w-28 shrink-0 truncate font-mono",children:m.class||"(unknown)"}),e.jsx("div",{className:"h-2.5 flex-1 overflow-hidden rounded bg-muted",children:e.jsx("div",{className:"h-full rounded bg-chart-1",style:{width:`${(w/C*100).toFixed(1)}%`}})}),e.jsx("span",{className:"w-12 shrink-0 text-right font-mono text-muted-foreground",children:xe(w)})]});return m.class?e.jsx(W,{entity:"agent",id:m.class,className:"-mx-1 flex items-center gap-3 rounded px-1 py-0.5 text-xs transition-colors hover:bg-accent/40",children:R},m.class):e.jsx("div",{className:"flex items-center gap-3 px-1 py-0.5 text-xs text-muted-foreground",children:R},"__unknown__")})]})]})]}),e.jsxs(me,{children:[e.jsxs(he,{className:"flex-row items-center justify-between pb-2",children:[e.jsx(fe,{className:"text-sm",children:"Cluster health"}),E>0?e.jsxs("span",{className:"flex items-center gap-1.5 text-[11px] text-warning",children:[e.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-warning"}),E," component",E>1?"s":""," degraded"]}):r&&e.jsxs("span",{className:"flex items-center gap-1.5 text-[11px] text-success",children:[e.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-success"}),"all healthy"]})]}),e.jsxs(pe,{className:"space-y-3",children:[l&&e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load cluster health: ",l]})}),r&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"grid grid-cols-2 gap-2 md:grid-cols-4",children:r.components.map(m=>e.jsxs("div",{className:"flex items-center justify-between rounded-md border bg-background px-3 py-2",children:[e.jsxs("span",{className:"flex items-center gap-2 font-mono text-xs",children:[e.jsx("span",{className:`h-1.5 w-1.5 rounded-full ${co[m.status]}`}),m.name]}),e.jsx("span",{className:`text-[10px] ${uo[m.status]}`,title:m.detail,children:m.status})]},m.name))}),e.jsxs("div",{className:"grid grid-cols-2 gap-2 md:grid-cols-4",children:[e.jsxs("div",{className:"rounded-md border bg-background px-3 py-2",children:[e.jsx("div",{className:"text-[10px] text-muted-foreground",children:"Pods"}),e.jsxs("div",{className:"mt-0.5 font-mono text-sm",children:[r.rollup.ready," / ",r.rollup.pods," ready"]})]}),e.jsxs("div",{className:"rounded-md border bg-background px-3 py-2",children:[e.jsx("div",{className:"text-[10px] text-muted-foreground",children:"CPU"}),e.jsx("div",{className:"mt-0.5 font-mono text-sm",children:r.rollup.cpu})]}),e.jsxs("div",{className:"rounded-md border bg-background px-3 py-2",children:[e.jsx("div",{className:"text-[10px] text-muted-foreground",children:"Memory"}),e.jsx("div",{className:"mt-0.5 font-mono text-sm",children:r.rollup.memory})]})]})]})]})]})]})}function Ps({text:t}){const[s,n]=d.useState(!1),r=()=>{var o;const a=(o=navigator.clipboard)==null?void 0:o.writeText(t);a&&typeof a.then=="function"&&a.then(()=>{n(!0),setTimeout(()=>n(!1),1200)}).catch(()=>{})};return e.jsx("button",{type:"button","aria-label":"Copy command",onClick:r,className:"inline-flex h-6 w-6 shrink-0 items-center justify-center rounded border border-input bg-background text-muted-foreground hover:bg-accent hover:text-accent-foreground",children:s?e.jsx(qn,{className:"h-3 w-3 text-success"}):e.jsx(Gn,{className:"h-3 w-3"})})}function lt({text:t}){return e.jsxs("div",{className:"flex items-center gap-2 rounded-md border bg-background px-3 py-2",children:[e.jsx("code",{className:"flex-1 truncate font-mono text-xs text-foreground",title:t,children:t}),e.jsx(Ps,{text:t})]})}const ns="rounded-full border px-2 py-0.5 text-[10px] transition-colors",rs="border-border bg-background text-muted-foreground hover:bg-accent/50",fo="border-primary/40 bg-primary/10 text-primary";function as({statuses:t,value:s,onChange:n}){return e.jsxs("div",{className:"flex flex-wrap items-center gap-1.5",children:[e.jsx("button",{type:"button","aria-pressed":s==="",onClick:()=>n(""),className:`${ns} ${s===""?fo:rs}`,children:"All"}),t.map(r=>{const a=s===r;return e.jsx("button",{type:"button","aria-pressed":a,onClick:()=>n(a?"":r),className:`${ns} ${a?Ds(Es(r)):rs}`,children:r},r)})]})}const po=new Set(["Degraded","Failed","Down","Invalid"]);function go(t){return po.has(t)}function Ks({status:t,reason:s}){return e.jsx("span",{title:s||void 0,className:`inline-flex items-center rounded-full border px-2.5 py-0.5 text-[11px] ${at(t)}`,children:t||"Unknown"})}function jo({status:t,reason:s}){return go(t)?e.jsxs(I,{variant:"destructive",children:[e.jsx(dn,{children:t}),s&&e.jsx(F,{children:s})]}):null}function le({label:t,children:s}){return e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx("span",{className:"text-[10px] font-medium uppercase tracking-wide text-muted-foreground",children:t}),e.jsx("div",{className:"text-sm text-foreground",children:s})]})}function yt({children:t}){return e.jsx("span",{className:"rounded-full border bg-background px-2 py-0.5 text-[10px] font-mono text-muted-foreground",children:t})}function ye(t,s){var n,r;return(r=(n=t.badges)==null?void 0:n.find(a=>a.key===s))==null?void 0:r.value}function it(t){return t.namespace?`${t.namespace}/${t.name}`:t.name}function bo({status:t,reason:s}){const n=e.jsx("span",{className:`inline-flex items-center rounded-full border px-2 py-0.5 text-[10px] ${at(t)}`,children:t||"—"});return s?e.jsx(un,{delayDuration:0,children:e.jsxs(xn,{children:[e.jsx(mn,{asChild:!0,children:n}),e.jsx(hn,{className:"max-w-xs whitespace-normal break-words text-xs",children:s})]})}):n}function vo(t,s){if(s.render)return s.render(t);if(s.source==="scope")return e.jsx(yt,{children:t.scope});if(s.source==="count"){const r=t.counts??[],a=s.key?r.find(o=>o.label===s.key):r[0];return a?e.jsx("span",{className:"font-mono text-xs text-muted-foreground",children:a.value}):e.jsx("span",{className:"text-muted-foreground",children:"—"})}const n=(t.badges??[]).filter(r=>s.key?r.key===s.key:!0);return n.length===0?e.jsx("span",{className:"text-muted-foreground",children:"—"}):e.jsx("span",{className:"flex flex-wrap gap-1",children:n.map((r,a)=>s.colorize?e.jsx(rt,{kind:r.value},`${r.key}-${r.value}-${a}`):e.jsx(yt,{children:r.value},`${r.key}-${r.value}-${a}`))})}function yo(t){const s=d.useState(""),n=$t(t??"","");return t?n:s}function _s({rows:t,columns:s,entity:n,facet:r,statusCookieKey:a,loading:o,note:i,emptyText:l}){const[c,u]=d.useState(""),[h,N]=yo(a),[p,b]=d.useState(""),x=d.useMemo(()=>{const m=new Set;for(const w of t)w.status&&m.add(w.status);return Array.from(m).sort()},[t]),j=d.useMemo(()=>{if(!r)return[];const m=new Set;for(const w of t)for(const R of w.badges??[])R.key===r.key&&m.add(R.value);return Array.from(m).sort()},[t,r]),$=t.some(m=>m.manageCmd),C=c.trim().toLowerCase(),E=t.filter(m=>(h===""||m.status===h)&&(p===""||(m.badges??[]).some(w=>r&&w.key===r.key&&w.value===p))&&(C===""||m.name.toLowerCase().includes(C)||(m.namespace??"").toLowerCase().includes(C)));return o?e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading…"}):t.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:l??"Nothing configured yet."}):e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("input",{type:"text",value:c,onChange:m=>u(m.target.value),placeholder:"Filter by name…","aria-label":"Filter by name",className:"h-8 w-56 rounded-md border border-input bg-background px-3 text-xs outline-none focus-visible:ring-1 focus-visible:ring-ring"}),x.length>1&&e.jsx(as,{statuses:x,value:h,onChange:N})]}),r&&j.length>1&&e.jsxs("div",{className:"flex flex-wrap items-center gap-1.5",children:[e.jsx("span",{className:"text-[10px] uppercase tracking-wide text-muted-foreground",children:r.label}),e.jsx(as,{statuses:j,value:p,onChange:b})]}),e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{children:"Name"}),s.map(m=>e.jsx(y,{className:m.align==="right"?"text-right":"",children:m.header},m.header)),e.jsx(y,{children:"Status"}),$&&e.jsx(y,{children:"Manage"})]})}),e.jsxs(X,{children:[E.map(m=>e.jsxs(M,{children:[e.jsxs(v,{children:[n?e.jsx(W,{entity:n,id:it(m),className:"font-mono text-xs text-link hover:underline",children:m.name}):e.jsx("div",{className:"font-mono text-xs text-foreground",children:m.name}),m.namespace&&e.jsx("div",{className:"font-mono text-[10px] text-muted-foreground",children:m.namespace})]}),s.map(w=>e.jsx(v,{className:w.align==="right"?"text-right":"",children:vo(m,w)},w.header)),e.jsx(v,{children:e.jsx(bo,{status:m.status,reason:m.statusReason})}),$&&e.jsx(v,{children:m.manageCmd?e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("code",{className:"truncate font-mono text-[11px] text-muted-foreground",title:m.manageCmd,children:m.manageCmd}),e.jsx(Ps,{text:m.manageCmd})]}):e.jsx("span",{className:"text-muted-foreground",children:"—"})})]},`${m.namespace??""}/${m.name}`)),E.length===0&&e.jsx(M,{children:e.jsx(v,{colSpan:s.length+($?3:2),className:"text-center text-xs text-muted-foreground",children:"No matches."})})]})]}),i&&e.jsx("p",{className:"text-[11px] text-muted-foreground",children:i})]})}const ce={agents:[{header:"Identity",source:"badge",key:"identityMode"},{header:"Tools",source:"count",key:"tools",align:"right"},{header:"Skills",source:"count",key:"skills",align:"right"}],tools:[{header:"Kind",source:"badge",key:"kind",colorize:!0},{header:"Capabilities",source:"count",align:"right"}],skills:[{header:"Kind",source:"badge",key:"kind",colorize:!0},{header:"Delivery",source:"badge",key:"delivery"},{header:"Pin",source:"badge",key:"pin"}],sources:[{header:"Kind",source:"badge",key:"kind",colorize:!0},{header:"Repo",source:"badge",key:"repo"},{header:"Ref",source:"badge",key:"ref"},{header:"Skills",source:"count",key:"discoveredSkills",align:"right"}],directory:[{header:"Kind",source:"badge",key:"kind",colorize:!0},{header:"Credential",source:"badge",key:"credential"},{header:"Scopes",source:"count",key:"scopes",align:"right"},{header:"Written",source:"count",key:"written",align:"right"},{header:"Join misses",source:"count",key:"joinMisses",align:"right"},{header:"Errors",source:"count",key:"errors",align:"right"}],channels:[{header:"Kind",source:"badge",key:"kind",colorize:!0},{header:"Role",source:"badge",key:"role"},{header:"Agent class",source:"badge",key:"agentClass"}],users:[{header:"Subject",source:"badge",key:"subject"},{header:"Credentials",source:"count",key:"availableCredentials",align:"right"},{header:"Resolved",source:"count",key:"resolved",align:"right"}],identities:[{header:"Credential kinds",source:"badge",key:"cred",colorize:!0},{header:"Credentials",source:"count",key:"credentials",align:"right"},{header:"Resolved",source:"count",key:"resolved",align:"right"}],providers:[{header:"Kind",source:"badge",key:"kind",colorize:!0},{header:"Issuer",source:"badge",key:"issuer"}]},Oe="w-full rounded-md border border-border bg-background px-2 py-1.5 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:opacity-50";function os(t){return t?`Dependency ${t}`:"Root agent"}function Ve(t){var n;const s=((n=t.agentPath)==null?void 0:n.split(" > ").map(r=>r.trim()).filter(Boolean))??[];return s.length===0?t.name:`${s.map(r=>`agents.${r}`).join(".")}.${t.name}`}function re(t){return`${t.agentPath??""}\0${t.name}\0${t.setupToken??""}`}function xt(t,s){const n={};for(const r of s)t[r]!==void 0&&(n[r]=t[r]);return n}function We(t){return t==null?"":typeof t=="string"?t:Array.isArray(t)?t.join(","):String(t)}function No(t,s){var r,a;const n=(r=t.enumLabels)==null?void 0:r[s];return n!==void 0&&n.trim()!==""?n:((a=t.enum)==null?void 0:a[s])??""}function ls({q:t,value:s,onChange:n,disabled:r=!1}){const a=t.required!==!1,o=`${t.prompt||t.name}${a?" *":""}`;return e.jsxs(le,{label:o,children:[t.type==="bool"?e.jsx("input",{type:"checkbox",checked:s==="true",onChange:i=>{r||n(i.target.checked?"true":"false")},disabled:r,"aria-label":o,className:"h-4 w-4 rounded border-border"}):t.type==="enum"?e.jsxs("select",{value:s,onChange:i=>{r||n(i.target.value)},disabled:r,"aria-label":o,className:Oe,children:[e.jsx("option",{value:"",disabled:!0,children:"Select…"}),(t.enum??[]).map((i,l)=>e.jsx("option",{value:i,children:No(t,l)},i))]}):e.jsx("input",{type:t.type==="secret"?"password":t.type==="int"?"number":"text",value:s,onChange:i=>{r||n(i.target.value)},disabled:r,"aria-label":o,placeholder:t.type==="resourceList"?"comma-separated":void 0,autoComplete:t.type==="secret"?"new-password":"off",className:Oe}),t.description&&e.jsx("p",{className:"text-[11px] text-muted-foreground",children:t.description})]})}function wo({apiBase:t,onInstalled:s}){const[n,r]=d.useState("file"),[a,o]=d.useState(null),[i,l]=d.useState(""),[c,u]=d.useState("default"),[h,N]=d.useState(""),[p,b]=d.useState({}),[x,j]=d.useState(null),[$,C]=d.useState([]),[E,m]=d.useState([]),[w,R]=d.useState([]),[O,L]=d.useState([]),[k,g]=d.useState([]),[T,P]=d.useState({}),[V,q]=d.useState({}),[ie,Ce]=d.useState({}),[Rt,Ne]=d.useState(null),[Ot,oe]=d.useState(null),[zs,Me]=d.useState(!1),[It,Ft]=d.useState(!1),qs=n==="file"?a!==null:i.trim()!=="",Mt=()=>{R([]),L([])},Gs=()=>{g([]),P({}),q({}),Ce({}),Ne(null)},we=()=>{Mt(),Gs()},Js=(f,A)=>{b(D=>({...D,[f]:A})),Mt();const S=new Set(Object.entries(V).filter(([,D])=>D==="staged").map(([D])=>D));g(D=>D.filter(K=>S.has(re(K)))),P(D=>xt(D,S)),q(D=>xt(D,S)),Ce(D=>xt(D,S)),Ne(null)},Pt=(f,A,S,D,K,B=!1)=>{f.length>0?j(f):B||j(null),R(A),g(S),C(D),m(K),b(H=>{const G={...H};for(const ne of f){const se=Ve(ne);G[se]===void 0&&ne.default!==void 0&&ne.default!==null&&(G[se]=We(ne.default))}return G}),P(H=>{const G={};for(const ne of S){const se=re(ne),ct={...H[se]??{}};for(const $e of ne.questions??[])ct[$e.name]===void 0&&$e.default!==void 0&&$e.default!==null&&(ct[$e.name]=We($e.default));G[se]=ct}return G}),q(H=>{const G={};for(const ne of S){const se=re(ne);G[se]=H[se]??"pending"}return G}),Ce(H=>{const G={};for(const ne of S){const se=re(ne);H[se]&&(G[se]=H[se])}return G})},Ys=(f,A,S)=>{const D=re(f);P(K=>({...K,[D]:{...K[D]??{},[A]:S}}))},Kt=(f,A)=>{const S=re(f);g(D=>D.map(K=>re(K)===S?{...K,questions:A}:K))},Qs=async f=>{const A=re(f);if(!f.setupToken){oe(`Channel ${f.name} has no setup token.`);return}oe(null),Ne(A);try{const S=await Ut(t,f.setupToken,T[A]??{});Ce(D=>({...D,[A]:{nextSteps:S.nextSteps??[],warnings:S.warnings??[]}})),q(D=>({...D,[A]:"staged"}))}catch(S){S instanceof ht?Kt(f,S.questions):S instanceof J&&S.status===403?Me(!0):oe(S.message)}finally{Ne(null)}},Xs=f=>{const A=Se(f.url);if(!A)return oe("Channel setup returned an unsafe handoff URL."),!1;if(!f.formFields||Object.keys(f.formFields).length===0)return window.open(A,"_blank","noopener,noreferrer"),!0;const S=document.createElement("form");S.method="POST",S.action=A,S.target="_blank",S.rel="noopener noreferrer";for(const[D,K]of Object.entries(f.formFields)){const B=document.createElement("input");B.type="hidden",B.name=D,B.value=K,S.appendChild(B)}document.body.appendChild(S);try{S.submit()}finally{S.remove()}return!0},Zs=async f=>{const A=re(f);if(!f.setupToken){oe(`Channel ${f.name} has no setup token.`);return}oe(null),Ne(A);try{const S=await tr(t,f.setupToken,T[A]??{});if(S.nextAction==="setup"){const D=await Ut(t,f.setupToken,T[A]??{});Ce(K=>({...K,[A]:{nextSteps:D.nextSteps??[],warnings:D.warnings??[]}})),q(K=>({...K,[A]:"staged"}));return}if(!S.url){oe("Channel setup returned no handoff URL or next action.");return}Xs({url:S.url,formFields:S.formFields})&&q(D=>({...D,[A]:"handoff-started"}))}catch(S){S instanceof ht?Kt(f,S.questions):S instanceof J&&S.status===403?Me(!0):oe(S.message)}finally{Ne(null)}},Bs=async()=>{oe(null),Me(!1),C([]),m([]),R([]),L([]),Ft(!0);try{const f=n==="file"?await nr(t,a,{namespace:c,name:h||void 0,values:p,adopt:O}):await sr(t,{ref:i.trim(),namespace:c,name:h||void 0,values:p,adopt:O}),A=k.flatMap(D=>{const K=ie[re(D)];return K?[...K.nextSteps,...K.warnings].map(B=>`${D.name}: ${B}`):[]}),S=A.length===0?f:{...f,warnings:[...f.warnings??[],...A]};j(null),g([]),s(S,c)}catch(f){f instanceof tt?Pt(f.questions,f.conflicts,f.channels,f.skillClones,f.warnings):f instanceof st?Pt(f.questions,f.conflicts,f.channels,f.skillClones,f.warnings,!0):f instanceof J&&f.status===403?Me(!0):oe(f.message)}finally{Ft(!1)}};return e.jsxs("div",{className:"flex flex-col gap-4",children:[zs&&e.jsx(I,{variant:"destructive",children:e.jsx(F,{children:"Not authorized to install agents."})}),Ot&&e.jsx(I,{variant:"destructive",children:e.jsx(F,{children:Ot})}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(U,{type:"button",variant:n==="file"?"default":"outline",size:"sm",onClick:()=>{r("file"),we()},children:"Upload a .oap file"}),e.jsx(U,{type:"button",variant:n==="ref"?"default":"outline",size:"sm",onClick:()=>{r("ref"),we()},children:"Registry ref"})]}),n==="file"?e.jsx(le,{label:"Bundle file",children:e.jsx("input",{type:"file",accept:".oap","aria-label":"Bundle file",onChange:f=>{var A;o(((A=f.target.files)==null?void 0:A[0])??null),we()},className:"text-sm text-foreground"},"file-input")}):e.jsx(le,{label:"Registry ref",children:e.jsx("input",{type:"text",value:i,onChange:f=>{l(f.target.value),we()},placeholder:"ghcr.io/acme/support-bot:1.0.0","aria-label":"Registry ref",className:Oe},"ref-input")}),e.jsxs("div",{className:"grid grid-cols-1 gap-4 sm:grid-cols-2",children:[e.jsx(le,{label:"Namespace *",children:e.jsx("input",{type:"text",value:c,onChange:f=>{u(f.target.value),we()},"aria-label":"Namespace",className:Oe})}),e.jsx(le,{label:"Name (optional)",children:e.jsx("input",{type:"text",value:h,onChange:f=>{N(f.target.value),we()},placeholder:"defaults to the bundled agent's name","aria-label":"Name",className:Oe})})]}),$.length>0&&e.jsxs("div",{className:"flex flex-col gap-1 rounded-md border border-dashed border-border p-3",children:[e.jsxs("p",{className:"text-xs font-medium text-foreground",children:["Installing this agent will clone ",$.length===1?"an external repository":"external repositories",":"]}),e.jsx("ul",{className:"list-disc pl-5 text-xs text-muted-foreground",children:$.map(f=>e.jsxs("li",{children:[e.jsx("span",{className:"text-foreground",children:f.repoURL})," @ ",f.ref||"default branch"," (SkillSource ",f.skillSource,")"]},f.skillSource))})]}),E.length>0&&e.jsx(I,{children:e.jsx(F,{children:e.jsx("ul",{className:"list-disc pl-5 text-xs",children:E.map(f=>e.jsx("li",{children:f},f))})})}),w.length>0&&e.jsxs("div",{className:"flex flex-col gap-2 rounded-md border border-destructive/50 p-3",children:[e.jsx("p",{className:"text-xs font-medium text-foreground",children:"These objects already exist and were not created by this install. Adopting one overwrites its spec with this bundle's, and uninstalling the agent will delete it."}),w.map(f=>{const A=`${f.kind}/${f.name}`,S=f.namespace?`${f.kind} ${f.namespace}/${f.name}`:A;return e.jsxs("label",{className:"flex items-center gap-2 text-xs text-foreground",children:[e.jsx("input",{type:"checkbox",checked:O.includes(A),"aria-label":S,onChange:D=>L(K=>D.target.checked?[...K,A]:K.filter(B=>B!==A)),className:"h-4 w-4 rounded border-border"}),e.jsx("span",{children:S}),f.secret&&e.jsx("span",{className:"text-destructive",children:"overwrites this Secret's data"})]},A)})]}),x&&x.length>0&&e.jsxs("div",{className:"flex flex-col gap-3 rounded-md border border-dashed border-border p-3",children:[e.jsxs("p",{className:"text-xs text-muted-foreground",children:["This bundle needs ",x.length===1?"an answer":"answers"," before it can install:"]}),x.map(f=>e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx("p",{className:"text-[11px] font-medium text-muted-foreground",children:os(f.agentPath)}),e.jsx(ls,{q:f,value:p[Ve(f)]??We(f.default),onChange:A=>Js(Ve(f),A)})]},Ve(f)))]}),k.length>0&&e.jsxs("div",{className:"flex flex-col gap-3 rounded-md border border-dashed border-border p-3",children:[e.jsx("p",{className:"text-xs text-muted-foreground",children:"Complete the required channel setup before resuming the install:"}),k.map(f=>{var K,B;const A=re(f),S=V[A]??"pending",D=T[A]??{};return e.jsxs("div",{className:"flex flex-col gap-2 rounded-md border border-border p-3",children:[e.jsx("p",{className:"text-[11px] font-medium text-muted-foreground",children:os(f.agentPath)}),e.jsx("p",{className:"text-sm font-medium text-foreground",children:f.name}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:[f.kind," · ",f.role]}),f.purpose&&e.jsx("p",{className:"text-xs text-foreground",children:f.purpose}),f.reason&&e.jsx("p",{className:"text-xs text-destructive",children:f.reason}),f.remedy&&e.jsx("p",{className:"text-xs text-muted-foreground",children:f.remedy}),(f.questions??[]).map(H=>e.jsx(ls,{q:H,value:D[H.name]??We(H.default),onChange:G=>Ys(f,H.name,G),disabled:S==="staged"},H.name)),S==="staged"?e.jsxs("div",{className:"flex flex-col gap-1 text-xs",children:[e.jsx("p",{className:"text-success",children:"Setup staged"}),(((K=ie[A])==null?void 0:K.nextSteps)??[]).map(H=>e.jsx("p",{className:"text-foreground",children:H},`next-${H}`)),(((B=ie[A])==null?void 0:B.warnings)??[]).map(H=>e.jsx("p",{className:"text-warning",children:H},`warning-${H}`))]}):f.status==="handoff"&&S==="pending"?e.jsxs(U,{type:"button",size:"sm",className:"self-start",disabled:Rt===A,onClick:()=>void Zs(f),children:["Start browser setup for ",f.name]}):f.status==="ask"||S==="handoff-started"?e.jsx(U,{type:"button",size:"sm",className:"self-start",disabled:Rt===A,onClick:()=>void Qs(f),children:S==="handoff-started"?`Resume ${f.name}`:`Set up ${f.name}`}):e.jsx("p",{className:"text-xs text-destructive",children:"This channel cannot be set up from the browser."})]},A)})]}),e.jsx(U,{type:"button",onClick:Bs,disabled:!qs||It,className:"self-start",children:It?"Installing…":w.length>0&&O.length>0&&Object.values(V).includes("staged")?"Adopt and resume install":w.length>0&&O.length>0?"Adopt and install":Object.values(V).includes("staged")?"Resume install":x?"Submit answers":"Install"})]})}function Us({agents:t}){return e.jsx("ul",{className:"flex flex-col gap-2 pl-4 text-xs text-muted-foreground",children:t.map(s=>e.jsxs("li",{children:[e.jsx("p",{children:s.agentPath?`Dependency ${s.agentPath}`:"Dependency"}),e.jsx("p",{className:"font-mono text-foreground",children:s.name}),s.agents&&s.agents.length>0&&e.jsx(Us,{agents:s.agents})]},`${s.agentPath??""}/${s.name}`))})}function ko({result:t,namespace:s,onClose:n}){return e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsxs("p",{className:"text-sm text-success",children:["Installed ",e.jsx("span",{className:"font-mono",children:t.name})," — ",t.appliedKinds.join(", "),t.secretsCreated>0?`, ${t.secretsCreated} secret${t.secretsCreated===1?"":"s"} created`:"","."]}),t.adopted&&t.adopted.length>0&&e.jsxs("div",{className:"flex flex-col gap-1 rounded-md border border-warning/40 bg-warning/5 p-3",children:[e.jsxs("p",{className:"text-xs font-medium text-warning",children:["This install seized ",t.adopted.length," pre-existing object",t.adopted.length===1?"":"s"," ","not created by it — their specs were overwritten with this bundle's, and"," ",e.jsx("span",{className:"font-mono",children:"oap agent uninstall"})," will delete them."]}),e.jsx("ul",{className:"list-disc pl-4 text-xs text-muted-foreground",children:t.adopted.map(r=>e.jsx("li",{className:"font-mono",children:r},r))})]}),t.warnings&&t.warnings.length>0&&e.jsx("ul",{className:"list-disc pl-4 text-xs text-muted-foreground",children:t.warnings.map(r=>e.jsx("li",{children:r},r))}),t.agents&&t.agents.length>0&&e.jsxs("div",{className:"flex flex-col gap-1 rounded-md border border-border p-3",children:[e.jsx("p",{className:"text-xs font-medium text-foreground",children:"Installed dependencies"}),e.jsx(Us,{agents:t.agents})]}),e.jsxs(et,{children:[e.jsx(U,{variant:"outline",onClick:n,children:"Close"}),e.jsx(U,{onClick:()=>{n(),te({type:"detail",entity:"agent",id:`${s}/${t.name}`})},children:"View agent"})]})]})}function So({apiBase:t,onInstalled:s}){const[n,r]=d.useState(!1),[a,o]=d.useState(null),i=l=>{r(l),l&&o(null)};return e.jsxs(Je,{open:n,onOpenChange:i,children:[e.jsx(Ye,{asChild:!0,children:e.jsx(U,{variant:"outline",size:"sm",children:"Install agent"})}),e.jsxs(Qe,{className:"max-w-xl",children:[e.jsxs(Xe,{children:[e.jsx(Ze,{children:"Install an agent"}),e.jsx(Be,{children:"Upload a packaged .oap bundle or pull one from a registry ref."})]}),a?e.jsx(ko,{result:a.result,namespace:a.namespace,onClose:()=>r(!1)}):e.jsx(wo,{apiBase:t,onInstalled:(l,c)=>{o({result:l,namespace:c}),s==null||s()}})]})]})}function Co(t){return t==="Valid"||t==="Ready"}function is(t,s){var n,r;return((r=(n=t.counts)==null?void 0:n.find(a=>a.label===s))==null?void 0:r.value)??0}function $o(t){return t==="agent"?"bg-state":t==="userPassthrough"?"bg-success":"bg-muted-foreground/40"}function Vs({row:t,linked:s=!0}){const n=ye(t,"identityMode"),r=ye(t,"identityRef");return e.jsxs("span",{className:"inline-flex items-center gap-1.5",children:[e.jsx("span",{"aria-hidden":"true",title:n||void 0,className:`inline-block h-2 w-2 shrink-0 rounded-full ${$o(n)}`}),r&&s?e.jsx(W,{entity:"identity",id:t.namespace?`${t.namespace}/${r}`:r,className:"font-mono text-[11px] text-link hover:underline",onClick:a=>a.stopPropagation(),children:r}):e.jsx("span",{className:"font-mono text-[11px] text-muted-foreground",children:r||n||"—"})]})}const To=ce.agents.map(t=>t.header==="Identity"?{...t,render:s=>e.jsx(Vs,{row:s})}:t);function Lo({a:t}){const s=Co(t.status),n=is(t,"tools"),r=is(t,"skills");return e.jsxs(W,{entity:"agent",id:it(t),className:"block rounded-xl border bg-card p-4 shadow transition-colors hover:border-primary/40",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"font-mono text-sm font-medium text-foreground",children:t.name}),e.jsx("span",{title:t.statusReason||void 0,className:`inline-flex items-center rounded-full border px-2 py-0.5 text-[10px] ${s?"border-success/40 bg-success/10 text-success":"border-destructive/40 bg-destructive/10 text-destructive"}`,children:t.status||"Unknown"})]}),t.namespace&&e.jsx("p",{className:"mt-0.5 font-mono text-[10px] text-muted-foreground",children:t.namespace}),!s&&t.statusReason&&e.jsx("p",{className:"mt-2 text-xs text-destructive",children:t.statusReason}),e.jsx("div",{className:"mt-3 flex flex-wrap gap-1.5",children:e.jsx(Vs,{row:t,linked:!1})}),e.jsxs("p",{className:"mt-3 font-mono text-xs text-muted-foreground",children:[n," tool",n===1?"":"s"," · ",r," skill",r===1?"":"s"]})]})}function Ao({apiBase:t}){const[s,n]=d.useState([]),[r,a]=d.useState(null),[o,i]=d.useState(!1),[l,c]=$t("agents_view","grid"),u=d.useCallback(()=>{let p=!0;return Ct(t,"agents").then(b=>{p&&(n(b),a(null),i(!0))}).catch(b=>{p&&(a(b.message),i(!0))}),()=>{p=!1}},[t]);d.useEffect(()=>u(),[u]);const h="AgentClass — readiness gates sessions · managed via oap class / kubectl agentclass",N=()=>r?e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load agents: ",r]})}):o?s.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No AgentClasses configured yet."}):l==="grid"?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"grid grid-cols-1 gap-3 sm:grid-cols-2 xl:grid-cols-3",children:s.map(p=>e.jsx(Lo,{a:p},it(p)))}),e.jsx("p",{className:"text-[11px] text-muted-foreground",children:h})]}):e.jsx(_s,{rows:s,columns:To,entity:"agent",statusCookieKey:"status_agents",note:h}):e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading agents…"});return e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(So,{apiBase:t,onInstalled:u}),o&&!r&&s.length>0&&e.jsx($s,{value:l,onChange:c})]}),N()]})}function je({apiBase:t,resource:s,columns:n,entity:r,facet:a,mapRows:o,note:i,emptyText:l}){const[c,u]=d.useState([]),[h,N]=d.useState(null),[p,b]=d.useState(!1);d.useEffect(()=>{let j=!0;return Ct(t,s).then($=>{j&&(u($??[]),N(null),b(!0))}).catch($=>{j&&(N($.message),b(!0))}),()=>{j=!1}},[t,s]);const x=o?o(c):c;return e.jsxs("div",{className:"space-y-3",children:[h&&e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load ",s,": ",h]})}),!h&&e.jsx(_s,{rows:x,columns:n,entity:r,facet:a,statusCookieKey:`status_${s}`,loading:!p,note:i,emptyText:l})]})}function Eo({apiBase:t}){return e.jsx(je,{apiBase:t,resource:"tools",entity:"tool",columns:ce.tools,note:"MCPServer · SidecarToolbox · SpiceboxToolkit · SpiceboxToolspec — managed via oap tools / kubectl",emptyText:"No tools configured yet."})}function Do({apiBase:t}){return e.jsx(je,{apiBase:t,resource:"skills",entity:"skill",columns:ce.skills,note:"Skill · ClusterSkill — instruction & executable skills · managed via oap skill / kubectl get skills",emptyText:"No skills configured yet."})}const Ro=ce.sources.map(t=>t.key==="repo"?{...t,render:s=>{const n=ye(s,"repo");return n?Se(n)?e.jsx("a",{href:n,target:"_blank",rel:"noopener noreferrer nofollow",className:"whitespace-nowrap font-mono text-[11px] text-link hover:underline",onClick:r=>r.stopPropagation(),children:n}):e.jsx("code",{className:"whitespace-nowrap font-mono text-[11px] text-muted-foreground",children:n}):e.jsx("span",{className:"text-muted-foreground",children:"—"})}}:t);function Oo({apiBase:t}){return e.jsx(je,{apiBase:t,resource:"sources",entity:"source",columns:Ro,note:"SkillSource · ClusterSkillSource — synced from git · managed via oap skill source add",emptyText:"No skill sources configured yet."})}function Io({apiBase:t}){return e.jsx(je,{apiBase:t,resource:"directory",entity:"directory",columns:ce.directory,note:"RelationshipSource — Slack · GitHub · 1Password · managed via oap directory configure",emptyText:"No directory sources configured yet."})}function Fo(t){return ye(t,"role")==="monitoring"}function Mo({row:t}){const s=ye(t,"role");if(!s)return e.jsx("span",{className:"text-muted-foreground",children:"—"});const n=s==="monitoring";return e.jsx("span",{className:`rounded-full border px-2 py-0.5 text-[10px] font-mono ${n?"border-border bg-background text-muted-foreground":"border-primary/40 bg-primary/10 text-primary"}`,children:s})}function Po({row:t}){const s=ye(t,"agentClass");if(!s)return e.jsx("span",{className:"text-muted-foreground",children:"—"});const n=t.namespace?`${t.namespace}/${s}`:s;return e.jsx(W,{entity:"agent",id:n,className:"font-mono text-[11px] text-link hover:underline",children:s})}const Ko=ce.channels.map(t=>t.key==="role"?{...t,render:s=>e.jsx(Mo,{row:s})}:t.key==="agentClass"?{...t,render:s=>e.jsx(Po,{row:s})}:t);function _o(t){return t.map(s=>Fo(s)?{...s,status:"monitoring"}:s)}function Uo({apiBase:t}){return e.jsx(je,{apiBase:t,resource:"channels",entity:"channel",columns:Ko,mapRows:_o,note:"Channel — where agents are reachable · managed via oap channel / kubectl channel",emptyText:"No channels configured yet."})}const mt=[{id:"identities",label:"Agent identities",sub:"how agents authenticate to upstreams"},{id:"providers",label:"Login providers",sub:"human login for the admin UI & CLI"}];function Vo({apiBase:t}){const[s,n]=d.useState("identities"),r=mt.find(a=>a.id===s)??mt[0];return e.jsxs("div",{className:"space-y-3",children:[e.jsx("div",{role:"tablist",className:"inline-flex h-9 items-center gap-1 rounded-lg bg-muted p-1 text-muted-foreground",children:mt.map(a=>{const o=s===a.id;return e.jsx("button",{type:"button",role:"tab","aria-selected":o,onClick:()=>n(a.id),className:["inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium transition-all",o?"bg-background text-foreground shadow":"hover:text-foreground"].join(" "),children:a.label},a.id)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:r.sub}),s==="identities"?e.jsx(je,{apiBase:t,resource:"identities",entity:"identity",columns:ce.identities,facet:{key:"cred",label:"Type"},note:"AgentIdentity — managed via oap identity · setup flows: github_pat, oauth_mcp, federated (ID-JAG)",emptyText:"No agent identities configured yet."}):e.jsx(je,{apiBase:t,resource:"providers",entity:"provider",columns:ce.providers,note:"ClusterIdentityProvider — managed via oap idp",emptyText:"No login providers configured yet."})]})}const Wo=ce.users.map(t=>t.key==="subject"?{...t,render:s=>{const n=ye(s,"subject");return n?e.jsx(yt,{children:ae(n)}):e.jsx("span",{className:"text-muted-foreground",children:"—"})}}:t);function Ho({apiBase:t}){return e.jsx(je,{apiBase:t,resource:"users",entity:"user",columns:Wo,note:"UserIdentity — people linked to the platform · managed via oap user-identity",emptyText:"No users linked yet."})}function cs({label:t,value:s,sub:n}){return e.jsxs("div",{className:"rounded-xl border bg-card p-4 shadow",children:[e.jsx("div",{className:"text-[11px] text-muted-foreground",children:t}),e.jsx("div",{className:"mt-1 text-2xl font-semibold",children:s}),e.jsx("div",{className:"text-[11px] text-muted-foreground",children:n})]})}function zo({apiBase:t}){const[s,n]=d.useState(null),[r,a]=d.useState(null);if(d.useEffect(()=>{let i=!0;return mr(t).then(l=>{i&&(n(l),a(null))}).catch(l=>{i&&a(l.message)}),()=>{i=!1}},[t]),r)return e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load access: ",r]})});if(!s)return e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading access…"});const o=s.stats.available;return e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsxs("div",{className:"mb-2 text-xs font-semibold text-muted-foreground",children:["Platform admins ",e.jsx("span",{className:"font-normal",children:"· who can reach this admin UI (platform:platform#admin)"})]}),s.admins.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No platform admins granted yet."}):e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{children:"Subject"}),e.jsx(y,{children:"Kind"})]})}),e.jsx(X,{children:s.admins.map(i=>e.jsxs(M,{children:[e.jsx(v,{className:"font-mono text-xs text-foreground",title:i.subject,children:ae(i.subject)}),e.jsx(v,{children:e.jsxs("span",{className:"inline-flex items-center gap-1.5 text-xs text-muted-foreground",children:[i.kind==="group"?e.jsx(ms,{className:"h-3.5 w-3.5"}):e.jsx(Jn,{className:"h-3.5 w-3.5"}),i.kind]})})]},i.subject))})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(lt,{text:s.grantCmd}),e.jsx("p",{className:"text-[11px] text-muted-foreground",children:"Run via the CLI — the admin UI is read-only. Also: oap platform revoke-admin / list-admins."})]}),o?e.jsxs("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-2",children:[e.jsx(cs,{label:"SpiceDB schema",value:s.stats.schemaDefs!=null?`${s.stats.schemaDefs}`:"—",sub:"definitions"}),e.jsx(cs,{label:"Relationships",value:s.stats.relationships!=null?s.stats.relationships.toLocaleString():"—",sub:"stored tuples"})]}):e.jsxs("div",{className:"rounded-xl border border-dashed bg-card p-4 shadow",children:[e.jsx("div",{className:"text-[11px] text-muted-foreground",children:"SpiceDB stats"}),e.jsx("div",{className:"mt-1 text-sm text-muted-foreground",children:"Stats unavailable — schema-definition & relationship counts aren't exposed through the permissions API in v1. Wiring a live source is a follow-up."})]}),e.jsx("p",{className:"text-[11px] text-muted-foreground",children:"Authorization primitive — schema composed by the operator · oap spicedb apply-schema / oap spicedb check"})]})}const ds=["Limits","Defaults"];function qo(t){const s=new Map;for(const r of t){const a=s.get(r.group)??[];a.push(r),s.set(r.group,a)}return[...s.keys()].sort((r,a)=>{const o=ds.indexOf(r),i=ds.indexOf(a);return o===-1&&i===-1?0:o===-1?1:i===-1?-1:o-i}).flatMap(r=>s.get(r).map((a,o)=>({row:a,group:o===0?r:void 0})))}function Go({apiBase:t}){const[s,n]=d.useState(null),[r,a]=d.useState(null);if(d.useEffect(()=>{let i=!0;return jr(t).then(l=>{i&&(n(l),a(null))}).catch(l=>{i&&a(l.message)}),()=>{i=!1}},[t]),r)return e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load settings: ",r]})});if(!s)return e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading settings…"});const o=qo(s.rows);return e.jsxs("div",{className:"space-y-4",children:[s.rows.length===0?e.jsx("div",{className:"rounded-xl border border-dashed bg-card p-4 shadow",children:e.jsx("p",{className:"text-sm text-muted-foreground",children:s.note||"No ClusterAgentSettings configured — cluster governance uses built-in defaults."})}):e.jsx("div",{className:"rounded-xl border bg-card shadow",children:e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{className:"w-28",children:"Group"}),e.jsx(y,{children:"Setting"}),e.jsx(y,{children:"Value"}),e.jsx(y,{children:"Note"})]})}),e.jsx(X,{children:o.map(({row:i,group:l},c)=>e.jsxs(M,{children:[e.jsx(v,{className:"align-top text-xs font-semibold text-muted-foreground",children:l??""}),e.jsx(v,{className:"align-top text-xs text-muted-foreground",children:i.label}),e.jsx(v,{className:"align-top font-mono text-xs text-foreground",children:i.value}),e.jsx(v,{className:"align-top text-[11px] text-muted-foreground",children:i.note??""})]},`${i.group}-${i.label}-${c}`))})]})}),e.jsx(lt,{text:s.manageCmd}),e.jsxs("p",{className:"text-[11px] text-muted-foreground",children:["ClusterAgentSettings (singleton ",e.jsx("span",{className:"font-mono",children:"cluster"}),") → namespace AgentSettings → AgentClass → session. Edit via the CLI — the admin UI is read-only."]})]})}const Jo=["oap agent pull "];function Yo(t){return Jo.some(s=>t.startsWith(s))}const Qo=new Set(["kind","channel kind","credential kind","credential type"]);function Xo(t){return Qo.has(t.trim().toLowerCase())}function Ws({section:t}){switch(t.kind){case"text":return e.jsx(el,{text:t.text??""});case"list":return e.jsx(tl,{items:t.items??[],notice:t.text});case"fields":default:return e.jsx(Bo,{fields:t.fields??[]})}}function Hs({entity:t,id:s,children:n}){return Ns(t)?e.jsx(W,{entity:t,id:s,className:"font-mono text-xs text-link hover:underline",children:n}):e.jsx(e.Fragment,{children:n})}function Nt({href:t,children:s}){return e.jsx("a",{href:t,target:"_blank",rel:"noopener noreferrer nofollow",className:"break-words font-mono text-xs text-link hover:underline",children:s})}function Zo({field:t}){if(t.link)return e.jsx(Hs,{entity:t.link.entity,id:t.link.id,children:t.value});if(t.href){const n=Se(t.href);if(n)return e.jsx(Nt,{href:n,children:t.value})}if(t.value&&Xo(t.label))return e.jsx(rt,{kind:t.value});if(Yo(t.value))return e.jsx(lt,{text:t.value});const s=Se(t.value);return s?e.jsx(Nt,{href:s,children:t.value}):e.jsx("span",{className:"break-words",children:t.value})}function Bo({fields:t}){return t.length===0?e.jsx(Dt,{}):e.jsx("div",{className:"flex flex-col gap-4",children:t.map((s,n)=>e.jsx(le,{label:s.label,children:e.jsx(Zo,{field:s})},`${s.label}-${n}`))})}function el({text:t}){return t===""?e.jsx(Dt,{}):e.jsx("pre",{className:"whitespace-pre-wrap break-words rounded-md border border-border bg-card p-4 font-mono text-xs text-foreground",children:t})}function tl({items:t,notice:s}){const n=s?e.jsx(I,{variant:"destructive",className:"mb-3",children:e.jsx(F,{children:s})}):null;return t.length===0?e.jsxs(e.Fragment,{children:[n,!s&&e.jsx(Dt,{})]}):e.jsxs(e.Fragment,{children:[n,e.jsx("ul",{className:"flex flex-col gap-2",children:t.map((r,a)=>e.jsxs("li",{className:"rounded-md border border-border bg-card p-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx(sl,{item:r}),e.jsx(nl,{badges:r.badges})]}),r.subtitle&&e.jsx("p",{className:"mt-1 text-[11px] text-muted-foreground",children:r.subtitle})]},`${r.title}-${a}`))})]})}function sl({item:t}){if(t.link)return e.jsx(Hs,{entity:t.link.entity,id:t.link.id,children:t.title});if(t.href){const s=Se(t.href);if(s)return e.jsx(Nt,{href:s,children:t.title})}return e.jsx("span",{className:"font-mono text-xs text-foreground",children:t.title})}function nl({badges:t}){const s=t??[];return s.length===0?null:e.jsx("span",{className:"flex flex-wrap gap-1",children:s.map((n,r)=>e.jsx(rt,{kind:n.value},`${n.key}-${n.value}-${r}`))})}function Dt(){return e.jsx("p",{className:"text-sm text-muted-foreground",children:"Nothing here."})}const us={detail:null,loading:!0,error:null,notFound:!1};function rl(t,s,n){const[r,a]=d.useState(us);return d.useEffect(()=>{let o=!0;return a(us),(async()=>{if(!n.includes("/")){const c=(await Ct(t,s)).find(u=>u.name===n);if(c)return Vt(t,s,it(c))}return Vt(t,s,n)})().then(l=>{o&&a({detail:l,loading:!1,error:null,notFound:!1})}).catch(l=>{o&&(l instanceof J&&l.status===404?a({detail:null,loading:!1,error:null,notFound:!0}):a({detail:null,loading:!1,error:l.message,notFound:!1}))}),()=>{o=!1}},[t,s,n]),r}function xs({detail:t,section:s}){return e.jsxs("div",{className:"flex flex-col gap-5",children:[t.description&&e.jsx("p",{className:"text-base text-foreground",children:t.description}),e.jsx(jo,{status:t.status,reason:t.statusReason}),e.jsxs("div",{className:"flex flex-wrap gap-8",children:[e.jsx(le,{label:"Status",children:e.jsx(Ks,{status:t.status,reason:t.statusReason})}),e.jsx(le,{label:"Scope",children:e.jsx("span",{className:"text-sm capitalize text-foreground",children:t.scope})}),t.namespace&&e.jsx(le,{label:"Namespace",children:e.jsx("span",{className:"font-mono text-xs text-foreground",children:t.namespace})})]}),s&&e.jsx(Ws,{section:s}),t.manageCmd&&e.jsx(le,{label:"Manage",children:e.jsx(lt,{text:t.manageCmd})})]})}function de({apiBase:t,resource:s,entity:n,id:r,tab:a,backRoute:o,extraTabs:i=[],subtitle:l}){var O;const{detail:c,loading:u,error:h,notFound:N}=rl(t,s,r),p=new Set(["overview",...i.map(L=>L.id)]),b=(O=c==null?void 0:c.sections)==null?void 0:O.find(L=>L.id==="overview"),x=((c==null?void 0:c.sections)??[]).filter(L=>!p.has(L.id)),j=[{id:"overview",label:"Overview"},...i.map(L=>({id:L.id,label:L.label})),...x.map(L=>({id:L.id,label:L.label}))],$=new Set(j.map(L=>L.id)),C=a&&$.has(a)?a:"overview",E=L=>te({type:"detail",entity:n,id:r,tab:L}),m=c?e.jsx(Z,{ns:c.namespace,name:c.name}):e.jsx(Z,{id:r}),w=c&&l?l(c):void 0,R=()=>{if(u)return e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading…"});if(h)return e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load ",s,": ",h]})});if(N||!c)return e.jsxs("p",{className:"text-sm text-muted-foreground",children:["Not found: ",r]});if(C==="overview")return e.jsx(xs,{detail:c,section:b});const L=i.find(g=>g.id===C);if(L)return L.render(c);const k=x.find(g=>g.id===C);return k?e.jsx(Ws,{section:k}):e.jsx(xs,{detail:c,section:b})};return e.jsx(nt,{title:m,subtitle:w,backRoute:o,tabs:j,activeTab:C,onTab:E,headerRight:c?e.jsx(Ks,{status:c.status,reason:c.statusReason}):void 0,children:R()})}function al({apiBase:t,agentClass:s}){const[n,r]=d.useState(null),[a,o]=d.useState(null);if(d.useEffect(()=>{let l=!0;return _(`${t}/sessions`).then(c=>{l&&(r(c),o(null))}).catch(c=>{l&&o(c.message)}),()=>{l=!1}},[t]),a)return e.jsxs("p",{className:"text-xs text-destructive",children:["Could not load sessions: ",a]});if(n===null)return e.jsx("p",{className:"text-xs text-muted-foreground",children:"Loading sessions…"});const i=n.filter(l=>l.class===s);return i.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No live sessions for this agent."}):e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{children:"Session"}),e.jsx(y,{children:"Phase"}),e.jsx(y,{children:"Started"})]})}),e.jsx(X,{children:i.map(l=>e.jsxs(M,{children:[e.jsx(v,{className:"font-mono text-xs",children:e.jsx(W,{entity:"session",id:`${l.namespace}/${l.name}`,className:"text-link hover:underline",children:e.jsx(Z,{ns:l.namespace,name:l.name})})}),e.jsx(v,{children:e.jsx(At,{phase:l.phase})}),e.jsx(v,{className:"whitespace-nowrap text-xs text-muted-foreground",children:Lt(l.startedAt)})]},`${l.namespace}/${l.name}`))})]})}function ol({apiBase:t,id:s,tab:n}){return e.jsx(de,{apiBase:t,resource:"agents",entity:"agent",id:s,tab:n,backRoute:{type:"view",view:"agents"},extraTabs:[{id:"sessions",label:"Sessions",render:r=>e.jsx(al,{apiBase:t,agentClass:r.name})}]})}function ll({apiBase:t,id:s,tab:n}){return e.jsx(de,{apiBase:t,resource:"tools",entity:"tool",id:s,tab:n,backRoute:{type:"view",view:"tools"}})}function il({apiBase:t,id:s,tab:n}){return e.jsx(de,{apiBase:t,resource:"skills",entity:"skill",id:s,tab:n,backRoute:{type:"view",view:"skills"}})}function cl({apiBase:t,id:s,tab:n}){return e.jsx(de,{apiBase:t,resource:"sources",entity:"source",id:s,tab:n,backRoute:{type:"view",view:"sources"}})}function dl({apiBase:t,id:s,tab:n}){return e.jsx(de,{apiBase:t,resource:"directory",entity:"directory",id:s,tab:n,backRoute:{type:"view",view:"directory"}})}function ul({apiBase:t,id:s,tab:n}){return e.jsx(de,{apiBase:t,resource:"channels",entity:"channel",id:s,tab:n,backRoute:{type:"view",view:"channels"}})}function xl({apiBase:t,id:s,tab:n}){return e.jsx(de,{apiBase:t,resource:"identities",entity:"identity",id:s,tab:n,backRoute:{type:"view",view:"identity"}})}function ml({apiBase:t,id:s,tab:n}){return e.jsx(de,{apiBase:t,resource:"providers",entity:"provider",id:s,tab:n,backRoute:{type:"view",view:"identity"}})}function hl({apiBase:t,id:s,tab:n}){return e.jsx(de,{apiBase:t,resource:"users",entity:"user",id:s,tab:n,backRoute:{type:"view",view:"users"},subtitle:r=>ae(r.description??"")})}fn();function fl({apiBase:t,currentUser:s}){const n=ks(),[r,a]=d.useState({});function o(u){a(u),te({type:"view",view:"logs"})}const i=Kr(n),l=n.type==="detail"?pl(n,t):c(n.view);function c(u){switch(u){case"overview":return e.jsx(ho,{apiBase:t});case"sessions":return e.jsx(ta,{apiBase:t});case"toolcalls":return e.jsx(ra,{apiBase:t});case"approvals":return e.jsx(ia,{apiBase:t,onOpenSession:(h,N)=>te({type:"detail",entity:"session",id:`${h}/${N}`})});case"workshops":return e.jsx(ma,{apiBase:t});case"logs":return e.jsx(Ka,{apiBase:t,initialFilter:r},JSON.stringify(r));case"sessionsAudit":return e.jsx(Ha,{apiBase:t,axis:"sessions",onDrill:o});case"budget":return e.jsx(ao,{apiBase:t});case"artifacts":return e.jsx(Qa,{apiBase:t,onDrill:o});case"memory":return e.jsx(oo,{apiBase:t});case"knowledge":return e.jsx(lo,{apiBase:t});case"agents":return e.jsx(Ao,{apiBase:t});case"tools":return e.jsx(Eo,{apiBase:t});case"skills":return e.jsx(Do,{apiBase:t});case"sources":return e.jsx(Oo,{apiBase:t});case"directory":return e.jsx(Io,{apiBase:t});case"channels":return e.jsx(Uo,{apiBase:t});case"identity":return e.jsx(Vo,{apiBase:t});case"users":return e.jsx(Ho,{apiBase:t});case"access":return e.jsx(zo,{apiBase:t});case"settings":return e.jsx(Go,{apiBase:t});default:return e.jsx(Or,{view:u})}}return e.jsx(Rr,{view:i,onNavigate:u=>te({type:"view",view:u}),currentUser:s,apiBase:t,children:l})}function pl(t,s){const{entity:n,id:r,tab:a}=t;switch(n){case"session":return e.jsx(wa,{apiBase:s,id:r,tab:a});case"agent":return e.jsx(ol,{apiBase:s,id:r,tab:a});case"tool":return e.jsx(ll,{apiBase:s,id:r,tab:a});case"skill":return e.jsx(il,{apiBase:s,id:r,tab:a});case"source":return e.jsx(cl,{apiBase:s,id:r,tab:a});case"directory":return e.jsx(dl,{apiBase:s,id:r,tab:a});case"channel":return e.jsx(ul,{apiBase:s,id:r,tab:a});case"identity":return e.jsx(xl,{apiBase:s,id:r,tab:a});case"provider":return e.jsx(ml,{apiBase:s,id:r,tab:a});case"user":return e.jsx(hl,{apiBase:s,id:r,tab:a});case"artifact":return e.jsx(eo,{apiBase:s,id:r,tab:a});default:return e.jsx(gl,{route:t})}}function gl({route:t}){const s=t.tab??"overview";return e.jsx(nt,{title:`${t.entity} ${t.id}`,subtitle:"Detail page lands in a later batch",tabs:[{id:"overview",label:"Overview"}],activeTab:s,onTab:n=>te({type:"detail",entity:t.entity,id:t.id,tab:n}),children:e.jsx("p",{className:"text-sm text-muted-foreground",children:"Detail page lands in a later batch."})})}pn(fl); +import{c as Ge,r as en,f as Pe,s as _t,C as me,b as he,d as fe,e as pe,T as tn,g as sn,h as nn,i as rn,A as I,a as F,j as Y,k as Q,l as M,n as y,o as X,p as v,B as U,D as Je,q as Ye,t as Qe,u as Xe,v as Ze,w as Be,x as et,y as wt,S as an,z as on,E as ln,F as cn,G as dn,H as un,I as xn,J as mn,K as hn,L as fn,m as pn}from"./mount.D4ypHaeQ.js";import{r as d,j as e,L as gn,A as jn,T as bn,S as vn,H as yn,B as Nn,W as wn,a as kn,G as Sn,F as Cn,b as $n,K as Tn,U as ms,c as Ln,d as An,e as En,f as Dn,g as Rn,h as On,D as In,N as hs,i as Fn,k as Mn,l as Pn,M as Kn,C as _n,m as Un,n as Vn,o as Wn,p as Hn,q as fs,X as zn,s as qn,t as Gn,u as Jn}from"./vendor.C5MRNvUt.js";import{B as z}from"./badge.hXhpY1Si.js";import{M as kt}from"./model-name.BXiF0QjK.js";const Ke="M159.186 7.59677C164.993 -2.53226 179.604 -2.53226 185.411 7.59677L342.572 281.702C348.349 291.779 341.075 304.335 329.459 304.335H15.138C3.52262 304.335 -3.75273 291.779 2.02468 281.702L159.186 7.59677Z",Yn="M178.855 133.226C175.951 128.161 168.646 128.161 165.742 133.226L117.254 217.794C114.366 222.832 118.003 229.11 123.811 229.11H220.786C226.594 229.11 230.232 222.832 227.343 217.794L178.855 133.226Z",Te=[1,2,3,4,5].map(t=>`hsl(var(--chart-${t}))`),_e=12,Qn=3.2,Xn=.55,Zn=.35;function Bn(){return typeof window<"u"&&typeof window.matchMedia=="function"?window.matchMedia("(prefers-reduced-motion: reduce)").matches:!1}function Le(t,s,n,r){if(t){if(n<=.05){t.style.opacity="0";return}t.style.opacity="1",t.style.stroke=r,t.style.strokeDasharray=`${n} ${100-n}`,t.style.strokeDashoffset=`${-s}`}}function er({className:t,title:s,active:n=!1,lapMs:r=2400,band:a=12,bandWidth:o=12,handoverEvery:i=2,...l}){const c=d.useRef(null),u=d.useRef(null),h=d.useRef([]),N=n&&!Bn();d.useEffect(()=>{if(!N)return;const b=performance.now();let x=0;const j=$=>{const C=($-b)/r,E=C*100%100,m=(E-a+100)%100,w=Math.floor(C*3),R=Math.floor(w/i),O=Te[R%Te.length],L=Te[(R-1+Te.length)%Te.length],k=w/3*100%100,g=(E-k+100)%100,T=w%i===0&&gcancelAnimationFrame(x)},[N,r,a,i]);const p={opacity:0};return e.jsxs("svg",{viewBox:"0 0 345 305",fill:"currentColor","aria-hidden":s?void 0:!0,role:s?"img":void 0,className:Ge("shrink-0 overflow-visible",t),"data-relay":N?"on":"off",...l,children:[s?e.jsx("title",{children:s}):null,e.jsx("path",{d:Ke+Yn,style:{opacity:N?Zn:1,transition:"opacity 240ms ease-out"},"data-ink":!0}),e.jsxs("g",{fill:"none",strokeWidth:o,strokeLinecap:"round",strokeLinejoin:"round",style:{opacity:N?1:0,transition:"opacity 240ms ease-out"},children:[Array.from({length:_e},(b,x)=>e.jsx("path",{ref:j=>{h.current[x]=j},d:Ke,pathLength:100,style:p,strokeLinecap:"butt","data-seg":"tail"},x)),e.jsx("path",{ref:c,d:Ke,pathLength:100,style:p,"data-seg":"a"}),e.jsx("path",{ref:u,d:Ke,pathLength:100,style:p,"data-seg":"b"})]})]})}const ps=[{group:"",items:[{id:"overview",label:"Overview",icon:gn}]},{group:"Live",items:[{id:"sessions",label:"Agent sessions",icon:jn},{id:"toolcalls",label:"Live tool calls",icon:bn},{id:"approvals",label:"Approvals",icon:vn},{id:"workshops",label:"Workshops",icon:yn}]},{group:"Config",items:[{id:"agents",label:"Agents",icon:Nn},{id:"tools",label:"Tools",icon:wn},{id:"skills",label:"Skills",icon:kn},{id:"sources",label:"Sources",icon:Sn},{id:"directory",label:"Directory",icon:Cn},{id:"channels",label:"Channels",icon:$n},{id:"identity",label:"Identity",icon:Tn},{id:"users",label:"Users",icon:ms},{id:"access",label:"Access",icon:Ln},{id:"settings",label:"Settings",icon:An}]},{group:"Audit",items:[{id:"logs",label:"Logs",icon:En},{id:"sessionsAudit",label:"Sessions",icon:Dn},{id:"budget",label:"Budget",icon:Rn},{id:"artifacts",label:"Artifacts",icon:On},{id:"memory",label:"Memory",icon:In},{id:"knowledge",label:"Knowledge",icon:hs}]}],gs={overview:{title:"Overview",sub:"Platform at a glance — usage, spend, and health"},sessions:{title:"Agent sessions",sub:"Live agent sessions across the platform"},toolcalls:{title:"Live tool calls",sub:"Tool invocations as they happen, across every session"},approvals:{title:"Approvals",sub:"Tool calls & leakage gates awaiting a decision"},workshops:{title:"Workshops",sub:"Agent-builder sessions' drafted bundles — install, decline, or kill"},agents:{title:"Agents",sub:"Configured AgentClasses and their readiness · oap class / kubectl agentclass"},tools:{title:"Tools",sub:"MCP servers, sandboxed CLIs, sidecars, toolkits · oap tools"},skills:{title:"Skills",sub:"Instruction & executable skills available to agents · oap skill"},sources:{title:"Sources",sub:"Skill sources synced from git · oap skill source"},directory:{title:"Directory",sub:"Directory syncs feeding SpiceDB — Slack, GitHub, 1Password · oap directory"},channels:{title:"Channels",sub:"Where agents are reachable · oap channel / kubectl channel"},identity:{title:"Identity",sub:"Agent identities, credentials, and login providers · oap identity / oap idp"},users:{title:"Users",sub:"People linked to the platform · oap user-identity"},access:{title:"Access",sub:"Platform admins & the SpiceDB authorization schema · oap platform / oap spicedb"},settings:{title:"Settings",sub:"Cluster configuration — defaults, ceilings, security · oap settings"},logs:{title:"Logs",sub:"Cross-session audit — approvals, authz, tool calls, scope changes · oap audit"},sessionsAudit:{title:"Sessions",sub:"Every agent session, current and historical"},budget:{title:"Budget",sub:"Estimated spend by model, agent, session, user"},artifacts:{title:"Artifacts",sub:"Rendered outputs agents produced · oap artifact"},memory:{title:"Memory",sub:"The searchable, authorized memory store · oap memory"},knowledge:{title:"Knowledge",sub:"The knowledge graph — entities, facts, communities · oap kg"}};class J extends Error{constructor(s,n){super(s),this.status=n}}class tt extends J{constructor(s,n,r=[],a=[],o=[],i=[]){super(s,400),this.questions=n,this.skillClones=r,this.warnings=a,this.channels=o,this.conflicts=i}}class st extends J{constructor(s,n,r=[],a=[],o=[],i=[]){super(s,409),this.conflicts=n,this.skillClones=r,this.channels=a,this.warnings=o,this.questions=i}}async function js(t,s){var a,o,i;const n=await fetch(`${t}/agents/oap-install`,s);if(n.ok)return await n.json();let r={};try{r=await n.json()}catch{}throw n.status===400&&((((a=r.questions)==null?void 0:a.length)??0)>0||(((o=r.channels)==null?void 0:o.length)??0)>0||(((i=r.conflicts)==null?void 0:i.length)??0)>0)?new tt(r.error||"missing required question(s)",r.questions??[],r.skillClones??[],r.warnings??[],r.channels??[],r.conflicts??[]):n.status===409&&r.conflicts&&r.conflicts.length>0?new st(r.error||"install would overwrite pre-existing object(s)",r.conflicts,r.skillClones??[],r.channels??[],r.warnings??[],r.questions??[]):new J(r.error||`request failed (${n.status})`,n.status)}class ht extends J{constructor(s,n){super(s,400),this.questions=n}}async function bs(t,s,n){var o;const r=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({setupToken:s,answers:n})});if(r.ok)return await r.json();let a={};try{a=await r.json()}catch{}throw r.status===400&&(((o=a.questions)==null?void 0:o.length)??0)>0?new ht(a.error||"missing required channel answer(s)",a.questions??[]):new J(a.error||`request failed (${r.status})`,r.status)}const Ut=(t,s,n)=>bs(`${t}/agents/channel-setup`,s,n),tr=(t,s,n)=>bs(`${t}/agents/channel-handoff`,s,n),sr=(t,s)=>js(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)}),nr=(t,s,n)=>{var a;const r=new FormData;return r.append("file",s),r.append("namespace",n.namespace),n.name&&r.append("name",n.name),n.values&&r.append("values",JSON.stringify(n.values)),(a=n.adopt)!=null&&a.length&&r.append("adopt",JSON.stringify(n.adopt)),js(t,{method:"POST",body:r})};async function rr(t,s){const n=await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(n.ok)return await n.json();let r={};try{r=await n.json()}catch{}throw n.status===400&&r.questions&&r.questions.length>0?new tt(r.error||"missing required question(s)",r.questions,r.skillClones??[],r.warnings??[]):n.status===409&&r.conflicts&&r.conflicts.length>0?new st(r.error||"install would overwrite pre-existing object(s)",r.conflicts,r.skillClones??[]):new J(r.error||`request failed (${n.status})`,n.status)}const ar=(t,s,n,r)=>rr(`${t}/workshops/${s}/${n}/install`,r);async function St(t){if(!t.ok){let s=`request failed (${t.status})`;try{const n=await t.json();n.error&&(s=n.error)}catch{}throw new J(s,t.status)}return await t.json()}const _=async t=>St(await fetch(t)),or=t=>_(`${t}/overview`),lr=t=>_(`${t}/health`),ir=t=>_(`${t}/cluster`),cr=t=>_(`${t}/budget`),dr=t=>_(`${t}/toolcalls`),ur=(t,s,n)=>_(`${t}/sessions/${s}/${n}/logs`),xr=t=>_(`${t}/approvals`),Ct=async(t,s)=>await _(`${t}/config/${s}`)??[],Vt=(t,s,n)=>_(`${t}/config/${s}/${n}`),mr=t=>_(`${t}/access`),hr=t=>_(`${t}/artifacts`),fr=(t,s,n)=>_(`${t}/artifacts/${s}/${n}`),pr=t=>_(`${t}/workshops`),gr=(t,s={})=>{const n=new URLSearchParams;s.q&&n.set("q",s.q),s.kind&&n.set("kind",s.kind);const r=n.toString();return _(`${t}/memory${r?`?${r}`:""}`)},jr=t=>_(`${t}/config/settings`),Fe=(t,s,n={})=>{const r=new URLSearchParams(n).toString();return`${t}/kg/${s}${r?`?${r}`:""}`},br=(t,s)=>_(Fe(t,"search",s?{q:s}:{})),vr=(t,s)=>_(Fe(t,"entity",{uuid:s})),yr=(t,s)=>_(Fe(t,"facts",{uuid:s})),Nr=(t,s)=>_(Fe(t,"related",{uuid:s})),wr=t=>_(Fe(t,"communities")),ft=async(t,s)=>St(await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)})),vs=async t=>{const s=await fetch(t,{method:"DELETE"});!s.ok&&s.status!==404&&await St(s)};function kr(t,s){const n=new EventSource(`${t}/sessions/stream`);let r;const a=()=>{r&&clearTimeout(r),s.onStale(!1),r=setTimeout(()=>s.onStale(!0),15e3)};return n.addEventListener("session",o=>{a(),s.onSession(JSON.parse(o.data))}),n.addEventListener("remove",o=>{a(),s.onRemove(JSON.parse(o.data))}),n.addEventListener("heartbeat",a),n.onerror=()=>s.onStale(!0),a(),()=>{r&&clearTimeout(r),n.close()}}const ee=t=>`${t.namespace}/${t.name}`;function Se(t){try{const s=new URL(t);return s.protocol==="http:"||s.protocol==="https:"?t:null}catch{return null}}const Sr={gke:"GKE",eks:"EKS",aks:"AKS",local:"Local",unknown:"Cluster"},Ie="h-3.5 w-3.5 shrink-0";function Cr(){return e.jsxs("svg",{viewBox:"0 0 24 24",className:Ie,"aria-hidden":"true",fill:"none",children:[e.jsx("path",{d:"M12 2.5 L20.16 7.25 V16.75 L12 21.5 L3.84 16.75 V7.25 Z",fill:"#4285F4",fillOpacity:"0.16",stroke:"#4285F4",strokeWidth:"1.5",strokeLinejoin:"round"}),e.jsx("circle",{cx:"12",cy:"12",r:"3",stroke:"#4285F4",strokeWidth:"1.5"})]})}function $r(){return e.jsxs("svg",{viewBox:"0 0 24 24",className:Ie,"aria-hidden":"true",fill:"none",children:[e.jsx("path",{d:"M4 12.5 C 8 16.2, 16 16.2, 20 12.5",stroke:"#FF9900",strokeWidth:"2",strokeLinecap:"round"}),e.jsx("path",{d:"M16.6 12.2 L20.4 12.4 L18.9 15.6 Z",fill:"#FF9900"})]})}function Tr(){return e.jsxs("svg",{viewBox:"0 0 24 24",className:Ie,"aria-hidden":"true",children:[e.jsx("path",{d:"M12.8 3 L21 20 H14.8 L12.4 13.6 Z",fill:"#0078D4"}),e.jsx("path",{d:"M10.8 8 L3.2 20 H15 L12.8 15.4 H9 Z",fill:"#0078D4",fillOpacity:"0.7"})]})}function Lr({type:t}){switch(t){case"gke":return e.jsx(Cr,{});case"eks":return e.jsx($r,{});case"aks":return e.jsx(Tr,{});case"local":return e.jsx(Mn,{"aria-hidden":"true",className:`${Ie} text-muted-foreground`});default:return e.jsx(Fn,{"aria-hidden":"true",className:`${Ie} text-muted-foreground`})}}function Ar({apiBase:t}){const[s,n]=d.useState(null);if(d.useEffect(()=>{let u=!0;return ir(t).then(h=>{u&&n(h)}).catch(h=>{console.warn("cluster info fetch failed",h)}),()=>{u=!1}},[t]),!s)return null;const r=Sr[s.type]??"Cluster",a=s.name||r||"cluster",o=!!s.name,i=s.consoleURL?Se(s.consoleURL):null,l=e.jsxs(e.Fragment,{children:[e.jsx(Lr,{type:s.type}),e.jsx("span",{className:"max-w-[16rem] truncate font-medium text-foreground",children:a}),o&&e.jsx("span",{className:"font-mono text-[10px] uppercase tracking-wide text-muted-foreground",children:r})]}),c="flex items-center gap-1.5 rounded-full border bg-card/60 px-2 py-0.5 text-xs";return i?e.jsx("a",{href:i,target:"_blank",rel:"noopener noreferrer",title:`Open ${a} in the cloud console`,className:`${c} transition-colors hover:border-primary/50 hover:bg-accent/40`,children:l}):e.jsx("span",{className:c,title:a,children:l})}const Er={email:"admin@example.com"};function Dr(){typeof window>"u"||window.location.assign("/admin/logout")}function Rr({view:t,onNavigate:s,currentUser:n=Er,apiBase:r="/admin/api",onSignOut:a=Dr,children:o}){const i=gs[t],[l,c]=d.useState(!1),[u,h]=d.useState(!1),[N,p]=d.useState(()=>en()),b=d.useRef(null);return d.useEffect(()=>{if(!l)return;function x($){b.current&&!b.current.contains($.target)&&c(!1)}function j($){$.key==="Escape"&&c(!1)}return document.addEventListener("mousedown",x),document.addEventListener("keydown",j),()=>{document.removeEventListener("mousedown",x),document.removeEventListener("keydown",j)}},[l]),e.jsxs("div",{className:"flex h-screen flex-col bg-background text-foreground",children:[e.jsxs("header",{className:"flex shrink-0 items-center border-b bg-card/30 px-5 py-2.5",children:[e.jsxs("div",{className:"mr-auto flex items-center gap-2.5",onPointerEnter:()=>h(!0),onPointerLeave:()=>h(!1),children:[e.jsx(er,{active:u,bandWidth:32,band:14,className:"h-5 w-5 text-foreground"}),e.jsx("span",{className:"text-sm font-semibold",children:"Open Agent Primitives"}),e.jsx(Ar,{apiBase:r})]}),e.jsx("button",{type:"button","aria-label":Pe(N)==="dark"?"Switch to light theme":"Switch to dark theme",title:Pe(N)==="dark"?"Light theme":"Dark theme",onClick:()=>{const x=Pe(N)==="dark"?"light":"dark";_t(x),p(x)},className:"mr-2 grid h-7 w-7 place-items-center rounded-md border text-muted-foreground transition-colors hover:bg-surface-2 hover:text-foreground",children:Pe(N)==="dark"?e.jsx(Pn,{className:"h-3.5 w-3.5","aria-hidden":"true"}):e.jsx(Kn,{className:"h-3.5 w-3.5","aria-hidden":"true"})}),e.jsxs("div",{ref:b,className:"relative",children:[e.jsxs("button",{type:"button","aria-haspopup":"menu","aria-expanded":l,"aria-label":"User menu",onClick:()=>c(x=>!x),className:"flex items-center gap-2 rounded-md border bg-card px-2 py-1 transition-colors hover:bg-accent/50",children:[e.jsx("div",{"aria-hidden":"true",className:"grid h-6 w-6 shrink-0 place-items-center rounded-full border border-border bg-surface-3 font-mono text-[11px] font-medium uppercase leading-none text-foreground",children:n.email.trim()[0]||"?"}),e.jsx("div",{className:"text-left leading-tight",children:e.jsx("div",{className:"font-mono text-xs",children:n.email})}),e.jsx(_n,{className:`h-3.5 w-3.5 text-muted-foreground transition-transform ${l?"rotate-180":""}`})]}),l&&e.jsxs("div",{role:"menu",className:"absolute right-0 z-50 mt-1 w-44 overflow-hidden rounded-md border bg-card shadow-lg",children:[e.jsx("div",{className:"px-3 pt-2 pb-1 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground",children:"Appearance"}),e.jsx("div",{role:"group","aria-label":"Appearance",className:"flex gap-1 px-2 pb-2",children:["dark","light","system"].map(x=>e.jsx("button",{type:"button",role:"menuitemradio","aria-checked":N===x,onClick:()=>{_t(x),p(x)},className:["flex-1 rounded px-2 py-1 text-xs capitalize transition-colors",N===x?"bg-surface-active text-foreground":"text-muted-foreground hover:bg-surface-2 hover:text-foreground"].join(" "),children:x},x))}),e.jsx("div",{className:"border-t"}),e.jsxs("button",{type:"button",role:"menuitem",onClick:()=>{c(!1),a()},className:"flex w-full items-center gap-2 px-3 py-2 text-left text-sm text-foreground transition-colors hover:bg-accent",children:[e.jsx(Un,{"aria-hidden":"true",className:"h-4 w-4 text-muted-foreground"}),"Sign Out"]})]})]})]}),e.jsxs("div",{className:"flex min-h-0 flex-1",children:[e.jsx("aside",{className:"flex w-48 shrink-0 flex-col border-r bg-card/20 lg:w-60",children:e.jsx("nav",{className:"flex-1 overflow-y-auto px-2 py-1",children:ps.map(x=>e.jsxs("div",{children:[x.group&&e.jsx("p",{className:"mt-3 mb-0.5 px-2 text-[10px] font-semibold uppercase tracking-wider text-muted-foreground",children:x.group}),x.items.map(j=>{const $=j.icon,C=t===j.id;return e.jsxs("button",{type:"button","aria-current":C?"page":void 0,onClick:()=>s(j.id),className:["flex w-full items-center gap-2 py-1.5 text-left text-sm transition-colors",C?"-ml-2 rounded-r-md bg-surface-active pl-4 pr-2 font-medium text-foreground shadow-[inset_3px_0_0_hsl(var(--state))]":"rounded-md px-2 text-foreground/80 hover:bg-surface-2 hover:text-foreground"].join(" "),children:[e.jsx($,{className:"h-4 w-4 shrink-0"}),j.label]},j.id)})]},x.group||"__root__"))})}),e.jsxs("div",{className:"flex min-w-0 flex-1 flex-col",children:[e.jsx("header",{className:"flex shrink-0 items-center justify-between border-b bg-card/10 px-6 py-3.5",children:e.jsxs("div",{children:[e.jsx("h1",{className:"text-base font-semibold",children:i.title}),e.jsx("p",{className:"text-xs text-muted-foreground",children:i.sub})]})}),e.jsx("main",{className:"flex-1 overflow-y-auto px-4 py-4 lg:px-6 lg:py-5",children:o})]})]})]})}function Or({view:t}){const s=gs[t];return e.jsxs(me,{className:"mt-2 border-dashed",children:[e.jsx(he,{children:e.jsx(fe,{className:"text-sm font-medium text-muted-foreground",children:s.title})}),e.jsx(pe,{children:e.jsx("p",{className:"text-xs text-muted-foreground",children:"This surface lands in a later Part 7 task."})})]})}const ve="/admin",Ir=new Set(ps.flatMap(t=>t.items.map(s=>s.id))),ys={session:"sessions",agent:"agents",tool:"tools",skill:"skills",source:"sources",directory:"directory",channel:"channels",identity:"identity",provider:"identity",artifact:"artifacts",user:"users"},Fr=Object.keys(ys),Mr=new Set(Fr);function Ns(t){return Mr.has(t)}const Wt={type:"view",view:"overview"};function Pr(t,s=""){const r=(t.startsWith(ve)?t.slice(ve.length):t).split("/").filter(Boolean);if(r.length===0)return Wt;const[a,...o]=r;if(r.length===1&&Ir.has(a)){const i=a,l=new URLSearchParams(s);return[...l].length>0?{type:"view",view:i,query:l}:{type:"view",view:i}}if(Ns(a)&&o.length>0){const i=o.join("/"),l=new URLSearchParams(s).get("tab")??void 0;return l?{type:"detail",entity:a,id:i,tab:l}:{type:"detail",entity:a,id:i}}return Wt}function ws(t){if(t.type==="detail"){const r=`${ve}/${t.entity}/${t.id}`;return t.tab?`${r}?tab=${encodeURIComponent(t.tab)}`:r}const s=t.query?t.query.toString():"";if(t.view==="overview"&&s==="")return ve;const n=`${ve}/${t.view}`;return s?`${n}?${s}`:n}function Kr(t){return t.type==="view"?t.view:ys[t.entity]}const pt=new Set;function _r(){for(const t of pt)t()}function Ur(t){return pt.add(t),typeof window<"u"&&window.addEventListener("popstate",t),()=>{pt.delete(t),typeof window<"u"&&window.removeEventListener("popstate",t)}}function Vr(){return typeof window>"u"?ve:window.location.pathname+window.location.search}function Wr(){return ve}function te(t){typeof window>"u"||(window.history.pushState({},"",ws(t)),_r())}function ks(){const t=d.useSyncExternalStore(Ur,Vr,Wr),s=t.indexOf("?"),n=s>=0?t.slice(0,s):t,r=s>=0?t.slice(s):"";return Pr(n,r)}function nt({title:t,subtitle:s,backLabel:n="Back",backRoute:r,tabs:a,activeTab:o,onTab:i,children:l,headerRight:c}){return e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsxs("div",{children:[e.jsxs("button",{type:"button",onClick:()=>{r?te(r):typeof window<"u"&&window.history.back()},className:"mb-2 inline-flex items-center gap-1 text-xs text-muted-foreground transition-colors hover:text-foreground",children:[e.jsx(Vn,{className:"h-3.5 w-3.5"}),n]}),e.jsxs("div",{className:"flex items-start justify-between gap-4",children:[e.jsxs("div",{className:"min-w-0",children:[e.jsx("h2",{className:"truncate text-lg font-semibold",children:t}),s&&e.jsx("p",{className:"text-sm text-muted-foreground",children:s})]}),c&&e.jsx("div",{className:"shrink-0",children:c})]})]}),e.jsxs(tn,{value:o,onValueChange:i,children:[e.jsx(sn,{children:a.map(u=>e.jsx(nn,{value:u.id,children:u.label},u.id))}),a.map(u=>e.jsx(rn,{value:u.id,className:"mt-4",forceMount:!0,hidden:u.id!==o,children:u.id===o?l:null},u.id))]})]})}const Ss="ap_admin_";function Cs(){return typeof document<"u"}function Hr(t){if(!Cs())return null;const s=Ss+t+"=";for(const n of document.cookie.split(";")){const r=n.trimStart();if(r.startsWith(s))return decodeURIComponent(r.slice(s.length))}return null}function zr(t,s,n){if(!Cs())return;let r=`${Ss+t}=${encodeURIComponent(s)}; path=/; SameSite=Lax`;const a=365;r+=`; Expires=${new Date(Date.now()+a*864e5).toUTCString()}`,document.cookie=r}function qr(t){if(t.length>0&&t[0]==='"')try{const s=JSON.parse(t);if(typeof s=="string")return s}catch{}return t}function $t(t,s){const[n,r]=d.useState(()=>{const o=Hr(t);return o===null?s:qr(o)}),a=d.useCallback(o=>{r(o),zr(t,o)},[t]);return[n,a]}function $s({value:t,onChange:s}){return e.jsxs("div",{className:"inline-flex items-center rounded-md border bg-background p-0.5",children:[e.jsx(Ht,{label:"Grid view",active:t==="grid",onClick:()=>s("grid"),children:e.jsx(Wn,{className:"h-3.5 w-3.5"})}),e.jsx(Ht,{label:"Table view",active:t==="table",onClick:()=>s("table"),children:e.jsx(Hn,{className:"h-3.5 w-3.5"})})]})}function Ht({label:t,active:s,onClick:n,children:r}){return e.jsx("button",{type:"button","aria-label":t,"aria-pressed":s,onClick:n,className:`inline-flex h-6 w-6 items-center justify-center rounded ${s?"bg-accent text-primary":"text-muted-foreground hover:text-foreground"}`,children:r})}function Gr(t){const s=t.indexOf("/");return s<0?{ns:"",name:t}:{ns:t.slice(0,s),name:t.slice(s+1)}}function Jr(t){return t===""||t==="default"}function Z({id:t,ns:s,name:n,className:r}){const a=t!=null?Gr(t):{ns:s??"",name:n??""};return e.jsxs("span",{className:r,children:[!Jr(a.ns)&&e.jsx("span",{className:"text-muted-foreground",children:`${a.ns}/`}),a.name]})}function Yr(t){return t.button===0&&!t.metaKey&&!t.ctrlKey&&!t.shiftKey&&!t.altKey}function Ts({route:t,className:s,onClick:n,children:r}){const a=ws(t);return e.jsx("a",{href:a,className:s,onClick:o=>{n==null||n(o),Yr(o)&&(o.preventDefault(),te(t))},children:r})}function W({entity:t,id:s,tab:n,className:r,onClick:a,children:o}){return e.jsx(Ts,{route:{type:"detail",entity:t,id:s,...n?{tab:n}:{}},className:r,onClick:a,children:o})}function zt({view:t,query:s,className:n,children:r}){return e.jsx(Ts,{route:{type:"view",view:t,...s?{query:s}:{}},className:n,children:r})}const He=["hsl(var(--chart-1))","hsl(var(--chart-2))","hsl(var(--chart-3))","hsl(var(--chart-4))","hsl(var(--chart-5))"];function Ls(t){const s=Array.from(new Set(t.filter(r=>r!==""))).sort(),n=new Map;return s.forEach((r,a)=>n.set(r,He[a%He.length])),n}function As(t){if(t==="")return;let s=0;for(let n=0;n>>0)%He.length]}function rt({kind:t,className:s}){return t?e.jsxs("span",{className:`inline-flex items-center gap-1.5 rounded-full border bg-background px-2 py-0.5 font-mono text-[10px] text-muted-foreground${s?` ${s}`:""}`,children:[e.jsx(Tt,{kind:t}),t]}):null}function Tt({kind:t}){const s=As(t);return s?e.jsx("span",{"aria-hidden":"true",className:"inline-block h-2 w-2 shrink-0 rounded-full",style:{backgroundColor:s}}):null}function Qr(t){const s=t.replace(/-/g,"+").replace(/_/g,"/"),n=s.length%4===0?"":"=".repeat(4-s.length%4),r=atob(s+n),a=new Uint8Array(r.length);for(let o=0;o=1e3?`${(t/1e3).toFixed(1)}K`:`${t}`}function xe(t){return t>=1e6?`${(t/1e6).toFixed(2)}M`:t>=1e3?`${Math.round(t/1e3)}K`:`${t}`}function Lt(t,s=Date.now()){if(!t)return"—";const n=new Date(t).getTime();if(Number.isNaN(n))return"—";const r=Math.round((s-n)/1e3);if(r<45)return"just now";const a=Math.round(r/60);if(a<60)return`${a}m ago`;const o=Math.round(a/60);if(o<24)return`${o}h ago`;const i=Math.round(o/24);return i<7?`${i}d ago`:new Date(n).toLocaleDateString()}const Xr={Valid:"success",Ready:"success",Connected:"success",Reachable:"success",Synced:"success",Healthy:"success",Active:"success",Degraded:"warning",Syncing:"warning",Pending:"warning",Progressing:"warning",Failed:"destructive",Invalid:"destructive",Error:"destructive",Down:"destructive",Running:"primary",Deferred:"primary"},Zr={success:"border-success/40 bg-success/10 text-success",warning:"border-warning/40 bg-warning/10 text-warning",destructive:"border-destructive/40 bg-destructive/10 text-destructive",primary:"border-primary/40 bg-primary/10 text-primary",muted:"border-border bg-background text-muted-foreground"};function Es(t){return Xr[t]??"muted"}function Ds(t){return Zr[t]}function at(t){return Ds(Es(t))}function At({phase:t}){return e.jsx("span",{className:`inline-flex items-center rounded-full border px-2 py-0.5 text-[10px] ${at(t??"")}`,children:t||"—"})}function Br({s:t,onOpen:s}){const n=t.active?"bg-primary":t.phase==="Failed"?"bg-destructive":"bg-success",r=t.pendingToolGrants+t.pendingLeakageApprovals;return e.jsxs(me,{className:"cursor-pointer transition-colors hover:border-primary/50",onClick:s,children:[e.jsx(he,{className:"pb-2",children:e.jsxs(fe,{className:"flex items-center justify-between text-sm font-medium",children:[e.jsxs("span",{className:"flex items-center gap-2",children:[e.jsx("span",{className:Ge("inline-block h-2 w-2 rounded-full",n,t.active&&"animate-ap-pulse-dot")}),e.jsxs("span",{className:"font-mono",children:[t.class??"?"," / ",e.jsx(Z,{ns:t.namespace,name:t.name})]})]}),e.jsx(At,{phase:t.phase})]})}),e.jsxs(pe,{className:"space-y-2 text-xs text-muted-foreground",children:[t.statusText&&e.jsx("p",{className:"truncate font-mono",children:t.statusText}),e.jsxs("p",{className:"font-mono",children:[ge(t.inputTokens)," in · ",ge(t.outputTokens)," out · ",t.elapsedSeconds,"s · ",t.toolCallCount," tools"]}),e.jsxs("div",{className:"flex gap-2",children:[t.channelKind&&e.jsx(z,{variant:"outline",children:t.channelKind}),r>0&&e.jsxs(z,{variant:"destructive",children:[r," approval",r>1?"s":""," pending"]})]}),t.active&&e.jsx("div",{className:"h-0.5 rounded bg-gradient-to-r from-primary via-state to-primary bg-[length:200%_100%] animate-ap-flow"})]})]})}function qt(t){te({type:"detail",entity:"session",id:`${t.namespace}/${t.name}`})}function ea({kinds:t,value:s,onChange:n}){const r="rounded-full border px-2 py-0.5 text-[10px] transition-colors",a="border-border bg-background text-muted-foreground hover:bg-accent/50",o="border-primary/40 bg-primary/10 text-primary";return e.jsxs("div",{className:"flex flex-wrap items-center gap-1.5",children:[e.jsx("button",{type:"button","aria-pressed":s==="",onClick:()=>n(""),className:`${r} ${s===""?o:a}`,children:"All"}),t.map(i=>{const l=s===i;return e.jsx("button",{type:"button","aria-pressed":l,onClick:()=>n(l?"":i),className:`${r} ${l?o:a}`,children:i},i)})]})}function ta({apiBase:t}){const[s,n]=d.useState(new Map),[r,a]=d.useState(!1),[o,i]=d.useState(null),[l,c]=d.useState(""),[u,h]=$t("sessions_view","grid");d.useEffect(()=>{let x=!1;const j=new Map;let $=0;const C=()=>{const w=++$;j.clear(),_(`${t}/sessions`).then(R=>{if(x||w!==$)return;const O=new Map(R.map(L=>[ee(L),L]));for(const[L,k]of j)k?O.set(L,k):O.delete(L);j.clear(),n(O),i(null)}).catch(R=>{x||i(R.message)})};C();let E=!1;const m=kr(t,{onSession:w=>{j.set(ee(w),w),n(R=>new Map(R).set(ee(w),w))},onRemove:w=>{j.set(ee(w),null),n(R=>{const O=new Map(R);return O.delete(ee(w)),O})},onStale:w=>{a(w),!w&&E&&C(),E=w}});return()=>{x=!0,m()}},[t]);const N=[...s.values()].sort((x,j)=>(j.startedAt??"").localeCompare(x.startedAt??"")),p=[...new Set(N.map(x=>x.channelKind).filter(x=>!!x))].sort(),b=l?N.filter(x=>x.channelKind===l):N;return e.jsxs("div",{className:"space-y-4",children:[o&&e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load sessions: ",o]})}),r&&e.jsx(I,{children:e.jsx(F,{children:"Live feed stalled — showing last known state."})}),e.jsxs("div",{className:"flex items-center justify-between gap-4",children:[p.length>0?e.jsx(ea,{kinds:p,value:l,onChange:c}):e.jsx("span",{}),e.jsx($s,{value:u,onChange:h})]}),b.length===0&&!o&&e.jsx("p",{className:"text-sm text-muted-foreground",children:N.length===0?"No sessions.":"No sessions match this filter."}),b.length>0&&u==="grid"&&e.jsx("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-3",children:b.map(x=>e.jsx(Br,{s:x,onOpen:()=>qt(x)},ee(x)))}),b.length>0&&u==="table"&&e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{children:"Session"}),e.jsx(y,{children:"Class"}),e.jsx(y,{children:"Channel"}),e.jsx(y,{children:"Phase"}),e.jsx(y,{children:"Tokens"}),e.jsx(y,{children:"Started"})]})}),e.jsx(X,{children:b.map(x=>e.jsxs(M,{className:"cursor-pointer",onClick:()=>qt(x),children:[e.jsx(v,{className:"font-mono text-xs text-foreground",children:e.jsx(Z,{id:ee(x)})}),e.jsx(v,{className:"font-mono text-xs",children:x.class?e.jsx(W,{entity:"agent",id:`${x.namespace}/${x.class}`,className:"text-link hover:underline",onClick:j=>j.stopPropagation(),children:x.class}):e.jsx("span",{className:"text-muted-foreground",children:"—"})}),e.jsxs(v,{className:"text-xs",children:[x.channelName?e.jsx(W,{entity:"channel",id:`${x.namespace}/${x.channelName}`,className:"font-mono text-link hover:underline",onClick:j=>j.stopPropagation(),children:e.jsx(Z,{ns:x.namespace,name:x.channelName})}):!x.channelKind&&e.jsx("span",{className:"font-mono text-muted-foreground",children:"—"}),x.channelKind&&e.jsx(rt,{kind:x.channelKind,className:x.channelName?"ml-1.5":""})]}),e.jsx(v,{children:e.jsx(At,{phase:x.phase})}),e.jsxs(v,{className:"whitespace-nowrap font-mono text-xs text-muted-foreground",children:[ge(x.inputTokens)," in · ",ge(x.outputTokens)," out"]}),e.jsxs(v,{className:"whitespace-nowrap text-xs text-muted-foreground",children:[Lt(x.startedAt),x.startedBy&&e.jsxs("span",{className:"mt-0.5 flex items-center gap-1.5 text-[10px] text-muted-foreground/70",children:[e.jsx(Tt,{kind:x.startedBy}),e.jsx(W,{entity:"user",id:x.startedBy,className:"font-mono text-link hover:underline",children:ae(x.startedBy)})]})]})]},ee(x)))})]})]})}function sa(t){const s=new Date(t);return Number.isNaN(s.getTime())?t:s.toLocaleTimeString()}const na=4e3;function ra({apiBase:t}){const[s,n]=d.useState([]),[r,a]=d.useState(null),[o,i]=d.useState(!1);return d.useEffect(()=>{let l=!0;const c=()=>{dr(t).then(h=>{l&&(n(h),a(null),i(!0))}).catch(h=>{l&&(a(h.message),i(!0))})};c();const u=setInterval(c,na);return()=>{l=!1,clearInterval(u)}},[t]),e.jsxs("div",{className:"space-y-3",children:[r&&e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load tool calls: ",r]})}),o&&s.length===0&&!r&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"No tool calls yet — they appear here as agents dispatch them."}),s.length>0&&e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{children:"When"}),e.jsx(y,{children:"Session"}),e.jsx(y,{children:"Agent"}),e.jsx(y,{children:"Tool"})]})}),e.jsx(X,{children:s.map((l,c)=>e.jsxs(M,{children:[e.jsx(v,{className:"whitespace-nowrap font-mono text-xs text-muted-foreground",children:sa(l.t)}),e.jsx(v,{className:"font-mono text-xs",children:e.jsx(W,{entity:"session",id:ee(l),className:"text-link hover:underline",children:e.jsx(Z,{id:ee(l)})})}),e.jsx(v,{className:"text-xs",children:l.agentClass?e.jsx(W,{entity:"agent",id:`${l.namespace}/${l.agentClass}`,className:"text-link hover:underline",children:l.agentClass}):"(unknown)"}),e.jsx(v,{className:"font-mono text-xs text-foreground",children:l.tool||"(tool)"})]},`${ee(l)}-${l.t}-${c}`))})]})]})}const aa=4e3,oa={tool_call:{label:"Tool call",cls:"border-warning/40 text-warning"},leakage:{label:"Leakage",cls:"border-state/40 text-state"},content_inspection:{label:"Content",cls:"border-warning/40 text-warning"}};function la(t){const s=new Date(t).getTime();if(Number.isNaN(s)||s{let c=!0;const u=()=>{xr(t).then(N=>{c&&(r(N),o(null),l(!0))}).catch(N=>{c&&(o(N.message),l(!0))})};u();const h=setInterval(u,aa);return()=>{c=!1,clearInterval(h)}},[t]),e.jsxs("div",{className:"space-y-3",children:[a&&e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load approvals: ",a]})}),i&&n.length===0&&!a&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"Nothing awaiting a decision — pending approvals appear here as agents request them."}),n.length>0&&e.jsx("div",{className:"grid grid-cols-1 gap-3 lg:grid-cols-2",children:n.map((c,u)=>{const h=oa[c.kind]??{label:c.kind,cls:"border-input text-muted-foreground"},N=la(c.requestedAt);return e.jsxs(me,{className:"ring-1 ring-warning/20",children:[e.jsx(he,{className:"pb-2",children:e.jsxs(fe,{className:"flex items-center justify-between text-sm font-medium",children:[e.jsx("span",{className:"font-mono",children:c.tool||h.label}),e.jsx(z,{variant:"outline",className:Ge(h.cls),children:h.label})]})}),e.jsxs(pe,{className:"space-y-3 text-xs text-muted-foreground",children:[e.jsxs("p",{className:"font-mono",children:[c.agentClass||"(unknown)"," / ",ee(c)]}),e.jsxs("div",{className:"flex items-center justify-between",children:[c.requester?e.jsxs("span",{children:["requested by ",e.jsx("span",{className:"text-foreground",children:c.requester})]}):e.jsx("span",{}),N&&e.jsxs("span",{className:"rounded-full border border-warning/40 bg-warning/10 px-2 py-0.5 text-[10px] text-warning",children:["waiting ",N]})]}),e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx(U,{variant:"outline",size:"sm",disabled:!s,onClick:()=>s==null?void 0:s(c.namespace,c.name),children:"Open session"}),e.jsx("span",{className:"text-[11px] text-muted-foreground",children:"decide in the channel thread"})]})]})]},`${ee(c)}-${c.kind}-${c.requestedAt}-${u}`)})}),n.length>0&&e.jsx("p",{className:"text-[11px] text-muted-foreground",children:"Read-only — decisions happen in the originating channel thread. Open the session to watch it."})]})}const ze="w-full rounded-md border border-border bg-background px-2 py-1.5 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:opacity-50";function gt({label:t,children:s}){return e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx("span",{className:"text-[10px] font-medium uppercase tracking-wide text-muted-foreground",children:t}),e.jsx("div",{className:"text-sm text-foreground",children:s})]})}function Gt(t){return t==null?"":typeof t=="string"?t:Array.isArray(t)?t.join(","):String(t)}function ca({q:t,value:s,onChange:n}){const r=t.required!==!1,a=`${t.prompt||t.name}${r?" *":""}`;return e.jsxs(gt,{label:a,children:[t.type==="bool"?e.jsx("input",{type:"checkbox",checked:s==="true",onChange:o=>n(o.target.checked?"true":"false"),"aria-label":a,className:"h-4 w-4 rounded border-border"}):t.type==="enum"?e.jsxs("select",{value:s,onChange:o=>n(o.target.value),"aria-label":a,className:ze,children:[e.jsx("option",{value:"",disabled:!0,children:"Select…"}),(t.enum??[]).map((o,i)=>{var u;const l=(u=t.enumLabels)==null?void 0:u[i],c=l!==void 0&&l.trim()!==""?l:o;return e.jsx("option",{value:o,children:c},o)})]}):e.jsx("input",{type:t.type==="secret"?"password":t.type==="int"?"number":"text",value:s,onChange:o=>n(o.target.value),"aria-label":a,placeholder:t.type==="resourceList"?"comma-separated":void 0,autoComplete:t.type==="secret"?"new-password":"off",className:ze}),t.description&&e.jsx("p",{className:"text-[11px] text-muted-foreground",children:t.description})]})}function da({apiBase:t,row:s,onDone:n}){const[r,a]=d.useState(!1),[o,i]=d.useState(s.namespace),[l,c]=d.useState(s.suggestedName??""),[u,h]=d.useState({}),[N,p]=d.useState(null),[b,x]=d.useState([]),[j,$]=d.useState([]),[C,E]=d.useState(null),[m,w]=d.useState(!1),R=()=>{x([]),$([])},O=(g,T)=>{h(P=>({...P,[g]:T})),R()},L=()=>{E(null),p(null),R()},k=async()=>{E(null),w(!0);try{await ar(t,s.namespace,s.name,{namespace:o,name:l,values:u,adopt:j}),a(!1),L(),n()}catch(g){g instanceof tt?(p(g.questions),h(T=>{const P={...T};for(const V of g.questions)P[V.name]===void 0&&V.default!==void 0&&V.default!==null&&(P[V.name]=Gt(V.default));return P})):g instanceof st?x(g.conflicts):(g instanceof J,E(g.message))}finally{w(!1)}};return e.jsxs(Je,{open:r,onOpenChange:g=>{a(g),g||L()},children:[e.jsx(Ye,{asChild:!0,children:e.jsx(U,{size:"sm",children:"Install"})}),e.jsxs(Qe,{children:[e.jsxs(Xe,{children:[e.jsxs(Ze,{children:["Install ",s.suggestedName||s.name]}),e.jsx(Be,{children:"Installs this workshop's drafted bundle under the operator identity. No secret answer is ever pre-filled — type it below."})]}),e.jsxs("div",{className:"flex flex-col gap-3",children:[C&&e.jsx(I,{variant:"destructive",children:e.jsx(F,{children:C})}),e.jsxs("div",{className:"grid grid-cols-1 gap-3 sm:grid-cols-2",children:[e.jsx(gt,{label:"Namespace *",children:e.jsx("input",{type:"text",value:o,onChange:g=>{i(g.target.value),R()},"aria-label":"Namespace",className:ze})}),e.jsx(gt,{label:"Name (optional)",children:e.jsx("input",{type:"text",value:l,onChange:g=>{c(g.target.value),R()},placeholder:"defaults to the bundle's own name","aria-label":"Name",className:ze})})]}),b.length>0&&e.jsxs("div",{className:"flex flex-col gap-2 rounded-md border border-destructive/50 p-3",children:[e.jsx("p",{className:"text-xs font-medium text-foreground",children:"These objects already exist and were not created by this install. Adopting one overwrites its spec with this bundle's."}),b.map(g=>{const T=`${g.kind}/${g.name}`,P=g.namespace?`${g.kind} ${g.namespace}/${g.name}`:T;return e.jsxs("label",{className:"flex items-center gap-2 text-xs text-foreground",children:[e.jsx("input",{type:"checkbox",checked:j.includes(T),"aria-label":P,onChange:V=>$(q=>V.target.checked?[...q,T]:q.filter(ie=>ie!==T)),className:"h-4 w-4 rounded border-border"}),e.jsx("span",{children:P}),g.secret&&e.jsx("span",{className:"text-destructive",children:"overwrites this Secret's data"})]},T)})]}),N&&N.length>0&&e.jsxs("div",{className:"flex flex-col gap-3 rounded-md border border-dashed border-border p-3",children:[e.jsxs("p",{className:"text-xs text-muted-foreground",children:["This bundle needs ",N.length===1?"an answer":"answers"," before it can install:"]}),N.map(g=>e.jsx(ca,{q:g,value:u[g.name]??Gt(g.default),onChange:T=>O(g.name,T)},g.name))]})]}),e.jsxs(et,{children:[e.jsx(wt,{asChild:!0,children:e.jsx(U,{variant:"outline",children:"Cancel"})}),e.jsx(U,{onClick:k,disabled:m||o.trim()==="",children:m?"Installing…":b.length>0&&j.length>0?"Adopt and install":N?"Submit answers":"Confirm install"})]})]})]})}function ua({apiBase:t,row:s,onDone:n}){const[r,a]=d.useState(!1),[o,i]=d.useState(null),l=async()=>{i(null),a(!0);try{await ft(`${t}/workshops/${s.namespace}/${s.name}/decline`,{}),n()}catch(c){i(c.message)}finally{a(!1)}};return e.jsxs("span",{className:"flex flex-col items-end gap-1",children:[e.jsx(U,{variant:"outline",size:"sm",onClick:l,disabled:r,children:r?"Declining…":"Decline"}),o&&e.jsx("span",{className:"text-[11px] text-destructive",children:o})]})}function xa({apiBase:t,row:s,onDone:n}){const[r,a]=d.useState(!1),[o,i]=d.useState(null),[l,c]=d.useState(!1),u=async()=>{i(null),c(!0);try{await vs(`${t}/workshops/${s.namespace}/${s.name}`),a(!1),n()}catch(h){i(h.message)}finally{c(!1)}};return e.jsxs(Je,{open:r,onOpenChange:a,children:[e.jsx(Ye,{asChild:!0,children:e.jsx(U,{variant:"destructive",size:"sm",children:"Kill"})}),e.jsxs(Qe,{children:[e.jsxs(Xe,{children:[e.jsxs(Ze,{children:["Kill workshop ",s.name,"?"]}),e.jsx(Be,{children:"Deletes the Workshop — its provisioned builder namespace is torn down. This cannot be undone."})]}),o&&e.jsx(I,{variant:"destructive",children:e.jsx(F,{children:o})}),e.jsxs(et,{children:[e.jsx(wt,{asChild:!0,children:e.jsx(U,{variant:"outline",children:"Cancel"})}),e.jsx(U,{variant:"destructive",onClick:u,disabled:l,children:l?"Killing…":"Kill it"})]})]})]})}function ma({apiBase:t}){const[s,n]=d.useState([]),[r,a]=d.useState(null),[o,i]=d.useState(!1),l=d.useCallback(()=>{pr(t).then(c=>{n(c),a(null),i(!0)}).catch(c=>{a(c.message),i(!0)})},[t]);return d.useEffect(()=>{l()},[l]),r?e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load workshops: ",r]})}):e.jsxs("div",{className:"space-y-3",children:[o&&s.length===0&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"No workshops yet."}),s.length>0&&e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{children:"Workshop"}),e.jsx(y,{children:"Session"}),e.jsx(y,{children:"Starter"}),e.jsx(y,{children:"Phase"}),e.jsx(y,{children:"Install"}),e.jsx(y,{className:"text-right",children:"Actions"})]})}),e.jsx(X,{children:s.map(c=>{const u=`${c.namespace}/${c.name}`;return e.jsxs(M,{children:[e.jsxs(v,{className:"font-mono text-xs",children:[u,c.exported&&e.jsx(z,{variant:"outline",className:"ml-2",children:"exported"})]}),e.jsx(v,{className:"font-mono text-xs text-muted-foreground",children:c.session}),e.jsx(v,{className:"font-mono text-xs text-muted-foreground",children:c.starter}),e.jsx(v,{children:e.jsx(z,{variant:"outline",children:c.phase||"—"})}),e.jsx(v,{className:"font-mono text-xs text-muted-foreground",children:c.installPhase?e.jsxs("span",{className:"flex items-center gap-2",children:[e.jsx(z,{variant:c.installPhase==="Failed"?"destructive":"outline",children:c.installPhase}),c.installedRef&&e.jsx("span",{children:c.installedRef})]}):c.pendingCapability?"capability requested":"—"}),e.jsx(v,{className:"text-right",children:e.jsxs("div",{className:"flex justify-end gap-2",children:[c.pendingInstall&&e.jsxs(e.Fragment,{children:[e.jsx(da,{apiBase:t,row:c,onDone:l}),e.jsx(ua,{apiBase:t,row:c,onDone:l})]}),e.jsx(xa,{apiBase:t,row:c,onDone:l})]})})]},u)})})]}),e.jsx("p",{className:"text-[11px] text-muted-foreground",children:"Workshop — an agent-builder session's drafted bundle, awaiting an admin's install/decline/kill decision."})]})}function qe({value:t,className:s}){const[n,r]=d.useState(!1);return e.jsxs("div",{className:Ge("rounded border border-border bg-background/40 text-xs",s),children:[e.jsx("div",{className:"flex justify-end border-b border-border/50 px-1.5 py-0.5",children:e.jsx("button",{type:"button",onClick:()=>r(a=>!a),className:"font-mono text-[10px] uppercase tracking-wide text-muted-foreground hover:text-foreground","aria-pressed":n,children:n?"tree":"raw"})}),e.jsx("div",{className:"overflow-x-auto p-2 font-mono leading-relaxed",children:n?e.jsx("pre",{className:"whitespace-pre-wrap break-words text-foreground",children:ha(t)}):e.jsx(Os,{value:t})})]})}function ha(t){const s=JSON.stringify(t,null,2);return s===void 0?String(t):s}function Rs(t){const s=t.trim();if(!(!s.startsWith("{")&&!s.startsWith("[")))try{return JSON.parse(s)}catch{return}}function Os({value:t,label:s}){return t===null||typeof t!="object"?e.jsxs("div",{className:"flex flex-wrap items-start gap-1.5",children:[s!==void 0&&e.jsxs("span",{className:"shrink-0 text-foreground/70",children:[s,":"]}),e.jsx(pa,{value:t})]}):e.jsx(ga,{value:t,label:s})}function fa(t){switch(typeof t){case"string":return"text-success";case"number":return"text-primary";case"boolean":return"text-state";default:return"text-muted-foreground"}}function pa({value:t}){const s=typeof t=="string"?JSON.stringify(t):String(t);return e.jsx("span",{className:fa(t),children:s})}function ga({value:t,label:s}){const[n,r]=d.useState(!0),a=Array.isArray(t),o=a?t.map((u,h)=>[String(h),u]):Object.entries(t),[i,l]=a?["[","]"]:["{","}"],c=s!==void 0?e.jsxs("span",{className:"text-foreground/70",children:[s,": "]}):null;return o.length===0?e.jsxs("div",{children:[c,e.jsxs("span",{className:"text-muted-foreground",children:[i,l]})]}):e.jsxs("div",{children:[e.jsxs("button",{type:"button",onClick:()=>r(u=>!u),"aria-expanded":n,className:"text-muted-foreground hover:text-foreground",children:[c,e.jsx("span",{"aria-hidden":"true",children:n?"▾":"▸"})," ",i,!n&&e.jsxs("span",{className:"text-muted-foreground",children:[" ","…",o.length," ",l]})]}),n&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"ml-2 border-l border-border/40 pl-2",children:o.map(([u,h])=>e.jsx(Os,{value:h,label:a?void 0:u},u))}),e.jsx("div",{className:"text-muted-foreground",children:l})]})]})}const ja=560,De=28,be={channel:60,agent:260,tools:470};function dt({x:t,y:s,label:n,stroke:r}){return e.jsxs("g",{children:[e.jsx("circle",{cx:t,cy:s,r:De,fill:"hsl(var(--card))",stroke:r,strokeWidth:1.5}),e.jsx("text",{x:t,y:s+4,textAnchor:"middle",fontSize:10,fill:"hsl(var(--foreground))",fontFamily:"monospace",children:n.length>11?n.slice(0,10)+"…":n})]})}function Jt({x1:t,y1:s,x2:n,y2:r,active:a}){return e.jsx("path",{className:a?"ap-edge-active":void 0,d:`M ${t} ${s} C ${(t+n)/2} ${s}, ${(t+n)/2} ${r}, ${n} ${r}`,fill:"none",stroke:a?"hsl(var(--primary))":"hsl(var(--border))",strokeWidth:1.5,strokeDasharray:a?"6 6":void 0,children:a&&e.jsx("animate",{attributeName:"stroke-dashoffset",from:"24",to:"0",dur:"0.9s",repeatCount:"indefinite"})})}function ba({channelKind:t,agentClass:s,tools:n,active:r}){const a=n.slice(0,8),o=Math.max(160,a.length*64+40),i=o/2;return e.jsxs("svg",{viewBox:`0 0 ${ja} ${o}`,className:"w-full",role:"img","aria-label":"session flow graph",children:[e.jsx(Jt,{x1:be.channel+De,y1:i,x2:be.agent-De,y2:i,active:r}),a.map((l,c)=>{const u=40+c*64+12;return e.jsxs(d.Fragment,{children:[e.jsx(Jt,{x1:be.agent+De,y1:i,x2:be.tools-De,y2:u,active:r}),e.jsx(dt,{x:be.tools,y:u,label:l,stroke:"hsl(var(--state))"})]},l)}),e.jsx(dt,{x:be.channel,y:i,label:t??"channel",stroke:"hsl(var(--success))"}),e.jsx(dt,{x:be.agent,y:i,label:s??"agent",stroke:"hsl(var(--primary))"})]})}const va=[{id:"overview",label:"Overview"},{id:"activity",label:"Recent Activity"},{id:"logs",label:"Full Logs"}];function ya(t){const s=t.indexOf("/");return s<0?{ns:"",name:t}:{ns:t.slice(0,s),name:t.slice(s+1)}}function Na(t){var n;const s=new Set;for(const r of t.recentEvents)if(r.kind==="tool_activity"){const a=(n=r.payload)==null?void 0:n.tool;a&&s.add(a)}return[...s]}function wa({apiBase:t,id:s,tab:n}){const{ns:r,name:a}=ya(s),o=n??"overview",i=`${t}/sessions/${r}/${a}`,[l,c]=d.useState(null),[u,h]=d.useState(null),[N,p]=d.useState(!1),[b,x]=d.useState(null),[j,$]=d.useState(null),[C,E]=d.useState(!1),m=d.useRef(null);d.useEffect(()=>()=>{m.current!==null&&clearTimeout(m.current)},[]),d.useEffect(()=>{let O=!0;return c(null),h(null),p(!1),_(i).then(L=>{O&&c(L)}).catch(L=>{O&&(L instanceof J&&L.status===404?p(!0):h(L.message))}),()=>{O=!1}},[i]);const w=async()=>{$(null);try{await vs(i),E(!1),x("Session terminated."),m.current=setTimeout(()=>te({type:"view",view:"sessions"}),800)}catch(O){E(!1),$(O.message)}},R=O=>te({type:"detail",entity:"session",id:s,tab:O});return e.jsx(nt,{title:e.jsxs("span",{className:"font-mono",children:[l&&`${l.class??"?"} / `,e.jsx(Z,{ns:r,name:a})]}),backRoute:{type:"view",view:"sessions"},tabs:va,activeTab:o,onTab:R,headerRight:l!=null&&l.phase?e.jsx(z,{variant:"outline",children:l.phase}):void 0,children:o==="logs"?e.jsx($a,{apiBase:t,ns:r,name:a}):u?e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load session: ",u]})}):N?e.jsxs("p",{className:"text-sm text-muted-foreground",children:["Session ",s," is not tracked — it may have completed or never started."]}):l?o==="activity"?e.jsx(Ca,{detail:l}):e.jsx(ka,{detail:l,name:a,killNote:b,killError:j,killOpen:C,onKillOpenChange:E,onKill:w}):e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading…"})})}function ka({detail:t,name:s,killNote:n,killError:r,killOpen:a,onKillOpenChange:o,onKill:i}){return e.jsxs("div",{className:"flex flex-col gap-4",children:[n&&e.jsx("p",{className:"text-sm text-success",children:n}),r&&e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not kill session: ",r]})}),e.jsx("div",{className:"rounded-lg border border-border bg-card p-4",children:e.jsx(ba,{channelKind:t.channelKind,agentClass:t.class,tools:Na(t),active:t.active})}),t.statusText&&e.jsx("p",{className:"font-mono text-sm text-muted-foreground",children:t.statusText}),e.jsxs("p",{className:"font-mono text-xs text-muted-foreground",children:[ge(t.inputTokens)," in · ",ge(t.outputTokens)," out · ",t.toolCallCount," tool calls · turn ",t.turnCount]}),e.jsxs("dl",{className:"grid grid-cols-2 gap-x-6 gap-y-2 text-xs sm:grid-cols-3",children:[e.jsx(Ae,{label:"Phase",value:t.phase??"—"}),e.jsx(Ae,{label:"Model",children:t.model?e.jsx(kt,{model:t.model}):"—"}),e.jsx(Ae,{label:"Elapsed",value:`${t.elapsedSeconds}s`}),t.startedAt&&e.jsx(Ae,{label:"Started",value:new Date(t.startedAt).toLocaleString()}),t.activityCause&&e.jsx(Ae,{label:"Activity",value:t.activityCause})]}),t.bundles&&t.bundles.length>0&&e.jsx(Sa,{bundles:t.bundles}),e.jsxs(Je,{open:a,onOpenChange:o,children:[e.jsx(Ye,{asChild:!0,children:e.jsx(U,{variant:"destructive",className:"mt-2 self-start",children:"Kill session"})}),e.jsxs(Qe,{children:[e.jsxs(Xe,{children:[e.jsxs(Ze,{children:["Kill ",s,"?"]}),e.jsx(Be,{children:"Deletes the AgentSession — the runner pod is torn down immediately. This cannot be undone."})]}),e.jsxs(et,{children:[e.jsx(wt,{asChild:!0,children:e.jsx(U,{variant:"outline",children:"Cancel"})}),e.jsx(U,{variant:"destructive",onClick:i,children:"Kill it"})]})]})]})]})}function Ae({label:t,value:s,children:n}){return e.jsxs("div",{className:"flex flex-col",children:[e.jsx("dt",{className:"text-[10px] uppercase tracking-wide text-muted-foreground",children:t}),e.jsx("dd",{className:"font-mono text-foreground",children:n??s})]})}function Sa({bundles:t}){return e.jsxs("div",{className:"rounded-lg border border-border bg-card p-4",children:[e.jsx("h3",{className:"mb-2 text-[10px] uppercase tracking-wide text-muted-foreground",children:"Bundles"}),e.jsx("ul",{className:"space-y-2",children:t.map(s=>e.jsxs("li",{className:"flex flex-wrap items-center gap-2 font-mono text-xs",children:[e.jsx("span",{className:"font-semibold text-foreground",children:s.name}),e.jsx("span",{className:"text-muted-foreground",children:s.spiceboxSessionName}),s.sandboxKind?e.jsxs(e.Fragment,{children:[e.jsx(z,{variant:"outline",children:s.sandboxKind}),e.jsx("span",{className:"break-all text-muted-foreground",children:s.sandboxRef}),s.prewarmed&&e.jsx(z,{variant:"outline",children:"warm"})]}):e.jsx("span",{className:"text-muted-foreground",children:"sandbox not yet resolved"}),s.workspaceMode&&e.jsxs(z,{variant:"outline",children:[s.workspaceMode," workspace"]}),s.phase&&e.jsx(z,{variant:s.phase==="Failed"?"destructive":"outline",children:s.phase}),s.reason&&e.jsx("span",{className:"text-muted-foreground",children:s.reason})]},s.name))})]})}function Ca({detail:t}){return t.recentEvents.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No recent activity."}):e.jsx("ul",{className:"space-y-1 font-mono text-xs text-muted-foreground",children:t.recentEvents.slice().reverse().map((s,n)=>e.jsxs("li",{children:[new Date(s.at).toLocaleTimeString()," · ",s.kind]},n))})}function $a({apiBase:t,ns:s,name:n}){const[r,a]=d.useState(null),[o,i]=d.useState(null);return d.useEffect(()=>{let l=!0;return a(null),i(null),ur(t,s,n).then(c=>{l&&a(c)}).catch(c=>{l&&i(c.message)}),()=>{l=!1}},[t,s,n]),o?e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load logs: ",o]})}):r?r.entries.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No transcript entries yet."}):e.jsxs("div",{className:"space-y-3",children:[r.truncated&&e.jsxs("p",{className:"text-xs text-warning",children:["Showing the latest ",r.entries.length," entries — older turns were truncated."]}),e.jsx("ul",{className:"space-y-2",children:r.entries.map(l=>e.jsx(La,{entry:l},l.id))})]}):e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading logs…"})}function Ta(t){switch(t){case"user":case"inbox":return{container:"border-state/40 bg-state/5",badge:"bg-state/15 text-state"};case"assistant":return{container:"border-primary/40 bg-primary/5",badge:"bg-primary/15 text-primary"};case"tool":return{container:"border-warning/40 bg-warning/5",badge:"bg-warning/15 text-warning"};default:return{container:"border-border bg-card",badge:"bg-muted text-muted-foreground"}}}function La({entry:t}){const s=t.role||t.kind,n=Ta(t.role??"");return e.jsxs("li",{className:`rounded-md border p-3 ${n.container}`,children:[e.jsxs("div",{className:"mb-2 flex items-center justify-between gap-2 font-mono text-[11px] text-muted-foreground",children:[e.jsxs("span",{className:"flex items-center gap-2",children:[e.jsx("span",{className:`rounded px-1.5 py-0.5 text-[10px] uppercase tracking-wide ${n.badge}`,children:s}),t.actor&&e.jsxs("span",{className:"flex items-center gap-1",children:[t.actorInferred?"requested by":"by"," ",e.jsx(W,{entity:"user",id:t.actor,className:"text-link hover:underline",children:ae(t.actor)}),t.actorInferred&&e.jsxs("span",{className:"text-muted-foreground/60",title:"Session initiator — this legacy turn predates per-turn authorship.",children:[" ","(session initiator)"]})]})]}),e.jsx("span",{children:new Date(t.createdAt).toLocaleString()})]}),t.blocks&&t.blocks.length>0?e.jsx("div",{className:"space-y-2",children:t.blocks.map((r,a)=>e.jsx(Aa,{block:r,role:t.role??""},a))}):e.jsx(jt,{text:t.content,className:"text-foreground"})]})}function Aa({block:t,role:s}){if(t.type==="tool_use")return e.jsxs("div",{className:"rounded border border-warning/40 bg-warning/5 p-2",children:[e.jsxs("div",{className:"mb-1 font-mono text-[11px] text-warning",children:["→ ",t.name||"tool"]}),e.jsx(qe,{value:t.input??{}})]});if(t.type==="tool_result"){const r=t.isError,a=r?"border-destructive/50 bg-destructive/10":"border-success/40 bg-success/5",o=r?"text-destructive":"text-success",i=Ea(t.content);return e.jsxs("div",{className:`rounded border p-2 ${a}`,children:[e.jsxs("div",{className:`mb-1 font-mono text-[11px] ${o}`,children:["← ",r?"error":"result"]}),i!==null?e.jsx(jt,{text:i,className:"text-foreground/90"}):e.jsx(qe,{value:t.content??""})]})}const n=s==="assistant"?"text-foreground":"text-foreground/90";return e.jsx(jt,{text:t.text??"",className:n})}function Ea(t){if(typeof t!="string")return null;let s=t;if(s.length>=2&&s.startsWith('"')&&s.endsWith('"'))try{const n=JSON.parse(s);typeof n=="string"&&(s=n)}catch{}return s.includes("]*)?>/g;function Yt({chunk:t}){const s=Rs(t);return s!==void 0?e.jsx(qe,{value:s,className:"my-1"}):e.jsx("span",{className:"rounded-sm bg-muted/40 text-muted-foreground",children:t})}function jt({text:t,className:s}){const n=`whitespace-pre-wrap break-words font-mono text-xs ${s??""}`;if(!t.includes("t.stopPropagation(),Ra=t=>t==="denied"||t==="read_denied"||t==="failed"?"destructive":t==="pending"?"secondary":"outline",Is=[{key:"kind",label:"Kind",value:t=>t.kind},{key:"outcome",label:"Outcome",value:t=>t.outcome},{key:"agent",label:"Agent",value:t=>t.agentClass??""},{key:"tool",label:"Tool",value:t=>t.tool??""},{key:"actor",label:"Actor",value:t=>t.actor?ae(t.actor):""}];function Oa(t){return{kind:t.kind,outcome:t.outcome,agent:t.agentClass??"",tool:t.tool??"",actor:t.actor?ae(t.actor):""}}function Ee({color:t}){return t?e.jsx("span",{className:"mr-1.5 inline-block h-2 w-2 shrink-0 rounded-full align-middle",style:{backgroundColor:t}}):null}function Ia({colorMaps:t}){return e.jsx("div",{role:"group","aria-label":"Color legends",className:"grid gap-2 rounded-md border border-border bg-card p-2 text-xs sm:grid-cols-2 lg:grid-cols-3",children:Is.map(s=>{const n=[...t[s.key].entries()];return e.jsxs("div",{className:"min-w-0",children:[e.jsx("div",{className:"mb-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground",children:s.label}),n.length===0?e.jsx("span",{className:"text-muted-foreground",children:"—"}):e.jsx("div",{className:"flex flex-wrap gap-1",children:n.map(([r,a])=>e.jsxs("span",{className:"inline-flex max-w-full items-center gap-1 rounded border border-border bg-background px-1.5 py-0.5 font-mono",children:[e.jsx("span",{className:"h-2 w-2 shrink-0 rounded-full",style:{backgroundColor:a}}),e.jsx("span",{className:"truncate",children:r})]},r))})]},s.key)})})}function Fa({events:t,onRow:s,colorMaps:n}){const r=(a,o)=>n==null?void 0:n[a].get(o);return e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{children:"When"}),e.jsx(y,{children:"Kind"}),e.jsx(y,{children:"Outcome"}),e.jsx(y,{children:"Agent"}),e.jsx(y,{children:"Tool"}),e.jsx(y,{children:"Actor"}),e.jsx(y,{children:"Session"}),e.jsx(y,{children:"Event"})]})}),e.jsx(X,{children:t.map(a=>{const o=Oa(a);return e.jsxs(M,{className:`cursor-pointer${a.outcome==="denied"||a.outcome==="read_denied"?" bg-destructive/5":""}`,onClick:()=>s(a),children:[e.jsx(v,{className:"whitespace-nowrap font-mono text-xs",children:new Date(a.time).toLocaleString()}),e.jsxs(v,{className:"whitespace-nowrap",children:[e.jsx(Ee,{color:r("kind",o.kind)}),e.jsx(z,{variant:"outline",children:a.kind})]}),e.jsxs(v,{className:"whitespace-nowrap",children:[e.jsx(Ee,{color:r("outcome",o.outcome)}),e.jsx(z,{variant:Ra(a.outcome),children:a.outcome})]}),e.jsxs(v,{className:"font-mono text-xs",children:[e.jsx(Ee,{color:r("agent",o.agent)}),a.agentClass?e.jsx(W,{entity:"agent",id:`${a.sessionNamespace}/${a.agentClass}`,className:"text-link hover:underline",onClick:Qt,children:a.agentClass}):"—"]}),e.jsxs(v,{className:"font-mono text-xs",children:[e.jsx(Ee,{color:r("tool",o.tool)}),a.tool||"—"]}),e.jsxs(v,{className:"font-mono text-xs",title:a.actor||void 0,children:[e.jsx(Ee,{color:r("actor",o.actor)}),o.actor||"—"]}),e.jsx(v,{className:"font-mono text-xs",children:e.jsxs(W,{entity:"session",id:`${a.sessionNamespace}/${a.sessionName}`,className:"text-link hover:underline",onClick:Qt,children:[a.sessionNamespace,"/",a.sessionName]})}),e.jsx(v,{className:"max-w-md truncate text-xs",children:a.summary})]},a.entryId)})})]})}function Ma({event:t,onClose:s}){return e.jsx(an,{open:!0,onOpenChange:n=>!n&&s(),children:e.jsxs(on,{side:"right",className:"w-full overflow-y-auto sm:max-w-xl",children:[e.jsx(ln,{children:e.jsx(cn,{className:"text-sm",children:t.summary})}),e.jsxs("dl",{className:"mt-4 space-y-1 font-mono text-xs",children:[e.jsxs("div",{children:[e.jsx("dt",{className:"inline text-muted-foreground",children:"when:"})," ",e.jsx("dd",{className:"inline",children:t.time})]}),e.jsxs("div",{children:[e.jsx("dt",{className:"inline text-muted-foreground",children:"session:"})," ",e.jsxs("dd",{className:"inline",children:[t.sessionNamespace,"/",t.sessionName]})]}),e.jsxs("div",{children:[e.jsx("dt",{className:"inline text-muted-foreground",children:"agent:"})," ",e.jsx("dd",{className:"inline",children:t.agentClass})]}),e.jsxs("div",{children:[e.jsx("dt",{className:"inline text-muted-foreground",children:"actor:"})," ",e.jsx("dd",{className:"inline",children:t.actor})]}),e.jsxs("div",{children:[e.jsx("dt",{className:"inline text-muted-foreground",children:"tool:"})," ",e.jsx("dd",{className:"inline",children:t.tool})]}),e.jsxs("div",{children:[e.jsx("dt",{className:"inline text-muted-foreground",children:"entry:"})," ",e.jsx("dd",{className:"inline",children:t.entryId})]})]}),e.jsx("h3",{className:"mt-4 text-xs font-semibold uppercase text-muted-foreground",children:"Raw"}),e.jsx("pre",{className:"mt-1 overflow-x-auto rounded bg-card p-3 font-mono text-xs",children:JSON.stringify(t.raw??{},null,2)})]})})}const Xt=50,Zt=[{facet:"kind",field:"kinds",label:"Kind"},{facet:"outcome",field:"outcome",label:"Outcome"},{facet:"agentClass",field:"agentClass",label:"Agent"},{facet:"tool",field:"tool",label:"Tool"},{facet:"actor",field:"actor",label:"Actor"}];function Pa(t,s){const n=s.trim().toLowerCase();return n?[t.kind,t.agentClass,t.sessionNamespace,t.sessionName,`${t.sessionNamespace}/${t.sessionName}`,t.outcome,t.tool,t.actor,t.actor?ae(t.actor):"",t.summary].filter(Boolean).join(" ").toLowerCase().includes(n):!0}function Ka({apiBase:t,initialFilter:s}){const[n,r]=d.useState(s),[a,o]=d.useState(0),[i,l]=d.useState(null),[c,u]=d.useState(null),[h,N]=d.useState(null),[p,b]=d.useState(null),[x,j]=d.useState(""),[$,C]=d.useState(!0);d.useEffect(()=>{let k=!0;const g={...n,limit:Xt,offset:a*Xt};return Promise.all([ft(`${t}/audit/query`,g),ft(`${t}/audit/facets`,n)]).then(([T,P])=>{k&&(l(T),u(P),b(null))}).catch(T=>{k&&b(T.message)}),()=>{k=!1}},[t,n,a]);const E=(k,g)=>{o(0),r(T=>({...T,[k]:k==="kinds"?[g]:g}))},m=k=>{o(0),r(g=>{const T={...g};return delete T[k],T})},w=Zt.filter(({field:k})=>n[k]).map(({field:k,label:g})=>({field:k,label:g,value:k==="kinds"?(n.kinds??[]).join(","):String(n[k])})),R=(i==null?void 0:i.events)??[],O=d.useMemo(()=>R.filter(k=>Pa(k,x)),[R,x]),L=d.useMemo(()=>{const k={};for(const g of Is)k[g.key]=Ls(O.map(g.value));return k},[O]);return e.jsxs("div",{className:"flex flex-col gap-4 lg:flex-row lg:gap-6",children:[e.jsx("aside",{className:"grid grid-cols-2 gap-4 sm:grid-cols-3 lg:block lg:w-48 lg:shrink-0 lg:space-y-4",children:Zt.map(({facet:k,field:g,label:T})=>e.jsxs("div",{children:[e.jsx("h4",{className:"text-xs font-semibold uppercase text-muted-foreground",children:T}),e.jsx("ul",{className:"mt-1 space-y-0.5 text-xs",children:Object.entries((c==null?void 0:c.counts[k])??{}).sort(([,P],[,V])=>V-P).slice(0,8).map(([P,V])=>e.jsx("li",{children:e.jsxs("button",{className:"hover:text-primary",onClick:()=>E(g,P),children:[P," (",V,")"]})},P))})]},k))}),e.jsxs("div",{className:"min-w-0 flex-1 space-y-3",children:[p&&e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Audit query failed: ",p]})}),(i==null?void 0:i.truncated)&&e.jsx(I,{children:e.jsx(F,{children:"Results truncated — narrow the time range or filters for complete counts."})}),e.jsx("div",{className:"flex flex-wrap gap-2",children:w.map(k=>e.jsxs(z,{variant:"secondary",className:"cursor-pointer",onClick:()=>m(k.field),children:[k.label.toLowerCase(),": ",k.value," ✕"]},k.field))}),e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("div",{className:"relative min-w-0 flex-1",children:e.jsx("input",{type:"search",value:x,onChange:k=>j(k.target.value),placeholder:"Filter loaded events…","aria-label":"Filter loaded events",className:"w-full rounded-md border border-border bg-background px-2 py-1 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring"})}),x&&e.jsx(U,{variant:"ghost",size:"sm",onClick:()=>j(""),children:"Clear"}),e.jsx(U,{variant:"outline",size:"sm",onClick:()=>C(k=>!k),children:$?"Hide legend":"Show legend"}),e.jsxs("span",{className:"whitespace-nowrap text-xs text-muted-foreground",children:[O.length,x?` of ${R.length}`:""," shown"]})]}),$&&e.jsx(Ia,{colorMaps:L}),e.jsx(Fa,{events:O,onRow:N,colorMaps:L}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx(U,{variant:"outline",size:"sm",disabled:a===0,onClick:()=>o(k=>k-1),children:"Prev"}),e.jsx(U,{variant:"outline",size:"sm",disabled:!(i!=null&&i.hasMore),onClick:()=>o(k=>k+1),children:"Next"}),e.jsxs("span",{className:"text-xs text-muted-foreground",children:["page ",a+1]})]})]}),h&&e.jsx(Ma,{event:h,onClose:()=>N(null)})]})}const _a={agents:"agent",sessions:"session",tools:"tool",users:"user"};function Ua(t,s){switch(t){case"agents":return{agentClass:s};case"sessions":{const n=s.indexOf("/");return n<0?{sessionName:s}:{sessionNamespace:s.slice(0,n),sessionName:s.slice(n+1)}}case"tools":return{tool:s};case"users":return{actor:s}}}function Va(t,s){return t==="users"?ae(s):s}function Wa({status:t}){return t?e.jsx("span",{className:`inline-flex rounded-full border px-2 py-0.5 text-[10px] font-medium ${at(t)}`,children:t}):e.jsx("span",{className:"text-muted-foreground",children:"—"})}function Ha({apiBase:t,axis:s,onDrill:n}){const[r,a]=d.useState([]),[o,i]=d.useState(null);d.useEffect(()=>{let u=!0;return _(`${t}/audit/entities/${s}`).then(h=>{u&&(a(h),i(null))}).catch(h=>{u&&i(h.message)}),()=>{u=!1}},[t,s]);const l=s==="sessions",c=_a[s];return e.jsxs("div",{className:"space-y-3",children:[o&&e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load rollups: ",o]})}),e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{className:"capitalize",children:s}),l&&e.jsx(y,{children:"Status"}),l&&e.jsx(y,{className:"text-right",children:"Est. tokens"}),l&&e.jsx(y,{children:"Started"}),l&&e.jsx(y,{children:"Started by"}),e.jsx(y,{className:"text-right",children:"Events"}),e.jsx(y,{className:"text-right",children:"Denied"}),e.jsx(y,{className:"text-right",children:"Logs"})]})}),e.jsx(X,{children:r.map(u=>e.jsxs(M,{children:[e.jsx(v,{className:"font-mono text-xs",children:e.jsx(W,{entity:c,id:u.key,className:"text-link hover:underline",children:l?e.jsx(Z,{id:u.key}):Va(s,u.key)})}),l&&e.jsx(v,{children:e.jsx(Wa,{status:u.status})}),l&&e.jsx(v,{className:"text-right font-mono text-xs text-muted-foreground",title:u.estimatedCostUSD?`~$${u.estimatedCostUSD.toFixed(2)} (est.)`:void 0,children:u.inputTokens||u.outputTokens?`${ge(u.inputTokens??0)} in · ${ge(u.outputTokens??0)} out`:"—"}),l&&e.jsx(v,{className:"whitespace-nowrap text-xs text-muted-foreground",children:Lt(u.startedAt)}),l&&e.jsx(v,{className:"text-xs",children:u.startedBy?e.jsxs("span",{className:"inline-flex items-center gap-1.5",children:[e.jsx(Tt,{kind:u.startedBy}),e.jsx(W,{entity:"user",id:u.startedBy,className:"font-mono text-link hover:underline",children:ae(u.startedBy)})]}):e.jsx("span",{className:"font-mono text-muted-foreground",children:"—"})}),e.jsx(v,{className:"text-right font-mono text-xs",children:u.events}),e.jsx(v,{className:"text-right font-mono text-xs text-destructive",children:u.denied||""}),e.jsx(v,{className:"text-right",children:e.jsx("button",{type:"button",className:"text-xs text-muted-foreground hover:text-link hover:underline",onClick:()=>n(Ua(s,u.key)),children:"filter logs"})})]},u.key))})]}),e.jsxs("p",{className:"text-[11px] text-muted-foreground",children:["Row → ",c," detail · “filter logs” → the audit log scoped to that ",c]})]})}const bt=14,Bt=8,ut=4;function Fs(t){return`${t.namespace}/${t.artifactId||t.name}`}function Re(t){return`${t.namespace}/${t.name}`}function za(t){const s=new Map;for(const n of t){const r=Fs(n),a=s.get(r);if(a===void 0){s.set(r,n);continue}const o=new Date(n.created).getTime(),i=new Date(a.created).getTime();(o>i||o===i&&Re(n){const x=Fs(p);a.push(x),s.has(x)||(s.set(x,b),r.set(x,As(x)??"#888")),n.set(x,b)});const o=[...s.keys()],i=[],l=new Map;for(const p of o){const b=s.get(p);let x=i.findIndex(j=>jnew Array(t.length).fill(void 0));for(const p of o){const b=l.get(p);for(let x=s.get(p);x<=n.get(p);x++)u[b][x]===void 0&&(u[b][x]=p)}const h=za(t),N=t.map((p,b)=>{const x=a[b],j=l.get(x),$=[];for(let C=0;Cs.get(E),R=E!==void 0&&b{const r=es(n.lane);return e.jsxs("g",{children:[n.up&&e.jsx("line",{x1:r,y1:0,x2:r,y2:5,stroke:n.color,strokeWidth:1.5,strokeOpacity:.7}),n.down&&e.jsx("line",{x1:r,y1:5,x2:r,y2:10,stroke:n.color,strokeWidth:1.5,strokeOpacity:.7})]},n.lane)})}),e.jsx("div",{className:"absolute inset-0 flex items-center",children:t.segments.filter(n=>n.dot).map(n=>e.jsx("span",{className:"absolute rounded-full border",style:{left:es(n.lane)-ut,width:ut*2,height:ut*2,backgroundColor:n.color,borderColor:"hsl(var(--card))",opacity:t.isLatest?1:.55},"data-lane":n.lane,"data-testid":"track-dot"},n.lane))})]})}const Ja={Ready:"border-success/40 bg-success/10 text-success",Failed:"border-destructive/40 bg-destructive/10 text-destructive",Rendering:"border-primary/40 bg-primary/10 text-primary",Pending:"border-border bg-muted text-muted-foreground"};function ot({phase:t}){const s=Ja[t]??"border-border bg-background text-muted-foreground";return e.jsx("span",{className:`inline-flex rounded-full border px-2 py-0.5 text-[10px] font-medium ${s}`,children:t||"—"})}function Et(t){if(!t)return"—";const s=["B","KB","MB","GB"];let n=0,r=t;for(;r>=1024&&n{let u=!0;return hr(t).then(h=>{u&&(r(h),o(null),l(!0))}).catch(h=>{u&&(o(h.message),l(!0))}),()=>{u=!1}},[t]);const c=d.useMemo(()=>qa(n),[n]);return a?e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load artifacts: ",a]})}):e.jsxs("div",{className:"space-y-3",children:[i&&n.length===0&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"No artifacts rendered yet."}),n.length>0&&e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{children:"When"}),e.jsx(y,{children:"Artifact"}),e.jsx(y,{children:"Session"}),e.jsx(y,{children:"Kind"}),e.jsx(y,{children:"MIME"}),e.jsx(y,{className:"text-right",children:"Size"}),e.jsx(y,{className:"text-right",children:"Revisions"}),e.jsx(y,{children:"Phase"}),e.jsx(y,{className:"text-right",children:"Tracks"})]})}),e.jsx(X,{children:n.map((u,h)=>{const N=!!(u.session&&s),p=c.rows[h],b=p.isLatest;return e.jsxs(M,{children:[e.jsx(v,{className:"whitespace-nowrap font-mono text-xs text-muted-foreground",children:new Date(u.created).toLocaleString()}),e.jsx(v,{className:"font-mono text-xs",children:e.jsx(W,{entity:"artifact",id:`${u.namespace}/${u.name}`,className:b?"text-link hover:underline":"text-muted-foreground hover:underline",children:u.name})}),e.jsx(v,{className:"font-mono text-xs text-muted-foreground",children:u.session?N?e.jsx("button",{type:"button",className:"hover:text-link hover:underline",onClick:()=>s(Ya(u.session)),children:e.jsx(Z,{id:u.session})}):e.jsx(Z,{id:u.session}):"—"}),e.jsx(v,{children:e.jsx(z,{variant:"outline",children:u.kind})}),e.jsx(v,{className:"font-mono text-xs text-muted-foreground",children:u.mime||"—"}),e.jsx(v,{className:"text-right font-mono text-xs text-muted-foreground",children:Et(u.size)}),e.jsx(v,{className:"text-right font-mono text-xs text-muted-foreground",children:u.revisions||""}),e.jsx(v,{children:e.jsx(ot,{phase:u.phase})}),e.jsx(v,{className:"p-0 pl-2 align-middle",children:e.jsx(Ga,{row:p,width:c.width})})]},p.uid)})})]}),e.jsx("p",{className:"text-[11px] text-muted-foreground",children:"ArtifactRender — versioned, sanitized agent outputs · click the name → artifact detail · the session → its Logs · Tracks = git-graph of revisions per logical artifact · oap artifact"})]})}const Xa=[{id:"overview",label:"Overview"},{id:"revisions",label:"Revisions"}];function Za(t){const s=t.indexOf("/");return s<0?{ns:"",name:t}:{ns:t.slice(0,s),name:t.slice(s+1)}}function Ba(t){try{return new URL(t,"http://placeholder.invalid").searchParams.has("artifactId")}catch{return!1}}function ke({label:t,children:s}){return e.jsxs("div",{className:"flex flex-col gap-0.5",children:[e.jsx("dt",{className:"text-[10px] uppercase tracking-wide text-muted-foreground",children:t}),e.jsx("dd",{className:"font-mono text-xs text-foreground",children:s})]})}function eo({apiBase:t,id:s,tab:n}){const{ns:r,name:a}=Za(s),o=n??"overview",[i,l]=d.useState(null),[c,u]=d.useState(null),[h,N]=d.useState(!1);d.useEffect(()=>{let b=!0;return l(null),u(null),N(!1),fr(t,r,a).then(x=>{b&&l(x)}).catch(x=>{b&&(x instanceof J&&x.status===404?N(!0):u(x.message))}),()=>{b=!1}},[t,r,a]);const p=b=>te({type:"detail",entity:"artifact",id:s,tab:b});return e.jsx(nt,{title:e.jsx("span",{className:"font-mono",children:e.jsx(Z,{ns:r,name:a})}),backRoute:{type:"view",view:"artifacts"},tabs:Xa,activeTab:o,onTab:p,headerRight:i?e.jsx(ot,{phase:i.phase}):void 0,children:c?e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load artifact: ",c]})}):h?e.jsxs("p",{className:"text-sm text-muted-foreground",children:["Artifact ",s," not found — it may have been garbage-collected."]}):i?o==="revisions"?e.jsx(so,{detail:i}):e.jsx(to,{detail:i}):e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading…"})})}function to({detail:t}){const s=Ba(t.viewPath);return e.jsxs("div",{className:"flex flex-col gap-5",children:[e.jsxs("dl",{className:"grid grid-cols-2 gap-x-6 gap-y-3 sm:grid-cols-3",children:[e.jsx(ke,{label:"Kind",children:t.kind||"—"}),e.jsx(ke,{label:"Phase",children:e.jsx(ot,{phase:t.phase})}),e.jsx(ke,{label:"MIME",children:t.mime||"—"}),e.jsx(ke,{label:"Size",children:Et(t.size)}),e.jsx(ke,{label:"Created",children:new Date(t.created).toLocaleString()}),e.jsx(ke,{label:"Session",children:t.session?e.jsx(W,{entity:"session",id:t.session,className:"text-link hover:underline",children:e.jsx(Z,{id:t.session})}):"—"})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("span",{className:"text-[10px] font-semibold uppercase tracking-wide text-muted-foreground",children:"Viewer"}),s?e.jsx("a",{href:t.viewPath,target:"_blank",rel:"noopener noreferrer",className:"w-fit text-sm text-link hover:underline",children:"Open viewer"}):e.jsx("span",{className:"text-[11px] text-muted-foreground",children:"No viewer available for this artifact."})]}),e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("span",{className:"text-[10px] font-semibold uppercase tracking-wide text-muted-foreground",children:"Download"}),t.outputRef?e.jsx("code",{className:"w-fit break-all rounded border border-border bg-background px-2 py-1 font-mono text-xs text-foreground",children:t.outputRef}):e.jsx("span",{className:"text-sm text-muted-foreground",children:"No content ref yet — the render has not reached Ready."})]})]})}function so({detail:t}){return t.revisions.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No revisions."}):e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{children:"Name"}),e.jsx(y,{children:"Phase"}),e.jsx(y,{children:"MIME"}),e.jsx(y,{className:"text-right",children:"Size"}),e.jsx(y,{children:"Created"})]})}),e.jsx(X,{children:t.revisions.map(s=>e.jsxs(M,{className:s.name===t.name?"bg-muted/40":void 0,children:[e.jsx(v,{className:"font-mono text-xs",children:e.jsx(W,{entity:"artifact",id:`${t.namespace}/${s.name}`,className:"text-link hover:underline",children:s.name})}),e.jsx(v,{children:e.jsx(ot,{phase:s.phase})}),e.jsx(v,{className:"font-mono text-xs text-muted-foreground",children:s.mime||"—"}),e.jsx(v,{className:"text-right font-mono text-xs text-muted-foreground",children:Et(s.size)}),e.jsx(v,{className:"whitespace-nowrap font-mono text-xs text-muted-foreground",children:new Date(s.created).toLocaleString()})]},s.name))})]})}const Ms=t=>t==null||Number.isNaN(t)?"NaN":`$${t.toFixed(2)}`,ue=[{id:"byModel",label:"By model",keyLabel:"Model"},{id:"byAgentClass",label:"By agent",keyLabel:"Agent class",keyEntity:"agent"},{id:"bySession",label:"By session",keyLabel:"Session",keyEntity:"session"},{id:"byUser",label:"By user",keyLabel:"User",decode:!0}];function no({color:t}){return t?e.jsx("span",{"aria-hidden":"true",className:"inline-block h-2.5 w-2.5 shrink-0 rounded-sm",style:{backgroundColor:t}}):null}function ro({rows:t,keyLabel:s,highlightKey:n,keyEntity:r,decode:a,isModel:o}){if(t.length===0)return e.jsx("p",{className:"px-1 py-6 text-center text-xs text-muted-foreground",children:"No usage recorded."});const i=Ls(t.map(l=>l.key));return e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{children:s}),e.jsx(y,{className:"text-right",children:"Input tokens"}),e.jsx(y,{className:"text-right",children:"Output tokens"}),e.jsx(y,{className:"text-right",children:"Est. cost"})]})}),e.jsx(X,{children:t.map(l=>{const c=n!=null&&l.key===n,u=r==="session"?e.jsx(Z,{id:l.key}):a?ae(l.key):l.key;return e.jsxs(M,{className:c?"bg-accent/60":void 0,children:[e.jsx(v,{className:"font-mono text-xs",children:e.jsxs("span",{className:"flex items-center gap-2",children:[e.jsx(no,{color:i.get(l.key)}),l.key&&r?e.jsx(W,{entity:r,id:l.key,className:"text-link hover:underline",children:u}):o&&l.key?e.jsx(kt,{model:l.key}):e.jsx("span",{children:l.key?u:"(unknown)"}),c&&e.jsx(z,{variant:"secondary",className:"align-middle text-[10px]",children:"from Overview"})]})}),e.jsx(v,{className:"text-right font-mono text-xs text-muted-foreground",children:xe(l.inputTokens)}),e.jsx(v,{className:"text-right font-mono text-xs text-muted-foreground",children:xe(l.outputTokens)}),e.jsx(v,{className:"text-right font-mono text-xs",children:Ms(l.estimatedCostUSD)})]},l.key)})})]})}function ao({apiBase:t}){const s=ks(),n=s.type==="view"&&s.query?s.query.get("model")??void 0:void 0,[r,a]=d.useState(null),[o,i]=d.useState(null);d.useEffect(()=>{let p=!0;return cr(t).then(b=>{p&&(a(b),i(null))}).catch(b=>{p&&i(b.message)}),()=>{p=!1}},[t]);const[l,c]=d.useState("byModel"),u=d.useRef(null),h=p=>{var C,E;if(!["ArrowRight","ArrowLeft","Home","End"].includes(p.key))return;p.preventDefault();const x=ue.findIndex(m=>m.id===l),j=p.key==="ArrowRight"?(x+1)%ue.length:p.key==="ArrowLeft"?(x-1+ue.length)%ue.length:p.key==="Home"?0:ue.length-1,$=ue[j].id;c($),(E=(C=u.current)==null?void 0:C.querySelector(`#budget-tab-${$}`))==null||E.focus()};if(o)return e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load budget: ",o]})});if(!r)return e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading budget…"});const N=r.byModel.reduce((p,b)=>p+(b.estimatedCostUSD??NaN),0);return e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-2 rounded-xl border bg-card p-4 shadow",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-[11px] text-muted-foreground",children:"Total estimated spend"}),e.jsx("div",{className:"mt-0.5 text-2xl font-semibold tracking-tight",children:Ms(N)})]}),e.jsx("p",{className:"max-w-md text-[11px] text-muted-foreground",children:"Estimated from list prices — not a metered bill. Same live-session scope as the Overview budget panel."})]}),e.jsx("div",{ref:u,role:"tablist","aria-label":"Budget breakdown axes",onKeyDown:h,className:"inline-flex h-9 items-center gap-1 rounded-lg bg-muted p-1 text-muted-foreground",children:ue.map(p=>{const b=l===p.id;return e.jsx("button",{id:`budget-tab-${p.id}`,type:"button",role:"tab","aria-selected":b,"aria-controls":`budget-panel-${p.id}`,tabIndex:b?0:-1,onClick:()=>c(p.id),className:["inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium transition-all",b?"bg-background text-foreground shadow":"hover:text-foreground"].join(" "),children:p.label},p.id)})}),ue.filter(p=>p.id===l).map(p=>e.jsx("div",{id:`budget-panel-${p.id}`,role:"tabpanel","aria-labelledby":`budget-tab-${p.id}`,tabIndex:0,className:"rounded-xl border bg-card p-2 shadow",children:e.jsx(ro,{rows:r[p.id],keyLabel:p.keyLabel,highlightKey:p.id==="byModel"?n:void 0,keyEntity:p.keyEntity,decode:p.decode,isModel:p.id==="byModel"})},p.id))]})}function oo({apiBase:t}){const[s,n]=d.useState(""),[r,a]=d.useState(""),[o,i]=d.useState(null),[l,c]=d.useState(null),[u,h]=d.useState(!1);d.useEffect(()=>{let j=!0;return gr(t,r?{q:r}:{}).then($=>{j&&(i($),c(null),h(!0))}).catch($=>{j&&(c($.message),h(!0))}),()=>{j=!1}},[t,r]);const N=j=>{j.preventDefault(),a(s.trim())},p=(o==null?void 0:o.rollups)??[],b=(o==null?void 0:o.entries)??[],x=r!=="";return e.jsxs("div",{className:"space-y-3",children:[e.jsx("form",{onSubmit:N,className:"flex items-center gap-2",children:e.jsxs("label",{className:"flex h-9 flex-1 items-center gap-2 rounded-md border border-input bg-background px-3 text-xs",children:[e.jsx(fs,{className:"h-3.5 w-3.5 text-muted-foreground"}),e.jsx("input",{type:"search",value:s,onChange:j=>n(j.target.value),placeholder:"search memory — text, tags, vectors…","aria-label":"Search memory",className:"flex-1 bg-transparent text-xs text-foreground outline-none placeholder:text-muted-foreground"})]})}),l&&e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load memory: ",l]})}),(o==null?void 0:o.truncated)&&e.jsx(I,{children:e.jsx(F,{children:"Results truncated — narrow the scan for complete rollup counts."})}),x?b.length===0?e.jsxs("p",{className:"text-sm text-muted-foreground",children:["No matches for “",r,"”."]}):e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{children:"Kind"}),e.jsx(y,{children:"Scope"}),e.jsx(y,{children:"Entry"}),e.jsx(y,{children:"When"}),e.jsx(y,{className:"text-right",children:"Score"})]})}),e.jsx(X,{children:b.map(j=>e.jsxs(M,{children:[e.jsx(v,{children:e.jsx(z,{variant:"outline",children:j.kind})}),e.jsx(v,{className:"font-mono text-xs text-muted-foreground",children:j.scope}),e.jsx(v,{className:"font-mono text-xs text-foreground",children:j.id}),e.jsx(v,{className:"whitespace-nowrap font-mono text-xs text-muted-foreground",children:j.created?new Date(j.created).toLocaleString():"—"}),e.jsx(v,{className:"text-right font-mono text-xs text-muted-foreground",children:j.score!=null?j.score.toFixed(2):""})]},`${j.scope}/${j.kind}/${j.id}`))})]}):p.length===0?u&&e.jsx("p",{className:"text-sm text-muted-foreground",children:"No memory entries yet."}):e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{children:"Kind"}),e.jsx(y,{className:"text-right",children:"Entries"}),e.jsx(y,{className:"text-right",children:"Scopes"}),e.jsx(y,{children:"Last write"}),e.jsx(y,{})]})}),e.jsx(X,{children:p.map(j=>e.jsxs(M,{children:[e.jsx(v,{className:"font-mono text-xs text-foreground",children:j.kind}),e.jsx(v,{className:"text-right font-mono text-xs text-muted-foreground",children:j.entries}),e.jsx(v,{className:"text-right font-mono text-xs text-muted-foreground",children:j.scopes}),e.jsx(v,{className:"whitespace-nowrap font-mono text-xs text-muted-foreground",children:j.lastWrite?new Date(j.lastWrite).toLocaleString():"—"}),e.jsx(v,{children:j.appendOnly&&e.jsx(z,{children:"append-only"})})]},j.kind))})]}),e.jsxs("p",{className:"text-[11px] text-muted-foreground",children:["Append-only kinds are tamper-evident (Ed25519 hash chains) — verify with"," ",e.jsx("span",{className:"font-mono",children:"oap audit verify"})," · oap memory list / search / query"]})]})}function vt({uuid:t,label:s,onOpen:n}){return t?e.jsxs("button",{type:"button",onClick:()=>n(t),className:"inline-flex items-center gap-2 rounded-full border bg-background px-3 py-1 font-mono text-xs hover:bg-accent hover:text-accent-foreground",children:[e.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-state"}),s||t]}):e.jsx("span",{className:"font-mono text-xs text-muted-foreground",children:s||"—"})}function ts({facts:t,onOpen:s}){return t.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No facts."}):e.jsx("ul",{className:"space-y-2",children:t.map(n=>e.jsxs("li",{className:"rounded-md border bg-background p-3",children:[e.jsx("div",{className:"text-sm text-foreground",children:n.fact||n.name}),e.jsxs("div",{className:"mt-1.5 flex flex-wrap items-center gap-1.5",children:[e.jsx(vt,{uuid:n.fromEntity,label:n.fromEntity,onOpen:s}),e.jsx("span",{className:"text-muted-foreground",children:"→"}),e.jsx(vt,{uuid:n.toEntity,label:n.toEntity,onOpen:s}),n.validAt&&e.jsx("span",{className:"ml-1 font-mono text-[11px] text-muted-foreground",children:new Date(n.validAt).toLocaleDateString()})]})]},n.uuid))})}function lo({apiBase:t}){var L,k;const[s,n]=d.useState(null),[r,a]=d.useState(""),[o,i]=d.useState(null),[l,c]=d.useState([]),[u,h]=d.useState(""),[N,p]=d.useState(""),[b,x]=d.useState(null),[j,$]=d.useState(null),[C,E]=d.useState(null),m=d.useRef(null);d.useEffect(()=>{let g=!0;return wr(t).then(T=>{g&&(n(T.available),a(T.note??""),c(T.communities??[]),i(T.error??null))}).catch(T=>{g&&(n(!0),i(T.message))}),()=>{g=!1}},[t]),d.useEffect(()=>{if(!N){x(null),$(null);return}let g=!0;return br(t,N).then(T=>{g&&(x(T.facts??[]),$(T.error??null))}).catch(T=>{g&&(x([]),$(T.message))}),()=>{g=!1}},[t,N]);const w=d.useCallback(g=>{g&&(m.current=g,E({uuid:g,loading:!0,entity:null,facts:[],related:[]}),Promise.all([vr(t,g),yr(t,g),Nr(t,g)]).then(([T,P,V])=>{m.current===g&&E({uuid:g,loading:!1,entity:T.entity??null,facts:P.facts??[],related:V.entities??[],error:T.error||P.error||V.error||void 0})}).catch(T=>{m.current===g&&E({uuid:g,loading:!1,entity:null,facts:[],related:[],error:T.message})}))},[t]),R=g=>{g.preventDefault(),p(u.trim())};if(s===!1)return e.jsxs("div",{className:"rounded-xl border border-dashed bg-card p-6 shadow",children:[e.jsxs("div",{className:"flex items-center gap-2 text-sm font-semibold text-foreground",children:[e.jsx(hs,{className:"h-4 w-4 text-muted-foreground"})," Knowledge graph not configured"]}),e.jsxs("p",{className:"mt-2 text-sm text-muted-foreground",children:[r||"The knowledge graph is not available."," Set"," ",e.jsx("span",{className:"font-mono",children:"--graphiti-endpoint"})," on the operator to enable graph-aware entity, fact, and community search."]}),e.jsx("p",{className:"mt-3 text-[11px] text-muted-foreground",children:"oap kg search / entity / facts / related / communities"})]});if(s===null&&!o)return e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading knowledge graph…"});const O=N!=="";return e.jsxs("div",{className:"space-y-4",children:[o&&e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load knowledge graph: ",o]})}),e.jsx("form",{onSubmit:R,className:"flex items-center gap-2",children:e.jsxs("label",{className:"flex h-9 flex-1 items-center gap-2 rounded-md border border-input bg-background px-3 text-xs",children:[e.jsx(fs,{className:"h-3.5 w-3.5 text-muted-foreground"}),e.jsx("input",{type:"search",value:u,onChange:g=>h(g.target.value),placeholder:"search facts — graph-aware…","aria-label":"Search facts",className:"flex-1 bg-transparent text-xs text-foreground outline-none placeholder:text-muted-foreground"})]})}),j&&e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Fact search degraded: ",j]})}),O&&e.jsxs("div",{className:"rounded-xl border bg-card p-4 shadow",children:[e.jsxs("div",{className:"text-sm font-semibold text-foreground",children:["Facts matching “",N,"”"]}),e.jsx("div",{className:"mt-3",children:b===null?e.jsx("p",{className:"text-sm text-muted-foreground",children:"Searching…"}):e.jsx(ts,{facts:b,onOpen:w})})]}),C&&e.jsxs("div",{className:"rounded-xl border bg-card p-4 shadow",children:[e.jsxs("div",{className:"flex items-start justify-between",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-sm font-semibold text-foreground",children:((L=C.entity)==null?void 0:L.name)||C.uuid}),((k=C.entity)==null?void 0:k.summary)&&e.jsx("div",{className:"mt-0.5 text-xs text-muted-foreground",children:C.entity.summary})]}),e.jsx("button",{type:"button","aria-label":"Close entity",onClick:()=>E(null),className:"inline-flex h-6 w-6 items-center justify-center rounded border border-input bg-background text-muted-foreground hover:bg-accent hover:text-accent-foreground",children:e.jsx(zn,{className:"h-3 w-3"})})]}),C.error&&e.jsx(I,{variant:"destructive",className:"mt-3",children:e.jsxs(F,{children:["Entity lookup degraded: ",C.error]})}),C.loading?e.jsx("p",{className:"mt-3 text-sm text-muted-foreground",children:"Loading entity…"}):e.jsxs("div",{className:"mt-3 space-y-4",children:[e.jsxs("div",{children:[e.jsx("div",{className:"mb-2 text-xs font-semibold text-muted-foreground",children:"Facts"}),e.jsx(ts,{facts:C.facts,onOpen:w})]}),e.jsxs("div",{children:[e.jsx("div",{className:"mb-2 text-xs font-semibold text-muted-foreground",children:"Related entities"}),C.related.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No related entities."}):e.jsx("div",{className:"flex flex-wrap gap-2",children:C.related.map(g=>e.jsx(vt,{uuid:g.uuid,label:g.name||g.uuid,onOpen:w},g.uuid))})]})]})]}),e.jsxs("div",{className:"rounded-xl border bg-card p-4 shadow",children:[e.jsx("div",{className:"text-sm font-semibold text-foreground",children:"Communities"}),l.length===0?e.jsx("p",{className:"mt-2 text-sm text-muted-foreground",children:"No communities yet."}):e.jsx("ul",{className:"mt-3 space-y-2",children:l.map(g=>e.jsxs("li",{className:"rounded-md border bg-background p-3",children:[e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("span",{className:"font-mono text-xs text-foreground",children:g.name||g.uuid}),e.jsxs(z,{variant:"outline",children:[g.members.length," members"]})]}),g.summary&&e.jsx("div",{className:"mt-1 text-xs text-muted-foreground",children:g.summary})]},g.uuid))}),e.jsx("p",{className:"mt-3 text-[11px] text-muted-foreground",children:"Graphiti knowledge graph — entities, facts, communities · oap kg search / entity / facts / related"})]})]})}const ss=t=>new URLSearchParams({model:t}),io=t=>t==null||Number.isNaN(t)?"NaN":`$${t.toFixed(2)}`,Ue=["bg-chart-1","bg-chart-2","bg-chart-3","bg-chart-4","bg-chart-5"],co={Healthy:"bg-success",Degraded:"bg-warning",Down:"bg-destructive",NotConfigured:"bg-muted-foreground"},uo={Healthy:"text-success",Degraded:"text-warning",Down:"text-destructive",NotConfigured:"text-muted-foreground"};function xo({values:t,width:s=600,height:n=150}){const r=Math.max(1,...t)*1.12,a=6,o=t.length,i=h=>a+(o<=1?0:h*(s-2*a)/(o-1)),l=h=>n-a-h/r*(n-2*a),c=t.map((h,N)=>`${N?"L":"M"} ${i(N).toFixed(1)} ${l(h).toFixed(1)}`).join(" "),u=`${c} L ${i(o-1).toFixed(1)} ${(n-a).toFixed(1)} L ${i(0).toFixed(1)} ${(n-a).toFixed(1)} Z`;return e.jsxs("svg",{viewBox:`0 0 ${s} ${n}`,className:"h-40 w-full",preserveAspectRatio:"none",role:"img","aria-label":"Tokens over time",children:[e.jsx("defs",{children:e.jsxs("linearGradient",{id:"ap-overview-area",x1:"0",x2:"0",y1:"0",y2:"1",children:[e.jsx("stop",{offset:"0%",stopColor:"hsl(var(--chart-1))",stopOpacity:"0.35"}),e.jsx("stop",{offset:"100%",stopColor:"hsl(var(--chart-1))",stopOpacity:"0"})]})}),e.jsx("path",{d:u,fill:"url(#ap-overview-area)"}),e.jsx("path",{d:c,fill:"none",stroke:"hsl(var(--chart-1))",strokeWidth:"1.5",vectorEffect:"non-scaling-stroke"})]})}function mo({label:t,value:s,sub:n}){return e.jsxs("div",{className:"rounded-xl border bg-card p-4 shadow",children:[e.jsx("div",{className:"text-[11px] text-muted-foreground",children:t}),e.jsx("div",{className:"mt-1 text-2xl font-semibold tracking-tight",children:s}),n&&e.jsx("div",{className:"mt-0.5 font-mono text-[11px] text-muted-foreground",children:n})]})}function ho({apiBase:t}){const[s,n]=d.useState(null),[r,a]=d.useState(null),[o,i]=d.useState(null),[l,c]=d.useState(null);if(d.useEffect(()=>{let m=!0;return or(t).then(w=>{m&&(n(w),i(null))}).catch(w=>{m&&i(w.message)}),lr(t).then(w=>{m&&(a(w),c(null))}).catch(w=>{m&&c(w.message)}),()=>{m=!1}},[t]),o)return e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load overview: ",o]})});if(!s)return e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading overview…"});const u=s.kpis,h=s.budget,N=s.series24h.map(m=>m.inputTokens+m.outputTokens),p=N.reduce((m,w)=>m+w,0),b=h.tokenCeiling&&h.tokenCeiling>0?h.tokensSpent/h.tokenCeiling*100:null,x=b!=null?`${b.toFixed(0)}%`:xe(h.tokensSpent),j=[{label:"Active sessions",value:`${u.activeSessions}`},{label:"Tokens today",value:xe(u.tokensToday)},{label:"Tool calls (24h)",value:`${u.toolCalls24h}`},{label:"Approvals pending",value:`${u.approvalsPending}`},{label:"Denials (24h)",value:`${u.denials24h}`}],$=s.byModel.reduce((m,w)=>m+w.inputTokens+w.outputTokens,0)||1,C=Math.max(1,...s.byAgentClass.map(m=>m.inputTokens+m.outputTokens)),E=((r==null?void 0:r.components)??[]).filter(m=>m.status==="Degraded"||m.status==="Down").length;return e.jsxs("div",{className:"space-y-4",children:[e.jsx("div",{className:"grid grid-cols-2 gap-3 md:grid-cols-3 xl:grid-cols-5",children:j.map(m=>e.jsx(mo,{label:m.label,value:m.value},m.label))}),e.jsxs("div",{className:"grid grid-cols-1 gap-4 lg:grid-cols-3",children:[e.jsxs(me,{className:"lg:col-span-2",children:[e.jsxs(he,{className:"flex-row items-center justify-between pb-2",children:[e.jsxs("div",{children:[e.jsx(fe,{className:"text-sm",children:"Tokens over time"}),e.jsx("div",{className:"text-[11px] text-muted-foreground",children:"last 24 hours · all models"})]}),e.jsxs("div",{className:"font-mono text-xs text-muted-foreground",children:[xe(p)," total"]})]}),e.jsx(pe,{children:e.jsx(xo,{values:N})})]}),e.jsx(zt,{view:"budget",className:"block h-full rounded-xl",children:e.jsxs(me,{className:"h-full transition-colors hover:border-primary/50 hover:bg-accent/20",children:[e.jsxs(he,{className:"flex-row items-center justify-between pb-2",children:[e.jsx(fe,{className:"text-sm",children:"Budget"}),e.jsx("span",{className:"text-[11px] text-link",children:"View breakdown →"})]}),e.jsxs(pe,{className:"space-y-2",children:[e.jsxs("div",{className:"flex items-end gap-2",children:[e.jsx("div",{className:"text-3xl font-semibold tracking-tight",children:x}),e.jsx("div",{className:"mb-1 font-mono text-xs text-muted-foreground",children:b!=null?`${xe(h.tokensSpent)} tokens`:"tokens spent"})]}),e.jsxs("div",{className:"font-mono text-sm text-muted-foreground",children:["est. ",io(h.estimatedCostUSD)]}),e.jsxs("div",{className:"text-[11px] text-muted-foreground",children:[h.estimated?"estimated · list-price":"metered"," · daily budget resets 00:00 UTC"]})]})]})})]}),e.jsxs("div",{className:"grid grid-cols-1 gap-4 lg:grid-cols-2",children:[e.jsxs(me,{children:[e.jsx(he,{className:"pb-2",children:e.jsx(fe,{className:"text-sm",children:"Tokens by model"})}),e.jsxs(pe,{className:"space-y-3",children:[e.jsx("div",{"aria-hidden":"true",className:"flex h-3 w-full overflow-hidden rounded",children:s.byModel.map((m,w)=>e.jsx("div",{onClick:()=>te({type:"view",view:"budget",query:ss(m.model)}),title:`${m.model||"(unknown)"} — view budget`,className:`h-full cursor-pointer ${Ue[w%Ue.length]}`,style:{width:`${((m.inputTokens+m.outputTokens)/$*100).toFixed(1)}%`}},m.model))}),e.jsxs("div",{className:"space-y-2",children:[s.byModel.length===0&&e.jsx("p",{className:"text-xs text-muted-foreground",children:"No live model usage."}),s.byModel.map((m,w)=>e.jsxs(zt,{view:"budget",query:ss(m.model),className:"-mx-1 flex items-center justify-between rounded px-1 py-0.5 text-xs transition-colors hover:bg-accent/40",children:[e.jsxs("span",{className:"flex items-center gap-2",children:[e.jsx("span",{"aria-hidden":"true",className:`h-2.5 w-2.5 rounded-sm ${Ue[w%Ue.length]}`}),m.model?e.jsx(kt,{model:m.model}):e.jsx("span",{className:"font-mono",children:"(unknown)"})]}),e.jsxs("span",{className:"font-mono text-muted-foreground",children:[xe(m.inputTokens+m.outputTokens)," · ",m.sessions," sess"]})]},m.model))]})]})]}),e.jsxs(me,{children:[e.jsx(he,{className:"pb-2",children:e.jsx(fe,{className:"text-sm",children:"Tokens by agent class"})}),e.jsxs(pe,{className:"space-y-2.5",children:[s.byAgentClass.length===0&&e.jsx("p",{className:"text-xs text-muted-foreground",children:"No live agent-class usage."}),s.byAgentClass.map(m=>{const w=m.inputTokens+m.outputTokens,R=e.jsxs(e.Fragment,{children:[e.jsx("span",{className:"w-28 shrink-0 truncate font-mono",children:m.class||"(unknown)"}),e.jsx("div",{className:"h-2.5 flex-1 overflow-hidden rounded bg-muted",children:e.jsx("div",{className:"h-full rounded bg-chart-1",style:{width:`${(w/C*100).toFixed(1)}%`}})}),e.jsx("span",{className:"w-12 shrink-0 text-right font-mono text-muted-foreground",children:xe(w)})]});return m.class?e.jsx(W,{entity:"agent",id:m.class,className:"-mx-1 flex items-center gap-3 rounded px-1 py-0.5 text-xs transition-colors hover:bg-accent/40",children:R},m.class):e.jsx("div",{className:"flex items-center gap-3 px-1 py-0.5 text-xs text-muted-foreground",children:R},"__unknown__")})]})]})]}),e.jsxs(me,{children:[e.jsxs(he,{className:"flex-row items-center justify-between pb-2",children:[e.jsx(fe,{className:"text-sm",children:"Cluster health"}),E>0?e.jsxs("span",{className:"flex items-center gap-1.5 text-[11px] text-warning",children:[e.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-warning"}),E," component",E>1?"s":""," degraded"]}):r&&e.jsxs("span",{className:"flex items-center gap-1.5 text-[11px] text-success",children:[e.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-success"}),"all healthy"]})]}),e.jsxs(pe,{className:"space-y-3",children:[l&&e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load cluster health: ",l]})}),r&&e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"grid grid-cols-2 gap-2 md:grid-cols-4",children:r.components.map(m=>e.jsxs("div",{className:"flex items-center justify-between rounded-md border bg-background px-3 py-2",children:[e.jsxs("span",{className:"flex items-center gap-2 font-mono text-xs",children:[e.jsx("span",{className:`h-1.5 w-1.5 rounded-full ${co[m.status]}`}),m.name]}),e.jsx("span",{className:`text-[10px] ${uo[m.status]}`,title:m.detail,children:m.status})]},m.name))}),e.jsxs("div",{className:"grid grid-cols-2 gap-2 md:grid-cols-4",children:[e.jsxs("div",{className:"rounded-md border bg-background px-3 py-2",children:[e.jsx("div",{className:"text-[10px] text-muted-foreground",children:"Pods"}),e.jsxs("div",{className:"mt-0.5 font-mono text-sm",children:[r.rollup.ready," / ",r.rollup.pods," ready"]})]}),e.jsxs("div",{className:"rounded-md border bg-background px-3 py-2",children:[e.jsx("div",{className:"text-[10px] text-muted-foreground",children:"CPU"}),e.jsx("div",{className:"mt-0.5 font-mono text-sm",children:r.rollup.cpu})]}),e.jsxs("div",{className:"rounded-md border bg-background px-3 py-2",children:[e.jsx("div",{className:"text-[10px] text-muted-foreground",children:"Memory"}),e.jsx("div",{className:"mt-0.5 font-mono text-sm",children:r.rollup.memory})]})]})]})]})]})]})}function Ps({text:t}){const[s,n]=d.useState(!1),r=()=>{var o;const a=(o=navigator.clipboard)==null?void 0:o.writeText(t);a&&typeof a.then=="function"&&a.then(()=>{n(!0),setTimeout(()=>n(!1),1200)}).catch(()=>{})};return e.jsx("button",{type:"button","aria-label":"Copy command",onClick:r,className:"inline-flex h-6 w-6 shrink-0 items-center justify-center rounded border border-input bg-background text-muted-foreground hover:bg-accent hover:text-accent-foreground",children:s?e.jsx(qn,{className:"h-3 w-3 text-success"}):e.jsx(Gn,{className:"h-3 w-3"})})}function lt({text:t}){return e.jsxs("div",{className:"flex items-center gap-2 rounded-md border bg-background px-3 py-2",children:[e.jsx("code",{className:"flex-1 truncate font-mono text-xs text-foreground",title:t,children:t}),e.jsx(Ps,{text:t})]})}const ns="rounded-full border px-2 py-0.5 text-[10px] transition-colors",rs="border-border bg-background text-muted-foreground hover:bg-accent/50",fo="border-primary/40 bg-primary/10 text-primary";function as({statuses:t,value:s,onChange:n}){return e.jsxs("div",{className:"flex flex-wrap items-center gap-1.5",children:[e.jsx("button",{type:"button","aria-pressed":s==="",onClick:()=>n(""),className:`${ns} ${s===""?fo:rs}`,children:"All"}),t.map(r=>{const a=s===r;return e.jsx("button",{type:"button","aria-pressed":a,onClick:()=>n(a?"":r),className:`${ns} ${a?Ds(Es(r)):rs}`,children:r},r)})]})}const po=new Set(["Degraded","Failed","Down","Invalid"]);function go(t){return po.has(t)}function Ks({status:t,reason:s}){return e.jsx("span",{title:s||void 0,className:`inline-flex items-center rounded-full border px-2.5 py-0.5 text-[11px] ${at(t)}`,children:t||"Unknown"})}function jo({status:t,reason:s}){return go(t)?e.jsxs(I,{variant:"destructive",children:[e.jsx(dn,{children:t}),s&&e.jsx(F,{children:s})]}):null}function le({label:t,children:s}){return e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx("span",{className:"text-[10px] font-medium uppercase tracking-wide text-muted-foreground",children:t}),e.jsx("div",{className:"text-sm text-foreground",children:s})]})}function yt({children:t}){return e.jsx("span",{className:"rounded-full border bg-background px-2 py-0.5 text-[10px] font-mono text-muted-foreground",children:t})}function ye(t,s){var n,r;return(r=(n=t.badges)==null?void 0:n.find(a=>a.key===s))==null?void 0:r.value}function it(t){return t.namespace?`${t.namespace}/${t.name}`:t.name}function bo({status:t,reason:s}){const n=e.jsx("span",{className:`inline-flex items-center rounded-full border px-2 py-0.5 text-[10px] ${at(t)}`,children:t||"—"});return s?e.jsx(un,{delayDuration:0,children:e.jsxs(xn,{children:[e.jsx(mn,{asChild:!0,children:n}),e.jsx(hn,{className:"max-w-xs whitespace-normal break-words text-xs",children:s})]})}):n}function vo(t,s){if(s.render)return s.render(t);if(s.source==="scope")return e.jsx(yt,{children:t.scope});if(s.source==="count"){const r=t.counts??[],a=s.key?r.find(o=>o.label===s.key):r[0];return a?e.jsx("span",{className:"font-mono text-xs text-muted-foreground",children:a.value}):e.jsx("span",{className:"text-muted-foreground",children:"—"})}const n=(t.badges??[]).filter(r=>s.key?r.key===s.key:!0);return n.length===0?e.jsx("span",{className:"text-muted-foreground",children:"—"}):e.jsx("span",{className:"flex flex-wrap gap-1",children:n.map((r,a)=>s.colorize?e.jsx(rt,{kind:r.value},`${r.key}-${r.value}-${a}`):e.jsx(yt,{children:r.value},`${r.key}-${r.value}-${a}`))})}function yo(t){const s=d.useState(""),n=$t(t??"","");return t?n:s}function _s({rows:t,columns:s,entity:n,facet:r,statusCookieKey:a,loading:o,note:i,emptyText:l}){const[c,u]=d.useState(""),[h,N]=yo(a),[p,b]=d.useState(""),x=d.useMemo(()=>{const m=new Set;for(const w of t)w.status&&m.add(w.status);return Array.from(m).sort()},[t]),j=d.useMemo(()=>{if(!r)return[];const m=new Set;for(const w of t)for(const R of w.badges??[])R.key===r.key&&m.add(R.value);return Array.from(m).sort()},[t,r]),$=t.some(m=>m.manageCmd),C=c.trim().toLowerCase(),E=t.filter(m=>(h===""||m.status===h)&&(p===""||(m.badges??[]).some(w=>r&&w.key===r.key&&w.value===p))&&(C===""||m.name.toLowerCase().includes(C)||(m.namespace??"").toLowerCase().includes(C)));return o?e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading…"}):t.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:l??"Nothing configured yet."}):e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("input",{type:"text",value:c,onChange:m=>u(m.target.value),placeholder:"Filter by name…","aria-label":"Filter by name",className:"h-8 w-56 rounded-md border border-input bg-background px-3 text-xs outline-none focus-visible:ring-1 focus-visible:ring-ring"}),x.length>1&&e.jsx(as,{statuses:x,value:h,onChange:N})]}),r&&j.length>1&&e.jsxs("div",{className:"flex flex-wrap items-center gap-1.5",children:[e.jsx("span",{className:"text-[10px] uppercase tracking-wide text-muted-foreground",children:r.label}),e.jsx(as,{statuses:j,value:p,onChange:b})]}),e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{children:"Name"}),s.map(m=>e.jsx(y,{className:m.align==="right"?"text-right":"",children:m.header},m.header)),e.jsx(y,{children:"Status"}),$&&e.jsx(y,{children:"Manage"})]})}),e.jsxs(X,{children:[E.map(m=>e.jsxs(M,{children:[e.jsxs(v,{children:[n?e.jsx(W,{entity:n,id:it(m),className:"font-mono text-xs text-link hover:underline",children:m.name}):e.jsx("div",{className:"font-mono text-xs text-foreground",children:m.name}),m.namespace&&e.jsx("div",{className:"font-mono text-[10px] text-muted-foreground",children:m.namespace})]}),s.map(w=>e.jsx(v,{className:w.align==="right"?"text-right":"",children:vo(m,w)},w.header)),e.jsx(v,{children:e.jsx(bo,{status:m.status,reason:m.statusReason})}),$&&e.jsx(v,{children:m.manageCmd?e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("code",{className:"truncate font-mono text-[11px] text-muted-foreground",title:m.manageCmd,children:m.manageCmd}),e.jsx(Ps,{text:m.manageCmd})]}):e.jsx("span",{className:"text-muted-foreground",children:"—"})})]},`${m.namespace??""}/${m.name}`)),E.length===0&&e.jsx(M,{children:e.jsx(v,{colSpan:s.length+($?3:2),className:"text-center text-xs text-muted-foreground",children:"No matches."})})]})]}),i&&e.jsx("p",{className:"text-[11px] text-muted-foreground",children:i})]})}const ce={agents:[{header:"Identity",source:"badge",key:"identityMode"},{header:"Tools",source:"count",key:"tools",align:"right"},{header:"Skills",source:"count",key:"skills",align:"right"}],tools:[{header:"Kind",source:"badge",key:"kind",colorize:!0},{header:"Capabilities",source:"count",align:"right"}],skills:[{header:"Kind",source:"badge",key:"kind",colorize:!0},{header:"Delivery",source:"badge",key:"delivery"},{header:"Pin",source:"badge",key:"pin"}],sources:[{header:"Kind",source:"badge",key:"kind",colorize:!0},{header:"Repo",source:"badge",key:"repo"},{header:"Ref",source:"badge",key:"ref"},{header:"Skills",source:"count",key:"discoveredSkills",align:"right"}],directory:[{header:"Kind",source:"badge",key:"kind",colorize:!0},{header:"Credential",source:"badge",key:"credential"},{header:"Scopes",source:"count",key:"scopes",align:"right"},{header:"Written",source:"count",key:"written",align:"right"},{header:"Join misses",source:"count",key:"joinMisses",align:"right"},{header:"Errors",source:"count",key:"errors",align:"right"}],channels:[{header:"Kind",source:"badge",key:"kind",colorize:!0},{header:"Role",source:"badge",key:"role"},{header:"Agent class",source:"badge",key:"agentClass"}],users:[{header:"Subject",source:"badge",key:"subject"},{header:"Credentials",source:"count",key:"availableCredentials",align:"right"},{header:"Resolved",source:"count",key:"resolved",align:"right"}],identities:[{header:"Credential kinds",source:"badge",key:"cred",colorize:!0},{header:"Credentials",source:"count",key:"credentials",align:"right"},{header:"Resolved",source:"count",key:"resolved",align:"right"}],providers:[{header:"Kind",source:"badge",key:"kind",colorize:!0},{header:"Issuer",source:"badge",key:"issuer"}]},Oe="w-full rounded-md border border-border bg-background px-2 py-1.5 text-sm text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:opacity-50";function os(t){return t?`Dependency ${t}`:"Root agent"}function Ve(t){var n;const s=((n=t.agentPath)==null?void 0:n.split(" > ").map(r=>r.trim()).filter(Boolean))??[];return s.length===0?t.name:`${s.map(r=>`agents.${r}`).join(".")}.${t.name}`}function re(t){return`${t.agentPath??""}\0${t.name}\0${t.setupToken??""}`}function xt(t,s){const n={};for(const r of s)t[r]!==void 0&&(n[r]=t[r]);return n}function We(t){return t==null?"":typeof t=="string"?t:Array.isArray(t)?t.join(","):String(t)}function No(t,s){var r,a;const n=(r=t.enumLabels)==null?void 0:r[s];return n!==void 0&&n.trim()!==""?n:((a=t.enum)==null?void 0:a[s])??""}function ls({q:t,value:s,onChange:n,disabled:r=!1}){const a=t.required!==!1,o=`${t.prompt||t.name}${a?" *":""}`;return e.jsxs(le,{label:o,children:[t.type==="bool"?e.jsx("input",{type:"checkbox",checked:s==="true",onChange:i=>{r||n(i.target.checked?"true":"false")},disabled:r,"aria-label":o,className:"h-4 w-4 rounded border-border"}):t.type==="enum"?e.jsxs("select",{value:s,onChange:i=>{r||n(i.target.value)},disabled:r,"aria-label":o,className:Oe,children:[e.jsx("option",{value:"",disabled:!0,children:"Select…"}),(t.enum??[]).map((i,l)=>e.jsx("option",{value:i,children:No(t,l)},i))]}):e.jsx("input",{type:t.type==="secret"?"password":t.type==="int"?"number":"text",value:s,onChange:i=>{r||n(i.target.value)},disabled:r,"aria-label":o,placeholder:t.type==="resourceList"?"comma-separated":void 0,autoComplete:t.type==="secret"?"new-password":"off",className:Oe}),t.description&&e.jsx("p",{className:"text-[11px] text-muted-foreground",children:t.description})]})}function wo({apiBase:t,onInstalled:s}){const[n,r]=d.useState("file"),[a,o]=d.useState(null),[i,l]=d.useState(""),[c,u]=d.useState("default"),[h,N]=d.useState(""),[p,b]=d.useState({}),[x,j]=d.useState(null),[$,C]=d.useState([]),[E,m]=d.useState([]),[w,R]=d.useState([]),[O,L]=d.useState([]),[k,g]=d.useState([]),[T,P]=d.useState({}),[V,q]=d.useState({}),[ie,Ce]=d.useState({}),[Rt,Ne]=d.useState(null),[Ot,oe]=d.useState(null),[zs,Me]=d.useState(!1),[It,Ft]=d.useState(!1),qs=n==="file"?a!==null:i.trim()!=="",Mt=()=>{R([]),L([])},Gs=()=>{g([]),P({}),q({}),Ce({}),Ne(null)},we=()=>{Mt(),Gs()},Js=(f,A)=>{b(D=>({...D,[f]:A})),Mt();const S=new Set(Object.entries(V).filter(([,D])=>D==="staged").map(([D])=>D));g(D=>D.filter(K=>S.has(re(K)))),P(D=>xt(D,S)),q(D=>xt(D,S)),Ce(D=>xt(D,S)),Ne(null)},Pt=(f,A,S,D,K,B=!1)=>{f.length>0?j(f):B||j(null),R(A),g(S),C(D),m(K),b(H=>{const G={...H};for(const ne of f){const se=Ve(ne);G[se]===void 0&&ne.default!==void 0&&ne.default!==null&&(G[se]=We(ne.default))}return G}),P(H=>{const G={};for(const ne of S){const se=re(ne),ct={...H[se]??{}};for(const $e of ne.questions??[])ct[$e.name]===void 0&&$e.default!==void 0&&$e.default!==null&&(ct[$e.name]=We($e.default));G[se]=ct}return G}),q(H=>{const G={};for(const ne of S){const se=re(ne);G[se]=H[se]??"pending"}return G}),Ce(H=>{const G={};for(const ne of S){const se=re(ne);H[se]&&(G[se]=H[se])}return G})},Ys=(f,A,S)=>{const D=re(f);P(K=>({...K,[D]:{...K[D]??{},[A]:S}}))},Kt=(f,A)=>{const S=re(f);g(D=>D.map(K=>re(K)===S?{...K,questions:A}:K))},Qs=async f=>{const A=re(f);if(!f.setupToken){oe(`Channel ${f.name} has no setup token.`);return}oe(null),Ne(A);try{const S=await Ut(t,f.setupToken,T[A]??{});Ce(D=>({...D,[A]:{nextSteps:S.nextSteps??[],warnings:S.warnings??[]}})),q(D=>({...D,[A]:"staged"}))}catch(S){S instanceof ht?Kt(f,S.questions):S instanceof J&&S.status===403?Me(!0):oe(S.message)}finally{Ne(null)}},Xs=f=>{const A=Se(f.url);if(!A)return oe("Channel setup returned an unsafe handoff URL."),!1;if(!f.formFields||Object.keys(f.formFields).length===0)return window.open(A,"_blank","noopener,noreferrer"),!0;const S=document.createElement("form");S.method="POST",S.action=A,S.target="_blank",S.rel="noopener noreferrer";for(const[D,K]of Object.entries(f.formFields)){const B=document.createElement("input");B.type="hidden",B.name=D,B.value=K,S.appendChild(B)}document.body.appendChild(S);try{S.submit()}finally{S.remove()}return!0},Zs=async f=>{const A=re(f);if(!f.setupToken){oe(`Channel ${f.name} has no setup token.`);return}oe(null),Ne(A);try{const S=await tr(t,f.setupToken,T[A]??{});if(S.nextAction==="setup"){const D=await Ut(t,f.setupToken,T[A]??{});Ce(K=>({...K,[A]:{nextSteps:D.nextSteps??[],warnings:D.warnings??[]}})),q(K=>({...K,[A]:"staged"}));return}if(!S.url){oe("Channel setup returned no handoff URL or next action.");return}Xs({url:S.url,formFields:S.formFields})&&q(D=>({...D,[A]:"handoff-started"}))}catch(S){S instanceof ht?Kt(f,S.questions):S instanceof J&&S.status===403?Me(!0):oe(S.message)}finally{Ne(null)}},Bs=async()=>{oe(null),Me(!1),C([]),m([]),R([]),L([]),Ft(!0);try{const f=n==="file"?await nr(t,a,{namespace:c,name:h||void 0,values:p,adopt:O}):await sr(t,{ref:i.trim(),namespace:c,name:h||void 0,values:p,adopt:O}),A=k.flatMap(D=>{const K=ie[re(D)];return K?[...K.nextSteps,...K.warnings].map(B=>`${D.name}: ${B}`):[]}),S=A.length===0?f:{...f,warnings:[...f.warnings??[],...A]};j(null),g([]),s(S,c)}catch(f){f instanceof tt?Pt(f.questions,f.conflicts,f.channels,f.skillClones,f.warnings):f instanceof st?Pt(f.questions,f.conflicts,f.channels,f.skillClones,f.warnings,!0):f instanceof J&&f.status===403?Me(!0):oe(f.message)}finally{Ft(!1)}};return e.jsxs("div",{className:"flex flex-col gap-4",children:[zs&&e.jsx(I,{variant:"destructive",children:e.jsx(F,{children:"Not authorized to install agents."})}),Ot&&e.jsx(I,{variant:"destructive",children:e.jsx(F,{children:Ot})}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx(U,{type:"button",variant:n==="file"?"default":"outline",size:"sm",onClick:()=>{r("file"),we()},children:"Upload a .oap file"}),e.jsx(U,{type:"button",variant:n==="ref"?"default":"outline",size:"sm",onClick:()=>{r("ref"),we()},children:"Registry ref"})]}),n==="file"?e.jsx(le,{label:"Bundle file",children:e.jsx("input",{type:"file",accept:".oap","aria-label":"Bundle file",onChange:f=>{var A;o(((A=f.target.files)==null?void 0:A[0])??null),we()},className:"text-sm text-foreground"},"file-input")}):e.jsx(le,{label:"Registry ref",children:e.jsx("input",{type:"text",value:i,onChange:f=>{l(f.target.value),we()},placeholder:"ghcr.io/acme/support-bot:1.0.0","aria-label":"Registry ref",className:Oe},"ref-input")}),e.jsxs("div",{className:"grid grid-cols-1 gap-4 sm:grid-cols-2",children:[e.jsx(le,{label:"Namespace *",children:e.jsx("input",{type:"text",value:c,onChange:f=>{u(f.target.value),we()},"aria-label":"Namespace",className:Oe})}),e.jsx(le,{label:"Name (optional)",children:e.jsx("input",{type:"text",value:h,onChange:f=>{N(f.target.value),we()},placeholder:"defaults to the bundled agent's name","aria-label":"Name",className:Oe})})]}),$.length>0&&e.jsxs("div",{className:"flex flex-col gap-1 rounded-md border border-dashed border-border p-3",children:[e.jsxs("p",{className:"text-xs font-medium text-foreground",children:["Installing this agent will clone ",$.length===1?"an external repository":"external repositories",":"]}),e.jsx("ul",{className:"list-disc pl-5 text-xs text-muted-foreground",children:$.map(f=>e.jsxs("li",{children:[e.jsx("span",{className:"text-foreground",children:f.repoURL})," @ ",f.ref||"default branch"," (SkillSource ",f.skillSource,")"]},f.skillSource))})]}),E.length>0&&e.jsx(I,{children:e.jsx(F,{children:e.jsx("ul",{className:"list-disc pl-5 text-xs",children:E.map(f=>e.jsx("li",{children:f},f))})})}),w.length>0&&e.jsxs("div",{className:"flex flex-col gap-2 rounded-md border border-destructive/50 p-3",children:[e.jsx("p",{className:"text-xs font-medium text-foreground",children:"These objects already exist and were not created by this install. Adopting one overwrites its spec with this bundle's, and uninstalling the agent will delete it."}),w.map(f=>{const A=`${f.kind}/${f.name}`,S=f.namespace?`${f.kind} ${f.namespace}/${f.name}`:A;return e.jsxs("label",{className:"flex items-center gap-2 text-xs text-foreground",children:[e.jsx("input",{type:"checkbox",checked:O.includes(A),"aria-label":S,onChange:D=>L(K=>D.target.checked?[...K,A]:K.filter(B=>B!==A)),className:"h-4 w-4 rounded border-border"}),e.jsx("span",{children:S}),f.secret&&e.jsx("span",{className:"text-destructive",children:"overwrites this Secret's data"})]},A)})]}),x&&x.length>0&&e.jsxs("div",{className:"flex flex-col gap-3 rounded-md border border-dashed border-border p-3",children:[e.jsxs("p",{className:"text-xs text-muted-foreground",children:["This bundle needs ",x.length===1?"an answer":"answers"," before it can install:"]}),x.map(f=>e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx("p",{className:"text-[11px] font-medium text-muted-foreground",children:os(f.agentPath)}),e.jsx(ls,{q:f,value:p[Ve(f)]??We(f.default),onChange:A=>Js(Ve(f),A)})]},Ve(f)))]}),k.length>0&&e.jsxs("div",{className:"flex flex-col gap-3 rounded-md border border-dashed border-border p-3",children:[e.jsx("p",{className:"text-xs text-muted-foreground",children:"Complete the required channel setup before resuming the install:"}),k.map(f=>{var K,B;const A=re(f),S=V[A]??"pending",D=T[A]??{};return e.jsxs("div",{className:"flex flex-col gap-2 rounded-md border border-border p-3",children:[e.jsx("p",{className:"text-[11px] font-medium text-muted-foreground",children:os(f.agentPath)}),e.jsx("p",{className:"text-sm font-medium text-foreground",children:f.name}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:[f.kind," · ",f.role]}),f.purpose&&e.jsx("p",{className:"text-xs text-foreground",children:f.purpose}),f.reason&&e.jsx("p",{className:"text-xs text-destructive",children:f.reason}),f.remedy&&e.jsx("p",{className:"text-xs text-muted-foreground",children:f.remedy}),(f.questions??[]).map(H=>e.jsx(ls,{q:H,value:D[H.name]??We(H.default),onChange:G=>Ys(f,H.name,G),disabled:S==="staged"},H.name)),S==="staged"?e.jsxs("div",{className:"flex flex-col gap-1 text-xs",children:[e.jsx("p",{className:"text-success",children:"Setup staged"}),(((K=ie[A])==null?void 0:K.nextSteps)??[]).map(H=>e.jsx("p",{className:"text-foreground",children:H},`next-${H}`)),(((B=ie[A])==null?void 0:B.warnings)??[]).map(H=>e.jsx("p",{className:"text-warning",children:H},`warning-${H}`))]}):f.status==="handoff"&&S==="pending"?e.jsxs(U,{type:"button",size:"sm",className:"self-start",disabled:Rt===A,onClick:()=>void Zs(f),children:["Start browser setup for ",f.name]}):f.status==="ask"||S==="handoff-started"?e.jsx(U,{type:"button",size:"sm",className:"self-start",disabled:Rt===A,onClick:()=>void Qs(f),children:S==="handoff-started"?`Resume ${f.name}`:`Set up ${f.name}`}):e.jsx("p",{className:"text-xs text-destructive",children:"This channel cannot be set up from the browser."})]},A)})]}),e.jsx(U,{type:"button",onClick:Bs,disabled:!qs||It,className:"self-start",children:It?"Installing…":w.length>0&&O.length>0&&Object.values(V).includes("staged")?"Adopt and resume install":w.length>0&&O.length>0?"Adopt and install":Object.values(V).includes("staged")?"Resume install":x?"Submit answers":"Install"})]})}function Us({agents:t}){return e.jsx("ul",{className:"flex flex-col gap-2 pl-4 text-xs text-muted-foreground",children:t.map(s=>e.jsxs("li",{children:[e.jsx("p",{children:s.agentPath?`Dependency ${s.agentPath}`:"Dependency"}),e.jsx("p",{className:"font-mono text-foreground",children:s.name}),s.agents&&s.agents.length>0&&e.jsx(Us,{agents:s.agents})]},`${s.agentPath??""}/${s.name}`))})}function ko({result:t,namespace:s,onClose:n}){return e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsxs("p",{className:"text-sm text-success",children:["Installed ",e.jsx("span",{className:"font-mono",children:t.name})," — ",t.appliedKinds.join(", "),t.secretsCreated>0?`, ${t.secretsCreated} secret${t.secretsCreated===1?"":"s"} created`:"","."]}),t.adopted&&t.adopted.length>0&&e.jsxs("div",{className:"flex flex-col gap-1 rounded-md border border-warning/40 bg-warning/5 p-3",children:[e.jsxs("p",{className:"text-xs font-medium text-warning",children:["This install seized ",t.adopted.length," pre-existing object",t.adopted.length===1?"":"s"," ","not created by it — their specs were overwritten with this bundle's, and"," ",e.jsx("span",{className:"font-mono",children:"oap agent uninstall"})," will delete them."]}),e.jsx("ul",{className:"list-disc pl-4 text-xs text-muted-foreground",children:t.adopted.map(r=>e.jsx("li",{className:"font-mono",children:r},r))})]}),t.warnings&&t.warnings.length>0&&e.jsx("ul",{className:"list-disc pl-4 text-xs text-muted-foreground",children:t.warnings.map(r=>e.jsx("li",{children:r},r))}),t.agents&&t.agents.length>0&&e.jsxs("div",{className:"flex flex-col gap-1 rounded-md border border-border p-3",children:[e.jsx("p",{className:"text-xs font-medium text-foreground",children:"Installed dependencies"}),e.jsx(Us,{agents:t.agents})]}),e.jsxs(et,{children:[e.jsx(U,{variant:"outline",onClick:n,children:"Close"}),e.jsx(U,{onClick:()=>{n(),te({type:"detail",entity:"agent",id:`${s}/${t.name}`})},children:"View agent"})]})]})}function So({apiBase:t,onInstalled:s}){const[n,r]=d.useState(!1),[a,o]=d.useState(null),i=l=>{r(l),l&&o(null)};return e.jsxs(Je,{open:n,onOpenChange:i,children:[e.jsx(Ye,{asChild:!0,children:e.jsx(U,{variant:"outline",size:"sm",children:"Install agent"})}),e.jsxs(Qe,{className:"max-w-xl",children:[e.jsxs(Xe,{children:[e.jsx(Ze,{children:"Install an agent"}),e.jsx(Be,{children:"Upload a packaged .oap bundle or pull one from a registry ref."})]}),a?e.jsx(ko,{result:a.result,namespace:a.namespace,onClose:()=>r(!1)}):e.jsx(wo,{apiBase:t,onInstalled:(l,c)=>{o({result:l,namespace:c}),s==null||s()}})]})]})}function Co(t){return t==="Valid"||t==="Ready"}function is(t,s){var n,r;return((r=(n=t.counts)==null?void 0:n.find(a=>a.label===s))==null?void 0:r.value)??0}function $o(t){return t==="agent"?"bg-state":t==="userPassthrough"?"bg-success":"bg-muted-foreground/40"}function Vs({row:t,linked:s=!0}){const n=ye(t,"identityMode"),r=ye(t,"identityRef");return e.jsxs("span",{className:"inline-flex items-center gap-1.5",children:[e.jsx("span",{"aria-hidden":"true",title:n||void 0,className:`inline-block h-2 w-2 shrink-0 rounded-full ${$o(n)}`}),r&&s?e.jsx(W,{entity:"identity",id:t.namespace?`${t.namespace}/${r}`:r,className:"font-mono text-[11px] text-link hover:underline",onClick:a=>a.stopPropagation(),children:r}):e.jsx("span",{className:"font-mono text-[11px] text-muted-foreground",children:r||n||"—"})]})}const To=ce.agents.map(t=>t.header==="Identity"?{...t,render:s=>e.jsx(Vs,{row:s})}:t);function Lo({a:t}){const s=Co(t.status),n=is(t,"tools"),r=is(t,"skills");return e.jsxs(W,{entity:"agent",id:it(t),className:"block rounded-xl border bg-card p-4 shadow transition-colors hover:border-primary/40",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("span",{className:"font-mono text-sm font-medium text-foreground",children:t.name}),e.jsx("span",{title:t.statusReason||void 0,className:`inline-flex items-center rounded-full border px-2 py-0.5 text-[10px] ${s?"border-success/40 bg-success/10 text-success":"border-destructive/40 bg-destructive/10 text-destructive"}`,children:t.status||"Unknown"})]}),t.namespace&&e.jsx("p",{className:"mt-0.5 font-mono text-[10px] text-muted-foreground",children:t.namespace}),!s&&t.statusReason&&e.jsx("p",{className:"mt-2 text-xs text-destructive",children:t.statusReason}),e.jsx("div",{className:"mt-3 flex flex-wrap gap-1.5",children:e.jsx(Vs,{row:t,linked:!1})}),e.jsxs("p",{className:"mt-3 font-mono text-xs text-muted-foreground",children:[n," tool",n===1?"":"s"," · ",r," skill",r===1?"":"s"]})]})}function Ao({apiBase:t}){const[s,n]=d.useState([]),[r,a]=d.useState(null),[o,i]=d.useState(!1),[l,c]=$t("agents_view","grid"),u=d.useCallback(()=>{let p=!0;return Ct(t,"agents").then(b=>{p&&(n(b),a(null),i(!0))}).catch(b=>{p&&(a(b.message),i(!0))}),()=>{p=!1}},[t]);d.useEffect(()=>u(),[u]);const h="AgentClass — readiness gates sessions · managed via oap class / kubectl agentclass",N=()=>r?e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load agents: ",r]})}):o?s.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No AgentClasses configured yet."}):l==="grid"?e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"grid grid-cols-1 gap-3 sm:grid-cols-2 xl:grid-cols-3",children:s.map(p=>e.jsx(Lo,{a:p},it(p)))}),e.jsx("p",{className:"text-[11px] text-muted-foreground",children:h})]}):e.jsx(_s,{rows:s,columns:To,entity:"agent",statusCookieKey:"status_agents",note:h}):e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading agents…"});return e.jsxs("div",{className:"space-y-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx(So,{apiBase:t,onInstalled:u}),o&&!r&&s.length>0&&e.jsx($s,{value:l,onChange:c})]}),N()]})}function je({apiBase:t,resource:s,columns:n,entity:r,facet:a,mapRows:o,note:i,emptyText:l}){const[c,u]=d.useState([]),[h,N]=d.useState(null),[p,b]=d.useState(!1);d.useEffect(()=>{let j=!0;return Ct(t,s).then($=>{j&&(u($??[]),N(null),b(!0))}).catch($=>{j&&(N($.message),b(!0))}),()=>{j=!1}},[t,s]);const x=o?o(c):c;return e.jsxs("div",{className:"space-y-3",children:[h&&e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load ",s,": ",h]})}),!h&&e.jsx(_s,{rows:x,columns:n,entity:r,facet:a,statusCookieKey:`status_${s}`,loading:!p,note:i,emptyText:l})]})}function Eo({apiBase:t}){return e.jsx(je,{apiBase:t,resource:"tools",entity:"tool",columns:ce.tools,note:"MCPServer · SidecarToolbox · SpiceboxToolkit · SpiceboxToolspec — managed via oap tools / kubectl",emptyText:"No tools configured yet."})}function Do({apiBase:t}){return e.jsx(je,{apiBase:t,resource:"skills",entity:"skill",columns:ce.skills,note:"Skill · ClusterSkill — instruction & executable skills · managed via oap skill / kubectl get skills",emptyText:"No skills configured yet."})}const Ro=ce.sources.map(t=>t.key==="repo"?{...t,render:s=>{const n=ye(s,"repo");return n?Se(n)?e.jsx("a",{href:n,target:"_blank",rel:"noopener noreferrer nofollow",className:"whitespace-nowrap font-mono text-[11px] text-link hover:underline",onClick:r=>r.stopPropagation(),children:n}):e.jsx("code",{className:"whitespace-nowrap font-mono text-[11px] text-muted-foreground",children:n}):e.jsx("span",{className:"text-muted-foreground",children:"—"})}}:t);function Oo({apiBase:t}){return e.jsx(je,{apiBase:t,resource:"sources",entity:"source",columns:Ro,note:"SkillSource · ClusterSkillSource — synced from git · managed via oap skill source add",emptyText:"No skill sources configured yet."})}function Io({apiBase:t}){return e.jsx(je,{apiBase:t,resource:"directory",entity:"directory",columns:ce.directory,note:"RelationshipSource — Slack · GitHub · 1Password · managed via oap directory configure",emptyText:"No directory sources configured yet."})}function Fo(t){return ye(t,"role")==="monitoring"}function Mo({row:t}){const s=ye(t,"role");if(!s)return e.jsx("span",{className:"text-muted-foreground",children:"—"});const n=s==="monitoring";return e.jsx("span",{className:`rounded-full border px-2 py-0.5 text-[10px] font-mono ${n?"border-border bg-background text-muted-foreground":"border-primary/40 bg-primary/10 text-primary"}`,children:s})}function Po({row:t}){const s=ye(t,"agentClass");if(!s)return e.jsx("span",{className:"text-muted-foreground",children:"—"});const n=t.namespace?`${t.namespace}/${s}`:s;return e.jsx(W,{entity:"agent",id:n,className:"font-mono text-[11px] text-link hover:underline",children:s})}const Ko=ce.channels.map(t=>t.key==="role"?{...t,render:s=>e.jsx(Mo,{row:s})}:t.key==="agentClass"?{...t,render:s=>e.jsx(Po,{row:s})}:t);function _o(t){return t.map(s=>Fo(s)?{...s,status:"monitoring"}:s)}function Uo({apiBase:t}){return e.jsx(je,{apiBase:t,resource:"channels",entity:"channel",columns:Ko,mapRows:_o,note:"Channel — where agents are reachable · managed via oap channel / kubectl channel",emptyText:"No channels configured yet."})}const mt=[{id:"identities",label:"Agent identities",sub:"how agents authenticate to upstreams"},{id:"providers",label:"Login providers",sub:"human login for the admin UI & CLI"}];function Vo({apiBase:t}){const[s,n]=d.useState("identities"),r=mt.find(a=>a.id===s)??mt[0];return e.jsxs("div",{className:"space-y-3",children:[e.jsx("div",{role:"tablist",className:"inline-flex h-9 items-center gap-1 rounded-lg bg-muted p-1 text-muted-foreground",children:mt.map(a=>{const o=s===a.id;return e.jsx("button",{type:"button",role:"tab","aria-selected":o,onClick:()=>n(a.id),className:["inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium transition-all",o?"bg-background text-foreground shadow":"hover:text-foreground"].join(" "),children:a.label},a.id)})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:r.sub}),s==="identities"?e.jsx(je,{apiBase:t,resource:"identities",entity:"identity",columns:ce.identities,facet:{key:"cred",label:"Type"},note:"AgentIdentity — managed via oap identity · setup flows: github_pat, oauth_mcp, federated (ID-JAG)",emptyText:"No agent identities configured yet."}):e.jsx(je,{apiBase:t,resource:"providers",entity:"provider",columns:ce.providers,note:"ClusterIdentityProvider — managed via oap idp",emptyText:"No login providers configured yet."})]})}const Wo=ce.users.map(t=>t.key==="subject"?{...t,render:s=>{const n=ye(s,"subject");return n?e.jsx(yt,{children:ae(n)}):e.jsx("span",{className:"text-muted-foreground",children:"—"})}}:t);function Ho({apiBase:t}){return e.jsx(je,{apiBase:t,resource:"users",entity:"user",columns:Wo,note:"UserIdentity — people linked to the platform · managed via oap user-identity",emptyText:"No users linked yet."})}function cs({label:t,value:s,sub:n}){return e.jsxs("div",{className:"rounded-xl border bg-card p-4 shadow",children:[e.jsx("div",{className:"text-[11px] text-muted-foreground",children:t}),e.jsx("div",{className:"mt-1 text-2xl font-semibold",children:s}),e.jsx("div",{className:"text-[11px] text-muted-foreground",children:n})]})}function zo({apiBase:t}){const[s,n]=d.useState(null),[r,a]=d.useState(null);if(d.useEffect(()=>{let i=!0;return mr(t).then(l=>{i&&(n(l),a(null))}).catch(l=>{i&&a(l.message)}),()=>{i=!1}},[t]),r)return e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load access: ",r]})});if(!s)return e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading access…"});const o=s.stats.available;return e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsxs("div",{className:"mb-2 text-xs font-semibold text-muted-foreground",children:["Platform admins ",e.jsx("span",{className:"font-normal",children:"· who can reach this admin UI (platform:platform#admin)"})]}),s.admins.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No platform admins granted yet."}):e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{children:"Subject"}),e.jsx(y,{children:"Kind"})]})}),e.jsx(X,{children:s.admins.map(i=>e.jsxs(M,{children:[e.jsx(v,{className:"font-mono text-xs text-foreground",title:i.subject,children:ae(i.subject)}),e.jsx(v,{children:e.jsxs("span",{className:"inline-flex items-center gap-1.5 text-xs text-muted-foreground",children:[i.kind==="group"?e.jsx(ms,{className:"h-3.5 w-3.5"}):e.jsx(Jn,{className:"h-3.5 w-3.5"}),i.kind]})})]},i.subject))})]})]}),e.jsxs("div",{className:"space-y-1.5",children:[e.jsx(lt,{text:s.grantCmd}),e.jsx("p",{className:"text-[11px] text-muted-foreground",children:"Run via the CLI — the admin UI is read-only. Also: oap platform revoke-admin / list-admins."})]}),o?e.jsxs("div",{className:"grid grid-cols-1 gap-4 md:grid-cols-2",children:[e.jsx(cs,{label:"SpiceDB schema",value:s.stats.schemaDefs!=null?`${s.stats.schemaDefs}`:"—",sub:"definitions"}),e.jsx(cs,{label:"Relationships",value:s.stats.relationships!=null?s.stats.relationships.toLocaleString():"—",sub:"stored tuples"})]}):e.jsxs("div",{className:"rounded-xl border border-dashed bg-card p-4 shadow",children:[e.jsx("div",{className:"text-[11px] text-muted-foreground",children:"SpiceDB stats"}),e.jsx("div",{className:"mt-1 text-sm text-muted-foreground",children:"Stats unavailable — schema-definition & relationship counts aren't exposed through the permissions API in v1. Wiring a live source is a follow-up."})]}),e.jsx("p",{className:"text-[11px] text-muted-foreground",children:"Authorization primitive — schema composed by the operator · oap spicedb apply-schema / oap spicedb check"})]})}const ds=["Limits","Defaults"];function qo(t){const s=new Map;for(const r of t){const a=s.get(r.group)??[];a.push(r),s.set(r.group,a)}return[...s.keys()].sort((r,a)=>{const o=ds.indexOf(r),i=ds.indexOf(a);return o===-1&&i===-1?0:o===-1?1:i===-1?-1:o-i}).flatMap(r=>s.get(r).map((a,o)=>({row:a,group:o===0?r:void 0})))}function Go({apiBase:t}){const[s,n]=d.useState(null),[r,a]=d.useState(null);if(d.useEffect(()=>{let i=!0;return jr(t).then(l=>{i&&(n(l),a(null))}).catch(l=>{i&&a(l.message)}),()=>{i=!1}},[t]),r)return e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load settings: ",r]})});if(!s)return e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading settings…"});const o=qo(s.rows);return e.jsxs("div",{className:"space-y-4",children:[s.rows.length===0?e.jsx("div",{className:"rounded-xl border border-dashed bg-card p-4 shadow",children:e.jsx("p",{className:"text-sm text-muted-foreground",children:s.note||"No ClusterAgentSettings configured — cluster governance uses built-in defaults."})}):e.jsx("div",{className:"rounded-xl border bg-card shadow",children:e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{className:"w-28",children:"Group"}),e.jsx(y,{children:"Setting"}),e.jsx(y,{children:"Value"}),e.jsx(y,{children:"Note"})]})}),e.jsx(X,{children:o.map(({row:i,group:l},c)=>e.jsxs(M,{children:[e.jsx(v,{className:"align-top text-xs font-semibold text-muted-foreground",children:l??""}),e.jsx(v,{className:"align-top text-xs text-muted-foreground",children:i.label}),e.jsx(v,{className:"align-top font-mono text-xs text-foreground",children:i.value}),e.jsx(v,{className:"align-top text-[11px] text-muted-foreground",children:i.note??""})]},`${i.group}-${i.label}-${c}`))})]})}),e.jsx(lt,{text:s.manageCmd}),e.jsxs("p",{className:"text-[11px] text-muted-foreground",children:["ClusterAgentSettings (singleton ",e.jsx("span",{className:"font-mono",children:"cluster"}),") → namespace AgentSettings → AgentClass → session. Edit via the CLI — the admin UI is read-only."]})]})}const Jo=["oap agent pull "];function Yo(t){return Jo.some(s=>t.startsWith(s))}const Qo=new Set(["kind","channel kind","credential kind","credential type"]);function Xo(t){return Qo.has(t.trim().toLowerCase())}function Ws({section:t}){switch(t.kind){case"text":return e.jsx(el,{text:t.text??""});case"list":return e.jsx(tl,{items:t.items??[],notice:t.text});case"fields":default:return e.jsx(Bo,{fields:t.fields??[]})}}function Hs({entity:t,id:s,children:n}){return Ns(t)?e.jsx(W,{entity:t,id:s,className:"font-mono text-xs text-link hover:underline",children:n}):e.jsx(e.Fragment,{children:n})}function Nt({href:t,children:s}){return e.jsx("a",{href:t,target:"_blank",rel:"noopener noreferrer nofollow",className:"break-words font-mono text-xs text-link hover:underline",children:s})}function Zo({field:t}){if(t.link)return e.jsx(Hs,{entity:t.link.entity,id:t.link.id,children:t.value});if(t.href){const n=Se(t.href);if(n)return e.jsx(Nt,{href:n,children:t.value})}if(t.value&&Xo(t.label))return e.jsx(rt,{kind:t.value});if(Yo(t.value))return e.jsx(lt,{text:t.value});const s=Se(t.value);return s?e.jsx(Nt,{href:s,children:t.value}):e.jsx("span",{className:"break-words",children:t.value})}function Bo({fields:t}){return t.length===0?e.jsx(Dt,{}):e.jsx("div",{className:"flex flex-col gap-4",children:t.map((s,n)=>e.jsx(le,{label:s.label,children:e.jsx(Zo,{field:s})},`${s.label}-${n}`))})}function el({text:t}){return t===""?e.jsx(Dt,{}):e.jsx("pre",{className:"whitespace-pre-wrap break-words rounded-md border border-border bg-card p-4 font-mono text-xs text-foreground",children:t})}function tl({items:t,notice:s}){const n=s?e.jsx(I,{variant:"destructive",className:"mb-3",children:e.jsx(F,{children:s})}):null;return t.length===0?e.jsxs(e.Fragment,{children:[n,!s&&e.jsx(Dt,{})]}):e.jsxs(e.Fragment,{children:[n,e.jsx("ul",{className:"flex flex-col gap-2",children:t.map((r,a)=>e.jsxs("li",{className:"rounded-md border border-border bg-card p-3",children:[e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx(sl,{item:r}),e.jsx(nl,{badges:r.badges})]}),r.subtitle&&e.jsx("p",{className:"mt-1 text-[11px] text-muted-foreground",children:r.subtitle})]},`${r.title}-${a}`))})]})}function sl({item:t}){if(t.link)return e.jsx(Hs,{entity:t.link.entity,id:t.link.id,children:t.title});if(t.href){const s=Se(t.href);if(s)return e.jsx(Nt,{href:s,children:t.title})}return e.jsx("span",{className:"font-mono text-xs text-foreground",children:t.title})}function nl({badges:t}){const s=t??[];return s.length===0?null:e.jsx("span",{className:"flex flex-wrap gap-1",children:s.map((n,r)=>e.jsx(rt,{kind:n.value},`${n.key}-${n.value}-${r}`))})}function Dt(){return e.jsx("p",{className:"text-sm text-muted-foreground",children:"Nothing here."})}const us={detail:null,loading:!0,error:null,notFound:!1};function rl(t,s,n){const[r,a]=d.useState(us);return d.useEffect(()=>{let o=!0;return a(us),(async()=>{if(!n.includes("/")){const c=(await Ct(t,s)).find(u=>u.name===n);if(c)return Vt(t,s,it(c))}return Vt(t,s,n)})().then(l=>{o&&a({detail:l,loading:!1,error:null,notFound:!1})}).catch(l=>{o&&(l instanceof J&&l.status===404?a({detail:null,loading:!1,error:null,notFound:!0}):a({detail:null,loading:!1,error:l.message,notFound:!1}))}),()=>{o=!1}},[t,s,n]),r}function xs({detail:t,section:s}){return e.jsxs("div",{className:"flex flex-col gap-5",children:[t.description&&e.jsx("p",{className:"text-base text-foreground",children:t.description}),e.jsx(jo,{status:t.status,reason:t.statusReason}),e.jsxs("div",{className:"flex flex-wrap gap-8",children:[e.jsx(le,{label:"Status",children:e.jsx(Ks,{status:t.status,reason:t.statusReason})}),e.jsx(le,{label:"Scope",children:e.jsx("span",{className:"text-sm capitalize text-foreground",children:t.scope})}),t.namespace&&e.jsx(le,{label:"Namespace",children:e.jsx("span",{className:"font-mono text-xs text-foreground",children:t.namespace})})]}),s&&e.jsx(Ws,{section:s}),t.manageCmd&&e.jsx(le,{label:"Manage",children:e.jsx(lt,{text:t.manageCmd})})]})}function de({apiBase:t,resource:s,entity:n,id:r,tab:a,backRoute:o,extraTabs:i=[],subtitle:l}){var O;const{detail:c,loading:u,error:h,notFound:N}=rl(t,s,r),p=new Set(["overview",...i.map(L=>L.id)]),b=(O=c==null?void 0:c.sections)==null?void 0:O.find(L=>L.id==="overview"),x=((c==null?void 0:c.sections)??[]).filter(L=>!p.has(L.id)),j=[{id:"overview",label:"Overview"},...i.map(L=>({id:L.id,label:L.label})),...x.map(L=>({id:L.id,label:L.label}))],$=new Set(j.map(L=>L.id)),C=a&&$.has(a)?a:"overview",E=L=>te({type:"detail",entity:n,id:r,tab:L}),m=c?e.jsx(Z,{ns:c.namespace,name:c.name}):e.jsx(Z,{id:r}),w=c&&l?l(c):void 0,R=()=>{if(u)return e.jsx("p",{className:"text-sm text-muted-foreground",children:"Loading…"});if(h)return e.jsx(I,{variant:"destructive",children:e.jsxs(F,{children:["Could not load ",s,": ",h]})});if(N||!c)return e.jsxs("p",{className:"text-sm text-muted-foreground",children:["Not found: ",r]});if(C==="overview")return e.jsx(xs,{detail:c,section:b});const L=i.find(g=>g.id===C);if(L)return L.render(c);const k=x.find(g=>g.id===C);return k?e.jsx(Ws,{section:k}):e.jsx(xs,{detail:c,section:b})};return e.jsx(nt,{title:m,subtitle:w,backRoute:o,tabs:j,activeTab:C,onTab:E,headerRight:c?e.jsx(Ks,{status:c.status,reason:c.statusReason}):void 0,children:R()})}function al({apiBase:t,agentClass:s}){const[n,r]=d.useState(null),[a,o]=d.useState(null);if(d.useEffect(()=>{let l=!0;return _(`${t}/sessions`).then(c=>{l&&(r(c),o(null))}).catch(c=>{l&&o(c.message)}),()=>{l=!1}},[t]),a)return e.jsxs("p",{className:"text-xs text-destructive",children:["Could not load sessions: ",a]});if(n===null)return e.jsx("p",{className:"text-xs text-muted-foreground",children:"Loading sessions…"});const i=n.filter(l=>l.class===s);return i.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"No live sessions for this agent."}):e.jsxs(Y,{children:[e.jsx(Q,{children:e.jsxs(M,{children:[e.jsx(y,{children:"Session"}),e.jsx(y,{children:"Phase"}),e.jsx(y,{children:"Started"})]})}),e.jsx(X,{children:i.map(l=>e.jsxs(M,{children:[e.jsx(v,{className:"font-mono text-xs",children:e.jsx(W,{entity:"session",id:`${l.namespace}/${l.name}`,className:"text-link hover:underline",children:e.jsx(Z,{ns:l.namespace,name:l.name})})}),e.jsx(v,{children:e.jsx(At,{phase:l.phase})}),e.jsx(v,{className:"whitespace-nowrap text-xs text-muted-foreground",children:Lt(l.startedAt)})]},`${l.namespace}/${l.name}`))})]})}function ol({apiBase:t,id:s,tab:n}){return e.jsx(de,{apiBase:t,resource:"agents",entity:"agent",id:s,tab:n,backRoute:{type:"view",view:"agents"},extraTabs:[{id:"sessions",label:"Sessions",render:r=>e.jsx(al,{apiBase:t,agentClass:r.name})}]})}function ll({apiBase:t,id:s,tab:n}){return e.jsx(de,{apiBase:t,resource:"tools",entity:"tool",id:s,tab:n,backRoute:{type:"view",view:"tools"}})}function il({apiBase:t,id:s,tab:n}){return e.jsx(de,{apiBase:t,resource:"skills",entity:"skill",id:s,tab:n,backRoute:{type:"view",view:"skills"}})}function cl({apiBase:t,id:s,tab:n}){return e.jsx(de,{apiBase:t,resource:"sources",entity:"source",id:s,tab:n,backRoute:{type:"view",view:"sources"}})}function dl({apiBase:t,id:s,tab:n}){return e.jsx(de,{apiBase:t,resource:"directory",entity:"directory",id:s,tab:n,backRoute:{type:"view",view:"directory"}})}function ul({apiBase:t,id:s,tab:n}){return e.jsx(de,{apiBase:t,resource:"channels",entity:"channel",id:s,tab:n,backRoute:{type:"view",view:"channels"}})}function xl({apiBase:t,id:s,tab:n}){return e.jsx(de,{apiBase:t,resource:"identities",entity:"identity",id:s,tab:n,backRoute:{type:"view",view:"identity"}})}function ml({apiBase:t,id:s,tab:n}){return e.jsx(de,{apiBase:t,resource:"providers",entity:"provider",id:s,tab:n,backRoute:{type:"view",view:"identity"}})}function hl({apiBase:t,id:s,tab:n}){return e.jsx(de,{apiBase:t,resource:"users",entity:"user",id:s,tab:n,backRoute:{type:"view",view:"users"},subtitle:r=>ae(r.description??"")})}fn();function fl({apiBase:t,currentUser:s}){const n=ks(),[r,a]=d.useState({});function o(u){a(u),te({type:"view",view:"logs"})}const i=Kr(n),l=n.type==="detail"?pl(n,t):c(n.view);function c(u){switch(u){case"overview":return e.jsx(ho,{apiBase:t});case"sessions":return e.jsx(ta,{apiBase:t});case"toolcalls":return e.jsx(ra,{apiBase:t});case"approvals":return e.jsx(ia,{apiBase:t,onOpenSession:(h,N)=>te({type:"detail",entity:"session",id:`${h}/${N}`})});case"workshops":return e.jsx(ma,{apiBase:t});case"logs":return e.jsx(Ka,{apiBase:t,initialFilter:r},JSON.stringify(r));case"sessionsAudit":return e.jsx(Ha,{apiBase:t,axis:"sessions",onDrill:o});case"budget":return e.jsx(ao,{apiBase:t});case"artifacts":return e.jsx(Qa,{apiBase:t,onDrill:o});case"memory":return e.jsx(oo,{apiBase:t});case"knowledge":return e.jsx(lo,{apiBase:t});case"agents":return e.jsx(Ao,{apiBase:t});case"tools":return e.jsx(Eo,{apiBase:t});case"skills":return e.jsx(Do,{apiBase:t});case"sources":return e.jsx(Oo,{apiBase:t});case"directory":return e.jsx(Io,{apiBase:t});case"channels":return e.jsx(Uo,{apiBase:t});case"identity":return e.jsx(Vo,{apiBase:t});case"users":return e.jsx(Ho,{apiBase:t});case"access":return e.jsx(zo,{apiBase:t});case"settings":return e.jsx(Go,{apiBase:t});default:return e.jsx(Or,{view:u})}}return e.jsx(Rr,{view:i,onNavigate:u=>te({type:"view",view:u}),currentUser:s,apiBase:t,children:l})}function pl(t,s){const{entity:n,id:r,tab:a}=t;switch(n){case"session":return e.jsx(wa,{apiBase:s,id:r,tab:a});case"agent":return e.jsx(ol,{apiBase:s,id:r,tab:a});case"tool":return e.jsx(ll,{apiBase:s,id:r,tab:a});case"skill":return e.jsx(il,{apiBase:s,id:r,tab:a});case"source":return e.jsx(cl,{apiBase:s,id:r,tab:a});case"directory":return e.jsx(dl,{apiBase:s,id:r,tab:a});case"channel":return e.jsx(ul,{apiBase:s,id:r,tab:a});case"identity":return e.jsx(xl,{apiBase:s,id:r,tab:a});case"provider":return e.jsx(ml,{apiBase:s,id:r,tab:a});case"user":return e.jsx(hl,{apiBase:s,id:r,tab:a});case"artifact":return e.jsx(eo,{apiBase:s,id:r,tab:a});default:return e.jsx(gl,{route:t})}}function gl({route:t}){const s=t.tab??"overview";return e.jsx(nt,{title:`${t.entity} ${t.id}`,subtitle:"Detail page lands in a later batch",tabs:[{id:"overview",label:"Overview"}],activeTab:s,onTab:n=>te({type:"detail",entity:t.entity,id:t.id,tab:n}),children:e.jsx("p",{className:"text-sm text-muted-foreground",children:"Detail page lands in a later batch."})})}pn(fl); diff --git a/pkg/web/webui/webassets/dist/artifact-view.D4Y_FHws.js b/pkg/web/webui/webassets/dist/artifact-view.BNqAlmdu.js similarity index 99% rename from pkg/web/webui/webassets/dist/artifact-view.D4Y_FHws.js rename to pkg/web/webui/webassets/dist/artifact-view.BNqAlmdu.js index 425a6b61..8614e552 100644 --- a/pkg/web/webui/webassets/dist/artifact-view.D4Y_FHws.js +++ b/pkg/web/webui/webassets/dist/artifact-view.BNqAlmdu.js @@ -1 +1 @@ -import{c as k,I as z,J as B,K as F,H as Z,B as T,A as ee,G as te,a as ne,m as se}from"./mount.BOEH1oNx.js";import{r as o,j as t,v as re,w as ae,x as ie,y as E,z as oe,E as P,I as ce,X as le}from"./vendor.C5MRNvUt.js";import{M as de}from"./markdown.FOTo-3Mz.js";function ue(e,n){return{kind:"annotation_batch",artifactId:n,payload:{annotations:e.annotations}}}function fe(e){try{const n=JSON.parse(e);return!n||typeof n.type!="string"?null:n}catch{return null}}function he(e){return`${e.protocol==="https:"?"wss:":"ws:"}//${e.host}/artifact-view/ws${e.search}`}const N=3;function xe(e,n){const[i,l]=o.useState("connecting"),f=o.useRef(e);f.current=e;const r=o.useRef(n);return r.current=n,o.useEffect(()=>{let c=null,x,g=!1,m=0;const h=()=>{var d;g||(m+=1,l(m>=N?"offline":"reconnecting"),m===N&&((d=r.current)==null||d.call(r)),x=window.setTimeout(b,2e3))},b=()=>{if(!g){l(m===0?"connecting":m>=N?"offline":"reconnecting");try{c=new WebSocket(he(window.location))}catch{h();return}c.onopen=()=>{m=0,l("connected")},c.onmessage=d=>{const v=fe(d.data);v&&f.current(v)},c.onerror=()=>{g||l(m>=N?"offline":"reconnecting")},c.onclose=h}};return b(),()=>{g=!0,x&&window.clearTimeout(x),c&&c.close()}},[]),{state:i}}function me(e,n){function i(l){var r;if(!!!e.getAttribute("src")){l.hostUrl&&e.setAttribute("src",l.hostUrl);return}if(l.contentUrl)try{(r=e.contentWindow)==null||r.postMessage({ap:"host",cmd:"swap",url:l.contentUrl},n)}catch{}}return{showRevision:i}}function ge(e,n){const i=o.useRef(null);return o.useEffect(()=>{e.current&&(i.current=me(e.current,n))},[e,n]),o.useCallback(l=>{var f;return(f=i.current)==null?void 0:f.showRevision(l)},[])}function we(e,n){if(!e)return"Working";switch(n){case"awaiting_approval":case"awaiting_leakage_approval":return"Awaiting approval";case"awaiting_reply":case"idle":return"Awaiting your reply";case"awaiting_retry":return"Retrying…";case"failed":return"Failed";case"complete":return"Done";default:return"Paused"}}function pe(e){return e==="done"?"✓":e==="error"?"✕":e==="in_progress"?"▸":"○"}function be(e){return e.find(n=>n.status==="in_progress")??e.find(n=>n.status!=="done"&&n.status!=="error")??null}function ve({status:e}){if(!e)return null;const n=!!e.paused,i=e.pauseCause||"",l=Array.isArray(e.plan)?e.plan:[],f=be(l),r=i==="failed",c=i==="complete",x=r?"bg-destructive":c?"bg-success":n?"bg-warning":"bg-success",g=r?"text-destructive":c?"text-success":n?"text-warning":"text-success",m=!n;return t.jsxs("div",{className:"flex flex-1 min-w-0 items-center gap-[9px] text-xs",children:[t.jsx("span",{className:k("h-[9px] w-[9px] rounded-full shrink-0",x,m&&"animate-ap-pulse-dot")}),t.jsx("span",{className:k("text-xs font-semibold shrink-0",g),children:we(n,i)}),e.statusMessage&&t.jsx("span",{className:"text-[13px] text-foreground truncate min-w-0",children:e.statusMessage}),l.length>0&&f&&t.jsxs("span",{className:"relative group min-w-0 truncate shrink-0",tabIndex:0,children:[t.jsx("span",{className:"text-[11px] text-muted-foreground before:content-['·_']",children:f.label||""}),l.length>1&&t.jsx("div",{"aria-hidden":"true",className:"hidden group-hover:block group-focus-within:block absolute top-[calc(100%+4px)] left-0 z-20 bg-card border border-border rounded-md p-2 min-w-[240px] max-w-[420px] shadow-xl whitespace-normal",children:l.map((h,b)=>t.jsxs("div",{className:"flex gap-2 px-1 py-0.5 leading-snug items-baseline",children:[t.jsx("span",{className:k("w-3 text-center shrink-0",h.status==="in_progress"&&"text-primary",h.status==="done"&&"text-success",h.status==="error"&&"text-destructive",(h.status==="pending"||!h.status)&&"text-muted-foreground"),children:pe(h.status)}),t.jsx("span",{children:h.label||""})]},b))})]})]})}function je({className:e}){return t.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",className:e,"aria-hidden":"true",children:[t.jsx("path",{fill:"#E01E5A",d:"M5.6 14.5a2.3 2.3 0 1 1-2.3-2.3h2.3z"}),t.jsx("path",{fill:"#E01E5A",d:"M6.8 14.5a2.3 2.3 0 0 1 4.6 0v5.7a2.3 2.3 0 1 1-4.6 0z"}),t.jsx("path",{fill:"#36C5F0",d:"M9.5 5.6a2.3 2.3 0 1 1 2.3-2.3v2.3z"}),t.jsx("path",{fill:"#36C5F0",d:"M9.5 6.8a2.3 2.3 0 0 1 0 4.6H3.8a2.3 2.3 0 1 1 0-4.6z"}),t.jsx("path",{fill:"#2EB67D",d:"M18.4 9.5a2.3 2.3 0 1 1 2.3 2.3h-2.3z"}),t.jsx("path",{fill:"#2EB67D",d:"M17.2 9.5a2.3 2.3 0 0 1-4.6 0V3.8a2.3 2.3 0 1 1 4.6 0z"}),t.jsx("path",{fill:"#ECB22E",d:"M14.5 18.4a2.3 2.3 0 1 1-2.3 2.3v-2.3z"}),t.jsx("path",{fill:"#ECB22E",d:"M14.5 17.2a2.3 2.3 0 0 1 0-4.6h5.7a2.3 2.3 0 1 1 0 4.6z"})]})}function ye({kind:e,className:n}){return e==="slack"?t.jsx(je,{className:n}):t.jsx(re,{className:n,"aria-hidden":"true"})}function Ne({href:e,channelKind:n}){if(!e)return null;const i=n==="slack"?"Open the Slack thread":"Open the thread";return t.jsxs(z,{children:[t.jsx(B,{asChild:!0,children:t.jsxs("a",{href:e,target:"_blank",rel:"noreferrer",className:"group flex items-center gap-[3px] rounded-md px-[7px] py-[5px] text-inherit no-underline hover:bg-muted",children:[t.jsx(ye,{kind:n,className:"h-4 w-4"}),t.jsx(ae,{className:"h-[11px] w-[11px] text-muted-foreground/70 group-hover:text-muted-foreground","aria-hidden":"true"})]})}),t.jsx(F,{children:i})]})}const ke={connected:{Icon:oe,color:"text-success",spin:!1,tip:"Live — connected"},connecting:{Icon:E,color:"text-warning",spin:!0,tip:"Connecting…"},reconnecting:{Icon:E,color:"text-warning",spin:!0,tip:"Reconnecting…"},offline:{Icon:ie,color:"text-destructive",spin:!1,tip:"Offline — retrying"}};function Se({state:e}){const n=ke[e],{Icon:i}=n;return t.jsxs(z,{children:[t.jsx(B,{asChild:!0,children:t.jsx("div",{className:`flex h-7 w-7 items-center justify-center rounded-md cursor-default ${n.color}`,children:t.jsx(i,{className:`h-[18px] w-[18px] ${n.spin?"animate-spin":""}`,"aria-hidden":"true"})})}),t.jsx(F,{children:n.tip})]})}function Ce({revisions:e,currentRevId:n,onSelect:i,downloadHref:l}){const f=[...e].reverse();return t.jsx("ul",{className:"list-none m-0 p-1.5",children:f.map(r=>{const c=r.revisionId&&r.revisionId===n;return t.jsxs("li",{onClick:()=>r.revisionId&&i(r.revisionId),className:k("relative px-2.5 py-2 rounded-md cursor-pointer border border-transparent text-xs leading-snug hover:bg-muted",c&&"bg-muted border-border"),children:[l&&r.revisionId&&t.jsx("a",{href:l(r.revisionId),download:!0,onClick:x=>x.stopPropagation(),"aria-label":`Download revision ${r.seq??""}`.trim(),title:"Download this revision",className:"absolute bottom-1.5 right-1.5 flex h-5 w-5 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-accent-foreground",children:t.jsx(P,{className:"h-3 w-3","aria-hidden":"true"})}),t.jsxs("span",{className:"font-semibold text-primary",children:["#",r.seq??"?",Array.isArray(r.tags)&&r.tags.includes("latest")&&t.jsx("span",{className:"ml-1.5 text-[10px] px-1.5 rounded-lg bg-success/20 text-success align-middle",children:"latest"})]}),t.jsx("span",{className:"block text-foreground my-0.5",children:r.changeDescription||"(no description)"}),r.createdAt&&t.jsx("span",{className:"block text-muted-foreground text-[11px]",children:r.createdAt})]},r.revisionId||r.seq)})})}function Ie(e){const[n,i]=o.useState(""),[l,f]=o.useState(!1),r=async()=>{const c=n.trim();if(!(!c||l)){f(!0);try{await e.onSend(c),i("")}finally{f(!1)}}};return t.jsxs("div",{className:"flex flex-col h-full border-l border-border bg-card",children:[t.jsx("div",{className:"flex-1 overflow-y-auto p-3 space-y-2",children:e.messages.map((c,x)=>t.jsx("div",{className:`flex ${c.role==="user"?"justify-end":"justify-start"}`,children:t.jsx("div",{className:`inline-block max-w-[85%] rounded-lg px-3 py-1.5 text-sm text-left ${c.role==="user"?"bg-primary text-primary-foreground":"bg-muted text-foreground"}`,children:t.jsx(de,{children:c.text})})},x))}),e.canCompose&&t.jsxs("div",{className:"flex gap-2 p-2 border-t border-border",children:[t.jsx("input",{className:"flex-1 rounded border border-border bg-background px-2 py-1 text-sm",value:n,onChange:c=>i(c.target.value),onKeyDown:c=>{c.key==="Enter"&&r()},placeholder:"Message the agent…",disabled:l}),t.jsx("button",{className:"rounded bg-primary px-3 text-sm text-primary-foreground disabled:opacity-50",onClick:()=>void r(),disabled:l,children:"Send"})]})]})}const L=200;function Re(e,n){const i=e.concat(n);return i.length>L?i.slice(i.length-L):i}function Ee(e){return{role:e.role==="user"?"user":"agent",text:e.text,author:e.author,at:e.at}}const A="ap_artifact_reauth_at",U="ap_artifact_pending_rev";function Ue(){const e=Number(window.sessionStorage.getItem(A)||"0");return Number.isFinite(e)&&Date.now()-e<15e3}function O(e){return Ue()?!1:(window.sessionStorage.setItem(A,String(Date.now())),e&&window.sessionStorage.setItem(U,e),window.location.reload(),!0)}function Ae(e){const n=o.useRef(null),i=ge(n,e.sandboxOrigin),[l,f]=o.useState(!1),[r,c]=o.useState(!1),x=o.useRef(!1);x.current=r;const[g,m]=o.useState([]),[h,b]=o.useState(null),[d,v]=o.useState(null),[S,W]=o.useState(null),[q,C]=o.useState(!!e.hostUrl),[j,_]=o.useState(null),[H,K]=o.useState([]),[M,y]=o.useState(null),$=o.useRef(null);$.current=d;const J=o.useCallback(s=>{var a,u;if(s.type==="status"){s.status&&W(s.status);return}if(s.type==="message"){s.message&&K(w=>Re(w,Ee(s.message)));return}v(s),Array.isArray(s.revisions)&&m(s.revisions),!x.current&&((a=s.current)!=null&&a.hostUrl||(u=s.current)!=null&&u.contentUrl)&&(i({hostUrl:s.current.hostUrl,contentUrl:s.current.contentUrl}),b(s.current.revisionId||null),C(!0))},[i]),G=o.useCallback(()=>{var a,u;const s=(u=(a=$.current)==null?void 0:a.current)==null?void 0:u.revisionId;s&&fetch(`/artifact-view/revision${window.location.search}&rev=${encodeURIComponent(s)}`).then(w=>{w.status===401&&O()}).catch(()=>{})},[]),{state:V}=xe(J,G),X=!!S&&!S.paused,I=o.useCallback(s=>{c(!0),fetch(`/artifact-view/revision${window.location.search}&rev=${encodeURIComponent(s)}`).then(a=>{if(a.status===401)return O(s),null;if(!a.ok)throw new Error(`revision fetch failed: ${a.status}`);return a.json()}).then(a=>{a&&(window.sessionStorage.removeItem(A),(a.hostUrl||a.contentUrl)&&(i({hostUrl:a.hostUrl,contentUrl:a.contentUrl}),b(s),C(!0)))}).catch(a=>{window.console&&console.warn("view-older failed",a)})},[i]),D=o.useCallback(s=>{const a=new URLSearchParams({artifactId:e.artifactId,sessionRef:`${e.ns}/${e.name}`});return s&&a.set("rev",s),`/artifact-download?${a.toString()}`},[e.artifactId,e.ns,e.name]),Y=o.useCallback(()=>{var s,a,u,w,p;c(!1),((s=d==null?void 0:d.current)!=null&&s.hostUrl||(a=d==null?void 0:d.current)!=null&&a.contentUrl)&&(i({hostUrl:(u=d==null?void 0:d.current)==null?void 0:u.hostUrl,contentUrl:(w=d==null?void 0:d.current)==null?void 0:w.contentUrl}),b(((p=d==null?void 0:d.current)==null?void 0:p.revisionId)||null),C(!0))},[d,i]);o.useEffect(()=>{const s=window.sessionStorage.getItem(U);s&&(window.sessionStorage.removeItem(U),_(s))},[]),o.useEffect(()=>{if(j&&g.some(s=>s.revisionId===j)){const s=j;_(null),I(s)}},[j,g,I]),o.useEffect(()=>{const s=a=>{var w;if(a.origin!==e.sandboxOrigin||a.source!==((w=n.current)==null?void 0:w.contentWindow))return;const u=a.data;(u==null?void 0:u.ap)!=="annot"||u.cmd!=="send"||!u.bundle||fetch(`/session/${e.ns}/${e.name}/interact`,{method:"POST",credentials:"same-origin",headers:{"Content-Type":"application/json"},body:JSON.stringify(ue(u.bundle,e.artifactId))}).then(async p=>{if(!p.ok){const R=await p.json().catch(()=>({}));console.error("annotation send failed",p.status,R),y(R.error?R.error:`The server returned ${p.status}.`);return}y(null)}).catch(p=>{console.error("annotation send failed (network)",p),y("The server was unreachable — check your connection and try again.")})};return window.addEventListener("message",s),()=>window.removeEventListener("message",s)},[e.sandboxOrigin,e.ns,e.name,e.artifactId]);const Q=o.useCallback(async s=>{const a=await fetch(`/session/${e.ns}/${e.name}/interact`,{method:"POST",credentials:"same-origin",headers:{"Content-Type":"application/json"},body:JSON.stringify({kind:"user_message",artifactId:e.artifactId,payload:{text:s}})});if(!a.ok){const u=await a.json().catch(()=>({}));throw console.error("send failed",a.status,u),new Error((u==null?void 0:u.error)||"send failed")}},[e.ns,e.name,e.artifactId]);return t.jsx(Z,{delayDuration:200,children:t.jsxs("div",{className:"h-screen flex flex-col bg-background text-foreground",children:[t.jsxs("div",{className:"relative flex items-center gap-3 px-3 py-2 min-h-[52px] bg-card border-b border-border",children:[t.jsx(T,{variant:"ghost",size:"icon",className:"h-7 w-7 text-muted-foreground",title:"Toggle revisions",onClick:()=>f(s=>!s),children:t.jsx(ce,{className:"h-4 w-4"})}),t.jsxs("div",{className:"flex flex-col min-w-0 max-w-[46%] shrink",children:[t.jsx("span",{className:"text-[13px] font-semibold leading-[1.25] truncate",title:e.artifactName,children:e.artifactName}),e.artifactDescription&&t.jsx("span",{className:"text-[11px] text-muted-foreground leading-[1.3] truncate",title:e.artifactDescription,children:e.artifactDescription})]}),t.jsx("div",{className:"w-px h-[26px] bg-border shrink-0"}),t.jsx(ve,{status:S}),t.jsxs("div",{className:"flex items-center gap-2 ml-auto shrink-0",children:[t.jsx("a",{href:D(r&&h?h:void 0),download:!0,"aria-label":"Download",title:"Download",className:"flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-accent-foreground",children:t.jsx(P,{className:"h-4 w-4","aria-hidden":"true"})}),t.jsx(Ne,{href:e.backLink,channelKind:e.channelKind}),r&&t.jsxs(T,{variant:"secondary",size:"sm",className:"h-7 gap-1.5 px-2.5",title:"Follow latest",onClick:Y,children:[t.jsx("span",{className:"inline-block h-[7px] w-[7px] rounded-full bg-success"}),"Live"]}),t.jsx(Se,{state:V})]}),X&&t.jsx("div",{"aria-hidden":"true",className:"absolute left-0 right-0 bottom-0 h-[2px] bg-[linear-gradient(90deg,transparent,hsl(var(--success)),transparent)] bg-[length:50%_100%] animate-ap-flow"})]}),t.jsxs("div",{className:"flex flex-1 min-h-0",children:[t.jsx("aside",{className:`bg-card border-r border-border overflow-hidden transition-[width] ${l?"w-[300px] overflow-y-auto":"w-0"}`,children:t.jsx(Ce,{revisions:g,currentRevId:h,onSelect:I,downloadHref:D})}),t.jsxs("div",{className:"relative flex-1 h-full",children:[t.jsx("iframe",{ref:n,className:"border-0 w-full h-full block bg-white",sandbox:"allow-scripts allow-same-origin",src:e.hostUrl||void 0,referrerPolicy:"no-referrer",title:"artifact content"}),!q&&t.jsxs("div",{className:"absolute inset-0 flex flex-col items-center justify-center gap-2 bg-background text-muted-foreground",children:[t.jsx(E,{className:"h-5 w-5 animate-spin","aria-hidden":"true"}),t.jsx("span",{className:"text-sm",children:"Generating preview…"})]}),M&&t.jsx("div",{className:"absolute inset-x-3 top-3 z-10",children:t.jsxs(ee,{variant:"destructive",className:"relative bg-card pr-9 shadow-lg",children:[t.jsx(te,{children:"Annotation not sent"}),t.jsx(ne,{children:M}),t.jsx("button",{type:"button","aria-label":"Dismiss",onClick:()=>y(null),className:"absolute right-2 top-2 rounded p-1 text-muted-foreground hover:bg-accent hover:text-accent-foreground",children:t.jsx(le,{className:"h-4 w-4","aria-hidden":"true"})})]})})]}),e.interactions.length>0&&t.jsx("div",{className:"w-[320px] shrink-0 h-full",children:t.jsx(Ie,{messages:H,canCompose:e.interactions.includes("user_message"),onSend:Q})})]})]})})}se(Ae); +import{c as k,I as z,J as B,K as F,H as Z,B as T,A as ee,G as te,a as ne,m as se}from"./mount.D4ypHaeQ.js";import{r as o,j as t,v as re,w as ae,x as ie,y as E,z as oe,E as P,I as ce,X as le}from"./vendor.C5MRNvUt.js";import{M as de}from"./markdown.DHnzytkE.js";function ue(e,n){return{kind:"annotation_batch",artifactId:n,payload:{annotations:e.annotations}}}function fe(e){try{const n=JSON.parse(e);return!n||typeof n.type!="string"?null:n}catch{return null}}function he(e){return`${e.protocol==="https:"?"wss:":"ws:"}//${e.host}/artifact-view/ws${e.search}`}const N=3;function xe(e,n){const[i,l]=o.useState("connecting"),f=o.useRef(e);f.current=e;const r=o.useRef(n);return r.current=n,o.useEffect(()=>{let c=null,x,g=!1,m=0;const h=()=>{var d;g||(m+=1,l(m>=N?"offline":"reconnecting"),m===N&&((d=r.current)==null||d.call(r)),x=window.setTimeout(b,2e3))},b=()=>{if(!g){l(m===0?"connecting":m>=N?"offline":"reconnecting");try{c=new WebSocket(he(window.location))}catch{h();return}c.onopen=()=>{m=0,l("connected")},c.onmessage=d=>{const v=fe(d.data);v&&f.current(v)},c.onerror=()=>{g||l(m>=N?"offline":"reconnecting")},c.onclose=h}};return b(),()=>{g=!0,x&&window.clearTimeout(x),c&&c.close()}},[]),{state:i}}function me(e,n){function i(l){var r;if(!!!e.getAttribute("src")){l.hostUrl&&e.setAttribute("src",l.hostUrl);return}if(l.contentUrl)try{(r=e.contentWindow)==null||r.postMessage({ap:"host",cmd:"swap",url:l.contentUrl},n)}catch{}}return{showRevision:i}}function ge(e,n){const i=o.useRef(null);return o.useEffect(()=>{e.current&&(i.current=me(e.current,n))},[e,n]),o.useCallback(l=>{var f;return(f=i.current)==null?void 0:f.showRevision(l)},[])}function we(e,n){if(!e)return"Working";switch(n){case"awaiting_approval":case"awaiting_leakage_approval":return"Awaiting approval";case"awaiting_reply":case"idle":return"Awaiting your reply";case"awaiting_retry":return"Retrying…";case"failed":return"Failed";case"complete":return"Done";default:return"Paused"}}function pe(e){return e==="done"?"✓":e==="error"?"✕":e==="in_progress"?"▸":"○"}function be(e){return e.find(n=>n.status==="in_progress")??e.find(n=>n.status!=="done"&&n.status!=="error")??null}function ve({status:e}){if(!e)return null;const n=!!e.paused,i=e.pauseCause||"",l=Array.isArray(e.plan)?e.plan:[],f=be(l),r=i==="failed",c=i==="complete",x=r?"bg-destructive":c?"bg-success":n?"bg-warning":"bg-success",g=r?"text-destructive":c?"text-success":n?"text-warning":"text-success",m=!n;return t.jsxs("div",{className:"flex flex-1 min-w-0 items-center gap-[9px] text-xs",children:[t.jsx("span",{className:k("h-[9px] w-[9px] rounded-full shrink-0",x,m&&"animate-ap-pulse-dot")}),t.jsx("span",{className:k("text-xs font-semibold shrink-0",g),children:we(n,i)}),e.statusMessage&&t.jsx("span",{className:"text-[13px] text-foreground truncate min-w-0",children:e.statusMessage}),l.length>0&&f&&t.jsxs("span",{className:"relative group min-w-0 truncate shrink-0",tabIndex:0,children:[t.jsx("span",{className:"text-[11px] text-muted-foreground before:content-['·_']",children:f.label||""}),l.length>1&&t.jsx("div",{"aria-hidden":"true",className:"hidden group-hover:block group-focus-within:block absolute top-[calc(100%+4px)] left-0 z-20 bg-card border border-border rounded-md p-2 min-w-[240px] max-w-[420px] shadow-xl whitespace-normal",children:l.map((h,b)=>t.jsxs("div",{className:"flex gap-2 px-1 py-0.5 leading-snug items-baseline",children:[t.jsx("span",{className:k("w-3 text-center shrink-0",h.status==="in_progress"&&"text-primary",h.status==="done"&&"text-success",h.status==="error"&&"text-destructive",(h.status==="pending"||!h.status)&&"text-muted-foreground"),children:pe(h.status)}),t.jsx("span",{children:h.label||""})]},b))})]})]})}function je({className:e}){return t.jsxs("svg",{width:"16",height:"16",viewBox:"0 0 24 24",className:e,"aria-hidden":"true",children:[t.jsx("path",{fill:"#E01E5A",d:"M5.6 14.5a2.3 2.3 0 1 1-2.3-2.3h2.3z"}),t.jsx("path",{fill:"#E01E5A",d:"M6.8 14.5a2.3 2.3 0 0 1 4.6 0v5.7a2.3 2.3 0 1 1-4.6 0z"}),t.jsx("path",{fill:"#36C5F0",d:"M9.5 5.6a2.3 2.3 0 1 1 2.3-2.3v2.3z"}),t.jsx("path",{fill:"#36C5F0",d:"M9.5 6.8a2.3 2.3 0 0 1 0 4.6H3.8a2.3 2.3 0 1 1 0-4.6z"}),t.jsx("path",{fill:"#2EB67D",d:"M18.4 9.5a2.3 2.3 0 1 1 2.3 2.3h-2.3z"}),t.jsx("path",{fill:"#2EB67D",d:"M17.2 9.5a2.3 2.3 0 0 1-4.6 0V3.8a2.3 2.3 0 1 1 4.6 0z"}),t.jsx("path",{fill:"#ECB22E",d:"M14.5 18.4a2.3 2.3 0 1 1-2.3 2.3v-2.3z"}),t.jsx("path",{fill:"#ECB22E",d:"M14.5 17.2a2.3 2.3 0 0 1 0-4.6h5.7a2.3 2.3 0 1 1 0 4.6z"})]})}function ye({kind:e,className:n}){return e==="slack"?t.jsx(je,{className:n}):t.jsx(re,{className:n,"aria-hidden":"true"})}function Ne({href:e,channelKind:n}){if(!e)return null;const i=n==="slack"?"Open the Slack thread":"Open the thread";return t.jsxs(z,{children:[t.jsx(B,{asChild:!0,children:t.jsxs("a",{href:e,target:"_blank",rel:"noreferrer",className:"group flex items-center gap-[3px] rounded-md px-[7px] py-[5px] text-inherit no-underline hover:bg-muted",children:[t.jsx(ye,{kind:n,className:"h-4 w-4"}),t.jsx(ae,{className:"h-[11px] w-[11px] text-muted-foreground/70 group-hover:text-muted-foreground","aria-hidden":"true"})]})}),t.jsx(F,{children:i})]})}const ke={connected:{Icon:oe,color:"text-success",spin:!1,tip:"Live — connected"},connecting:{Icon:E,color:"text-warning",spin:!0,tip:"Connecting…"},reconnecting:{Icon:E,color:"text-warning",spin:!0,tip:"Reconnecting…"},offline:{Icon:ie,color:"text-destructive",spin:!1,tip:"Offline — retrying"}};function Se({state:e}){const n=ke[e],{Icon:i}=n;return t.jsxs(z,{children:[t.jsx(B,{asChild:!0,children:t.jsx("div",{className:`flex h-7 w-7 items-center justify-center rounded-md cursor-default ${n.color}`,children:t.jsx(i,{className:`h-[18px] w-[18px] ${n.spin?"animate-spin":""}`,"aria-hidden":"true"})})}),t.jsx(F,{children:n.tip})]})}function Ce({revisions:e,currentRevId:n,onSelect:i,downloadHref:l}){const f=[...e].reverse();return t.jsx("ul",{className:"list-none m-0 p-1.5",children:f.map(r=>{const c=r.revisionId&&r.revisionId===n;return t.jsxs("li",{onClick:()=>r.revisionId&&i(r.revisionId),className:k("relative px-2.5 py-2 rounded-md cursor-pointer border border-transparent text-xs leading-snug hover:bg-muted",c&&"bg-muted border-border"),children:[l&&r.revisionId&&t.jsx("a",{href:l(r.revisionId),download:!0,onClick:x=>x.stopPropagation(),"aria-label":`Download revision ${r.seq??""}`.trim(),title:"Download this revision",className:"absolute bottom-1.5 right-1.5 flex h-5 w-5 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-accent-foreground",children:t.jsx(P,{className:"h-3 w-3","aria-hidden":"true"})}),t.jsxs("span",{className:"font-semibold text-primary",children:["#",r.seq??"?",Array.isArray(r.tags)&&r.tags.includes("latest")&&t.jsx("span",{className:"ml-1.5 text-[10px] px-1.5 rounded-lg bg-success/20 text-success align-middle",children:"latest"})]}),t.jsx("span",{className:"block text-foreground my-0.5",children:r.changeDescription||"(no description)"}),r.createdAt&&t.jsx("span",{className:"block text-muted-foreground text-[11px]",children:r.createdAt})]},r.revisionId||r.seq)})})}function Ie(e){const[n,i]=o.useState(""),[l,f]=o.useState(!1),r=async()=>{const c=n.trim();if(!(!c||l)){f(!0);try{await e.onSend(c),i("")}finally{f(!1)}}};return t.jsxs("div",{className:"flex flex-col h-full border-l border-border bg-card",children:[t.jsx("div",{className:"flex-1 overflow-y-auto p-3 space-y-2",children:e.messages.map((c,x)=>t.jsx("div",{className:`flex ${c.role==="user"?"justify-end":"justify-start"}`,children:t.jsx("div",{className:`inline-block max-w-[85%] rounded-lg px-3 py-1.5 text-sm text-left ${c.role==="user"?"bg-primary text-primary-foreground":"bg-muted text-foreground"}`,children:t.jsx(de,{children:c.text})})},x))}),e.canCompose&&t.jsxs("div",{className:"flex gap-2 p-2 border-t border-border",children:[t.jsx("input",{className:"flex-1 rounded border border-border bg-background px-2 py-1 text-sm",value:n,onChange:c=>i(c.target.value),onKeyDown:c=>{c.key==="Enter"&&r()},placeholder:"Message the agent…",disabled:l}),t.jsx("button",{className:"rounded bg-primary px-3 text-sm text-primary-foreground disabled:opacity-50",onClick:()=>void r(),disabled:l,children:"Send"})]})]})}const L=200;function Re(e,n){const i=e.concat(n);return i.length>L?i.slice(i.length-L):i}function Ee(e){return{role:e.role==="user"?"user":"agent",text:e.text,author:e.author,at:e.at}}const A="ap_artifact_reauth_at",U="ap_artifact_pending_rev";function Ue(){const e=Number(window.sessionStorage.getItem(A)||"0");return Number.isFinite(e)&&Date.now()-e<15e3}function O(e){return Ue()?!1:(window.sessionStorage.setItem(A,String(Date.now())),e&&window.sessionStorage.setItem(U,e),window.location.reload(),!0)}function Ae(e){const n=o.useRef(null),i=ge(n,e.sandboxOrigin),[l,f]=o.useState(!1),[r,c]=o.useState(!1),x=o.useRef(!1);x.current=r;const[g,m]=o.useState([]),[h,b]=o.useState(null),[d,v]=o.useState(null),[S,W]=o.useState(null),[q,C]=o.useState(!!e.hostUrl),[j,_]=o.useState(null),[H,K]=o.useState([]),[M,y]=o.useState(null),$=o.useRef(null);$.current=d;const J=o.useCallback(s=>{var a,u;if(s.type==="status"){s.status&&W(s.status);return}if(s.type==="message"){s.message&&K(w=>Re(w,Ee(s.message)));return}v(s),Array.isArray(s.revisions)&&m(s.revisions),!x.current&&((a=s.current)!=null&&a.hostUrl||(u=s.current)!=null&&u.contentUrl)&&(i({hostUrl:s.current.hostUrl,contentUrl:s.current.contentUrl}),b(s.current.revisionId||null),C(!0))},[i]),G=o.useCallback(()=>{var a,u;const s=(u=(a=$.current)==null?void 0:a.current)==null?void 0:u.revisionId;s&&fetch(`/artifact-view/revision${window.location.search}&rev=${encodeURIComponent(s)}`).then(w=>{w.status===401&&O()}).catch(()=>{})},[]),{state:V}=xe(J,G),X=!!S&&!S.paused,I=o.useCallback(s=>{c(!0),fetch(`/artifact-view/revision${window.location.search}&rev=${encodeURIComponent(s)}`).then(a=>{if(a.status===401)return O(s),null;if(!a.ok)throw new Error(`revision fetch failed: ${a.status}`);return a.json()}).then(a=>{a&&(window.sessionStorage.removeItem(A),(a.hostUrl||a.contentUrl)&&(i({hostUrl:a.hostUrl,contentUrl:a.contentUrl}),b(s),C(!0)))}).catch(a=>{window.console&&console.warn("view-older failed",a)})},[i]),D=o.useCallback(s=>{const a=new URLSearchParams({artifactId:e.artifactId,sessionRef:`${e.ns}/${e.name}`});return s&&a.set("rev",s),`/artifact-download?${a.toString()}`},[e.artifactId,e.ns,e.name]),Y=o.useCallback(()=>{var s,a,u,w,p;c(!1),((s=d==null?void 0:d.current)!=null&&s.hostUrl||(a=d==null?void 0:d.current)!=null&&a.contentUrl)&&(i({hostUrl:(u=d==null?void 0:d.current)==null?void 0:u.hostUrl,contentUrl:(w=d==null?void 0:d.current)==null?void 0:w.contentUrl}),b(((p=d==null?void 0:d.current)==null?void 0:p.revisionId)||null),C(!0))},[d,i]);o.useEffect(()=>{const s=window.sessionStorage.getItem(U);s&&(window.sessionStorage.removeItem(U),_(s))},[]),o.useEffect(()=>{if(j&&g.some(s=>s.revisionId===j)){const s=j;_(null),I(s)}},[j,g,I]),o.useEffect(()=>{const s=a=>{var w;if(a.origin!==e.sandboxOrigin||a.source!==((w=n.current)==null?void 0:w.contentWindow))return;const u=a.data;(u==null?void 0:u.ap)!=="annot"||u.cmd!=="send"||!u.bundle||fetch(`/session/${e.ns}/${e.name}/interact`,{method:"POST",credentials:"same-origin",headers:{"Content-Type":"application/json"},body:JSON.stringify(ue(u.bundle,e.artifactId))}).then(async p=>{if(!p.ok){const R=await p.json().catch(()=>({}));console.error("annotation send failed",p.status,R),y(R.error?R.error:`The server returned ${p.status}.`);return}y(null)}).catch(p=>{console.error("annotation send failed (network)",p),y("The server was unreachable — check your connection and try again.")})};return window.addEventListener("message",s),()=>window.removeEventListener("message",s)},[e.sandboxOrigin,e.ns,e.name,e.artifactId]);const Q=o.useCallback(async s=>{const a=await fetch(`/session/${e.ns}/${e.name}/interact`,{method:"POST",credentials:"same-origin",headers:{"Content-Type":"application/json"},body:JSON.stringify({kind:"user_message",artifactId:e.artifactId,payload:{text:s}})});if(!a.ok){const u=await a.json().catch(()=>({}));throw console.error("send failed",a.status,u),new Error((u==null?void 0:u.error)||"send failed")}},[e.ns,e.name,e.artifactId]);return t.jsx(Z,{delayDuration:200,children:t.jsxs("div",{className:"h-screen flex flex-col bg-background text-foreground",children:[t.jsxs("div",{className:"relative flex items-center gap-3 px-3 py-2 min-h-[52px] bg-card border-b border-border",children:[t.jsx(T,{variant:"ghost",size:"icon",className:"h-7 w-7 text-muted-foreground",title:"Toggle revisions",onClick:()=>f(s=>!s),children:t.jsx(ce,{className:"h-4 w-4"})}),t.jsxs("div",{className:"flex flex-col min-w-0 max-w-[46%] shrink",children:[t.jsx("span",{className:"text-[13px] font-semibold leading-[1.25] truncate",title:e.artifactName,children:e.artifactName}),e.artifactDescription&&t.jsx("span",{className:"text-[11px] text-muted-foreground leading-[1.3] truncate",title:e.artifactDescription,children:e.artifactDescription})]}),t.jsx("div",{className:"w-px h-[26px] bg-border shrink-0"}),t.jsx(ve,{status:S}),t.jsxs("div",{className:"flex items-center gap-2 ml-auto shrink-0",children:[t.jsx("a",{href:D(r&&h?h:void 0),download:!0,"aria-label":"Download",title:"Download",className:"flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-accent-foreground",children:t.jsx(P,{className:"h-4 w-4","aria-hidden":"true"})}),t.jsx(Ne,{href:e.backLink,channelKind:e.channelKind}),r&&t.jsxs(T,{variant:"secondary",size:"sm",className:"h-7 gap-1.5 px-2.5",title:"Follow latest",onClick:Y,children:[t.jsx("span",{className:"inline-block h-[7px] w-[7px] rounded-full bg-success"}),"Live"]}),t.jsx(Se,{state:V})]}),X&&t.jsx("div",{"aria-hidden":"true",className:"absolute left-0 right-0 bottom-0 h-[2px] bg-[linear-gradient(90deg,transparent,hsl(var(--success)),transparent)] bg-[length:50%_100%] animate-ap-flow"})]}),t.jsxs("div",{className:"flex flex-1 min-h-0",children:[t.jsx("aside",{className:`bg-card border-r border-border overflow-hidden transition-[width] ${l?"w-[300px] overflow-y-auto":"w-0"}`,children:t.jsx(Ce,{revisions:g,currentRevId:h,onSelect:I,downloadHref:D})}),t.jsxs("div",{className:"relative flex-1 h-full",children:[t.jsx("iframe",{ref:n,className:"border-0 w-full h-full block bg-white",sandbox:"allow-scripts allow-same-origin",src:e.hostUrl||void 0,referrerPolicy:"no-referrer",title:"artifact content"}),!q&&t.jsxs("div",{className:"absolute inset-0 flex flex-col items-center justify-center gap-2 bg-background text-muted-foreground",children:[t.jsx(E,{className:"h-5 w-5 animate-spin","aria-hidden":"true"}),t.jsx("span",{className:"text-sm",children:"Generating preview…"})]}),M&&t.jsx("div",{className:"absolute inset-x-3 top-3 z-10",children:t.jsxs(ee,{variant:"destructive",className:"relative bg-card pr-9 shadow-lg",children:[t.jsx(te,{children:"Annotation not sent"}),t.jsx(ne,{children:M}),t.jsx("button",{type:"button","aria-label":"Dismiss",onClick:()=>y(null),className:"absolute right-2 top-2 rounded p-1 text-muted-foreground hover:bg-accent hover:text-accent-foreground",children:t.jsx(le,{className:"h-4 w-4","aria-hidden":"true"})})]})})]}),e.interactions.length>0&&t.jsx("div",{className:"w-[320px] shrink-0 h-full",children:t.jsx(Ie,{messages:H,canCompose:e.interactions.includes("user_message"),onSend:Q})})]})]})})}se(Ae); diff --git a/pkg/web/webui/webassets/dist/badge.CIlGQKPh.js b/pkg/web/webui/webassets/dist/badge.hXhpY1Si.js similarity index 91% rename from pkg/web/webui/webassets/dist/badge.CIlGQKPh.js rename to pkg/web/webui/webassets/dist/badge.hXhpY1Si.js index f3826925..4183c725 100644 --- a/pkg/web/webui/webassets/dist/badge.CIlGQKPh.js +++ b/pkg/web/webui/webassets/dist/badge.hXhpY1Si.js @@ -1 +1 @@ -import{j as o,ac as n}from"./vendor.C5MRNvUt.js";import{c as a}from"./mount.BOEH1oNx.js";const s=n("inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",{variants:{variant:{default:"border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",secondary:"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",destructive:"border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",outline:"text-foreground"}},defaultVariants:{variant:"default"}});function c({className:r,variant:e,...t}){return o.jsx("div",{className:a(s({variant:e}),r),...t})}export{c as B}; +import{j as o,ac as n}from"./vendor.C5MRNvUt.js";import{c as a}from"./mount.D4ypHaeQ.js";const s=n("inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",{variants:{variant:{default:"border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",secondary:"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",destructive:"border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",outline:"text-foreground"}},defaultVariants:{variant:"default"}});function c({className:r,variant:e,...t}){return o.jsx("div",{className:a(s({variant:e}),r),...t})}export{c as B}; diff --git a/pkg/web/webui/webassets/dist/chat-embed.B187PZKG.js b/pkg/web/webui/webassets/dist/chat-embed.DZrJJN4s.js similarity index 50% rename from pkg/web/webui/webassets/dist/chat-embed.B187PZKG.js rename to pkg/web/webui/webassets/dist/chat-embed.DZrJJN4s.js index ac71ce58..8b38a195 100644 --- a/pkg/web/webui/webassets/dist/chat-embed.B187PZKG.js +++ b/pkg/web/webui/webassets/dist/chat-embed.DZrJJN4s.js @@ -1 +1 @@ -import{m as s}from"./mount.BOEH1oNx.js";import{j as e}from"./vendor.C5MRNvUt.js";import{S as o,a,C as i}from"./StartupLine.D55RHpak.js";import"./markdown.FOTo-3Mz.js";function m({ns:t,name:r}){return e.jsx(o,{ns:t,name:r,children:e.jsxs("div",{"data-testid":"chat-embed-root",className:"flex h-full min-h-screen flex-col",children:[e.jsx(a,{}),e.jsx(i,{ns:t,name:r,readOnly:!1})]})})}s(m); +import{m as s}from"./mount.D4ypHaeQ.js";import{j as e}from"./vendor.C5MRNvUt.js";import{S as o,a,C as i}from"./StartupLine.o9MnUGnk.js";import"./markdown.DHnzytkE.js";function m({ns:t,name:r}){return e.jsx(o,{ns:t,name:r,children:e.jsxs("div",{"data-testid":"chat-embed-root",className:"flex h-full min-h-screen flex-col",children:[e.jsx(a,{}),e.jsx(i,{ns:t,name:r,readOnly:!1})]})})}s(m); diff --git a/pkg/web/webui/webassets/dist/health.DtWM4D-G.js b/pkg/web/webui/webassets/dist/health.B5R65KFZ.js similarity index 86% rename from pkg/web/webui/webassets/dist/health.DtWM4D-G.js rename to pkg/web/webui/webassets/dist/health.B5R65KFZ.js index eea297d5..03fc5ca3 100644 --- a/pkg/web/webui/webassets/dist/health.DtWM4D-G.js +++ b/pkg/web/webui/webassets/dist/health.B5R65KFZ.js @@ -1 +1 @@ -import{j as e}from"./vendor.C5MRNvUt.js";import{m as r,C as t,b as a,d as n,e as d}from"./mount.BOEH1oNx.js";function m({status:s="ok"}){return e.jsx("div",{className:"min-h-screen flex items-center justify-center bg-background text-foreground",children:e.jsxs(t,{className:"max-w-sm w-full",children:[e.jsx(a,{children:e.jsx(n,{children:"webd"})}),e.jsx(d,{children:e.jsxs("p",{className:"text-sm text-muted-foreground",children:["status: ",s]})})]})})}r(m); +import{j as e}from"./vendor.C5MRNvUt.js";import{m as r,C as t,b as a,d as n,e as d}from"./mount.D4ypHaeQ.js";function m({status:s="ok"}){return e.jsx("div",{className:"min-h-screen flex items-center justify-center bg-background text-foreground",children:e.jsxs(t,{className:"max-w-sm w-full",children:[e.jsx(a,{children:e.jsx(n,{children:"webd"})}),e.jsx(d,{children:e.jsxs("p",{className:"text-sm text-muted-foreground",children:["status: ",s]})})]})})}r(m); diff --git a/pkg/web/webui/webassets/dist/identity-link-form.vFiHWBBM.js b/pkg/web/webui/webassets/dist/identity-link-form.BlrHwqYw.js similarity index 65% rename from pkg/web/webui/webassets/dist/identity-link-form.vFiHWBBM.js rename to pkg/web/webui/webassets/dist/identity-link-form.BlrHwqYw.js index 24102f40..d40fc491 100644 --- a/pkg/web/webui/webassets/dist/identity-link-form.vFiHWBBM.js +++ b/pkg/web/webui/webassets/dist/identity-link-form.BlrHwqYw.js @@ -1 +1 @@ -import{B as n,m as i}from"./mount.BOEH1oNx.js";import{j as e}from"./vendor.C5MRNvUt.js";import{I as a}from"./IdentityShell.D-zSSgc9.js";import{N as o}from"./NoticeBanner.lKrMgKCy.js";import{P as s}from"./PatForm.BuKUBhkS.js";function m(t){return e.jsxs(a,{title:`Link ${t.credentialLabel||t.credentialName}`,children:[e.jsx(o,{search:window.location.search}),e.jsx("p",{className:"text-xs text-muted-foreground mb-3 font-mono",children:t.credentialName}),e.jsx(s,{action:`/my/accounts/${encodeURIComponent(t.credentialName)}/link/submit`,submitLabel:"Connect",instructions:t.instructions,docsUrl:t.docsUrl}),e.jsx(n,{asChild:!0,variant:"ghost",size:"sm",className:"mt-3",children:e.jsx("a",{href:"/my/accounts",children:"Cancel"})})]})}i(m); +import{B as n,m as i}from"./mount.D4ypHaeQ.js";import{j as e}from"./vendor.C5MRNvUt.js";import{I as a}from"./IdentityShell.DBeEfGP6.js";import{N as o}from"./NoticeBanner.C_F8xF59.js";import{P as s}from"./PatForm.BrJ1dS20.js";function m(t){return e.jsxs(a,{title:`Link ${t.credentialLabel||t.credentialName}`,children:[e.jsx(o,{search:window.location.search}),e.jsx("p",{className:"text-xs text-muted-foreground mb-3 font-mono",children:t.credentialName}),e.jsx(s,{action:`/my/accounts/${encodeURIComponent(t.credentialName)}/link/submit`,submitLabel:"Connect",instructions:t.instructions,docsUrl:t.docsUrl}),e.jsx(n,{asChild:!0,variant:"ghost",size:"sm",className:"mt-3",children:e.jsx("a",{href:"/my/accounts",children:"Cancel"})})]})}i(m); diff --git a/pkg/web/webui/webassets/dist/identity-link.BpTVpI-G.js b/pkg/web/webui/webassets/dist/identity-link.DIirqNR1.js similarity index 90% rename from pkg/web/webui/webassets/dist/identity-link.BpTVpI-G.js rename to pkg/web/webui/webassets/dist/identity-link.DIirqNR1.js index c272c45a..d1922bcd 100644 --- a/pkg/web/webui/webassets/dist/identity-link.BpTVpI-G.js +++ b/pkg/web/webui/webassets/dist/identity-link.DIirqNR1.js @@ -1 +1 @@ -import{c as a,B as i,m as c}from"./mount.BOEH1oNx.js";import{j as t,r as l}from"./vendor.C5MRNvUt.js";import{I as r}from"./IdentityShell.D-zSSgc9.js";import{N as d}from"./NoticeBanner.lKrMgKCy.js";import{P as m}from"./PatForm.BuKUBhkS.js";function o(e){l.useEffect(()=>{if(!e)return;const s=()=>fetch(`/heartbeat?session=${encodeURIComponent(e)}`,{method:"POST",credentials:"same-origin"}).catch(()=>{}),n=window.setInterval(s,3e4);return()=>window.clearInterval(n)},[e])}function u({row:e,signedLink:s}){return t.jsxs("li",{className:"flex flex-col gap-1.5 py-3 border-b border-border last:border-0",children:[t.jsxs("div",{className:"flex items-center gap-2",children:[e.iconUrl&&t.jsx("img",{src:e.iconUrl,alt:"",className:"h-4 w-4 rounded-sm"}),t.jsx("span",{className:"font-medium text-sm",children:e.label||e.credentialName}),e.status==="linked"&&t.jsx("span",{className:"ml-auto text-[10px] px-2 py-0.5 rounded-lg bg-success/20 text-success",children:"linked"})]}),e.why&&t.jsx("p",{className:"text-xs text-muted-foreground",children:e.why}),e.status==="missing"&&e.kind==="pat"&&t.jsx(m,{action:"/link/submit",submitLabel:"Save",hidden:{link:s,credential:e.credentialName},instructions:e.instructions,docsUrl:e.docsUrl}),e.status==="missing"&&e.kind==="oauth"&&t.jsx(i,{asChild:!0,variant:"secondary",size:"sm",className:"self-start",children:t.jsxs("a",{href:e.oauthUrl,children:["Connect ",e.label||e.credentialName]})})]})}function x(e){o(e.sessionRef);const s=e.agentName?`for ${e.agentName}`:void 0;return t.jsxs(r,{title:"Connect your credentials",subtitle:s,children:[t.jsx(d,{search:window.location.search}),e.what.length>0&&t.jsx("p",{className:"text-sm text-muted-foreground mb-3",children:e.what.join(" ")}),t.jsx("ul",{className:a("list-none m-0 p-0"),children:e.rows.map(n=>t.jsx(u,{row:n,signedLink:e.signedLink},n.credentialName))}),t.jsxs("p",{className:"text-[11px] text-muted-foreground/60 mt-4",children:["Session: ",e.sessionRef]})]})}c(x); +import{c as a,B as i,m as c}from"./mount.D4ypHaeQ.js";import{j as t,r as l}from"./vendor.C5MRNvUt.js";import{I as r}from"./IdentityShell.DBeEfGP6.js";import{N as d}from"./NoticeBanner.C_F8xF59.js";import{P as m}from"./PatForm.BrJ1dS20.js";function o(e){l.useEffect(()=>{if(!e)return;const s=()=>fetch(`/heartbeat?session=${encodeURIComponent(e)}`,{method:"POST",credentials:"same-origin"}).catch(()=>{}),n=window.setInterval(s,3e4);return()=>window.clearInterval(n)},[e])}function u({row:e,signedLink:s}){return t.jsxs("li",{className:"flex flex-col gap-1.5 py-3 border-b border-border last:border-0",children:[t.jsxs("div",{className:"flex items-center gap-2",children:[e.iconUrl&&t.jsx("img",{src:e.iconUrl,alt:"",className:"h-4 w-4 rounded-sm"}),t.jsx("span",{className:"font-medium text-sm",children:e.label||e.credentialName}),e.status==="linked"&&t.jsx("span",{className:"ml-auto text-[10px] px-2 py-0.5 rounded-lg bg-success/20 text-success",children:"linked"})]}),e.why&&t.jsx("p",{className:"text-xs text-muted-foreground",children:e.why}),e.status==="missing"&&e.kind==="pat"&&t.jsx(m,{action:"/link/submit",submitLabel:"Save",hidden:{link:s,credential:e.credentialName},instructions:e.instructions,docsUrl:e.docsUrl}),e.status==="missing"&&e.kind==="oauth"&&t.jsx(i,{asChild:!0,variant:"secondary",size:"sm",className:"self-start",children:t.jsxs("a",{href:e.oauthUrl,children:["Connect ",e.label||e.credentialName]})})]})}function x(e){o(e.sessionRef);const s=e.agentName?`for ${e.agentName}`:void 0;return t.jsxs(r,{title:"Connect your credentials",subtitle:s,children:[t.jsx(d,{search:window.location.search}),e.what.length>0&&t.jsx("p",{className:"text-sm text-muted-foreground mb-3",children:e.what.join(" ")}),t.jsx("ul",{className:a("list-none m-0 p-0"),children:e.rows.map(n=>t.jsx(u,{row:n,signedLink:e.signedLink},n.credentialName))}),t.jsxs("p",{className:"text-[11px] text-muted-foreground/60 mt-4",children:["Session: ",e.sessionRef]})]})}c(x); diff --git a/pkg/web/webui/webassets/dist/identity-portal.BFvlFsRb.js b/pkg/web/webui/webassets/dist/identity-portal.62gtlh5n.js similarity index 90% rename from pkg/web/webui/webassets/dist/identity-portal.BFvlFsRb.js rename to pkg/web/webui/webassets/dist/identity-portal.62gtlh5n.js index 908d6c5a..415e9e07 100644 --- a/pkg/web/webui/webassets/dist/identity-portal.BFvlFsRb.js +++ b/pkg/web/webui/webassets/dist/identity-portal.62gtlh5n.js @@ -1 +1 @@ -import{B as t,m as i}from"./mount.BOEH1oNx.js";import{j as e}from"./vendor.C5MRNvUt.js";import{I as m}from"./IdentityShell.D-zSSgc9.js";import{N as r}from"./NoticeBanner.lKrMgKCy.js";function a({c:s,action:n}){return e.jsxs("li",{className:"flex items-center gap-2 py-2.5 border-b border-border last:border-0",children:[s.iconUrl&&e.jsx("img",{src:s.iconUrl,alt:"",className:"h-4 w-4 rounded-sm"}),e.jsx("span",{className:"text-sm",children:s.label||s.name}),e.jsx("span",{className:"ml-auto",children:n})]})}function o(s){return e.jsxs(m,{title:"Your connected accounts",subtitle:s.displayName?`Signed in as ${s.displayName}`:void 0,children:[e.jsx(r,{search:window.location.search}),e.jsx("h3",{className:"text-xs uppercase tracking-wide text-muted-foreground mt-1 mb-1",children:"Linked"}),s.linked.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"Nothing linked yet."}):e.jsx("ul",{className:"list-none m-0 p-0",children:s.linked.map(n=>e.jsx(a,{c:n,action:e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(t,{asChild:!0,variant:"ghost",size:"sm",children:e.jsx("a",{href:n.isOAuth?`/link/oauth/${encodeURIComponent(n.name)}`:`/my/accounts/${encodeURIComponent(n.name)}/link`,children:"Replace"})}),e.jsx("form",{method:"POST",action:`/my/accounts/${encodeURIComponent(n.name)}/revoke`,className:"m-0",children:e.jsx(t,{type:"submit",variant:"ghost",size:"sm",className:"text-destructive",children:"Remove"})})]})},n.name))}),s.suggested.length>0&&e.jsxs(e.Fragment,{children:[e.jsx("h3",{className:"text-xs uppercase tracking-wide text-muted-foreground mt-5 mb-1",children:"Suggested"}),e.jsx("ul",{className:"list-none m-0 p-0",children:s.suggested.map(n=>e.jsx(a,{c:n,action:e.jsx(t,{asChild:!0,variant:"secondary",size:"sm",children:e.jsx("a",{href:n.isOAuth?`/link/oauth/${encodeURIComponent(n.name)}`:`/my/accounts/${encodeURIComponent(n.name)}/link`,children:n.isOAuth?"Connect":"Link"})})},n.name))})]})]})}i(o); +import{B as t,m as i}from"./mount.D4ypHaeQ.js";import{j as e}from"./vendor.C5MRNvUt.js";import{I as m}from"./IdentityShell.DBeEfGP6.js";import{N as r}from"./NoticeBanner.C_F8xF59.js";function a({c:s,action:n}){return e.jsxs("li",{className:"flex items-center gap-2 py-2.5 border-b border-border last:border-0",children:[s.iconUrl&&e.jsx("img",{src:s.iconUrl,alt:"",className:"h-4 w-4 rounded-sm"}),e.jsx("span",{className:"text-sm",children:s.label||s.name}),e.jsx("span",{className:"ml-auto",children:n})]})}function o(s){return e.jsxs(m,{title:"Your connected accounts",subtitle:s.displayName?`Signed in as ${s.displayName}`:void 0,children:[e.jsx(r,{search:window.location.search}),e.jsx("h3",{className:"text-xs uppercase tracking-wide text-muted-foreground mt-1 mb-1",children:"Linked"}),s.linked.length===0?e.jsx("p",{className:"text-sm text-muted-foreground",children:"Nothing linked yet."}):e.jsx("ul",{className:"list-none m-0 p-0",children:s.linked.map(n=>e.jsx(a,{c:n,action:e.jsxs("div",{className:"flex items-center gap-1",children:[e.jsx(t,{asChild:!0,variant:"ghost",size:"sm",children:e.jsx("a",{href:n.isOAuth?`/link/oauth/${encodeURIComponent(n.name)}`:`/my/accounts/${encodeURIComponent(n.name)}/link`,children:"Replace"})}),e.jsx("form",{method:"POST",action:`/my/accounts/${encodeURIComponent(n.name)}/revoke`,className:"m-0",children:e.jsx(t,{type:"submit",variant:"ghost",size:"sm",className:"text-destructive",children:"Remove"})})]})},n.name))}),s.suggested.length>0&&e.jsxs(e.Fragment,{children:[e.jsx("h3",{className:"text-xs uppercase tracking-wide text-muted-foreground mt-5 mb-1",children:"Suggested"}),e.jsx("ul",{className:"list-none m-0 p-0",children:s.suggested.map(n=>e.jsx(a,{c:n,action:e.jsx(t,{asChild:!0,variant:"secondary",size:"sm",children:e.jsx("a",{href:n.isOAuth?`/link/oauth/${encodeURIComponent(n.name)}`:`/my/accounts/${encodeURIComponent(n.name)}/link`,children:n.isOAuth?"Connect":"Link"})})},n.name))})]})]})}i(o); diff --git a/pkg/web/webui/webassets/dist/identity-verify-warn.CN_Li5hi.js b/pkg/web/webui/webassets/dist/identity-verify-warn.jH6WhRVY.js similarity index 86% rename from pkg/web/webui/webassets/dist/identity-verify-warn.CN_Li5hi.js rename to pkg/web/webui/webassets/dist/identity-verify-warn.jH6WhRVY.js index 09f25b6f..29830456 100644 --- a/pkg/web/webui/webassets/dist/identity-verify-warn.CN_Li5hi.js +++ b/pkg/web/webui/webassets/dist/identity-verify-warn.jH6WhRVY.js @@ -1 +1 @@ -import{A as n,a,B as i,m as o}from"./mount.BOEH1oNx.js";import{j as e}from"./vendor.C5MRNvUt.js";import{I as c}from"./IdentityShell.D-zSSgc9.js";function d(t){return e.jsxs(c,{title:"Token could not be verified",children:[e.jsx(n,{className:"mb-4 border-destructive text-destructive",children:e.jsx(a,{children:t.warning})}),e.jsx("p",{className:"text-sm text-muted-foreground mb-4",children:"The provider rejected this token, so it probably won't work. You can store it anyway if you're sure it's correct — for example, a token restricted to specific source IPs."}),e.jsxs("form",{method:"POST",action:t.action,className:"flex gap-2 items-center",children:[Object.entries(t.hidden).map(([r,s])=>e.jsx("input",{type:"hidden",name:r,value:s},r)),e.jsx(i,{type:"submit",variant:"destructive",size:"sm",children:"Store anyway"}),e.jsx(i,{asChild:!0,variant:"ghost",size:"sm",children:e.jsx("a",{href:t.cancelUrl,children:"Go back"})})]})]})}o(d); +import{A as n,a,B as i,m as o}from"./mount.D4ypHaeQ.js";import{j as e}from"./vendor.C5MRNvUt.js";import{I as c}from"./IdentityShell.DBeEfGP6.js";function d(t){return e.jsxs(c,{title:"Token could not be verified",children:[e.jsx(n,{className:"mb-4 border-destructive text-destructive",children:e.jsx(a,{children:t.warning})}),e.jsx("p",{className:"text-sm text-muted-foreground mb-4",children:"The provider rejected this token, so it probably won't work. You can store it anyway if you're sure it's correct — for example, a token restricted to specific source IPs."}),e.jsxs("form",{method:"POST",action:t.action,className:"flex gap-2 items-center",children:[Object.entries(t.hidden).map(([r,s])=>e.jsx("input",{type:"hidden",name:r,value:s},r)),e.jsx(i,{type:"submit",variant:"destructive",size:"sm",children:"Store anyway"}),e.jsx(i,{asChild:!0,variant:"ghost",size:"sm",children:e.jsx("a",{href:t.cancelUrl,children:"Go back"})})]})]})}o(d); diff --git a/pkg/web/webui/webassets/dist/manifest.json b/pkg/web/webui/webassets/dist/manifest.json index dc4be0a9..d8a6c288 100644 --- a/pkg/web/webui/webassets/dist/manifest.json +++ b/pkg/web/webui/webassets/dist/manifest.json @@ -1,50 +1,50 @@ { "identity-link": { "scripts": [ - "/assets/identity-link.BpTVpI-G.js" + "/assets/identity-link.DIirqNR1.js" ], "css": [ - "/assets/mount.BnXLt6oF.css" + "/assets/mount.CtR1PZHB.css" ] }, "identity-link-form": { "scripts": [ - "/assets/identity-link-form.vFiHWBBM.js" + "/assets/identity-link-form.BlrHwqYw.js" ], "css": [ - "/assets/mount.BnXLt6oF.css" + "/assets/mount.CtR1PZHB.css" ] }, "identity-portal": { "scripts": [ - "/assets/identity-portal.BFvlFsRb.js" + "/assets/identity-portal.62gtlh5n.js" ], "css": [ - "/assets/mount.BnXLt6oF.css" + "/assets/mount.CtR1PZHB.css" ] }, "identity-verify-warn": { "scripts": [ - "/assets/identity-verify-warn.CN_Li5hi.js" + "/assets/identity-verify-warn.jH6WhRVY.js" ], "css": [ - "/assets/mount.BnXLt6oF.css" + "/assets/mount.CtR1PZHB.css" ] }, "admin": { "scripts": [ - "/assets/admin.C9jbAoMt.js" + "/assets/admin.D8BEorQ0.js" ], "css": [ - "/assets/mount.BnXLt6oF.css" + "/assets/mount.CtR1PZHB.css" ] }, "settings": { "scripts": [ - "/assets/settings.Bs9xT9hr.js" + "/assets/settings.D2ZpUumf.js" ], "css": [ - "/assets/mount.BnXLt6oF.css" + "/assets/mount.CtR1PZHB.css" ] }, "artifact-host": { @@ -55,42 +55,42 @@ }, "artifact-view": { "scripts": [ - "/assets/artifact-view.D4Y_FHws.js" + "/assets/artifact-view.BNqAlmdu.js" ], "css": [ - "/assets/mount.BnXLt6oF.css" + "/assets/mount.CtR1PZHB.css" ] }, "chat-embed": { "scripts": [ - "/assets/chat-embed.B187PZKG.js" + "/assets/chat-embed.DZrJJN4s.js" ], "css": [ - "/assets/mount.BnXLt6oF.css" + "/assets/mount.CtR1PZHB.css" ] }, "health": { "scripts": [ - "/assets/health.DtWM4D-G.js" + "/assets/health.B5R65KFZ.js" ], "css": [ - "/assets/mount.BnXLt6oF.css" + "/assets/mount.CtR1PZHB.css" ] }, "sessions": { "scripts": [ - "/assets/sessions.DrV0Blkf.js" + "/assets/sessions.Bnnp3HNU.js" ], "css": [ - "/assets/mount.BnXLt6oF.css" + "/assets/mount.CtR1PZHB.css" ] }, "session-view": { "scripts": [ - "/assets/session-view.dtf-izky.js" + "/assets/session-view.D5Vt5OlU.js" ], "css": [ - "/assets/mount.BnXLt6oF.css" + "/assets/mount.CtR1PZHB.css" ] }, "mcpui-host": { @@ -101,10 +101,10 @@ }, "system": { "scripts": [ - "/assets/system.DT_ax8I5.js" + "/assets/system.BC8KWmm_.js" ], "css": [ - "/assets/mount.BnXLt6oF.css" + "/assets/mount.CtR1PZHB.css" ] } } \ No newline at end of file diff --git a/pkg/web/webui/webassets/dist/markdown.FOTo-3Mz.js b/pkg/web/webui/webassets/dist/markdown.DHnzytkE.js similarity index 96% rename from pkg/web/webui/webassets/dist/markdown.FOTo-3Mz.js rename to pkg/web/webui/webassets/dist/markdown.DHnzytkE.js index 663700d1..18aa3757 100644 --- a/pkg/web/webui/webassets/dist/markdown.FOTo-3Mz.js +++ b/pkg/web/webui/webassets/dist/markdown.DHnzytkE.js @@ -1 +1 @@ -import{j as e,au as d,av as l}from"./vendor.C5MRNvUt.js";import{c as n}from"./mount.BOEH1oNx.js";function m({children:r,className:t}){return e.jsx("div",{className:n("leading-relaxed break-words","[&>*:first-child]:mt-0 [&>*:last-child]:mb-0","[&_p]:my-1.5","[&_ul]:my-1.5 [&_ul]:list-disc [&_ul]:pl-5 [&_ol]:my-1.5 [&_ol]:list-decimal [&_ol]:pl-5 [&_li]:my-0.5","[&_h1]:mb-1.5 [&_h1]:mt-2 [&_h1]:text-base [&_h1]:font-semibold","[&_h2]:mb-1.5 [&_h2]:mt-2 [&_h2]:text-[0.95rem] [&_h2]:font-semibold","[&_h3]:mb-1 [&_h3]:mt-2 [&_h3]:font-semibold","[&_a]:underline [&_a]:underline-offset-2 hover:[&_a]:no-underline","[&_blockquote]:my-1.5 [&_blockquote]:border-l-2 [&_blockquote]:border-border [&_blockquote]:pl-2.5 [&_blockquote]:text-muted-foreground","[&_hr]:my-2 [&_hr]:border-border","[&_:not(pre)>code]:rounded [&_:not(pre)>code]:bg-black/10 [&_:not(pre)>code]:px-1 [&_:not(pre)>code]:py-0.5 [&_:not(pre)>code]:font-mono [&_:not(pre)>code]:text-[0.85em] dark:[&_:not(pre)>code]:bg-white/15","[&_pre]:my-1.5 [&_pre]:overflow-x-auto [&_pre]:rounded-md [&_pre]:bg-black/10 [&_pre]:p-2.5 [&_pre]:text-[0.8rem] dark:[&_pre]:bg-white/10","[&_pre_code]:font-mono [&_pre_code]:whitespace-pre","[&_table]:w-full [&_table]:border-collapse [&_table]:text-xs","[&_th]:border [&_th]:border-border [&_th]:bg-muted [&_th]:px-2 [&_th]:py-1 [&_th]:text-left [&_th]:font-semibold","[&_td]:border [&_td]:border-border [&_td]:px-2 [&_td]:py-1 [&_td]:align-top",t),children:e.jsx(d,{remarkPlugins:[l],components:{a:({node:_,...o})=>e.jsx("a",{...o,target:"_blank",rel:"noopener noreferrer"}),table:({node:_,...o})=>e.jsx("div",{className:"my-1.5 overflow-x-auto",children:e.jsx("table",{...o})})},children:r})})}export{m as M}; +import{j as e,au as d,av as l}from"./vendor.C5MRNvUt.js";import{c as n}from"./mount.D4ypHaeQ.js";function m({children:r,className:t}){return e.jsx("div",{className:n("leading-relaxed break-words","[&>*:first-child]:mt-0 [&>*:last-child]:mb-0","[&_p]:my-1.5","[&_ul]:my-1.5 [&_ul]:list-disc [&_ul]:pl-5 [&_ol]:my-1.5 [&_ol]:list-decimal [&_ol]:pl-5 [&_li]:my-0.5","[&_h1]:mb-1.5 [&_h1]:mt-2 [&_h1]:text-base [&_h1]:font-semibold","[&_h2]:mb-1.5 [&_h2]:mt-2 [&_h2]:text-[0.95rem] [&_h2]:font-semibold","[&_h3]:mb-1 [&_h3]:mt-2 [&_h3]:font-semibold","[&_a]:underline [&_a]:underline-offset-2 hover:[&_a]:no-underline","[&_blockquote]:my-1.5 [&_blockquote]:border-l-2 [&_blockquote]:border-border [&_blockquote]:pl-2.5 [&_blockquote]:text-muted-foreground","[&_hr]:my-2 [&_hr]:border-border","[&_:not(pre)>code]:rounded [&_:not(pre)>code]:bg-black/10 [&_:not(pre)>code]:px-1 [&_:not(pre)>code]:py-0.5 [&_:not(pre)>code]:font-mono [&_:not(pre)>code]:text-[0.85em] dark:[&_:not(pre)>code]:bg-white/15","[&_pre]:my-1.5 [&_pre]:overflow-x-auto [&_pre]:rounded-md [&_pre]:bg-black/10 [&_pre]:p-2.5 [&_pre]:text-[0.8rem] dark:[&_pre]:bg-white/10","[&_pre_code]:font-mono [&_pre_code]:whitespace-pre","[&_table]:w-full [&_table]:border-collapse [&_table]:text-xs","[&_th]:border [&_th]:border-border [&_th]:bg-muted [&_th]:px-2 [&_th]:py-1 [&_th]:text-left [&_th]:font-semibold","[&_td]:border [&_td]:border-border [&_td]:px-2 [&_td]:py-1 [&_td]:align-top",t),children:e.jsx(d,{remarkPlugins:[l],components:{a:({node:_,...o})=>e.jsx("a",{...o,target:"_blank",rel:"noopener noreferrer"}),table:({node:_,...o})=>e.jsx("div",{className:"my-1.5 overflow-x-auto",children:e.jsx("table",{...o})})},children:r})})}export{m as M}; diff --git a/pkg/web/webui/webassets/dist/model-name.DtAiu0oG.js b/pkg/web/webui/webassets/dist/model-name.BXiF0QjK.js similarity index 92% rename from pkg/web/webui/webassets/dist/model-name.DtAiu0oG.js rename to pkg/web/webui/webassets/dist/model-name.BXiF0QjK.js index c49fac45..df34ecff 100644 --- a/pkg/web/webui/webassets/dist/model-name.DtAiu0oG.js +++ b/pkg/web/webui/webassets/dist/model-name.BXiF0QjK.js @@ -1 +1 @@ -import{j as i}from"./vendor.C5MRNvUt.js";import{c as o}from"./mount.BOEH1oNx.js";import{B as a}from"./badge.CIlGQKPh.js";function c(e){if(!e)return{name:""};const r=e.indexOf("/");if(r<0)return{name:e};const t=e.slice(0,r),n=e.slice(r+1);if(t!=="openrouter")return{provider:t,name:n};const s=n.indexOf("/");return s<0?{via:"openrouter",name:n}:{via:"openrouter",provider:n.slice(0,s),name:n.slice(s+1)}}function f({model:e,className:r}){if(!e)return null;const{via:t,provider:n,name:s}=c(e);return i.jsxs("span",{className:o("inline-flex items-center gap-1.5",r),children:[t&&i.jsx(a,{variant:"secondary",className:"rounded-full px-2 py-0 text-[10px] font-normal",children:t}),n&&i.jsx("span",{className:"inline-flex items-center rounded-full border bg-background px-2 py-0.5 font-mono text-[10px] text-muted-foreground",children:n}),i.jsx("span",{className:"font-mono text-xs",children:s})]})}export{f as M}; +import{j as i}from"./vendor.C5MRNvUt.js";import{c as o}from"./mount.D4ypHaeQ.js";import{B as a}from"./badge.hXhpY1Si.js";function c(e){if(!e)return{name:""};const r=e.indexOf("/");if(r<0)return{name:e};const t=e.slice(0,r),n=e.slice(r+1);if(t!=="openrouter")return{provider:t,name:n};const s=n.indexOf("/");return s<0?{via:"openrouter",name:n}:{via:"openrouter",provider:n.slice(0,s),name:n.slice(s+1)}}function f({model:e,className:r}){if(!e)return null;const{via:t,provider:n,name:s}=c(e);return i.jsxs("span",{className:o("inline-flex items-center gap-1.5",r),children:[t&&i.jsx(a,{variant:"secondary",className:"rounded-full px-2 py-0 text-[10px] font-normal",children:t}),n&&i.jsx("span",{className:"inline-flex items-center rounded-full border bg-background px-2 py-0.5 font-mono text-[10px] text-muted-foreground",children:n}),i.jsx("span",{className:"font-mono text-xs",children:s})]})}export{f as M}; diff --git a/pkg/web/webui/webassets/dist/mount.BnXLt6oF.css b/pkg/web/webui/webassets/dist/mount.CtR1PZHB.css similarity index 53% rename from pkg/web/webui/webassets/dist/mount.BnXLt6oF.css rename to pkg/web/webui/webassets/dist/mount.CtR1PZHB.css index d2f41ace..9a0576e9 100644 --- a/pkg/web/webui/webassets/dist/mount.BnXLt6oF.css +++ b/pkg/web/webui/webassets/dist/mount.CtR1PZHB.css @@ -1 +1 @@ -@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/inter-cyrillic-ext-wght-normal.BOeWTOD4.woff2) format("woff2-variations");unicode-range:U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/inter-cyrillic-wght-normal.DqGufNeO.woff2) format("woff2-variations");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/inter-greek-ext-wght-normal.DlzME5K_.woff2) format("woff2-variations");unicode-range:U+1F00-1FFF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/inter-greek-wght-normal.CkhJZR-_.woff2) format("woff2-variations");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/inter-vietnamese-wght-normal.CBcvBZtf.woff2) format("woff2-variations");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/inter-latin-ext-wght-normal.DO1Apj_S.woff2) format("woff2-variations");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/inter-latin-wght-normal.Dx4kXJAl.woff2) format("woff2-variations");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(data:font/woff2;base64,d09GMgABAAAAAAfsABQAAAAAEAwAAAeCAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGhwbHhwoP0hWQVJbBmA/U1RBVIFiJyYAdC9qEQgKhGSEAAsgADCGCAE2AiQDOgQgBYlMB4EUDAcbLQ4onoexrSC/2ZyLAa8p8VHB8/x3Vue+V0hVJalMJg2nx/TCrQXxBeqLjQG7FyM1WEa/X1tEXN7cFz9EJEMmMUz3RihWSSKeQCbcIou0izz/C8v+fq3VfajEa9gDD11CImXS7qL/RJFVzC1qiB6KmKeD6TZdQ6IRGv78dL6uSVVCfgni5mzu7kcgQBgAEAQTQRCoL++STTYybkJxNfQxAAIAGu8OdEB9teW2jh4BpgDqFjAeSEByW3zFP0CBBgNMsMCGEDjgggdhiEAUAeIIED7ABTDUEnkIE9Q9ahFgKttcVhApo4ACB4qobHaccgDfEjFO6aaWUhjMLt2SyIvHKoDqoA4CSUwEIYQCEjhAO9R1G6keDeDZGjNo+AhxOjCEGTr1WeIF3kYBiLAOKvkJSMiKX0VdAyQt3SDJClCkxJCHkCzfqyVTriJZLcolS32JZHUekq2TYNkYtCtjYHMQXSxGjXDz2t/yLWXzDzxz+o3zFwDEaN23F+13pyMdQAEaSKAR9vcGq4A4MTSKCElGW+M7UcY7xqkggITb28ZJhlqc9q2twYKTt0NjixBgYvO9BIihEBLYuOFXQzfIQ7dXGUEEEgFDooBfAzqiQbpJrhiWSuKJCRFKYbHCyJKI2G5GiZbNAvgAu5pc3vwx4G+g3aDkhklABiSz0BICXrYghtYhx/cdJ+44rY2oZ0aMNRFz3VZjb6W33F3gzltqtOCV8tTHSpOeXuItfvr5lCdfzFpqtEitvqdcdGGFd28ZqqC0tPbeChGXgrIlnhSWu/eUso4uKWFLugyDzQJhflY4659+WjQ++6x72WUMv9G8mw6QJl7BVxX5fe/kpUsOvnZwee9uQ0cGXYd0o89XB2748sDSnt8d2VphdOTTgceDVvOds0v9P/s7HPq15aGun/6Vllb56f1dl0t1LejqrNkpdRZsG8TOnM5vkBG5oiVyVGnS8LHps5cfNWJs6qKPfaNSxiQNBUm3cKNWROr0GSur7Za31k1vieq7LH11VF+jXdRIasRKflc7jkobm1Z9te1IyZA0pDkhLR98+H37Zf1c/8at+dB7x+7GfVyTfJMPiYztsnl59Y5l4j+0n1RXlpHnF3Tq7HecmNF/CJodEMAikruxiyJaGLvHOdAfoA+oDvpjBm2b91cHGRZMU9n25xEU0A8fgEEAdKI3Q1iDtc034sug5YVMkE2jsE+BIkwSoQ3gxXMqz9tELp48bd0cFKOKS7xYjEuXBnZP5ia7DyiO/X/YI+PQSbt2uSdqAkWL9nQbV1XB94/+uPfdZz8dnXYFBYrcTl2SIR/ybxJNJPz/Gupb0JaZeens2ekC7EKr8t+Ls/P5VJPYJdHKyqfg2nqU6bhlidzcddQV/7MmecTzJ5VPcKXkNKSEogHjYFx6QZ7rQ+FSe8njaiNuOnXS8H2ScQ619c2mC3VTtauL0rRbXd/CkSOP37FY9Zkjz8+GibYUMOEWF+RdrFS8Ecv1SHOpPUPZGEIpjPvFyU5cXKjd6OXqorTqy9GwRd++HVufPGnVsW+aO3vggKZ18jR9sXaTC1PWTEsVUaK0FkNySbTQDqlm2PfDjZcu4aalnSLKjnOoYQ0nUlqqXcGpPu/4VgV/xU2pAqW4BW3qzhQ8/hFKhV2qE3+BKAtDqBXjfgnVdH4y0wg5tbVNRenNdTWOrenWLcupQdmsbq5b+18piTe/xRdp1xbILxNPJGInm2z6hoB21Lal0i+ePTtd7B45+3XhFJ329evskXm7qurUVREotqSluSo/L29d3qDhI4YOQqWhI4YNvBNfsMHeXKemXrxQfKeuPOGRVayA3JtkJKEgbPp+dXUDluddutRYLFoXGXWX6N3WFaGLbQtRSitVYNacTNSdy7AaG/HSaUEANcBoGXNdcZvZsOqQ1icBDv21/gzAoYPHH/WDW0qNR3QTYKEAEHig6o13NXbND06CQPlRtYjGNnSktRc09k1mAMDvAlDKfQjgy6fssInlfzmNAjKkDxoxHOBLdVRAIVt9j4qo+hA1w9T1aNBNTUOTTNUHLbqokE+UAfJXCIGw/IxCSL5GRUJeR40rL/UxTm4Q08H6MbCs70ObuNyIIXrINHQYInF06UUlevTjbQzTh5upiDMzMMogUtEnjPs/Y7jAHCJeB0GBHh04tC6FiB6ZFB1oArUSIoFoqhzCeAN6lHwm0T4C3VVPWvjpSMXReuWesMEcoqrmgtNBGd2noWeV0hNAz9rFeShNJxHGsPa3HXeKTk8b55hahySYHaYKKFFLpCfN8rsoaJn01CR04Gkc+5k7KVTCmClX8Q10HCrUEkVlSX+XO33oQR9609tJ516H497WSobWs5Up6TLaS10/dessIskgJSLiDlWvHVUywpkQ7hdPZqGyiEF0uVQerVcPamT1A3eKXdyI1vG9OoflrSXihZ1qqGE3nhmAgiIbRCQgPLEPtOM3UQwTLYaYYomNlpA44opnjV6jkD6id80OOrzf6BzmMD6eEa1zKyeYG1fzfEf16V6jw9XYOaar1/b2kP/IYX8oR2mcFvv2GtBV3JXgd437AQAA) format("woff2-variations");unicode-range:U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-cyrillic-wght-normal.D73BlboJ.woff2) format("woff2-variations");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-greek-wght-normal.Bw9x6K1M.woff2) format("woff2-variations");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-vietnamese-wght-normal.Bt-aOZkq.woff2) format("woff2-variations");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-latin-ext-wght-normal.DBQx-q_a.woff2) format("woff2-variations");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-latin-wght-normal.B9CIFXIH.woff2) format("woff2-variations");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}:root{--background: 282 50% 4%;--foreground: 300 5% 91%;--card: 278 29% 11%;--card-foreground: 300 5% 91%;--popover: 278 29% 11%;--popover-foreground: 300 5% 91%;--border: 279 11% 24%;--input: 279 11% 24%;--primary: 269 2% 87%;--primary-foreground: 282 50% 4%;--secondary: 278 29% 11%;--secondary-foreground: 300 5% 91%;--muted: 278 29% 16%;--muted-foreground: 279 11% 60%;--accent: 278 24% 17%;--accent-foreground: 300 5% 91%;--state: 176 29% 57%;--state-foreground: 282 50% 4%;--destructive: 355 91% 74%;--destructive-foreground: 282 50% 4%;--success: 283 4% 66%;--warning: 28 100% 72%;--chart-1: 25 88% 68%;--chart-2: 82 55% 70%;--chart-3: 205 85% 72%;--chart-4: 265 75% 78%;--chart-5: 330 70% 72%;--surface-2: 278 24% 17%;--surface-3: 279 18% 21%;--surface-hover: 278 22% 23%;--surface-active: 279 16% 28%;--ring: 269 2% 87%;--link: 269 5% 78%;--radius: .5rem}:root[data-theme=light]{--background: 0 0% 98.8%;--foreground: 279 36% 8%;--card: 299 6% 97%;--card-foreground: 279 36% 8%;--popover: 299 6% 97%;--popover-foreground: 279 36% 8%;--border: 284 4% 82%;--input: 284 4% 82%;--primary: 279 36% 8%;--primary-foreground: 299 6% 97%;--secondary: 299 6% 97%;--secondary-foreground: 279 36% 8%;--muted: 299 3% 91%;--muted-foreground: 279 6% 39%;--accent: 299 3% 91%;--accent-foreground: 279 36% 8%;--state: 177 26% 39%;--state-foreground: 299 6% 97%;--destructive: 351 55% 53%;--destructive-foreground: 299 6% 97%;--success: 275 5% 47%;--warning: 20 36% 46%;--chart-1: 25 80% 38%;--chart-2: 82 65% 32%;--chart-3: 205 85% 37%;--chart-4: 265 65% 47%;--chart-5: 330 75% 41%;--surface-2: 299 3% 91%;--surface-3: 269 2% 87%;--surface-hover: 269 2% 87%;--surface-active: 269 5% 78%;--ring: 279 36% 8%;--link: 278 9% 31%;--radius: .5rem}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter Variable,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:JetBrains Mono Variable,ui-monospace,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}*{border-color:hsl(var(--border))}html{color-scheme:dark}html[data-theme=light]{color-scheme:light}body{background-color:hsl(var(--background));color:hsl(var(--foreground));font-family:Inter Variable,system-ui,sans-serif}code,pre,.font-mono{font-family:JetBrains Mono Variable,ui-monospace,monospace}.container{width:100%}@media (min-width: 640px){.container{max-width:640px}}@media (min-width: 768px){.container{max-width:768px}}@media (min-width: 1024px){.container{max-width:1024px}}@media (min-width: 1280px){.container{max-width:1280px}}@media (min-width: 1536px){.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.invisible{visibility:hidden}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.inset-x-0{left:0;right:0}.inset-x-3{left:.75rem;right:.75rem}.inset-y-0{top:0;bottom:0}.bottom-0{bottom:0}.bottom-1\.5{bottom:.375rem}.left-0{left:0}.left-\[50\%\]{left:50%}.right-0{right:0}.right-1\.5{right:.375rem}.right-2{right:.5rem}.right-4{right:1rem}.top-0{top:0}.top-2{top:.5rem}.top-3{top:.75rem}.top-4{top:1rem}.top-\[50\%\]{top:50%}.top-\[calc\(100\%\+4px\)\]{top:calc(100% + 4px)}.isolate{isolation:isolate}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.m-0{margin:0}.-mx-1{margin-left:-.25rem;margin-right:-.25rem}.-mx-4{margin-left:-1rem;margin-right:-1rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-0\.5{margin-top:.125rem;margin-bottom:.125rem}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-1\.5{margin-top:.375rem;margin-bottom:.375rem}.-ml-2{margin-left:-.5rem}.mb-0\.5{margin-bottom:.125rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.ml-0\.5{margin-left:.125rem}.ml-1{margin-left:.25rem}.ml-1\.5{margin-left:.375rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-\[18px\]{margin-left:18px}.ml-auto{margin-left:auto}.mr-1\.5{margin-right:.375rem}.mr-2{margin-right:.5rem}.mr-auto{margin-right:auto}.mt-0{margin-top:0}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-\[8vh\]{margin-top:8vh}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.table-cell{display:table-cell}.grid{display:grid}.contents{display:contents}.hidden{display:none}.aspect-square{aspect-ratio:1 / 1}.size-4{width:1rem;height:1rem}.size-\[--cell-size\]{width:var(--cell-size);height:var(--cell-size)}.h-0\.5{height:.125rem}.h-1\.5{height:.375rem}.h-10{height:2.5rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-40{height:10rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-\[--cell-size\]{height:var(--cell-size)}.h-\[11px\]{height:11px}.h-\[18px\]{height:18px}.h-\[26px\]{height:26px}.h-\[2px\]{height:2px}.h-\[7px\]{height:7px}.h-\[9px\]{height:9px}.h-\[var\(--radix-select-trigger-height\)\]{height:var(--radix-select-trigger-height)}.h-auto{height:auto}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.max-h-40{max-height:10rem}.max-h-48{max-height:12rem}.max-h-64{max-height:16rem}.max-h-80{max-height:20rem}.max-h-\[--radix-select-content-available-height\]{max-height:var(--radix-select-content-available-height)}.min-h-0{min-height:0px}.min-h-16{min-height:4rem}.min-h-20{min-height:5rem}.min-h-5{min-height:1.25rem}.min-h-\[1\.75rem\]{min-height:1.75rem}.min-h-\[36px\]{min-height:36px}.min-h-\[52px\]{min-height:52px}.min-h-full{min-height:100%}.min-h-screen{min-height:100vh}.w-0{width:0px}.w-1\.5{width:.375rem}.w-1\/3{width:33.333333%}.w-12{width:3rem}.w-2{width:.5rem}.w-2\.5{width:.625rem}.w-28{width:7rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-3\/4{width:75%}.w-4{width:1rem}.w-40{width:10rem}.w-44{width:11rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-5\/6{width:83.333333%}.w-56{width:14rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-7{width:1.75rem}.w-72{width:18rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-\[--cell-size\]{width:var(--cell-size)}.w-\[11px\]{width:11px}.w-\[18px\]{width:18px}.w-\[2px\]{width:2px}.w-\[300px\]{width:300px}.w-\[320px\]{width:320px}.w-\[7px\]{width:7px}.w-\[9px\]{width:9px}.w-auto{width:auto}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.w-px{width:1px}.min-w-0{min-width:0px}.min-w-\[--cell-size\]{min-width:var(--cell-size)}.min-w-\[240px\]{min-width:240px}.min-w-\[8rem\]{min-width:8rem}.min-w-\[var\(--radix-select-trigger-width\)\]{min-width:var(--radix-select-trigger-width)}.max-w-3xl{max-width:48rem}.max-w-6xl{max-width:72rem}.max-w-\[16rem\]{max-width:16rem}.max-w-\[420px\]{max-width:420px}.max-w-\[46\%\]{max-width:46%}.max-w-\[75\%\]{max-width:75%}.max-w-\[85\%\]{max-width:85%}.max-w-full{max-width:100%}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-sm{max-width:24rem}.max-w-xl{max-width:36rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.caption-bottom{caption-side:bottom}.border-collapse{border-collapse:collapse}.origin-\[--radix-popover-content-transform-origin\]{transform-origin:var(--radix-popover-content-transform-origin)}.origin-\[--radix-select-content-transform-origin\]{transform-origin:var(--radix-select-content-transform-origin)}.translate-x-\[-50\%\]{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-0\.5{--tw-translate-y: .125rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-\[-50\%\]{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-90{--tw-rotate: 90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes ap-flow{0%{background-position:-50% 0}to{background-position:150% 0}}.animate-ap-flow{animation:ap-flow 1.8s linear infinite}@keyframes ap-pulse-dot{0%,to{opacity:.5;transform:scale(.85)}50%{opacity:1;transform:scale(1.1)}}.animate-ap-pulse-dot{animation:ap-pulse-dot 1.4s ease-in-out infinite}@keyframes bounce{0%,to{transform:translateY(-25%);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{transform:none;animation-timing-function:cubic-bezier(0,0,.2,1)}}.animate-bounce{animation:bounce 1s infinite}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-help{cursor:help}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize-none{resize:none}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.list-none{list-style-type:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.items-stretch{align-items:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0{gap:0px}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.gap-\[3px\]{gap:3px}.gap-\[9px\]{gap:9px}.gap-x-1\.5{-moz-column-gap:.375rem;column-gap:.375rem}.gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.gap-x-6{-moz-column-gap:1.5rem;column-gap:1.5rem}.gap-y-2{row-gap:.5rem}.gap-y-3{row-gap:.75rem}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * var(--tw-space-y-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-2\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.625rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.625rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-border>:not([hidden])~:not([hidden]){border-color:hsl(var(--border))}.self-start{align-self:flex-start}.self-end{align-self:flex-end}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-visible{overflow:visible}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-x-hidden{overflow-x:hidden}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-normal{white-space:normal}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-line{white-space:pre-line}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-none{border-radius:0}.rounded-sm{border-radius:calc(var(--radius) - 4px)}.rounded-xl{border-radius:.75rem}.rounded-l-md{border-top-left-radius:calc(var(--radius) - 2px);border-bottom-left-radius:calc(var(--radius) - 2px)}.rounded-r-md{border-top-right-radius:calc(var(--radius) - 2px);border-bottom-right-radius:calc(var(--radius) - 2px)}.rounded-bl-sm{border-bottom-left-radius:calc(var(--radius) - 4px)}.rounded-br-sm{border-bottom-right-radius:calc(var(--radius) - 4px)}.border{border-width:1px}.border-0{border-width:0px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-l-2{border-left-width:2px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-\[hsl\(var\(--primary\)\)\]{border-color:hsl(var(--primary))}.border-border{border-color:hsl(var(--border))}.border-border\/40{border-color:hsl(var(--border) / .4)}.border-border\/50{border-color:hsl(var(--border) / .5)}.border-border\/60{border-color:hsl(var(--border) / .6)}.border-destructive{border-color:hsl(var(--destructive))}.border-destructive\/40{border-color:hsl(var(--destructive) / .4)}.border-destructive\/50{border-color:hsl(var(--destructive) / .5)}.border-input{border-color:hsl(var(--input))}.border-primary\/40{border-color:hsl(var(--primary) / .4)}.border-state\/40{border-color:hsl(var(--state) / .4)}.border-success{border-color:hsl(var(--success))}.border-success\/40{border-color:hsl(var(--success) / .4)}.border-success\/50{border-color:hsl(var(--success) / .5)}.border-transparent{border-color:transparent}.border-warning\/30{border-color:hsl(var(--warning) / .3)}.border-warning\/40{border-color:hsl(var(--warning) / .4)}.border-warning\/50{border-color:hsl(var(--warning) / .5)}.border-l-primary{border-left-color:hsl(var(--primary))}.border-l-warning{border-left-color:hsl(var(--warning))}.bg-\[hsl\(var\(--primary\)\)\]{background-color:hsl(var(--primary))}.bg-\[hsl\(var\(--success\)\)\]{background-color:hsl(var(--success))}.bg-\[hsl\(var\(--warning\)\)\]{background-color:hsl(var(--warning))}.bg-accent{background-color:hsl(var(--accent))}.bg-accent\/10{background-color:hsl(var(--accent) / .1)}.bg-accent\/60{background-color:hsl(var(--accent) / .6)}.bg-background{background-color:hsl(var(--background))}.bg-background\/40{background-color:hsl(var(--background) / .4)}.bg-background\/60{background-color:hsl(var(--background) / .6)}.bg-black\/80{background-color:#000c}.bg-border{background-color:hsl(var(--border))}.bg-card{background-color:hsl(var(--card))}.bg-card\/10{background-color:hsl(var(--card) / .1)}.bg-card\/20{background-color:hsl(var(--card) / .2)}.bg-card\/30{background-color:hsl(var(--card) / .3)}.bg-card\/40{background-color:hsl(var(--card) / .4)}.bg-card\/60{background-color:hsl(var(--card) / .6)}.bg-chart-1{background-color:hsl(var(--chart-1))}.bg-chart-2{background-color:hsl(var(--chart-2))}.bg-chart-3{background-color:hsl(var(--chart-3))}.bg-chart-4{background-color:hsl(var(--chart-4))}.bg-chart-5{background-color:hsl(var(--chart-5))}.bg-current{background-color:currentColor}.bg-destructive{background-color:hsl(var(--destructive))}.bg-destructive\/10{background-color:hsl(var(--destructive) / .1)}.bg-destructive\/5{background-color:hsl(var(--destructive) / .05)}.bg-muted{background-color:hsl(var(--muted))}.bg-muted-foreground{background-color:hsl(var(--muted-foreground))}.bg-muted-foreground\/40{background-color:hsl(var(--muted-foreground) / .4)}.bg-muted\/30{background-color:hsl(var(--muted) / .3)}.bg-muted\/40{background-color:hsl(var(--muted) / .4)}.bg-muted\/50{background-color:hsl(var(--muted) / .5)}.bg-muted\/60{background-color:hsl(var(--muted) / .6)}.bg-popover{background-color:hsl(var(--popover))}.bg-primary{background-color:hsl(var(--primary))}.bg-primary\/10{background-color:hsl(var(--primary) / .1)}.bg-primary\/15{background-color:hsl(var(--primary) / .15)}.bg-primary\/5{background-color:hsl(var(--primary) / .05)}.bg-secondary{background-color:hsl(var(--secondary))}.bg-secondary\/80{background-color:hsl(var(--secondary) / .8)}.bg-state{background-color:hsl(var(--state))}.bg-state\/15{background-color:hsl(var(--state) / .15)}.bg-state\/5,.bg-state\/\[0\.05\]{background-color:hsl(var(--state) / .05)}.bg-state\/\[0\.06\]{background-color:hsl(var(--state) / .06)}.bg-success{background-color:hsl(var(--success))}.bg-success\/10{background-color:hsl(var(--success) / .1)}.bg-success\/20{background-color:hsl(var(--success) / .2)}.bg-success\/5{background-color:hsl(var(--success) / .05)}.bg-success\/\[0\.08\]{background-color:hsl(var(--success) / .08)}.bg-surface-3{background-color:hsl(var(--surface-3))}.bg-surface-active{background-color:hsl(var(--surface-active))}.bg-transparent{background-color:transparent}.bg-warning{background-color:hsl(var(--warning))}.bg-warning\/10{background-color:hsl(var(--warning) / .1)}.bg-warning\/15{background-color:hsl(var(--warning) / .15)}.bg-warning\/5{background-color:hsl(var(--warning) / .05)}.bg-warning\/\[0\.08\]{background-color:hsl(var(--warning) / .08)}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-\[linear-gradient\(90deg\,transparent\,hsl\(var\(--success\)\)\,transparent\)\]{background-image:linear-gradient(90deg,transparent,hsl(var(--success)),transparent)}.bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.from-primary{--tw-gradient-from: hsl(var(--primary)) var(--tw-gradient-from-position);--tw-gradient-to: hsl(var(--primary) / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.via-state{--tw-gradient-to: hsl(var(--state) / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), hsl(var(--state)) var(--tw-gradient-via-position), var(--tw-gradient-to)}.to-primary{--tw-gradient-to: hsl(var(--primary)) var(--tw-gradient-to-position)}.bg-\[length\:200\%_100\%\]{background-size:200% 100%}.bg-\[length\:50\%_100\%\]{background-size:50% 100%}.p-0{padding:0}.p-0\.5{padding:.125rem}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-3\.5{padding-left:.875rem;padding-right:.875rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.px-\[--cell-size\]{padding-left:var(--cell-size);padding-right:var(--cell-size)}.px-\[7px\]{padding-left:7px;padding-right:7px}.py-0{padding-top:0;padding-bottom:0}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-3\.5{padding-top:.875rem;padding-bottom:.875rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-\[5px\]{padding-top:5px;padding-bottom:5px}.py-px{padding-top:1px;padding-bottom:1px}.pb-1{padding-bottom:.25rem}.pb-2{padding-bottom:.5rem}.pl-2{padding-left:.5rem}.pl-3{padding-left:.75rem}.pl-4{padding-left:1rem}.pl-5{padding-left:1.25rem}.pr-1{padding-right:.25rem}.pr-2{padding-right:.5rem}.pr-8{padding-right:2rem}.pr-9{padding-right:2.25rem}.pt-0{padding-top:0}.pt-2{padding-top:.5rem}.pt-4{padding-top:1rem}.pt-6{padding-top:1.5rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-top{vertical-align:top}.align-middle{vertical-align:middle}.font-mono{font-family:JetBrains Mono Variable,ui-monospace,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-\[0\.8rem\]{font-size:.8rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.capitalize{text-transform:capitalize}.normal-case{text-transform:none}.italic{font-style:italic}.ordinal{--tw-ordinal: ordinal;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.tabular-nums{--tw-numeric-spacing: tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-\[1\.25\]{line-height:1.25}.leading-\[1\.3\]{line-height:1.3}.leading-\[1\.45\]{line-height:1.45}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.leading-snug{line-height:1.375}.leading-tight{line-height:1.25}.tracking-normal{letter-spacing:0em}.tracking-tight{letter-spacing:-.025em}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.text-\[hsl\(var\(--destructive\)\)\]{color:hsl(var(--destructive))}.text-\[hsl\(var\(--primary\)\)\]{color:hsl(var(--primary))}.text-\[hsl\(var\(--primary-foreground\)\)\]{color:hsl(var(--primary-foreground))}.text-\[hsl\(var\(--success\)\)\]{color:hsl(var(--success))}.text-accent-foreground{color:hsl(var(--accent-foreground))}.text-card-foreground{color:hsl(var(--card-foreground))}.text-destructive{color:hsl(var(--destructive))}.text-destructive-foreground{color:hsl(var(--destructive-foreground))}.text-foreground{color:hsl(var(--foreground))}.text-foreground\/70{color:hsl(var(--foreground) / .7)}.text-foreground\/80{color:hsl(var(--foreground) / .8)}.text-foreground\/90{color:hsl(var(--foreground) / .9)}.text-inherit{color:inherit}.text-input{color:hsl(var(--input))}.text-link{color:hsl(var(--link))}.text-muted-foreground{color:hsl(var(--muted-foreground))}.text-muted-foreground\/50{color:hsl(var(--muted-foreground) / .5)}.text-muted-foreground\/60{color:hsl(var(--muted-foreground) / .6)}.text-muted-foreground\/70{color:hsl(var(--muted-foreground) / .7)}.text-popover-foreground{color:hsl(var(--popover-foreground))}.text-primary{color:hsl(var(--primary))}.text-primary-foreground{color:hsl(var(--primary-foreground))}.text-red-300\/90{color:#fca5a5e6}.text-secondary-foreground{color:hsl(var(--secondary-foreground))}.text-state{color:hsl(var(--state))}.text-success{color:hsl(var(--success))}.text-warning{color:hsl(var(--warning))}.underline{text-decoration-line:underline}.line-through{text-decoration-line:line-through}.no-underline{text-decoration-line:none}.decoration-link\/40{text-decoration-color:hsl(var(--link) / .4)}.decoration-muted-foreground\/60{text-decoration-color:hsl(var(--muted-foreground) / .6)}.decoration-dotted{text-decoration-style:dotted}.underline-offset-2{text-underline-offset:2px}.underline-offset-4{text-underline-offset:4px}.opacity-0{opacity:0}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[0_6px_20px_rgba\(0\,0\,0\,0\.55\)\]{--tw-shadow: 0 6px 20px rgba(0,0,0,.55);--tw-shadow-colored: 0 6px 20px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[inset_3px_0_0_hsl\(var\(--state\)\)\]{--tw-shadow: inset 3px 0 0 hsl(var(--state));--tw-shadow-colored: inset 3px 0 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.ring{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-1{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-2{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-inset{--tw-ring-inset: inset}.ring-\[hsl\(var\(--primary\)\)\]\/30{--tw-ring-color: hsl(var(--primary) / .3)}.ring-warning\/20{--tw-ring-color: hsl(var(--warning) / .2)}.ring-warning\/30{--tw-ring-color: hsl(var(--warning) / .3)}.ring-offset-background{--tw-ring-offset-color: hsl(var(--background))}.blur{--tw-blur: blur(8px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.invert{--tw-invert: invert(100%);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.sepia{--tw-sepia: sepia(100%);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\[width\]{transition-property:width;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-200{transition-duration:.2s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.\[--cell-size\:2rem\]{--cell-size: 2rem}.file\:border-0::file-selector-button{border-width:0px}.file\:bg-transparent::file-selector-button{background-color:transparent}.file\:text-sm::file-selector-button{font-size:.875rem;line-height:1.25rem}.file\:font-medium::file-selector-button{font-weight:500}.file\:text-foreground::file-selector-button{color:hsl(var(--foreground))}.placeholder\:text-muted-foreground::-moz-placeholder{color:hsl(var(--muted-foreground))}.placeholder\:text-muted-foreground::placeholder{color:hsl(var(--muted-foreground))}.before\:content-\[\'·_\'\]:before{--tw-content: "· ";content:var(--tw-content)}.last\:border-0:last-child{border-width:0px}.hover\:border-primary\/40:hover{border-color:hsl(var(--primary) / .4)}.hover\:border-primary\/50:hover{border-color:hsl(var(--primary) / .5)}.hover\:bg-accent:hover{background-color:hsl(var(--accent))}.hover\:bg-accent\/20:hover{background-color:hsl(var(--accent) / .2)}.hover\:bg-accent\/40:hover{background-color:hsl(var(--accent) / .4)}.hover\:bg-accent\/50:hover{background-color:hsl(var(--accent) / .5)}.hover\:bg-destructive\/80:hover{background-color:hsl(var(--destructive) / .8)}.hover\:bg-destructive\/90:hover{background-color:hsl(var(--destructive) / .9)}.hover\:bg-foreground\/5:hover{background-color:hsl(var(--foreground) / .05)}.hover\:bg-muted:hover{background-color:hsl(var(--muted))}.hover\:bg-muted\/40:hover{background-color:hsl(var(--muted) / .4)}.hover\:bg-muted\/50:hover{background-color:hsl(var(--muted) / .5)}.hover\:bg-primary\/80:hover{background-color:hsl(var(--primary) / .8)}.hover\:bg-primary\/90:hover{background-color:hsl(var(--primary) / .9)}.hover\:bg-secondary\/80:hover{background-color:hsl(var(--secondary) / .8)}.hover\:bg-surface-2:hover{background-color:hsl(var(--surface-2))}.hover\:text-accent-foreground:hover{color:hsl(var(--accent-foreground))}.hover\:text-foreground:hover{color:hsl(var(--foreground))}.hover\:text-link:hover{color:hsl(var(--link))}.hover\:text-primary:hover{color:hsl(var(--primary))}.hover\:underline:hover{text-decoration-line:underline}.hover\:no-underline:hover{text-decoration-line:none}.hover\:decoration-link:hover{text-decoration-color:hsl(var(--link))}.hover\:opacity-100:hover{opacity:1}.focus\:bg-accent:focus{background-color:hsl(var(--accent))}.focus\:text-accent-foreground:focus{color:hsl(var(--accent-foreground))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-1:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-ring:focus{--tw-ring-color: hsl(var(--ring))}.focus\:ring-offset-2:focus{--tw-ring-offset-width: 2px}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-1:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-ring:focus-visible{--tw-ring-color: hsl(var(--ring))}.focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width: 2px}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.group:focus-within .group-focus-within\:block{display:block}.group:hover .group-hover\:block{display:block}.group:hover .group-hover\:text-muted-foreground{color:hsl(var(--muted-foreground))}.peer:disabled~.peer-disabled\:cursor-not-allowed{cursor:not-allowed}.peer:disabled~.peer-disabled\:opacity-70{opacity:.7}.aria-disabled\:opacity-50[aria-disabled=true]{opacity:.5}.aria-selected\:text-muted-foreground[aria-selected=true]{color:hsl(var(--muted-foreground))}.data-\[disabled\]\:pointer-events-none[data-disabled]{pointer-events:none}.data-\[side\=bottom\]\:translate-y-1[data-side=bottom]{--tw-translate-y: .25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=left\]\:-translate-x-1[data-side=left]{--tw-translate-x: -.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=right\]\:translate-x-1[data-side=right]{--tw-translate-x: .25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=top\]\:-translate-y-1[data-side=top]{--tw-translate-y: -.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[range-end\=true\]\:rounded-md[data-range-end=true]{border-radius:calc(var(--radius) - 2px)}.data-\[range-middle\=true\]\:rounded-none[data-range-middle=true]{border-radius:0}.data-\[range-start\=true\]\:rounded-md[data-range-start=true]{border-radius:calc(var(--radius) - 2px)}.data-\[selected\=true\]\:rounded-none[data-selected=true]{border-radius:0}.data-\[range-end\=true\]\:bg-primary[data-range-end=true]{background-color:hsl(var(--primary))}.data-\[range-middle\=true\]\:bg-accent[data-range-middle=true]{background-color:hsl(var(--accent))}.data-\[range-start\=true\]\:bg-primary[data-range-start=true],.data-\[selected-single\=true\]\:bg-primary[data-selected-single=true]{background-color:hsl(var(--primary))}.data-\[state\=active\]\:bg-background[data-state=active]{background-color:hsl(var(--background))}.data-\[state\=active\]\:bg-muted[data-state=active]{background-color:hsl(var(--muted))}.data-\[state\=open\]\:bg-accent[data-state=open]{background-color:hsl(var(--accent))}.data-\[state\=open\]\:bg-secondary[data-state=open]{background-color:hsl(var(--secondary))}.data-\[state\=selected\]\:bg-muted[data-state=selected]{background-color:hsl(var(--muted))}.data-\[placeholder\]\:text-muted-foreground[data-placeholder]{color:hsl(var(--muted-foreground))}.data-\[range-end\=true\]\:text-primary-foreground[data-range-end=true]{color:hsl(var(--primary-foreground))}.data-\[range-middle\=true\]\:text-accent-foreground[data-range-middle=true]{color:hsl(var(--accent-foreground))}.data-\[range-start\=true\]\:text-primary-foreground[data-range-start=true],.data-\[selected-single\=true\]\:text-primary-foreground[data-selected-single=true]{color:hsl(var(--primary-foreground))}.data-\[state\=active\]\:text-foreground[data-state=active]{color:hsl(var(--foreground))}.data-\[state\=open\]\:text-muted-foreground[data-state=open]{color:hsl(var(--muted-foreground))}.data-\[disabled\]\:opacity-50[data-disabled]{opacity:.5}.data-\[state\=active\]\:shadow[data-state=active]{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.data-\[state\=closed\]\:duration-300[data-state=closed]{transition-duration:.3s}.data-\[state\=open\]\:duration-500[data-state=open]{transition-duration:.5s}.group\/day[data-focused=true] .group-data-\[focused\=true\]\/day\:relative{position:relative}.group\/day[data-focused=true] .group-data-\[focused\=true\]\/day\:z-10{z-index:10}.group\/day[data-focused=true] .group-data-\[focused\=true\]\/day\:border-ring{border-color:hsl(var(--ring))}.group\/day[data-focused=true] .group-data-\[focused\=true\]\/day\:ring-\[3px\]{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.group\/day[data-focused=true] .group-data-\[focused\=true\]\/day\:ring-ring\/50{--tw-ring-color: hsl(var(--ring) / .5)}@media (min-width: 640px){.sm\:inline{display:inline}.sm\:hidden{display:none}.sm\:max-w-sm{max-width:24rem}.sm\:max-w-xl{max-width:36rem}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:justify-end{justify-content:flex-end}.sm\:space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.sm\:rounded-lg{border-radius:var(--radius)}.sm\:text-left{text-align:left}}@media (min-width: 768px){.md\:sticky{position:sticky}.md\:top-4{top:1rem}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:grid-cols-\[220px_minmax\(0\,1fr\)\]{grid-template-columns:220px minmax(0,1fr)}.md\:flex-row{flex-direction:row}.md\:self-start{align-self:flex-start}.md\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width: 1024px){.lg\:col-span-2{grid-column:span 2 / span 2}.lg\:block{display:block}.lg\:w-48{width:12rem}.lg\:w-60{width:15rem}.lg\:shrink-0{flex-shrink:0}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:flex-row{flex-direction:row}.lg\:gap-6{gap:1.5rem}.lg\:space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.lg\:px-6{padding-left:1.5rem;padding-right:1.5rem}.lg\:py-5{padding-top:1.25rem;padding-bottom:1.25rem}}@media (min-width: 1280px){.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.xl\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}}@media (prefers-color-scheme: dark){.dark\:border-destructive{border-color:hsl(var(--destructive))}}.\[\&\:\:-webkit-details-marker\]\:hidden::-webkit-details-marker{display:none}.\[\&\:first-child\[data-selected\=true\]_button\]\:rounded-l-md:first-child[data-selected=true] button{border-top-left-radius:calc(var(--radius) - 2px);border-bottom-left-radius:calc(var(--radius) - 2px)}.\[\&\:has\(\[role\=checkbox\]\)\]\:pr-0:has([role=checkbox]){padding-right:0}.\[\&\:last-child\[data-selected\=true\]_button\]\:rounded-r-md:last-child[data-selected=true] button{border-top-right-radius:calc(var(--radius) - 2px);border-bottom-right-radius:calc(var(--radius) - 2px)}.\[\&\>\*\:first-child\]\:mt-0>*:first-child{margin-top:0}.\[\&\>\*\:last-child\]\:mb-0>*:last-child{margin-bottom:0}.\[\&\>\[role\=checkbox\]\]\:translate-y-\[2px\]>[role=checkbox]{--tw-translate-y: 2px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.\[\&\>span\]\:line-clamp-1>span{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1}.\[\&\>span\]\:text-xs>span{font-size:.75rem;line-height:1rem}.\[\&\>span\]\:opacity-70>span{opacity:.7}.\[\&\>svg\+div\]\:translate-y-\[-3px\]>svg+div{--tw-translate-y: -3px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.\[\&\>svg\]\:absolute>svg{position:absolute}.\[\&\>svg\]\:left-4>svg{left:1rem}.\[\&\>svg\]\:top-4>svg{top:1rem}.\[\&\>svg\]\:size-3\.5>svg{width:.875rem;height:.875rem}.\[\&\>svg\]\:text-destructive>svg{color:hsl(var(--destructive))}.\[\&\>svg\]\:text-foreground>svg{color:hsl(var(--foreground))}.\[\&\>svg\]\:text-muted-foreground>svg{color:hsl(var(--muted-foreground))}.\[\&\>svg\]\:text-warning>svg{color:hsl(var(--warning))}.\[\&\>svg\~\*\]\:pl-7>svg~*{padding-left:1.75rem}.\[\&\>tr\]\:last\:border-b-0:last-child>tr{border-bottom-width:0px}.\[\&_\:not\(pre\)\>code\]\:rounded :not(pre)>code{border-radius:.25rem}.\[\&_\:not\(pre\)\>code\]\:bg-black\/10 :not(pre)>code{background-color:#0000001a}.\[\&_\:not\(pre\)\>code\]\:px-1 :not(pre)>code{padding-left:.25rem;padding-right:.25rem}.\[\&_\:not\(pre\)\>code\]\:py-0\.5 :not(pre)>code{padding-top:.125rem;padding-bottom:.125rem}.\[\&_\:not\(pre\)\>code\]\:font-mono :not(pre)>code{font-family:JetBrains Mono Variable,ui-monospace,monospace}.\[\&_\:not\(pre\)\>code\]\:text-\[0\.85em\] :not(pre)>code{font-size:.85em}@media (prefers-color-scheme: dark){.dark\:\[\&_\:not\(pre\)\>code\]\:bg-white\/15 :not(pre)>code{background-color:#ffffff26}}.\[\&_a\]\:underline a{text-decoration-line:underline}.\[\&_a\]\:underline-offset-2 a{text-underline-offset:2px}.hover\:\[\&_a\]\:no-underline a:hover{text-decoration-line:none}.\[\&_blockquote\]\:my-1\.5 blockquote{margin-top:.375rem;margin-bottom:.375rem}.\[\&_blockquote\]\:border-l-2 blockquote{border-left-width:2px}.\[\&_blockquote\]\:border-border blockquote{border-color:hsl(var(--border))}.\[\&_blockquote\]\:pl-2\.5 blockquote{padding-left:.625rem}.\[\&_blockquote\]\:text-muted-foreground blockquote{color:hsl(var(--muted-foreground))}.\[\&_h1\]\:mb-1\.5 h1{margin-bottom:.375rem}.\[\&_h1\]\:mt-2 h1{margin-top:.5rem}.\[\&_h1\]\:text-base h1{font-size:1rem;line-height:1.5rem}.\[\&_h1\]\:font-semibold h1{font-weight:600}.\[\&_h2\]\:mb-1\.5 h2{margin-bottom:.375rem}.\[\&_h2\]\:mt-2 h2{margin-top:.5rem}.\[\&_h2\]\:text-\[0\.95rem\] h2{font-size:.95rem}.\[\&_h2\]\:font-semibold h2{font-weight:600}.\[\&_h3\]\:mb-1 h3{margin-bottom:.25rem}.\[\&_h3\]\:mt-2 h3{margin-top:.5rem}.\[\&_h3\]\:font-semibold h3{font-weight:600}.\[\&_hr\]\:my-2 hr{margin-top:.5rem;margin-bottom:.5rem}.\[\&_hr\]\:border-border hr{border-color:hsl(var(--border))}.\[\&_li\]\:my-0\.5 li{margin-top:.125rem;margin-bottom:.125rem}.\[\&_ol\]\:my-1\.5 ol{margin-top:.375rem;margin-bottom:.375rem}.\[\&_ol\]\:list-decimal ol{list-style-type:decimal}.\[\&_ol\]\:pl-5 ol{padding-left:1.25rem}.\[\&_p\]\:my-1\.5 p{margin-top:.375rem;margin-bottom:.375rem}.\[\&_p\]\:leading-relaxed p{line-height:1.625}.\[\&_pre\]\:my-1\.5 pre{margin-top:.375rem;margin-bottom:.375rem}.\[\&_pre\]\:overflow-x-auto pre{overflow-x:auto}.\[\&_pre\]\:rounded-md pre{border-radius:calc(var(--radius) - 2px)}.\[\&_pre\]\:bg-black\/10 pre{background-color:#0000001a}.\[\&_pre\]\:p-2\.5 pre{padding:.625rem}.\[\&_pre\]\:text-\[0\.8rem\] pre{font-size:.8rem}@media (prefers-color-scheme: dark){.dark\:\[\&_pre\]\:bg-white\/10 pre{background-color:#ffffff1a}}.\[\&_pre_code\]\:whitespace-pre pre code{white-space:pre}.\[\&_pre_code\]\:font-mono pre code{font-family:JetBrains Mono Variable,ui-monospace,monospace}.\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.\[\&_svg\]\:size-4 svg{width:1rem;height:1rem}.\[\&_svg\]\:shrink-0 svg{flex-shrink:0}.\[\&_table\]\:w-full table{width:100%}.\[\&_table\]\:border-collapse table{border-collapse:collapse}.\[\&_table\]\:text-xs table{font-size:.75rem;line-height:1rem}.\[\&_td\]\:border td{border-width:1px}.\[\&_td\]\:border-border td{border-color:hsl(var(--border))}.\[\&_td\]\:px-2 td{padding-left:.5rem;padding-right:.5rem}.\[\&_td\]\:py-1 td{padding-top:.25rem;padding-bottom:.25rem}.\[\&_td\]\:align-top td{vertical-align:top}.\[\&_th\]\:border th{border-width:1px}.\[\&_th\]\:border-border th{border-color:hsl(var(--border))}.\[\&_th\]\:bg-muted th{background-color:hsl(var(--muted))}.\[\&_th\]\:px-2 th{padding-left:.5rem;padding-right:.5rem}.\[\&_th\]\:py-1 th{padding-top:.25rem;padding-bottom:.25rem}.\[\&_th\]\:text-left th{text-align:left}.\[\&_th\]\:font-semibold th{font-weight:600}.\[\&_tr\:last-child\]\:border-0 tr:last-child{border-width:0px}.\[\&_tr\]\:border-b tr{border-bottom-width:1px}.\[\&_ul\]\:my-1\.5 ul{margin-top:.375rem;margin-bottom:.375rem}.\[\&_ul\]\:list-disc ul{list-style-type:disc}.\[\&_ul\]\:pl-5 ul{padding-left:1.25rem}[data-slot=card-content] .\[\[data-slot\=card-content\]_\&\]\:bg-transparent,[data-slot=popover-content] .\[\[data-slot\=popover-content\]_\&\]\:bg-transparent{background-color:transparent} +@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/inter-cyrillic-ext-wght-normal.BOeWTOD4.woff2) format("woff2-variations");unicode-range:U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/inter-cyrillic-wght-normal.DqGufNeO.woff2) format("woff2-variations");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/inter-greek-ext-wght-normal.DlzME5K_.woff2) format("woff2-variations");unicode-range:U+1F00-1FFF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/inter-greek-wght-normal.CkhJZR-_.woff2) format("woff2-variations");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/inter-vietnamese-wght-normal.CBcvBZtf.woff2) format("woff2-variations");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/inter-latin-ext-wght-normal.DO1Apj_S.woff2) format("woff2-variations");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(/assets/inter-latin-wght-normal.Dx4kXJAl.woff2) format("woff2-variations");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(data:font/woff2;base64,d09GMgABAAAAAAfsABQAAAAAEAwAAAeCAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGhwbHhwoP0hWQVJbBmA/U1RBVIFiJyYAdC9qEQgKhGSEAAsgADCGCAE2AiQDOgQgBYlMB4EUDAcbLQ4onoexrSC/2ZyLAa8p8VHB8/x3Vue+V0hVJalMJg2nx/TCrQXxBeqLjQG7FyM1WEa/X1tEXN7cFz9EJEMmMUz3RihWSSKeQCbcIou0izz/C8v+fq3VfajEa9gDD11CImXS7qL/RJFVzC1qiB6KmKeD6TZdQ6IRGv78dL6uSVVCfgni5mzu7kcgQBgAEAQTQRCoL++STTYybkJxNfQxAAIAGu8OdEB9teW2jh4BpgDqFjAeSEByW3zFP0CBBgNMsMCGEDjgggdhiEAUAeIIED7ABTDUEnkIE9Q9ahFgKttcVhApo4ACB4qobHaccgDfEjFO6aaWUhjMLt2SyIvHKoDqoA4CSUwEIYQCEjhAO9R1G6keDeDZGjNo+AhxOjCEGTr1WeIF3kYBiLAOKvkJSMiKX0VdAyQt3SDJClCkxJCHkCzfqyVTriJZLcolS32JZHUekq2TYNkYtCtjYHMQXSxGjXDz2t/yLWXzDzxz+o3zFwDEaN23F+13pyMdQAEaSKAR9vcGq4A4MTSKCElGW+M7UcY7xqkggITb28ZJhlqc9q2twYKTt0NjixBgYvO9BIihEBLYuOFXQzfIQ7dXGUEEEgFDooBfAzqiQbpJrhiWSuKJCRFKYbHCyJKI2G5GiZbNAvgAu5pc3vwx4G+g3aDkhklABiSz0BICXrYghtYhx/cdJ+44rY2oZ0aMNRFz3VZjb6W33F3gzltqtOCV8tTHSpOeXuItfvr5lCdfzFpqtEitvqdcdGGFd28ZqqC0tPbeChGXgrIlnhSWu/eUso4uKWFLugyDzQJhflY4659+WjQ++6x72WUMv9G8mw6QJl7BVxX5fe/kpUsOvnZwee9uQ0cGXYd0o89XB2748sDSnt8d2VphdOTTgceDVvOds0v9P/s7HPq15aGun/6Vllb56f1dl0t1LejqrNkpdRZsG8TOnM5vkBG5oiVyVGnS8LHps5cfNWJs6qKPfaNSxiQNBUm3cKNWROr0GSur7Za31k1vieq7LH11VF+jXdRIasRKflc7jkobm1Z9te1IyZA0pDkhLR98+H37Zf1c/8at+dB7x+7GfVyTfJMPiYztsnl59Y5l4j+0n1RXlpHnF3Tq7HecmNF/CJodEMAikruxiyJaGLvHOdAfoA+oDvpjBm2b91cHGRZMU9n25xEU0A8fgEEAdKI3Q1iDtc034sug5YVMkE2jsE+BIkwSoQ3gxXMqz9tELp48bd0cFKOKS7xYjEuXBnZP5ia7DyiO/X/YI+PQSbt2uSdqAkWL9nQbV1XB94/+uPfdZz8dnXYFBYrcTl2SIR/ybxJNJPz/Gupb0JaZeens2ekC7EKr8t+Ls/P5VJPYJdHKyqfg2nqU6bhlidzcddQV/7MmecTzJ5VPcKXkNKSEogHjYFx6QZ7rQ+FSe8njaiNuOnXS8H2ScQ619c2mC3VTtauL0rRbXd/CkSOP37FY9Zkjz8+GibYUMOEWF+RdrFS8Ecv1SHOpPUPZGEIpjPvFyU5cXKjd6OXqorTqy9GwRd++HVufPGnVsW+aO3vggKZ18jR9sXaTC1PWTEsVUaK0FkNySbTQDqlm2PfDjZcu4aalnSLKjnOoYQ0nUlqqXcGpPu/4VgV/xU2pAqW4BW3qzhQ8/hFKhV2qE3+BKAtDqBXjfgnVdH4y0wg5tbVNRenNdTWOrenWLcupQdmsbq5b+18piTe/xRdp1xbILxNPJGInm2z6hoB21Lal0i+ePTtd7B45+3XhFJ329evskXm7qurUVREotqSluSo/L29d3qDhI4YOQqWhI4YNvBNfsMHeXKemXrxQfKeuPOGRVayA3JtkJKEgbPp+dXUDluddutRYLFoXGXWX6N3WFaGLbQtRSitVYNacTNSdy7AaG/HSaUEANcBoGXNdcZvZsOqQ1icBDv21/gzAoYPHH/WDW0qNR3QTYKEAEHig6o13NXbND06CQPlRtYjGNnSktRc09k1mAMDvAlDKfQjgy6fssInlfzmNAjKkDxoxHOBLdVRAIVt9j4qo+hA1w9T1aNBNTUOTTNUHLbqokE+UAfJXCIGw/IxCSL5GRUJeR40rL/UxTm4Q08H6MbCs70ObuNyIIXrINHQYInF06UUlevTjbQzTh5upiDMzMMogUtEnjPs/Y7jAHCJeB0GBHh04tC6FiB6ZFB1oArUSIoFoqhzCeAN6lHwm0T4C3VVPWvjpSMXReuWesMEcoqrmgtNBGd2noWeV0hNAz9rFeShNJxHGsPa3HXeKTk8b55hahySYHaYKKFFLpCfN8rsoaJn01CR04Gkc+5k7KVTCmClX8Q10HCrUEkVlSX+XO33oQR9609tJ516H497WSobWs5Up6TLaS10/dessIskgJSLiDlWvHVUywpkQ7hdPZqGyiEF0uVQerVcPamT1A3eKXdyI1vG9OoflrSXihZ1qqGE3nhmAgiIbRCQgPLEPtOM3UQwTLYaYYomNlpA44opnjV6jkD6id80OOrzf6BzmMD6eEa1zKyeYG1fzfEf16V6jw9XYOaar1/b2kP/IYX8oR2mcFvv2GtBV3JXgd437AQAA) format("woff2-variations");unicode-range:U+0460-052F,U+1C80-1C8A,U+20B4,U+2DE0-2DFF,U+A640-A69F,U+FE2E-FE2F}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-cyrillic-wght-normal.D73BlboJ.woff2) format("woff2-variations");unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-greek-wght-normal.Bw9x6K1M.woff2) format("woff2-variations");unicode-range:U+0370-0377,U+037A-037F,U+0384-038A,U+038C,U+038E-03A1,U+03A3-03FF}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-vietnamese-wght-normal.Bt-aOZkq.woff2) format("woff2-variations");unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-latin-ext-wght-normal.DBQx-q_a.woff2) format("woff2-variations");unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}@font-face{font-family:JetBrains Mono Variable;font-style:normal;font-display:swap;font-weight:100 800;src:url(/assets/jetbrains-mono-latin-wght-normal.B9CIFXIH.woff2) format("woff2-variations");unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}:root{--background: 282 50% 4%;--foreground: 300 5% 91%;--card: 278 29% 11%;--card-foreground: 300 5% 91%;--popover: 278 29% 11%;--popover-foreground: 300 5% 91%;--border: 279 11% 24%;--input: 279 11% 24%;--primary: 269 2% 87%;--primary-foreground: 282 50% 4%;--secondary: 278 29% 11%;--secondary-foreground: 300 5% 91%;--muted: 278 29% 16%;--muted-foreground: 279 11% 60%;--accent: 278 24% 17%;--accent-foreground: 300 5% 91%;--state: 176 29% 57%;--state-foreground: 282 50% 4%;--destructive: 355 91% 74%;--destructive-foreground: 282 50% 4%;--success: 283 4% 66%;--warning: 28 100% 72%;--chart-1: 25 88% 68%;--chart-2: 82 55% 70%;--chart-3: 205 85% 72%;--chart-4: 265 75% 78%;--chart-5: 330 70% 72%;--surface-2: 278 24% 17%;--surface-3: 279 18% 21%;--surface-hover: 278 22% 23%;--surface-active: 279 16% 28%;--ring: 269 2% 87%;--link: 269 5% 78%;--radius: .5rem}:root[data-theme=light]{--background: 0 0% 98.8%;--foreground: 279 36% 8%;--card: 299 6% 97%;--card-foreground: 279 36% 8%;--popover: 299 6% 97%;--popover-foreground: 279 36% 8%;--border: 284 4% 82%;--input: 284 4% 82%;--primary: 279 36% 8%;--primary-foreground: 299 6% 97%;--secondary: 299 6% 97%;--secondary-foreground: 279 36% 8%;--muted: 299 3% 91%;--muted-foreground: 279 6% 39%;--accent: 299 3% 91%;--accent-foreground: 279 36% 8%;--state: 177 26% 39%;--state-foreground: 299 6% 97%;--destructive: 351 55% 53%;--destructive-foreground: 299 6% 97%;--success: 275 5% 47%;--warning: 20 36% 46%;--chart-1: 25 80% 38%;--chart-2: 82 65% 32%;--chart-3: 205 85% 37%;--chart-4: 265 65% 47%;--chart-5: 330 75% 41%;--surface-2: 299 3% 91%;--surface-3: 269 2% 87%;--surface-hover: 269 2% 87%;--surface-active: 269 5% 78%;--ring: 279 36% 8%;--link: 278 9% 31%;--radius: .5rem}*,:before,:after{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x: 0;--tw-border-spacing-y: 0;--tw-translate-x: 0;--tw-translate-y: 0;--tw-rotate: 0;--tw-skew-x: 0;--tw-skew-y: 0;--tw-scale-x: 1;--tw-scale-y: 1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness: proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width: 0px;--tw-ring-offset-color: #fff;--tw-ring-color: rgb(59 130 246 / .5);--tw-ring-offset-shadow: 0 0 #0000;--tw-ring-shadow: 0 0 #0000;--tw-shadow: 0 0 #0000;--tw-shadow-colored: 0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content: ""}html,:host{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:Inter Variable,system-ui,sans-serif;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:JetBrains Mono Variable,ui-monospace,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dl,dd,h1,h2,h3,h4,h5,h6,hr,figure,p,pre{margin:0}fieldset{margin:0;padding:0}legend{padding:0}ol,ul,menu{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}button,[role=button]{cursor:pointer}:disabled{cursor:default}img,svg,video,canvas,audio,iframe,embed,object{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}*{border-color:hsl(var(--border))}html{color-scheme:dark}html[data-theme=light]{color-scheme:light}body{background-color:hsl(var(--background));color:hsl(var(--foreground));font-family:Inter Variable,system-ui,sans-serif}code,pre,.font-mono{font-family:JetBrains Mono Variable,ui-monospace,monospace}.container{width:100%}@media (min-width: 640px){.container{max-width:640px}}@media (min-width: 768px){.container{max-width:768px}}@media (min-width: 1024px){.container{max-width:1024px}}@media (min-width: 1280px){.container{max-width:1280px}}@media (min-width: 1536px){.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.invisible{visibility:hidden}.collapse{visibility:collapse}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{top:0;right:0;bottom:0;left:0}.inset-x-0{left:0;right:0}.inset-x-3{left:.75rem;right:.75rem}.inset-y-0{top:0;bottom:0}.bottom-0{bottom:0}.bottom-1\.5{bottom:.375rem}.left-0{left:0}.left-\[50\%\]{left:50%}.right-0{right:0}.right-1\.5{right:.375rem}.right-2{right:.5rem}.right-4{right:1rem}.top-0{top:0}.top-2{top:.5rem}.top-3{top:.75rem}.top-4{top:1rem}.top-\[50\%\]{top:50%}.top-\[calc\(100\%\+4px\)\]{top:calc(100% + 4px)}.isolate{isolation:isolate}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.m-0{margin:0}.-mx-1{margin-left:-.25rem;margin-right:-.25rem}.-mx-4{margin-left:-1rem;margin-right:-1rem}.mx-2{margin-left:.5rem;margin-right:.5rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-0\.5{margin-top:.125rem;margin-bottom:.125rem}.my-1{margin-top:.25rem;margin-bottom:.25rem}.my-1\.5{margin-top:.375rem;margin-bottom:.375rem}.-ml-2{margin-left:-.5rem}.mb-0\.5{margin-bottom:.125rem}.mb-1{margin-bottom:.25rem}.mb-1\.5{margin-bottom:.375rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.ml-0\.5{margin-left:.125rem}.ml-1{margin-left:.25rem}.ml-1\.5{margin-left:.375rem}.ml-2{margin-left:.5rem}.ml-3{margin-left:.75rem}.ml-\[18px\]{margin-left:18px}.ml-auto{margin-left:auto}.mr-1\.5{margin-right:.375rem}.mr-2{margin-right:.5rem}.mr-auto{margin-right:auto}.mt-0{margin-top:0}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-\[8vh\]{margin-top:8vh}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.table-cell{display:table-cell}.grid{display:grid}.contents{display:contents}.hidden{display:none}.aspect-square{aspect-ratio:1 / 1}.size-4{width:1rem;height:1rem}.size-\[--cell-size\]{width:var(--cell-size);height:var(--cell-size)}.h-0\.5{height:.125rem}.h-1\.5{height:.375rem}.h-10{height:2.5rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-3{height:.75rem}.h-3\.5{height:.875rem}.h-4{height:1rem}.h-40{height:10rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-9{height:2.25rem}.h-\[--cell-size\]{height:var(--cell-size)}.h-\[11px\]{height:11px}.h-\[18px\]{height:18px}.h-\[26px\]{height:26px}.h-\[2px\]{height:2px}.h-\[7px\]{height:7px}.h-\[9px\]{height:9px}.h-\[var\(--radix-select-trigger-height\)\]{height:var(--radix-select-trigger-height)}.h-auto{height:auto}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.max-h-40{max-height:10rem}.max-h-48{max-height:12rem}.max-h-64{max-height:16rem}.max-h-80{max-height:20rem}.max-h-\[--radix-select-content-available-height\]{max-height:var(--radix-select-content-available-height)}.min-h-0{min-height:0px}.min-h-16{min-height:4rem}.min-h-20{min-height:5rem}.min-h-5{min-height:1.25rem}.min-h-\[1\.75rem\]{min-height:1.75rem}.min-h-\[36px\]{min-height:36px}.min-h-\[52px\]{min-height:52px}.min-h-full{min-height:100%}.min-h-screen{min-height:100vh}.w-0{width:0px}.w-1\.5{width:.375rem}.w-1\/3{width:33.333333%}.w-12{width:3rem}.w-2{width:.5rem}.w-2\.5{width:.625rem}.w-28{width:7rem}.w-3{width:.75rem}.w-3\.5{width:.875rem}.w-3\/4{width:75%}.w-4{width:1rem}.w-40{width:10rem}.w-44{width:11rem}.w-48{width:12rem}.w-5{width:1.25rem}.w-5\/6{width:83.333333%}.w-56{width:14rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-7{width:1.75rem}.w-72{width:18rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-\[--cell-size\]{width:var(--cell-size)}.w-\[11px\]{width:11px}.w-\[18px\]{width:18px}.w-\[2px\]{width:2px}.w-\[300px\]{width:300px}.w-\[320px\]{width:320px}.w-\[7px\]{width:7px}.w-\[9px\]{width:9px}.w-auto{width:auto}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.w-px{width:1px}.min-w-0{min-width:0px}.min-w-\[--cell-size\]{min-width:var(--cell-size)}.min-w-\[240px\]{min-width:240px}.min-w-\[8rem\]{min-width:8rem}.min-w-\[var\(--radix-select-trigger-width\)\]{min-width:var(--radix-select-trigger-width)}.max-w-3xl{max-width:48rem}.max-w-6xl{max-width:72rem}.max-w-\[16rem\]{max-width:16rem}.max-w-\[420px\]{max-width:420px}.max-w-\[46\%\]{max-width:46%}.max-w-\[75\%\]{max-width:75%}.max-w-\[85\%\]{max-width:85%}.max-w-full{max-width:100%}.max-w-lg{max-width:32rem}.max-w-md{max-width:28rem}.max-w-sm{max-width:24rem}.max-w-xl{max-width:36rem}.max-w-xs{max-width:20rem}.flex-1{flex:1 1 0%}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.caption-bottom{caption-side:bottom}.border-collapse{border-collapse:collapse}.origin-\[--radix-popover-content-transform-origin\]{transform-origin:var(--radix-popover-content-transform-origin)}.origin-\[--radix-select-content-transform-origin\]{transform-origin:var(--radix-select-content-transform-origin)}.translate-x-\[-50\%\]{--tw-translate-x: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-0\.5{--tw-translate-y: .125rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-\[-50\%\]{--tw-translate-y: -50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-180{--tw-rotate: 180deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.rotate-90{--tw-rotate: 90deg;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes ap-flow{0%{background-position:-50% 0}to{background-position:150% 0}}.animate-ap-flow{animation:ap-flow 1.8s linear infinite}@keyframes ap-pulse-dot{0%,to{opacity:.5;transform:scale(.85)}50%{opacity:1;transform:scale(1.1)}}.animate-ap-pulse-dot{animation:ap-pulse-dot 1.4s ease-in-out infinite}@keyframes bounce{0%,to{transform:translateY(-25%);animation-timing-function:cubic-bezier(.8,0,1,1)}50%{transform:none;animation-timing-function:cubic-bezier(0,0,.2,1)}}.animate-bounce{animation:bounce 1s infinite}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(360deg)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-help{cursor:help}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize-none{resize:none}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.list-none{list-style-type:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.items-baseline{align-items:baseline}.items-stretch{align-items:stretch}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0{gap:0px}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-2\.5{gap:.625rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-5{gap:1.25rem}.gap-6{gap:1.5rem}.gap-8{gap:2rem}.gap-\[3px\]{gap:3px}.gap-\[9px\]{gap:9px}.gap-x-1\.5{-moz-column-gap:.375rem;column-gap:.375rem}.gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.gap-x-6{-moz-column-gap:1.5rem;column-gap:1.5rem}.gap-y-2{row-gap:.5rem}.gap-y-3{row-gap:.75rem}.space-y-0\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.125rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.125rem * var(--tw-space-y-reverse))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.25rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem * var(--tw-space-y-reverse))}.space-y-1\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.375rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.375rem * var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.5rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem * var(--tw-space-y-reverse))}.space-y-2\.5>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.625rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.625rem * var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(.75rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem * var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse: 0;border-top-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px * var(--tw-divide-y-reverse))}.divide-border>:not([hidden])~:not([hidden]){border-color:hsl(var(--border))}.self-start{align-self:flex-start}.self-end{align-self:flex-end}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-visible{overflow:visible}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-x-hidden{overflow-x:hidden}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.whitespace-normal{white-space:normal}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-line{white-space:pre-line}.whitespace-pre-wrap{white-space:pre-wrap}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:var(--radius)}.rounded-md{border-radius:calc(var(--radius) - 2px)}.rounded-none{border-radius:0}.rounded-sm{border-radius:calc(var(--radius) - 4px)}.rounded-xl{border-radius:.75rem}.rounded-l-md{border-top-left-radius:calc(var(--radius) - 2px);border-bottom-left-radius:calc(var(--radius) - 2px)}.rounded-r-md{border-top-right-radius:calc(var(--radius) - 2px);border-bottom-right-radius:calc(var(--radius) - 2px)}.rounded-bl-sm{border-bottom-left-radius:calc(var(--radius) - 4px)}.rounded-br-sm{border-bottom-right-radius:calc(var(--radius) - 4px)}.border{border-width:1px}.border-0{border-width:0px}.border-b{border-bottom-width:1px}.border-l{border-left-width:1px}.border-l-2{border-left-width:2px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-dashed{border-style:dashed}.border-\[hsl\(var\(--primary\)\)\]{border-color:hsl(var(--primary))}.border-border{border-color:hsl(var(--border))}.border-border\/40{border-color:hsl(var(--border) / .4)}.border-border\/50{border-color:hsl(var(--border) / .5)}.border-border\/60{border-color:hsl(var(--border) / .6)}.border-destructive{border-color:hsl(var(--destructive))}.border-destructive\/40{border-color:hsl(var(--destructive) / .4)}.border-destructive\/50{border-color:hsl(var(--destructive) / .5)}.border-input{border-color:hsl(var(--input))}.border-primary\/40{border-color:hsl(var(--primary) / .4)}.border-state\/40{border-color:hsl(var(--state) / .4)}.border-success{border-color:hsl(var(--success))}.border-success\/40{border-color:hsl(var(--success) / .4)}.border-success\/50{border-color:hsl(var(--success) / .5)}.border-transparent{border-color:transparent}.border-warning\/30{border-color:hsl(var(--warning) / .3)}.border-warning\/40{border-color:hsl(var(--warning) / .4)}.border-warning\/50{border-color:hsl(var(--warning) / .5)}.border-l-primary{border-left-color:hsl(var(--primary))}.border-l-warning{border-left-color:hsl(var(--warning))}.bg-\[hsl\(var\(--primary\)\)\]{background-color:hsl(var(--primary))}.bg-\[hsl\(var\(--success\)\)\]{background-color:hsl(var(--success))}.bg-\[hsl\(var\(--warning\)\)\]{background-color:hsl(var(--warning))}.bg-accent{background-color:hsl(var(--accent))}.bg-accent\/10{background-color:hsl(var(--accent) / .1)}.bg-accent\/60{background-color:hsl(var(--accent) / .6)}.bg-background{background-color:hsl(var(--background))}.bg-background\/40{background-color:hsl(var(--background) / .4)}.bg-background\/60{background-color:hsl(var(--background) / .6)}.bg-black\/80{background-color:#000c}.bg-border{background-color:hsl(var(--border))}.bg-card{background-color:hsl(var(--card))}.bg-card\/10{background-color:hsl(var(--card) / .1)}.bg-card\/20{background-color:hsl(var(--card) / .2)}.bg-card\/30{background-color:hsl(var(--card) / .3)}.bg-card\/40{background-color:hsl(var(--card) / .4)}.bg-card\/60{background-color:hsl(var(--card) / .6)}.bg-chart-1{background-color:hsl(var(--chart-1))}.bg-chart-2{background-color:hsl(var(--chart-2))}.bg-chart-3{background-color:hsl(var(--chart-3))}.bg-chart-4{background-color:hsl(var(--chart-4))}.bg-chart-5{background-color:hsl(var(--chart-5))}.bg-current{background-color:currentColor}.bg-destructive{background-color:hsl(var(--destructive))}.bg-destructive\/10{background-color:hsl(var(--destructive) / .1)}.bg-destructive\/5{background-color:hsl(var(--destructive) / .05)}.bg-muted{background-color:hsl(var(--muted))}.bg-muted-foreground{background-color:hsl(var(--muted-foreground))}.bg-muted-foreground\/40{background-color:hsl(var(--muted-foreground) / .4)}.bg-muted\/30{background-color:hsl(var(--muted) / .3)}.bg-muted\/40{background-color:hsl(var(--muted) / .4)}.bg-muted\/50{background-color:hsl(var(--muted) / .5)}.bg-muted\/60{background-color:hsl(var(--muted) / .6)}.bg-popover{background-color:hsl(var(--popover))}.bg-primary{background-color:hsl(var(--primary))}.bg-primary\/10{background-color:hsl(var(--primary) / .1)}.bg-primary\/15{background-color:hsl(var(--primary) / .15)}.bg-primary\/5{background-color:hsl(var(--primary) / .05)}.bg-secondary{background-color:hsl(var(--secondary))}.bg-secondary\/80{background-color:hsl(var(--secondary) / .8)}.bg-state{background-color:hsl(var(--state))}.bg-state\/15{background-color:hsl(var(--state) / .15)}.bg-state\/5,.bg-state\/\[0\.05\]{background-color:hsl(var(--state) / .05)}.bg-state\/\[0\.06\]{background-color:hsl(var(--state) / .06)}.bg-success{background-color:hsl(var(--success))}.bg-success\/10{background-color:hsl(var(--success) / .1)}.bg-success\/20{background-color:hsl(var(--success) / .2)}.bg-success\/5{background-color:hsl(var(--success) / .05)}.bg-success\/\[0\.08\]{background-color:hsl(var(--success) / .08)}.bg-surface-3{background-color:hsl(var(--surface-3))}.bg-surface-active{background-color:hsl(var(--surface-active))}.bg-transparent{background-color:transparent}.bg-warning{background-color:hsl(var(--warning))}.bg-warning\/10{background-color:hsl(var(--warning) / .1)}.bg-warning\/15{background-color:hsl(var(--warning) / .15)}.bg-warning\/5{background-color:hsl(var(--warning) / .05)}.bg-warning\/\[0\.08\]{background-color:hsl(var(--warning) / .08)}.bg-white{--tw-bg-opacity: 1;background-color:rgb(255 255 255 / var(--tw-bg-opacity, 1))}.bg-\[linear-gradient\(90deg\,transparent\,hsl\(var\(--success\)\)\,transparent\)\]{background-image:linear-gradient(90deg,transparent,hsl(var(--success)),transparent)}.bg-gradient-to-r{background-image:linear-gradient(to right,var(--tw-gradient-stops))}.from-primary{--tw-gradient-from: hsl(var(--primary)) var(--tw-gradient-from-position);--tw-gradient-to: hsl(var(--primary) / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to)}.via-state{--tw-gradient-to: hsl(var(--state) / 0) var(--tw-gradient-to-position);--tw-gradient-stops: var(--tw-gradient-from), hsl(var(--state)) var(--tw-gradient-via-position), var(--tw-gradient-to)}.to-primary{--tw-gradient-to: hsl(var(--primary)) var(--tw-gradient-to-position)}.bg-\[length\:200\%_100\%\]{background-size:200% 100%}.bg-\[length\:50\%_100\%\]{background-size:50% 100%}.object-contain{-o-object-fit:contain;object-fit:contain}.object-top{-o-object-position:top;object-position:top}.p-0{padding:0}.p-0\.5{padding:.125rem}.p-1{padding:.25rem}.p-1\.5{padding:.375rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-2\.5{padding-left:.625rem;padding-right:.625rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-3\.5{padding-left:.875rem;padding-right:.875rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.px-\[--cell-size\]{padding-left:var(--cell-size);padding-right:var(--cell-size)}.px-\[7px\]{padding-left:7px;padding-right:7px}.py-0{padding-top:0;padding-bottom:0}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-10{padding-top:2.5rem;padding-bottom:2.5rem}.py-16{padding-top:4rem;padding-bottom:4rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-3\.5{padding-top:.875rem;padding-bottom:.875rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-\[5px\]{padding-top:5px;padding-bottom:5px}.py-px{padding-top:1px;padding-bottom:1px}.pb-1{padding-bottom:.25rem}.pb-2{padding-bottom:.5rem}.pl-2{padding-left:.5rem}.pl-3{padding-left:.75rem}.pl-4{padding-left:1rem}.pl-5{padding-left:1.25rem}.pr-1{padding-right:.25rem}.pr-2{padding-right:.5rem}.pr-8{padding-right:2rem}.pr-9{padding-right:2.25rem}.pt-0{padding-top:0}.pt-2{padding-top:.5rem}.pt-4{padding-top:1rem}.pt-6{padding-top:1.5rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-top{vertical-align:top}.align-middle{vertical-align:middle}.font-mono{font-family:JetBrains Mono Variable,ui-monospace,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-\[0\.8rem\]{font-size:.8rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.lowercase{text-transform:lowercase}.capitalize{text-transform:capitalize}.normal-case{text-transform:none}.italic{font-style:italic}.ordinal{--tw-ordinal: ordinal;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.tabular-nums{--tw-numeric-spacing: tabular-nums;font-variant-numeric:var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction)}.leading-\[1\.25\]{line-height:1.25}.leading-\[1\.3\]{line-height:1.3}.leading-\[1\.45\]{line-height:1.45}.leading-none{line-height:1}.leading-relaxed{line-height:1.625}.leading-snug{line-height:1.375}.leading-tight{line-height:1.25}.tracking-normal{letter-spacing:0em}.tracking-tight{letter-spacing:-.025em}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.text-\[hsl\(var\(--destructive\)\)\]{color:hsl(var(--destructive))}.text-\[hsl\(var\(--primary\)\)\]{color:hsl(var(--primary))}.text-\[hsl\(var\(--primary-foreground\)\)\]{color:hsl(var(--primary-foreground))}.text-\[hsl\(var\(--success\)\)\]{color:hsl(var(--success))}.text-accent-foreground{color:hsl(var(--accent-foreground))}.text-card-foreground{color:hsl(var(--card-foreground))}.text-destructive{color:hsl(var(--destructive))}.text-destructive-foreground{color:hsl(var(--destructive-foreground))}.text-foreground{color:hsl(var(--foreground))}.text-foreground\/70{color:hsl(var(--foreground) / .7)}.text-foreground\/80{color:hsl(var(--foreground) / .8)}.text-foreground\/90{color:hsl(var(--foreground) / .9)}.text-inherit{color:inherit}.text-input{color:hsl(var(--input))}.text-link{color:hsl(var(--link))}.text-muted-foreground{color:hsl(var(--muted-foreground))}.text-muted-foreground\/50{color:hsl(var(--muted-foreground) / .5)}.text-muted-foreground\/60{color:hsl(var(--muted-foreground) / .6)}.text-muted-foreground\/70{color:hsl(var(--muted-foreground) / .7)}.text-popover-foreground{color:hsl(var(--popover-foreground))}.text-primary{color:hsl(var(--primary))}.text-primary-foreground{color:hsl(var(--primary-foreground))}.text-red-300\/90{color:#fca5a5e6}.text-secondary-foreground{color:hsl(var(--secondary-foreground))}.text-state{color:hsl(var(--state))}.text-success{color:hsl(var(--success))}.text-warning{color:hsl(var(--warning))}.underline{text-decoration-line:underline}.line-through{text-decoration-line:line-through}.no-underline{text-decoration-line:none}.decoration-link\/40{text-decoration-color:hsl(var(--link) / .4)}.decoration-muted-foreground\/60{text-decoration-color:hsl(var(--muted-foreground) / .6)}.decoration-dotted{text-decoration-style:dotted}.underline-offset-2{text-underline-offset:2px}.underline-offset-4{text-underline-offset:4px}.opacity-0{opacity:0}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.shadow{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[0_6px_20px_rgba\(0\,0\,0\,0\.55\)\]{--tw-shadow: 0 6px 20px rgba(0,0,0,.55);--tw-shadow-colored: 0 6px 20px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-\[inset_3px_0_0_hsl\(var\(--state\)\)\]{--tw-shadow: inset 3px 0 0 hsl(var(--state));--tw-shadow-colored: inset 3px 0 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / .1), 0 4px 6px -4px rgb(0 0 0 / .1);--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow: 0 1px 2px 0 rgb(0 0 0 / .05);--tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.shadow-xl{--tw-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1);--tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), 0 8px 10px -6px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.outline{outline-style:solid}.ring{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-1{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-2{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.ring-inset{--tw-ring-inset: inset}.ring-\[hsl\(var\(--primary\)\)\]\/30{--tw-ring-color: hsl(var(--primary) / .3)}.ring-warning\/20{--tw-ring-color: hsl(var(--warning) / .2)}.ring-warning\/30{--tw-ring-color: hsl(var(--warning) / .3)}.ring-offset-background{--tw-ring-offset-color: hsl(var(--background))}.blur{--tw-blur: blur(8px);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.invert{--tw-invert: invert(100%);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.sepia{--tw-sepia: sepia(100%);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-\[width\]{transition-property:width;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-all{transition-property:all;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.duration-200{transition-duration:.2s}.ease-in-out{transition-timing-function:cubic-bezier(.4,0,.2,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.\[--cell-size\:2rem\]{--cell-size: 2rem}.file\:border-0::file-selector-button{border-width:0px}.file\:bg-transparent::file-selector-button{background-color:transparent}.file\:text-sm::file-selector-button{font-size:.875rem;line-height:1.25rem}.file\:font-medium::file-selector-button{font-weight:500}.file\:text-foreground::file-selector-button{color:hsl(var(--foreground))}.placeholder\:text-muted-foreground::-moz-placeholder{color:hsl(var(--muted-foreground))}.placeholder\:text-muted-foreground::placeholder{color:hsl(var(--muted-foreground))}.before\:content-\[\'·_\'\]:before{--tw-content: "· ";content:var(--tw-content)}.last\:border-0:last-child{border-width:0px}.hover\:border-primary\/40:hover{border-color:hsl(var(--primary) / .4)}.hover\:border-primary\/50:hover{border-color:hsl(var(--primary) / .5)}.hover\:bg-accent:hover{background-color:hsl(var(--accent))}.hover\:bg-accent\/20:hover{background-color:hsl(var(--accent) / .2)}.hover\:bg-accent\/40:hover{background-color:hsl(var(--accent) / .4)}.hover\:bg-accent\/50:hover{background-color:hsl(var(--accent) / .5)}.hover\:bg-destructive\/80:hover{background-color:hsl(var(--destructive) / .8)}.hover\:bg-destructive\/90:hover{background-color:hsl(var(--destructive) / .9)}.hover\:bg-foreground\/5:hover{background-color:hsl(var(--foreground) / .05)}.hover\:bg-muted:hover{background-color:hsl(var(--muted))}.hover\:bg-muted\/40:hover{background-color:hsl(var(--muted) / .4)}.hover\:bg-muted\/50:hover{background-color:hsl(var(--muted) / .5)}.hover\:bg-primary\/80:hover{background-color:hsl(var(--primary) / .8)}.hover\:bg-primary\/90:hover{background-color:hsl(var(--primary) / .9)}.hover\:bg-secondary\/80:hover{background-color:hsl(var(--secondary) / .8)}.hover\:bg-surface-2:hover{background-color:hsl(var(--surface-2))}.hover\:text-accent-foreground:hover{color:hsl(var(--accent-foreground))}.hover\:text-foreground:hover{color:hsl(var(--foreground))}.hover\:text-link:hover{color:hsl(var(--link))}.hover\:text-primary:hover{color:hsl(var(--primary))}.hover\:underline:hover{text-decoration-line:underline}.hover\:no-underline:hover{text-decoration-line:none}.hover\:decoration-link:hover{text-decoration-color:hsl(var(--link))}.hover\:opacity-100:hover{opacity:1}.focus\:bg-accent:focus{background-color:hsl(var(--accent))}.focus\:text-accent-foreground:focus{color:hsl(var(--accent-foreground))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-1:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus\:ring-ring:focus{--tw-ring-color: hsl(var(--ring))}.focus\:ring-offset-2:focus{--tw-ring-offset-width: 2px}.focus-visible\:outline-none:focus-visible{outline:2px solid transparent;outline-offset:2px}.focus-visible\:ring-1:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.focus-visible\:ring-ring:focus-visible{--tw-ring-color: hsl(var(--ring))}.focus-visible\:ring-offset-2:focus-visible{--tw-ring-offset-width: 2px}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.group:focus-within .group-focus-within\:block{display:block}.group:hover .group-hover\:block{display:block}.group:hover .group-hover\:text-muted-foreground{color:hsl(var(--muted-foreground))}.peer:disabled~.peer-disabled\:cursor-not-allowed{cursor:not-allowed}.peer:disabled~.peer-disabled\:opacity-70{opacity:.7}.aria-disabled\:opacity-50[aria-disabled=true]{opacity:.5}.aria-selected\:text-muted-foreground[aria-selected=true]{color:hsl(var(--muted-foreground))}.data-\[disabled\]\:pointer-events-none[data-disabled]{pointer-events:none}.data-\[side\=bottom\]\:translate-y-1[data-side=bottom]{--tw-translate-y: .25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=left\]\:-translate-x-1[data-side=left]{--tw-translate-x: -.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=right\]\:translate-x-1[data-side=right]{--tw-translate-x: .25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[side\=top\]\:-translate-y-1[data-side=top]{--tw-translate-y: -.25rem;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.data-\[range-end\=true\]\:rounded-md[data-range-end=true]{border-radius:calc(var(--radius) - 2px)}.data-\[range-middle\=true\]\:rounded-none[data-range-middle=true]{border-radius:0}.data-\[range-start\=true\]\:rounded-md[data-range-start=true]{border-radius:calc(var(--radius) - 2px)}.data-\[selected\=true\]\:rounded-none[data-selected=true]{border-radius:0}.data-\[range-end\=true\]\:bg-primary[data-range-end=true]{background-color:hsl(var(--primary))}.data-\[range-middle\=true\]\:bg-accent[data-range-middle=true]{background-color:hsl(var(--accent))}.data-\[range-start\=true\]\:bg-primary[data-range-start=true],.data-\[selected-single\=true\]\:bg-primary[data-selected-single=true]{background-color:hsl(var(--primary))}.data-\[state\=active\]\:bg-background[data-state=active]{background-color:hsl(var(--background))}.data-\[state\=active\]\:bg-muted[data-state=active]{background-color:hsl(var(--muted))}.data-\[state\=open\]\:bg-accent[data-state=open]{background-color:hsl(var(--accent))}.data-\[state\=open\]\:bg-secondary[data-state=open]{background-color:hsl(var(--secondary))}.data-\[state\=selected\]\:bg-muted[data-state=selected]{background-color:hsl(var(--muted))}.data-\[placeholder\]\:text-muted-foreground[data-placeholder]{color:hsl(var(--muted-foreground))}.data-\[range-end\=true\]\:text-primary-foreground[data-range-end=true]{color:hsl(var(--primary-foreground))}.data-\[range-middle\=true\]\:text-accent-foreground[data-range-middle=true]{color:hsl(var(--accent-foreground))}.data-\[range-start\=true\]\:text-primary-foreground[data-range-start=true],.data-\[selected-single\=true\]\:text-primary-foreground[data-selected-single=true]{color:hsl(var(--primary-foreground))}.data-\[state\=active\]\:text-foreground[data-state=active]{color:hsl(var(--foreground))}.data-\[state\=open\]\:text-muted-foreground[data-state=open]{color:hsl(var(--muted-foreground))}.data-\[disabled\]\:opacity-50[data-disabled]{opacity:.5}.data-\[state\=active\]\:shadow[data-state=active]{--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1);--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow, 0 0 #0000),var(--tw-ring-shadow, 0 0 #0000),var(--tw-shadow)}.data-\[state\=closed\]\:duration-300[data-state=closed]{transition-duration:.3s}.data-\[state\=open\]\:duration-500[data-state=open]{transition-duration:.5s}.group\/day[data-focused=true] .group-data-\[focused\=true\]\/day\:relative{position:relative}.group\/day[data-focused=true] .group-data-\[focused\=true\]\/day\:z-10{z-index:10}.group\/day[data-focused=true] .group-data-\[focused\=true\]\/day\:border-ring{border-color:hsl(var(--ring))}.group\/day[data-focused=true] .group-data-\[focused\=true\]\/day\:ring-\[3px\]{--tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow, 0 0 #0000)}.group\/day[data-focused=true] .group-data-\[focused\=true\]\/day\:ring-ring\/50{--tw-ring-color: hsl(var(--ring) / .5)}@media (min-width: 640px){.sm\:inline{display:inline}.sm\:hidden{display:none}.sm\:max-w-sm{max-width:24rem}.sm\:max-w-xl{max-width:36rem}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:justify-end{justify-content:flex-end}.sm\:space-x-2>:not([hidden])~:not([hidden]){--tw-space-x-reverse: 0;margin-right:calc(.5rem * var(--tw-space-x-reverse));margin-left:calc(.5rem * calc(1 - var(--tw-space-x-reverse)))}.sm\:rounded-lg{border-radius:var(--radius)}.sm\:text-left{text-align:left}}@media (min-width: 768px){.md\:sticky{position:sticky}.md\:top-4{top:1rem}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:grid-cols-\[220px_minmax\(0\,1fr\)\]{grid-template-columns:220px minmax(0,1fr)}.md\:flex-row{flex-direction:row}.md\:self-start{align-self:flex-start}.md\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width: 1024px){.lg\:col-span-2{grid-column:span 2 / span 2}.lg\:block{display:block}.lg\:w-48{width:12rem}.lg\:w-60{width:15rem}.lg\:shrink-0{flex-shrink:0}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:flex-row{flex-direction:row}.lg\:gap-6{gap:1.5rem}.lg\:space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse: 0;margin-top:calc(1rem * calc(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem * var(--tw-space-y-reverse))}.lg\:px-6{padding-left:1.5rem;padding-right:1.5rem}.lg\:py-5{padding-top:1.25rem;padding-bottom:1.25rem}}@media (min-width: 1280px){.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.xl\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}}@media (prefers-color-scheme: dark){.dark\:border-destructive{border-color:hsl(var(--destructive))}}.\[\&\:\:-webkit-details-marker\]\:hidden::-webkit-details-marker{display:none}.\[\&\:first-child\[data-selected\=true\]_button\]\:rounded-l-md:first-child[data-selected=true] button{border-top-left-radius:calc(var(--radius) - 2px);border-bottom-left-radius:calc(var(--radius) - 2px)}.\[\&\:has\(\[role\=checkbox\]\)\]\:pr-0:has([role=checkbox]){padding-right:0}.\[\&\:last-child\[data-selected\=true\]_button\]\:rounded-r-md:last-child[data-selected=true] button{border-top-right-radius:calc(var(--radius) - 2px);border-bottom-right-radius:calc(var(--radius) - 2px)}.\[\&\>\*\:first-child\]\:mt-0>*:first-child{margin-top:0}.\[\&\>\*\:last-child\]\:mb-0>*:last-child{margin-bottom:0}.\[\&\>\[role\=checkbox\]\]\:translate-y-\[2px\]>[role=checkbox]{--tw-translate-y: 2px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.\[\&\>span\]\:line-clamp-1>span{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:1}.\[\&\>span\]\:text-xs>span{font-size:.75rem;line-height:1rem}.\[\&\>span\]\:opacity-70>span{opacity:.7}.\[\&\>svg\+div\]\:translate-y-\[-3px\]>svg+div{--tw-translate-y: -3px;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skew(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.\[\&\>svg\]\:absolute>svg{position:absolute}.\[\&\>svg\]\:left-4>svg{left:1rem}.\[\&\>svg\]\:top-4>svg{top:1rem}.\[\&\>svg\]\:size-3\.5>svg{width:.875rem;height:.875rem}.\[\&\>svg\]\:text-destructive>svg{color:hsl(var(--destructive))}.\[\&\>svg\]\:text-foreground>svg{color:hsl(var(--foreground))}.\[\&\>svg\]\:text-muted-foreground>svg{color:hsl(var(--muted-foreground))}.\[\&\>svg\]\:text-warning>svg{color:hsl(var(--warning))}.\[\&\>svg\~\*\]\:pl-7>svg~*{padding-left:1.75rem}.\[\&\>tr\]\:last\:border-b-0:last-child>tr{border-bottom-width:0px}.\[\&_\:not\(pre\)\>code\]\:rounded :not(pre)>code{border-radius:.25rem}.\[\&_\:not\(pre\)\>code\]\:bg-black\/10 :not(pre)>code{background-color:#0000001a}.\[\&_\:not\(pre\)\>code\]\:px-1 :not(pre)>code{padding-left:.25rem;padding-right:.25rem}.\[\&_\:not\(pre\)\>code\]\:py-0\.5 :not(pre)>code{padding-top:.125rem;padding-bottom:.125rem}.\[\&_\:not\(pre\)\>code\]\:font-mono :not(pre)>code{font-family:JetBrains Mono Variable,ui-monospace,monospace}.\[\&_\:not\(pre\)\>code\]\:text-\[0\.85em\] :not(pre)>code{font-size:.85em}@media (prefers-color-scheme: dark){.dark\:\[\&_\:not\(pre\)\>code\]\:bg-white\/15 :not(pre)>code{background-color:#ffffff26}}.\[\&_a\]\:underline a{text-decoration-line:underline}.\[\&_a\]\:underline-offset-2 a{text-underline-offset:2px}.hover\:\[\&_a\]\:no-underline a:hover{text-decoration-line:none}.\[\&_blockquote\]\:my-1\.5 blockquote{margin-top:.375rem;margin-bottom:.375rem}.\[\&_blockquote\]\:border-l-2 blockquote{border-left-width:2px}.\[\&_blockquote\]\:border-border blockquote{border-color:hsl(var(--border))}.\[\&_blockquote\]\:pl-2\.5 blockquote{padding-left:.625rem}.\[\&_blockquote\]\:text-muted-foreground blockquote{color:hsl(var(--muted-foreground))}.\[\&_h1\]\:mb-1\.5 h1{margin-bottom:.375rem}.\[\&_h1\]\:mt-2 h1{margin-top:.5rem}.\[\&_h1\]\:text-base h1{font-size:1rem;line-height:1.5rem}.\[\&_h1\]\:font-semibold h1{font-weight:600}.\[\&_h2\]\:mb-1\.5 h2{margin-bottom:.375rem}.\[\&_h2\]\:mt-2 h2{margin-top:.5rem}.\[\&_h2\]\:text-\[0\.95rem\] h2{font-size:.95rem}.\[\&_h2\]\:font-semibold h2{font-weight:600}.\[\&_h3\]\:mb-1 h3{margin-bottom:.25rem}.\[\&_h3\]\:mt-2 h3{margin-top:.5rem}.\[\&_h3\]\:font-semibold h3{font-weight:600}.\[\&_hr\]\:my-2 hr{margin-top:.5rem;margin-bottom:.5rem}.\[\&_hr\]\:border-border hr{border-color:hsl(var(--border))}.\[\&_li\]\:my-0\.5 li{margin-top:.125rem;margin-bottom:.125rem}.\[\&_ol\]\:my-1\.5 ol{margin-top:.375rem;margin-bottom:.375rem}.\[\&_ol\]\:list-decimal ol{list-style-type:decimal}.\[\&_ol\]\:pl-5 ol{padding-left:1.25rem}.\[\&_p\]\:my-1\.5 p{margin-top:.375rem;margin-bottom:.375rem}.\[\&_p\]\:leading-relaxed p{line-height:1.625}.\[\&_pre\]\:my-1\.5 pre{margin-top:.375rem;margin-bottom:.375rem}.\[\&_pre\]\:overflow-x-auto pre{overflow-x:auto}.\[\&_pre\]\:rounded-md pre{border-radius:calc(var(--radius) - 2px)}.\[\&_pre\]\:bg-black\/10 pre{background-color:#0000001a}.\[\&_pre\]\:p-2\.5 pre{padding:.625rem}.\[\&_pre\]\:text-\[0\.8rem\] pre{font-size:.8rem}@media (prefers-color-scheme: dark){.dark\:\[\&_pre\]\:bg-white\/10 pre{background-color:#ffffff1a}}.\[\&_pre_code\]\:whitespace-pre pre code{white-space:pre}.\[\&_pre_code\]\:font-mono pre code{font-family:JetBrains Mono Variable,ui-monospace,monospace}.\[\&_svg\]\:pointer-events-none svg{pointer-events:none}.\[\&_svg\]\:size-4 svg{width:1rem;height:1rem}.\[\&_svg\]\:shrink-0 svg{flex-shrink:0}.\[\&_table\]\:w-full table{width:100%}.\[\&_table\]\:border-collapse table{border-collapse:collapse}.\[\&_table\]\:text-xs table{font-size:.75rem;line-height:1rem}.\[\&_td\]\:border td{border-width:1px}.\[\&_td\]\:border-border td{border-color:hsl(var(--border))}.\[\&_td\]\:px-2 td{padding-left:.5rem;padding-right:.5rem}.\[\&_td\]\:py-1 td{padding-top:.25rem;padding-bottom:.25rem}.\[\&_td\]\:align-top td{vertical-align:top}.\[\&_th\]\:border th{border-width:1px}.\[\&_th\]\:border-border th{border-color:hsl(var(--border))}.\[\&_th\]\:bg-muted th{background-color:hsl(var(--muted))}.\[\&_th\]\:px-2 th{padding-left:.5rem;padding-right:.5rem}.\[\&_th\]\:py-1 th{padding-top:.25rem;padding-bottom:.25rem}.\[\&_th\]\:text-left th{text-align:left}.\[\&_th\]\:font-semibold th{font-weight:600}.\[\&_tr\:last-child\]\:border-0 tr:last-child{border-width:0px}.\[\&_tr\]\:border-b tr{border-bottom-width:1px}.\[\&_ul\]\:my-1\.5 ul{margin-top:.375rem;margin-bottom:.375rem}.\[\&_ul\]\:list-disc ul{list-style-type:disc}.\[\&_ul\]\:pl-5 ul{padding-left:1.25rem}[data-slot=card-content] .\[\[data-slot\=card-content\]_\&\]\:bg-transparent,[data-slot=popover-content] .\[\[data-slot\=popover-content\]_\&\]\:bg-transparent{background-color:transparent} diff --git a/pkg/web/webui/webassets/dist/mount.BOEH1oNx.js b/pkg/web/webui/webassets/dist/mount.D4ypHaeQ.js similarity index 100% rename from pkg/web/webui/webassets/dist/mount.BOEH1oNx.js rename to pkg/web/webui/webassets/dist/mount.D4ypHaeQ.js diff --git a/pkg/web/webui/webassets/dist/session-view.dtf-izky.js b/pkg/web/webui/webassets/dist/session-view.D5Vt5OlU.js similarity index 99% rename from pkg/web/webui/webassets/dist/session-view.dtf-izky.js rename to pkg/web/webui/webassets/dist/session-view.D5Vt5OlU.js index 4d034f8b..bd07cce9 100644 --- a/pkg/web/webui/webassets/dist/session-view.dtf-izky.js +++ b/pkg/web/webui/webassets/dist/session-view.D5Vt5OlU.js @@ -1,2 +1,2 @@ -import{H as ee,I as te,J as re,K as ne,c as N,B as se,m as ae}from"./mount.BOEH1oNx.js";import{r as c,j as t,a6 as z,ao as q,x as oe,y as P,z as ie,af as K,an as W,ag as V,c as ce,ae as le,ap as de,at as ue,ar as fe,E as xe,as as me,ah as pe}from"./vendor.C5MRNvUt.js";import{M as he}from"./markdown.FOTo-3Mz.js";function H(e){const r=e.payload??{};return{kind:"mcp_ui_action",payload:{type:e.type,...r}}}function ge(e){if(e==null)return"";if(typeof e=="string"){try{const r=JSON.parse(e);if(typeof r=="string")return r}catch{}return e}try{return JSON.stringify(e)}catch{return String(e)}}function be(e){switch(e.status){case"ok":return{content:[{type:"text",text:ge(e.result)}],isError:e.isError===!0};case"requires_approval":return{content:[{type:"text",text:e.message||"Approval requested — pending; ask in chat for the result."}],isError:!0};case"denied":return{content:[{type:"text",text:e.message||"Not authorized to run this action."}],isError:!0};case"rate_limited":return{content:[{type:"text",text:e.message||"Rate limit reached; try again shortly."}],isError:!0};case"error":default:return{content:[{type:"text",text:e.message||"The action could not be completed."}],isError:!0}}}function we(e){try{const r=JSON.parse(e);return!r||typeof r.type!="string"?null:r}catch{return null}}function ye(e,r,n){return`${e.protocol==="https:"?"wss:":"ws:"}//${e.host}/session-view/${encodeURIComponent(r)}/${encodeURIComponent(n)}/live`}const A=3;function je(e,r,n){const[l,u]=c.useState("connecting"),x=c.useRef(n);return x.current=n,c.useEffect(()=>{let p=null,m,y=!1,j=0;const v=()=>{y||(j+=1,u(j>=A?"offline":"reconnecting"),m=window.setTimeout(S,2e3))},S=()=>{if(!y){u(j===0?"connecting":j>=A?"offline":"reconnecting");try{p=new WebSocket(ye(window.location,e,r))}catch{v();return}p.onopen=()=>{j=0,u("connected")},p.onmessage=I=>{const T=we(I.data);T&&x.current(T)},p.onerror=()=>{y||u(j>=A?"offline":"reconnecting")},p.onclose=v}};return S(),()=>{y=!0,m&&window.clearTimeout(m),p&&p.close()}},[e,r]),{state:l}}const Ne={connected:{Icon:ie,color:"text-success",spin:!1,tip:"Live — connected"},connecting:{Icon:P,color:"text-warning",spin:!0,tip:"Connecting…"},reconnecting:{Icon:P,color:"text-warning",spin:!0,tip:"Reconnecting…"},offline:{Icon:oe,color:"text-destructive",spin:!1,tip:"Offline — retrying"}};function ke({state:e}){const r=Ne[e],{Icon:n}=r;return t.jsxs(te,{children:[t.jsx(re,{asChild:!0,children:t.jsx("div",{className:`flex h-7 w-7 items-center justify-center rounded-md cursor-default ${r.color}`,children:t.jsx(n,{className:`h-[18px] w-[18px] ${r.spin?"animate-spin":""}`,"aria-hidden":"true"})})}),t.jsx(ne,{children:r.tip})]})}function D(e){return`widget:${e}`}function ve(e){return e.startsWith("widget:")?e.slice(7):""}function Se({id:e,hostUrl:r,registerFrame:n}){return t.jsx("div",{className:"mx-auto w-full max-w-[85%] rounded-lg border border-border overflow-hidden bg-card/60",style:{height:480},children:t.jsx("iframe",{ref:l=>n(e,l),sandbox:"allow-scripts allow-same-origin",src:r,referrerPolicy:"no-referrer",title:"interactive widget",className:"w-full h-full border-0 block bg-white"})})}function Y(e){return e==="done"||e==="complete"||e==="completed"||e==="skipped"}function Ie(e,r){if(Y(e))return t.jsx(K,{className:"h-3.5 w-3.5 shrink-0 text-success","aria-hidden":"true"});switch(e){case"in_progress":case"active":case"running":return t.jsx(P,{className:N("h-3.5 w-3.5 shrink-0 text-primary",r&&"animate-spin"),"aria-hidden":"true"});case"blocked":case"failed":case"error":return t.jsx(pe,{className:"h-3.5 w-3.5 shrink-0 text-destructive","aria-hidden":"true"});default:return t.jsx(me,{className:"h-3.5 w-3.5 shrink-0 text-muted-foreground","aria-hidden":"true"})}}function Te({plan:e,live:r}){const n=e.items??[];return t.jsxs("div",{className:"mx-auto w-full max-w-[85%] rounded-lg border border-border bg-card/60 px-3 py-2",children:[t.jsxs("div",{className:"flex items-center gap-1.5 text-xs font-medium text-muted-foreground mb-1.5",children:[t.jsx(fe,{className:"h-3.5 w-3.5","aria-hidden":"true"}),t.jsxs("span",{children:["Plan",n.length>0?` · ${n.length} step${n.length===1?"":"s"}`:""]})]}),n.length===0?t.jsx("div",{className:"text-xs text-muted-foreground",children:"Plan updated."}):t.jsx("ul",{className:"flex flex-col gap-1",children:n.map(l=>{const u=Y(l.status);return t.jsxs("li",{className:"flex items-start gap-1.5 text-xs leading-snug",children:[t.jsx("span",{className:"mt-0.5",children:Ie(l.status,r)}),t.jsx("span",{className:N("break-words",u?"text-muted-foreground":"text-card-foreground"),children:l.label})]},l.id)})})]})}function Ce({isUser:e,children:r}){return t.jsx("div",{className:N("flex",e?"justify-end":"justify-start"),children:t.jsx("div",{className:N("max-w-[75%] rounded-2xl px-3.5 py-2 text-sm leading-relaxed",e?"bg-primary text-primary-foreground rounded-br-sm":"bg-card border border-border text-card-foreground rounded-bl-sm"),children:r})})}function $e({ns:e,name:r,attachments:n}){return t.jsx("div",{className:"flex flex-wrap gap-1.5",children:n.map((l,u)=>{const x=new URLSearchParams({artifactId:l.artifactId??"",sessionRef:`${e}/${r}`,fn:l.filename});return t.jsxs("a",{href:`/artifact-download?${x.toString()}`,download:l.filename,className:"inline-flex items-center gap-1.5 rounded-lg border border-border bg-card px-2.5 py-1 text-xs text-card-foreground hover:bg-accent hover:text-accent-foreground",children:[t.jsx(xe,{className:"h-3.5 w-3.5 shrink-0","aria-hidden":"true"}),t.jsx("span",{className:"break-all",children:l.filename})]},u)})})}function Ee({line:e,ns:r,name:n,live:l,registerWidgetFrame:u}){if(e.role==="widget")return e.hostUrl?t.jsx(Se,{id:e.id,hostUrl:e.hostUrl,registerFrame:u}):null;if(e.role==="plan"&&e.plan)return t.jsx(Te,{plan:e.plan,live:l});if(e.role==="system"||e.role==="error")return t.jsx("div",{className:N("mx-auto max-w-[85%] text-center text-xs py-1",e.role==="error"?"text-destructive":"text-muted-foreground"),children:t.jsx("span",{className:"whitespace-pre-wrap break-words",children:e.text})});const x=e.attachments??[];return t.jsxs("div",{className:N("flex flex-col gap-1",e.role==="user"?"items-end":"items-start"),children:[t.jsx(Ce,{isUser:e.role==="user",children:t.jsx(he,{children:e.text})}),x.length>0&&t.jsx($e,{ns:r,name:n,attachments:x})]})}function Re(){return t.jsx("div",{className:"flex justify-start",role:"status","aria-label":"Agent is working",children:t.jsx("div",{className:"flex items-center gap-2 rounded-2xl rounded-bl-sm border border-border bg-card px-3.5 py-2.5",children:t.jsx("div",{className:"flex items-center gap-1",children:[0,150,300].map(e=>t.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-muted-foreground animate-bounce",style:{animationDelay:`${e}ms`}},e))})})})}function Oe({text:e}){return t.jsx("div",{className:"flex items-center justify-center text-[11px] text-muted-foreground py-0.5",children:t.jsx("span",{className:"animate-pulse",children:e})})}const Le={critical:{Icon:le,color:"text-destructive"},privacy:{Icon:ce,color:"text-warning"},degraded:{Icon:q,color:"text-warning"},waiting:{Icon:V,color:"text-muted-foreground"},routine:{Icon:W,color:"text-muted-foreground"},housekeeping:{Icon:W,color:"text-muted-foreground"},resolved:{Icon:K,color:"text-success"}},_e={Icon:W,color:"text-muted-foreground"},Fe={money:de,clock:V};function Ue({notice:e}){var l;const r=Le[e.tone??""]??_e,n=Fe[e.glyph??""]??r.Icon;return t.jsxs("div",{className:"flex flex-col gap-1.5 px-4 py-2 text-xs border-t border-border bg-card","data-testid":"notice-banner","data-tone":e.tone||"",children:[t.jsxs("div",{className:N("flex items-center gap-2 font-medium",r.color),children:[t.jsx(n,{className:"h-3.5 w-3.5 shrink-0","aria-hidden":"true"}),t.jsx("span",{className:"break-words text-card-foreground",children:e.lead})]}),e.body&&t.jsx("div",{className:"text-muted-foreground",children:e.body}),(l=e.fields)==null?void 0:l.map((u,x)=>t.jsxs("div",{className:"leading-snug",children:[t.jsxs("span",{className:"font-medium text-card-foreground",children:[u.label,":"]})," ",t.jsx("span",{className:"text-muted-foreground",children:u.value})]},`${u.label}:${x}`)),e.excerpt&&t.jsx("pre",{className:"max-h-40 overflow-auto whitespace-pre-wrap break-words rounded-md border border-border bg-background px-2 py-1.5 text-[11px] leading-snug text-card-foreground",children:t.jsxs("code",{children:[e.excerpt.label?`${e.excerpt.label}: +import{H as ee,I as te,J as re,K as ne,c as N,B as se,m as ae}from"./mount.D4ypHaeQ.js";import{r as c,j as t,a6 as z,ao as q,x as oe,y as P,z as ie,af as K,an as W,ag as V,c as ce,ae as le,ap as de,at as ue,ar as fe,E as xe,as as me,ah as pe}from"./vendor.C5MRNvUt.js";import{M as he}from"./markdown.DHnzytkE.js";function H(e){const r=e.payload??{};return{kind:"mcp_ui_action",payload:{type:e.type,...r}}}function ge(e){if(e==null)return"";if(typeof e=="string"){try{const r=JSON.parse(e);if(typeof r=="string")return r}catch{}return e}try{return JSON.stringify(e)}catch{return String(e)}}function be(e){switch(e.status){case"ok":return{content:[{type:"text",text:ge(e.result)}],isError:e.isError===!0};case"requires_approval":return{content:[{type:"text",text:e.message||"Approval requested — pending; ask in chat for the result."}],isError:!0};case"denied":return{content:[{type:"text",text:e.message||"Not authorized to run this action."}],isError:!0};case"rate_limited":return{content:[{type:"text",text:e.message||"Rate limit reached; try again shortly."}],isError:!0};case"error":default:return{content:[{type:"text",text:e.message||"The action could not be completed."}],isError:!0}}}function we(e){try{const r=JSON.parse(e);return!r||typeof r.type!="string"?null:r}catch{return null}}function ye(e,r,n){return`${e.protocol==="https:"?"wss:":"ws:"}//${e.host}/session-view/${encodeURIComponent(r)}/${encodeURIComponent(n)}/live`}const A=3;function je(e,r,n){const[l,u]=c.useState("connecting"),x=c.useRef(n);return x.current=n,c.useEffect(()=>{let p=null,m,y=!1,j=0;const v=()=>{y||(j+=1,u(j>=A?"offline":"reconnecting"),m=window.setTimeout(S,2e3))},S=()=>{if(!y){u(j===0?"connecting":j>=A?"offline":"reconnecting");try{p=new WebSocket(ye(window.location,e,r))}catch{v();return}p.onopen=()=>{j=0,u("connected")},p.onmessage=I=>{const T=we(I.data);T&&x.current(T)},p.onerror=()=>{y||u(j>=A?"offline":"reconnecting")},p.onclose=v}};return S(),()=>{y=!0,m&&window.clearTimeout(m),p&&p.close()}},[e,r]),{state:l}}const Ne={connected:{Icon:ie,color:"text-success",spin:!1,tip:"Live — connected"},connecting:{Icon:P,color:"text-warning",spin:!0,tip:"Connecting…"},reconnecting:{Icon:P,color:"text-warning",spin:!0,tip:"Reconnecting…"},offline:{Icon:oe,color:"text-destructive",spin:!1,tip:"Offline — retrying"}};function ke({state:e}){const r=Ne[e],{Icon:n}=r;return t.jsxs(te,{children:[t.jsx(re,{asChild:!0,children:t.jsx("div",{className:`flex h-7 w-7 items-center justify-center rounded-md cursor-default ${r.color}`,children:t.jsx(n,{className:`h-[18px] w-[18px] ${r.spin?"animate-spin":""}`,"aria-hidden":"true"})})}),t.jsx(ne,{children:r.tip})]})}function D(e){return`widget:${e}`}function ve(e){return e.startsWith("widget:")?e.slice(7):""}function Se({id:e,hostUrl:r,registerFrame:n}){return t.jsx("div",{className:"mx-auto w-full max-w-[85%] rounded-lg border border-border overflow-hidden bg-card/60",style:{height:480},children:t.jsx("iframe",{ref:l=>n(e,l),sandbox:"allow-scripts allow-same-origin",src:r,referrerPolicy:"no-referrer",title:"interactive widget",className:"w-full h-full border-0 block bg-white"})})}function Y(e){return e==="done"||e==="complete"||e==="completed"||e==="skipped"}function Ie(e,r){if(Y(e))return t.jsx(K,{className:"h-3.5 w-3.5 shrink-0 text-success","aria-hidden":"true"});switch(e){case"in_progress":case"active":case"running":return t.jsx(P,{className:N("h-3.5 w-3.5 shrink-0 text-primary",r&&"animate-spin"),"aria-hidden":"true"});case"blocked":case"failed":case"error":return t.jsx(pe,{className:"h-3.5 w-3.5 shrink-0 text-destructive","aria-hidden":"true"});default:return t.jsx(me,{className:"h-3.5 w-3.5 shrink-0 text-muted-foreground","aria-hidden":"true"})}}function Te({plan:e,live:r}){const n=e.items??[];return t.jsxs("div",{className:"mx-auto w-full max-w-[85%] rounded-lg border border-border bg-card/60 px-3 py-2",children:[t.jsxs("div",{className:"flex items-center gap-1.5 text-xs font-medium text-muted-foreground mb-1.5",children:[t.jsx(fe,{className:"h-3.5 w-3.5","aria-hidden":"true"}),t.jsxs("span",{children:["Plan",n.length>0?` · ${n.length} step${n.length===1?"":"s"}`:""]})]}),n.length===0?t.jsx("div",{className:"text-xs text-muted-foreground",children:"Plan updated."}):t.jsx("ul",{className:"flex flex-col gap-1",children:n.map(l=>{const u=Y(l.status);return t.jsxs("li",{className:"flex items-start gap-1.5 text-xs leading-snug",children:[t.jsx("span",{className:"mt-0.5",children:Ie(l.status,r)}),t.jsx("span",{className:N("break-words",u?"text-muted-foreground":"text-card-foreground"),children:l.label})]},l.id)})})]})}function Ce({isUser:e,children:r}){return t.jsx("div",{className:N("flex",e?"justify-end":"justify-start"),children:t.jsx("div",{className:N("max-w-[75%] rounded-2xl px-3.5 py-2 text-sm leading-relaxed",e?"bg-primary text-primary-foreground rounded-br-sm":"bg-card border border-border text-card-foreground rounded-bl-sm"),children:r})})}function $e({ns:e,name:r,attachments:n}){return t.jsx("div",{className:"flex flex-wrap gap-1.5",children:n.map((l,u)=>{const x=new URLSearchParams({artifactId:l.artifactId??"",sessionRef:`${e}/${r}`,fn:l.filename});return t.jsxs("a",{href:`/artifact-download?${x.toString()}`,download:l.filename,className:"inline-flex items-center gap-1.5 rounded-lg border border-border bg-card px-2.5 py-1 text-xs text-card-foreground hover:bg-accent hover:text-accent-foreground",children:[t.jsx(xe,{className:"h-3.5 w-3.5 shrink-0","aria-hidden":"true"}),t.jsx("span",{className:"break-all",children:l.filename})]},u)})})}function Ee({line:e,ns:r,name:n,live:l,registerWidgetFrame:u}){if(e.role==="widget")return e.hostUrl?t.jsx(Se,{id:e.id,hostUrl:e.hostUrl,registerFrame:u}):null;if(e.role==="plan"&&e.plan)return t.jsx(Te,{plan:e.plan,live:l});if(e.role==="system"||e.role==="error")return t.jsx("div",{className:N("mx-auto max-w-[85%] text-center text-xs py-1",e.role==="error"?"text-destructive":"text-muted-foreground"),children:t.jsx("span",{className:"whitespace-pre-wrap break-words",children:e.text})});const x=e.attachments??[];return t.jsxs("div",{className:N("flex flex-col gap-1",e.role==="user"?"items-end":"items-start"),children:[t.jsx(Ce,{isUser:e.role==="user",children:t.jsx(he,{children:e.text})}),x.length>0&&t.jsx($e,{ns:r,name:n,attachments:x})]})}function Re(){return t.jsx("div",{className:"flex justify-start",role:"status","aria-label":"Agent is working",children:t.jsx("div",{className:"flex items-center gap-2 rounded-2xl rounded-bl-sm border border-border bg-card px-3.5 py-2.5",children:t.jsx("div",{className:"flex items-center gap-1",children:[0,150,300].map(e=>t.jsx("span",{className:"h-1.5 w-1.5 rounded-full bg-muted-foreground animate-bounce",style:{animationDelay:`${e}ms`}},e))})})})}function Oe({text:e}){return t.jsx("div",{className:"flex items-center justify-center text-[11px] text-muted-foreground py-0.5",children:t.jsx("span",{className:"animate-pulse",children:e})})}const Le={critical:{Icon:le,color:"text-destructive"},privacy:{Icon:ce,color:"text-warning"},degraded:{Icon:q,color:"text-warning"},waiting:{Icon:V,color:"text-muted-foreground"},routine:{Icon:W,color:"text-muted-foreground"},housekeeping:{Icon:W,color:"text-muted-foreground"},resolved:{Icon:K,color:"text-success"}},_e={Icon:W,color:"text-muted-foreground"},Fe={money:de,clock:V};function Ue({notice:e}){var l;const r=Le[e.tone??""]??_e,n=Fe[e.glyph??""]??r.Icon;return t.jsxs("div",{className:"flex flex-col gap-1.5 px-4 py-2 text-xs border-t border-border bg-card","data-testid":"notice-banner","data-tone":e.tone||"",children:[t.jsxs("div",{className:N("flex items-center gap-2 font-medium",r.color),children:[t.jsx(n,{className:"h-3.5 w-3.5 shrink-0","aria-hidden":"true"}),t.jsx("span",{className:"break-words text-card-foreground",children:e.lead})]}),e.body&&t.jsx("div",{className:"text-muted-foreground",children:e.body}),(l=e.fields)==null?void 0:l.map((u,x)=>t.jsxs("div",{className:"leading-snug",children:[t.jsxs("span",{className:"font-medium text-card-foreground",children:[u.label,":"]})," ",t.jsx("span",{className:"text-muted-foreground",children:u.value})]},`${u.label}:${x}`)),e.excerpt&&t.jsx("pre",{className:"max-h-40 overflow-auto whitespace-pre-wrap break-words rounded-md border border-border bg-background px-2 py-1.5 text-[11px] leading-snug text-card-foreground",children:t.jsxs("code",{children:[e.excerpt.label?`${e.excerpt.label}: `:"",e.excerpt.content]})}),e.nextStep&&t.jsx("div",{className:"font-medium text-card-foreground",children:e.nextStep})]})}function Ae({disabled:e,placeholder:r,onSend:n}){const[l,u]=c.useState(""),x=()=>{const m=l.trim();!m||e||(n(m),u(""))},p=m=>{m.key==="Enter"&&!m.shiftKey&&(m.preventDefault(),x())};return t.jsxs("div",{className:"flex items-end gap-2 px-4 py-3 border-t border-border bg-card",children:[t.jsx("textarea",{rows:1,value:l,disabled:e,placeholder:r,onChange:m=>u(m.target.value),onKeyDown:p,className:N("flex-1 resize-none max-h-40 rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm","placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring","disabled:cursor-not-allowed disabled:opacity-50")}),t.jsx(se,{size:"icon",className:"h-9 w-9 shrink-0",disabled:e||!l.trim(),onClick:x,title:"Send",children:t.jsx(ue,{className:"h-4 w-4"})})]})}function De(e,r){return e.map(n=>n.kind==="plan"&&n.plan?{id:`plan:${n.plan.planName}`,role:"plan",text:"",plan:n.plan}:{id:r(),role:n.role==="user"?"user":"agent",text:n.text??""})}function Pe(e){const{ns:r,name:n}=e,[l,u]=c.useState([]),[x,p]=c.useState(!1),[m,y]=c.useState(""),[j,v]=c.useState(!1),[S,I]=c.useState(null),[T,_]=c.useState(null),g=c.useCallback(s=>{_(null),I(s)},[]),k=c.useCallback(s=>{I(null),_(s!=null&&s.lead?s:null)},[]),C=c.useRef(!1),G=c.useRef(0),E=c.useCallback(()=>`l${G.current++}`,[]),$=c.useCallback((s,i,a)=>{u(o=>[...o,{id:E(),role:s,text:i,attachments:a}])},[E]),X=c.useCallback(s=>{if(s.type==="snapshot"){u(a=>[...De(s.history??[],E),...a.filter(o=>o.role==="widget")]),C.current=!1,p(!1),y("");return}const i=s.event;if(i)switch(i.kind){case"user_message":{const a=i.payload,o=(a.attachments??[]).filter(d=>d.artifactId);$("agent",a.text,o.length?o:void 0);break}case"user_echo":{const a=i.payload;$("user",a.text);break}case"plan_update":{const a=i.payload;C.current&&p(!0);const o=`plan:${a.planName}`;u(d=>{const f=d.findIndex(b=>b.role==="plan"&&b.id===o);if(f>=0){const b=d.slice();return b[f]={...d[f],plan:a},b}return[...d,{id:o,role:"plan",text:"",plan:a}]});break}case"notification":{if(!C.current)break;const a=i.payload;p(!0),y(a.text);break}case"turn_activity":{i.payload.active?(C.current=!0,p(!0)):(C.current=!1,p(!1),y(""));break}case"widget_offer":{const a=i.payload;if(!a.hostUrl)break;const o=D(a.artifactId);u(d=>d.some(f=>f.id===o)?d:[...d,{id:o,role:"widget",text:"",hostUrl:a.hostUrl}]);break}}},[$,E]);c.useEffect(()=>{const s=e.activeWidgets??[];s.length!==0&&u(i=>{const a=new Set(i.map(d=>d.id)),o=s.filter(d=>!a.has(D(d.artifactId))).map(d=>({id:D(d.artifactId),role:"widget",text:"",hostUrl:d.hostUrl}));return o.length?[...i,...o]:i})},[]);const F=c.useRef(new Map),Q=c.useCallback((s,i)=>{i?F.current.set(s,i):F.current.delete(s)},[]),{state:R}=je(r,n,X),U=c.useRef(!1);c.useEffect(()=>{if(R==="connected"){U.current=!1;return}R==="offline"&&!U.current&&(U.current=!0,$("system","Connection lost — retrying…"))},[R,$]);const Z=c.useCallback(async s=>{I(null),_(null),v(!0);try{const i=await fetch(`/session/${r}/${n}/interact`,{method:"POST",credentials:"same-origin",headers:{"Content-Type":"application/json"},body:JSON.stringify({kind:"user_message",payload:{text:s}})}),a=await i.json().catch(()=>({}));if(!i.ok){const o=a.error||`Failed to send (${i.status}).`;g(o);return}k(a.notice)}catch{g("Network error while sending your message.")}finally{v(!1)}},[r,n,g,k]),M=c.useCallback(async(s,i,a,o)=>{var f,b;const d=h=>{if(e.sandboxOrigin)try{a.postMessage({ap:"mcpui",cmd:"appToolCallReply",corrId:i,response:h},e.sandboxOrigin)}catch(O){console.error("app-tool-call reply postMessage failed",O)}};try{const h=await fetch(`/session/${r}/${n}/app-tool-call`,{method:"POST",credentials:"same-origin",headers:{"Content-Type":"application/json"},body:JSON.stringify({toolName:(f=s.payload)==null?void 0:f.toolName,args:((b=s.payload)==null?void 0:b.params)??{},artifactId:o})});if(!h.ok){const w=await h.json().catch(()=>({}));console.error("app-tool-call send failed",h.status,w),g(w.error||`The widget action could not be sent (${h.status}).`),d({content:[{type:"text",text:"The action could not be sent."}],isError:!0});return}const O=await h.json();if(O.status==="not_found"){try{const w=await fetch(`/session/${r}/${n}/interact`,{method:"POST",credentials:"same-origin",headers:{"Content-Type":"application/json"},body:JSON.stringify(H(s))});if(w.ok){const L=await w.json().catch(()=>({}));k(L.notice)}else{const L=await w.json().catch(()=>({}));console.error("widget action send failed (not_found fallback)",w.status,L),g(L.error||`The widget action could not be sent (${w.status}).`)}}catch(w){console.error("widget action send failed (not_found fallback, network)",w),g("The server was unreachable while sending the widget action.")}d({content:[{type:"text",text:"Sent to the agent."}],isError:!1});return}d(be(O))}catch(h){console.error("app-tool-call send failed (network)",h),g("The server was unreachable while sending the widget action."),d({content:[{type:"text",text:"The server was unreachable."}],isError:!0})}},[r,n,e.sandboxOrigin,g,k]);c.useEffect(()=>{const s=i=>{var d;if(!e.sandboxOrigin||i.origin!==e.sandboxOrigin)return;const a=Array.from(F.current.entries()).find(([,f])=>f.contentWindow===i.source);if(!a)return;const o=i.data;if((o==null?void 0:o.ap)==="mcpui"){if(o.cmd==="appToolCall"&&typeof o.corrId=="string"&&((d=o.result)==null?void 0:d.type)==="tool"&&i.source){M(o.result,o.corrId,i.source,ve(a[0]));return}o.cmd!=="action"||!o.result||fetch(`/session/${r}/${n}/interact`,{method:"POST",credentials:"same-origin",headers:{"Content-Type":"application/json"},body:JSON.stringify(H(o.result))}).then(async f=>{if(!f.ok){const h=await f.json().catch(()=>({}));console.error("widget action send failed",f.status,h),g(h.error||`The widget action could not be sent (${f.status}).`);return}const b=await f.json().catch(()=>({}));k(b.notice)}).catch(f=>{console.error("widget action send failed (network)",f),g("The server was unreachable while sending the widget action.")})}};return window.addEventListener("message",s),()=>window.removeEventListener("message",s)},[e.sandboxOrigin,r,n,M,g,k]);const J=c.useRef(null),B=c.useRef(null);return c.useEffect(()=>{var a,o;const s=B.current;!s||!(s.scrollHeight-s.scrollTop-s.clientHeight<120)||(o=(a=J.current)==null?void 0:a.scrollIntoView)==null||o.call(a,{block:"end"})},[l.length,x,m]),t.jsx(ee,{delayDuration:200,children:t.jsxs("div",{className:"h-screen flex flex-col bg-background text-foreground",children:[t.jsxs("div",{className:"flex items-center gap-3 px-3 py-2 min-h-[52px] bg-card border-b border-border",children:[t.jsx(z,{className:"h-4 w-4 text-muted-foreground shrink-0","aria-hidden":"true"}),t.jsxs("span",{className:"text-[13px] font-semibold truncate",title:`${r}/${n}`,children:[r,"/",n]}),t.jsx("div",{className:"ml-auto shrink-0",children:t.jsx(ke,{state:R})})]}),t.jsx("div",{ref:B,className:"flex-1 min-h-0 overflow-y-auto px-4 py-4",children:t.jsxs("div",{className:"flex flex-col gap-2.5 max-w-3xl mx-auto",children:[l.length===0&&t.jsxs("div",{className:"flex flex-1 flex-col items-center justify-center gap-2 py-16 text-muted-foreground",children:[t.jsx(z,{className:"h-8 w-8","aria-hidden":"true"}),t.jsx("span",{className:"text-sm",children:"No messages yet."})]}),l.map(s=>t.jsx("div",{"data-testid":"session-view-line","data-role":s.role,children:t.jsx(Ee,{line:s,ns:r,name:n,live:x,registerWidgetFrame:Q})},s.id)),x&&!m&&t.jsx(Re,{}),x&&m&&t.jsx(Oe,{text:m}),t.jsx("div",{ref:J})]})}),S&&t.jsxs("div",{className:"flex items-center gap-2 px-4 py-2 text-xs text-destructive border-t border-border bg-card",children:[t.jsx(q,{className:"h-3.5 w-3.5 shrink-0","aria-hidden":"true"}),t.jsx("span",{className:"break-words",children:S})]}),T&&t.jsx(Ue,{notice:T}),t.jsx(Ae,{disabled:j,placeholder:"Message the agent…",onSend:Z})]})})}ae(Pe); diff --git a/pkg/web/webui/webassets/dist/sessions.DrV0Blkf.js b/pkg/web/webui/webassets/dist/sessions.Bnnp3HNU.js similarity index 99% rename from pkg/web/webui/webassets/dist/sessions.DrV0Blkf.js rename to pkg/web/webui/webassets/dist/sessions.Bnnp3HNU.js index bc1bd817..7a685e88 100644 --- a/pkg/web/webui/webassets/dist/sessions.DrV0Blkf.js +++ b/pkg/web/webui/webassets/dist/sessions.Bnnp3HNU.js @@ -1 +1 @@ -import{c as L,A as W,V as Ie,G as Y,a as J,C as ge,b as bt,d as wt,e as Pe,B,M as oe,T as ts,g as ss,h as ns,i as as,W as rs,N as Ae,j as os,k as is,l as Je,n as Ge,o as ls,p as Xe,D as Oe,t as Me,u as Le,v as pe,w as me,x as cs,L as ds,m as us}from"./mount.BOEH1oNx.js";import{j as s,R as fs,J as ps,r as i,E as ms,O as hs,y as ve,X as xs,P as gs,Q as vs,V as bs,Y as ws,Z as js,_ as ys,$ as Ns,a0 as Ss,a1 as ks,a2 as Cs,a3 as Rs,a4 as Ts,a5 as As,a as Es,a6 as $s,f as Qe,a7 as Is,M as Ps,a8 as Os,a9 as Ms,aa as Ls,ab as _s}from"./vendor.C5MRNvUt.js";import{M as _e}from"./markdown.FOTo-3Mz.js";import{B as Ds}from"./badge.CIlGQKPh.js";import{s as jt,u as Us,b as qs,i as Fs,c as yt,I as Vs,S as Bs,a as Hs,C as Ws}from"./StartupLine.D55RHpak.js";import{M as Ks}from"./model-name.DtAiu0oG.js";const Ze=["hsl(var(--chart-1))","hsl(var(--chart-2))","hsl(var(--chart-3))","hsl(var(--chart-4))","hsl(var(--chart-5))"];function de(e){return Ze[e%Ze.length]}function je({height:e=240,className:t,children:n}){return s.jsx("div",{className:L("w-full text-xs",t),style:{height:e},children:s.jsx(fs,{width:"100%",height:"100%",children:n})})}function zs(e){return s.jsx(ps,{cursor:{stroke:"hsl(var(--border))"},contentStyle:{background:"hsl(var(--popover))",border:"1px solid hsl(var(--border))",borderRadius:"var(--radius)",color:"hsl(var(--popover-foreground))",fontSize:"0.75rem"},...e})}const Ys=new Set(["submitted","awaiting_approval","running"]);function ie(e){return Ys.has(e)}function De(e){if(e.phase==="idle")return null;if(e.phase==="succeeded")return e.message??null;if(e.message)return e.message;switch(e.phase){case"submitted":return"Request submitted.";case"awaiting_approval":return e.approvalAddressedToViewer?"Your approval is needed to continue.":"Waiting on approval from someone else.";case"running":return"In progress.";case"failed":return"The request failed. You can try again.";case"denied":return"The request was denied.";case"expired":return"The approval window expired. You can try again.";case"rate_limited":return"Too many requests right now. Try again shortly.";default:return null}}const Js={states:{},invoke:()=>{},answer:()=>Promise.reject(new Error("agentui: no ActionsProvider"))},Nt=i.createContext(Js);function Gs({value:e,children:t}){return s.jsx(Nt.Provider,{value:e,children:t})}function le(){return i.useContext(Nt)}const P=e=>e.props??{},m=(e,t,n="")=>{const a=P(e)[t];return typeof a=="string"?a:typeof a=="number"?Number.isFinite(a)?String(a):n:typeof a=="boolean"?String(a):n};function Ue(e){if(typeof e!="string")return null;const t=e.split("/");if(t.length!==2)return null;for(const n of t)if(n===""||n==="."||n==="..")return null;return[t[0],t[1]]}function Xs(e){const t=Ue(e);return t===null?null:`/chat-embed/${encodeURIComponent(t[0])}/${encodeURIComponent(t[1])}`}function St({sessionRef:e}){const t=Xs(e);return t===null?s.jsx(W,{children:"Chat unavailable: no valid session reference."}):s.jsx("iframe",{"data-testid":"ap-chat",src:t,title:"Test chat",className:"w-full rounded-md bg-background",style:{height:"520px",border:"0"}})}function Qs({n:e}){return s.jsx(St,{sessionRef:P(e).sessionRef})}const Zs=/^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/;function et(e){return e.length>0&&e.length<=63&&Zs.test(e)}function qe(e){const t=m(e,"namespace"),n=m(e,"agentClass"),a=m(e,"label");if(!et(t))throw new Error(`ap:agentlink: namespace ${JSON.stringify(t)} is not a DNS-1123 label`);if(!et(n))throw new Error(`ap:agentlink: agentClass ${JSON.stringify(n)} is not a DNS-1123 label`);if(a==="")throw new Error("ap:agentlink: label is required");const r=new URLSearchParams({new:"1",ns:t,agentClass:n}),o=m(e,"prompt");return o!==""&&r.set("prompt",o),`/sessions?${r.toString()}`}function en(e,t){return`ap-agentlink:${e}/${t}`}function tt(e){try{return window.sessionStorage.getItem(e)}catch(t){return console.error("agentui: ap:agentlink could not read the remembered test session",t),null}}function tn(e,t){try{window.sessionStorage.setItem(e,t)}catch(n){console.error("agentui: ap:agentlink could not remember the test session",n)}}function sn(e){try{window.sessionStorage.removeItem(e)}catch(t){console.error("agentui: ap:agentlink could not forget the remembered test session",t)}}function nn(e){return`/sessions?${new URLSearchParams({session:e}).toString()}`}function an(e){return typeof e!="string"?null:!e.startsWith("/")||e.startsWith("//")||e.startsWith("/\\")?(console.error("agentui: ap:agentlink refused a start href that is not a same-origin path; using the rebuilt address",e),null):e}const rn="The test could not start.",st="We could not confirm whether that session started. Reload before trying again.";function on({n:e}){const t=qe(e),n=m(e,"namespace"),a=m(e,"agentClass"),r=en(n,a),[o,l]=i.useState(()=>tt(r)),[d,f]=i.useState(null),[p,u]=i.useState(!1),[c,h]=i.useState(null);if(i.useEffect(()=>{const x=tt(r);if(x===null)return;let g=!0;const w=()=>{g&&(sn(r),l(null))},C=Ue(x);if(C===null){w();return}return(async()=>{try{(await fetch(`/sessions/api/${encodeURIComponent(C[0])}/${encodeURIComponent(C[1])}/detail`,{credentials:"same-origin"})).ok||w()}catch(N){console.error("agentui: ap:agentlink could not check the remembered test session",N),w()}})(),()=>{g=!1}},[r]),o!==null)return s.jsxs("div",{className:"flex flex-col gap-2",children:[s.jsx(St,{sessionRef:o}),s.jsx("a",{"data-testid":"ap-agentlink-open-tab",href:d??nn(o),target:"_blank",rel:"noopener noreferrer",className:"self-end text-xs text-[hsl(var(--primary))]",children:"Open in a tab"})]});async function b(){u(!0),h(null);let x;try{x=await fetch("/sessions/api/start",{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json"},body:JSON.stringify({ns:n,agentClass:a,prompt:m(e,"prompt")})})}catch(g){console.error("agentui: ap:agentlink embed start did not complete",g),h({text:st,retryable:!1}),u(!1);return}if(!x.ok){let g="";try{const w=await x.json();g=typeof(w==null?void 0:w.error)=="string"?w.error:""}catch{g=""}console.error("agentui: ap:agentlink embed start was refused",{status:x.status}),h({text:g||rn,retryable:!0}),u(!1);return}try{const g=await x.json();if(!g.ns||!g.name)throw new Error("start answered without a session");const w=`${g.ns}/${g.name}`;tn(r,w),f(an(g.href)),l(w)}catch(g){console.error("agentui: ap:agentlink embed start succeeded but its answer could not be addressed",g),h({text:st,retryable:!1})}finally{u(!1)}}return s.jsxs("div",{className:"flex flex-col gap-2",children:[s.jsx("button",{type:"button","data-testid":"ap-agentlink-embed",onClick:()=>void b(),disabled:p||(c==null?void 0:c.retryable)===!1,className:Ie({variant:"default"}),children:m(e,"label")}),c!==null&&s.jsxs("p",{role:"alert",className:"text-sm text-[hsl(var(--destructive))]",children:[c.text,c.retryable&&s.jsxs(s.Fragment,{children:[" ","Try again, or"," ",s.jsx("a",{href:t,target:"_blank",rel:"noopener noreferrer",className:"underline",children:"open it in a tab"}),"."]})]})]})}function ln({n:e}){return P(e).embed?s.jsx(on,{n:e}):s.jsx("a",{"data-testid":"ap-agentlink",href:qe(e),target:"_blank",rel:"noopener noreferrer",className:Ie({variant:"default"}),children:m(e,"label")})}const kt=i.createContext(null);function cn({value:e,children:t}){return s.jsx(kt.Provider,{value:e,children:t})}function dn(){return i.useContext(kt)}const un="application/vnd.agentprimitives.authzed.com.agent.v1";function fn(e){return e===un?"Agent bundle":e==="text/html"?"Web page":e.startsWith("image/")?"Image":e}function pn(e){const[t,n]=e>=1e6?[e/1e6,"megabyte"]:e>=1e3?[e/1e3,"kilobyte"]:[e,"byte"];return new Intl.NumberFormat(void 0,{style:"unit",unit:n,unitDisplay:"short",maximumFractionDigits:1}).format(t)}function nt({reason:e}){return s.jsxs(W,{variant:"destructive","data-testid":"ap-attachment-unavailable",children:[s.jsx(Y,{children:"Attachment unavailable"}),s.jsx(J,{children:e})]})}function mn({n:e}){const t=dn(),n=m(e,"artifact"),a=m(e,"label"),[r,o]=i.useState(null),[l,d]=i.useState(null);if(i.useEffect(()=>{if(t===null||n==="")return;let p=!1;const u=new URLSearchParams({artifactId:n,sessionRef:`${t.ns}/${t.name}`});return fetch(`/artifact-view/meta?${u.toString()}`,{credentials:"same-origin"}).then(async c=>{if(!c.ok)throw new Error(`${c.status} ${await c.text()}`);return await c.json()}).then(c=>{p||o(c)}).catch(c=>{console.error("agentui: ap:attachment lookup failed",n,c),p||d("This file could not be found in this conversation.")}),()=>{p=!0}},[t,n]),t===null)return s.jsx(nt,{reason:"This page is not attached to a conversation."});if(l!==null)return s.jsx(nt,{reason:l});if(r===null)return s.jsx("div",{"data-testid":"ap-attachment-loading",className:"text-sm text-muted-foreground",children:"Loading file…"});const f=new URLSearchParams({artifactId:n,sessionRef:`${t.ns}/${t.name}`,fn:r.filename||n});return s.jsxs("div",{"data-testid":"ap-attachment",className:"flex items-center justify-between gap-3 rounded-md border border-border px-3 py-2",children:[s.jsxs("div",{className:"min-w-0",children:[s.jsx("div",{className:"truncate text-sm font-medium",children:a||r.filename||r.name}),s.jsxs("div",{className:"text-xs text-muted-foreground",children:[fn(r.mime)," · ",pn(r.size)]})]}),s.jsxs("a",{href:`/artifact-download?${f.toString()}`,download:r.filename||void 0,className:L(Ie({variant:"outline",size:"sm"}),"shrink-0"),"aria-label":`Download ${r.filename||r.name}`,children:[s.jsx(ms,{className:"mr-1.5 h-4 w-4","aria-hidden":"true"}),"Download"]})]})}function Ct({title:e,collapsed:t,testId:n,children:a}){const[r,o]=i.useState(!t);return i.useEffect(()=>{o(!t)},[t]),s.jsxs("details",{"data-testid":n,open:r,className:"w-full",children:[s.jsxs("summary",{className:"flex cursor-pointer select-none items-center gap-2 px-1 py-2 text-sm font-medium [&::-webkit-details-marker]:hidden",onClick:l=>{l.preventDefault(),o(d=>!d)},children:[s.jsx(hs,{className:L("h-4 w-4 shrink-0 transition-transform",r&&"rotate-90"),"aria-hidden":"true"}),e]}),s.jsx("div",{className:"px-1 pb-2",children:a})]})}const hn={layout:"column",selectedStep:null,selectStep:()=>{}},Ee=i.createContext(hn);function Rt(){return i.useContext(Ee)}function xn(e){var t;return(e==null?void 0:e.component)==="oap:page"&&((t=e.props)==null?void 0:t.layout)==="rail"?"rail":"column"}const Tt="oap:generative",gn={composed:new Set,updated:new Map,stale:new Set,waiting:new Set,answered:new Set,collapsed:new Map},At=i.createContext(gn);function vn({value:e,children:t}){return s.jsx(At.Provider,{value:e,children:t})}function Fe(){return i.useContext(At)}function ne(e){var t;return e.component!==Tt?null:typeof((t=e.props)==null?void 0:t.name)=="string"?e.props.name:""}const bn="rounded-md bg-state/[0.05] px-3 py-2",Et=i.createContext(null);function wn(){return i.useContext(Et)}function jn({name:e,title:t,children:n}){const{composed:a,updated:r,stale:o,waiting:l,collapsed:d}=Fe(),{layout:f}=Rt(),p=a.has(e),u=r.has(e),c=o.has(e),h=l.has(e),b=i.Children.count(n)>0,x=d.get(e),g=f!=="rail"&&x!==void 0&&b,w=f==="rail"&&t!==void 0&&t!==""&&b,C=h&&f!=="rail";return s.jsxs("section",{"data-hook":e,"data-agent-composed":p?"true":void 0,"data-hook-updated":u?"true":void 0,"data-hook-waiting":h?"true":void 0,"data-hook-collapsed":g?"true":void 0,"aria-live":"polite","aria-busy":c||void 0,className:L("relative w-full",p&&b&&bn,c&&"opacity-60 transition-opacity"),children:[(C||u||c)&&s.jsxs("div",{"data-testid":"agent-ui-hook-cues",className:"pointer-events-none mb-1 flex min-h-5 items-center justify-between gap-2 text-[11px]",children:[s.jsx("span",{children:C&&s.jsx("span",{"data-testid":"agent-ui-hook-waiting",className:"rounded bg-accent/10 px-1.5 py-0.5 font-medium text-accent-foreground",children:"Waiting on you"})}),u?s.jsx("span",{"data-testid":"agent-ui-hook-updated",className:"rounded bg-accent/10 px-1.5 py-0.5 text-muted-foreground",children:"Updated"}):c?s.jsxs("div",{"data-testid":"agent-ui-hook-refreshing",className:"flex items-center gap-1.5 text-muted-foreground",children:[s.jsx(ve,{className:"h-3.5 w-3.5 animate-spin","aria-hidden":"true"}),s.jsx("span",{children:"Updating…"})]}):null]}),s.jsxs(Et.Provider,{value:e,children:[w&&s.jsx("h3",{"data-testid":"agent-ui-hook-title",className:"mb-2 text-sm font-medium text-foreground",children:t}),g?s.jsx(Ct,{title:x,collapsed:!0,testId:"agent-ui-hook-collapsed",children:n}):n]})]})}const yn=["info","success","warning"],Nn={info:"border-state/40 bg-state/[0.06]",success:"border-success/50 bg-success/[0.08]",warning:"border-warning/50 bg-warning/[0.08]"},Sn=4;function $t(e){return Array.isArray(e)?e.filter(t=>!!t&&typeof t.label=="string"&&typeof t.action=="string"&&t.action!=="").slice(0,Sn):[]}function It(e){const t=m(e,"tone");return yn.includes(t)?t:"info"}function kn(e){return JSON.stringify([m(e,"title"),m(e,"body"),It(e),$t(P(e).buttons)])}const Pt="agentui:notice:dismissed:";function Cn(e){try{return window.localStorage.getItem(Pt+e)==="1"}catch(t){return console.error("agentui: could not read dismissed notices",t),!1}}function Rn(e){try{window.localStorage.setItem(Pt+e,"1")}catch(t){console.error("agentui: could not remember a dismissed notice",t)}}function Tn({n:e}){const t=kn(e);return s.jsx(An,{n:e,identity:t},t)}function An({n:e,identity:t}){const{states:n,invoke:a,busy:r}=le(),[o,l]=i.useState(()=>Cn(t)),[d,f]=i.useState(null);if(o)return null;const p=It(e),u=m(e,"title"),c=$t(P(e).buttons),h=c.some(g=>ie((n[g.action]??{phase:"idle"}).phase)),b=d!==null||h||!!r,x=d!==null?n[d]??{phase:"submitted"}:null;return s.jsxs(ge,{"data-testid":"ap-notice","data-tone":p,className:L("relative",Nn[p]),children:[s.jsx("button",{type:"button","aria-label":"Dismiss",className:"absolute right-2 top-2 rounded p-1 text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",onClick:()=>{Rn(t),l(!0)},children:s.jsx(xs,{className:"h-4 w-4","aria-hidden":"true"})}),u&&s.jsx(bt,{className:"pb-2 pr-8",children:s.jsx(wt,{className:"text-base",children:u})}),s.jsxs(Pe,{className:L("flex flex-col gap-3 pr-8",!u&&"pt-6"),children:[s.jsx(_e,{children:m(e,"body")}),c.length>0&&s.jsx("div",{className:"flex flex-wrap gap-2",children:c.map((g,w)=>s.jsx(B,{type:"button",variant:w===0?"default":"secondary",disabled:b,onClick:()=>{f(g.action),a(g.action,void 0)},children:g.label},`${g.action}:${w}`))}),x!==null&&s.jsx("p",{"data-testid":"ap-notice-sent",className:"text-xs text-muted-foreground",children:De(x)??"Sent."})]})]})}function $e(e,t){return e?e.component===t?!0:(e.children??[]).some(n=>$e(n,t)):!1}function En(e,t){const n=new Set,a=(r,o)=>{const l=ne(r)??o;r.component===t&&l!==null&&n.add(l);for(const d of r.children??[])a(d,l)};return e&&a(e,null),n}function $n(e){const t=(n,a)=>{const r=ne(n)??a;return n.component==="ap:question"&&r===null?!0:(n.children??[]).some(o=>t(o,r))};return e?t(e,null):!1}function Ot(e){var o;if(!e)return[];const t=[],n=l=>{l.component==="ap:steps"&&t.push(l);for(const d of l.children??[])n(d)};if(n(e),t.length!==1)return[];const a=(o=t[0].props)==null?void 0:o.steps,r=[];for(const l of Array.isArray(a)?a:[]){if(!l||typeof l.id!="string"||l.id==="")continue;const d=l.state==="done"||l.state==="active"?l.state:"upcoming";r.push({id:l.id,label:typeof l.label=="string"?l.label:l.id,state:d})}return r}function In(e){const t=new Map;if(!e)return t;const n=new Map;for(const r of Ot(e))n.set(r.id,{step:r.id,label:r.label,state:r.state});if(n.size===0)return t;const a=r=>{var d,f;const o=ne(r),l=(d=r.props)==null?void 0:d.step;if(o!==null&&typeof l=="string"){const p=n.get(l);if(p){const u=(f=r.props)==null?void 0:f.title;t.set(o,typeof u=="string"&&u!==""?{...p,title:u}:p)}}for(const p of r.children??[])a(p)};return a(e),t}function Mt(e,t){return e.component===t?!0:(e.children??[]).some(n=>Mt(n,t))}function Pn(e){var n;const t=e.component===Tt?(n=e.props)==null?void 0:n.step:void 0;return typeof t=="string"&&t!==""?t:null}function On({node:e,renderChild:t}){var x;const n=((x=e.props)==null?void 0:x.layout)==="rail"?"rail":"column",a=e.children??[],{waiting:r}=Fe(),o=i.useMemo(()=>Ot(e),[e]),l=i.useMemo(()=>{const g=o.find(C=>C.state==="active");if(g)return g.id;const w=o.filter(C=>C.state==="done");return w.length>0?w[w.length-1].id:o.length>0?o[0].id:null},[o]),[d,f]=i.useState(null);i.useEffect(()=>{f(null)},[l]);const p=d??l,u=i.useMemo(()=>({layout:n,selectedStep:p,selectStep:f}),[n,p]);if(n!=="rail")return s.jsx(Ee.Provider,{value:u,children:s.jsx("div",{className:"flex flex-col gap-2",children:a.map(t)})});const c=a.findIndex(g=>Mt(g,"ap:steps")),h=c>=0?a[c]:null,b=(g,w)=>{if(w===c)return!1;const C=Pn(g);if(C===null||C===p)return!0;const N=ne(g);return N!==null&&r.has(N)};return s.jsx(Ee.Provider,{value:u,children:s.jsxs("div",{className:"grid gap-6 md:grid-cols-[220px_minmax(0,1fr)]",children:[s.jsx("div",{"data-testid":"agent-ui-page-rail",className:"md:sticky md:top-4 md:self-start",children:h?t(h,"rail"):null}),s.jsx("div",{"data-testid":"agent-ui-page-stage",className:"flex min-w-0 flex-col gap-3",children:a.map((g,w)=>b(g,w)?t(g,w):null)})]})})}const Mn={"ap:select":{prop:"param",values:[{valueProp:"value"}]},"ap:daterange":{prop:"param",values:[{suffix:"from",valueProp:"from"},{suffix:"to",valueProp:"to"}]}};function he(e,t){return t?`${e}.${t}`:e}function Ve(e){const t=Mn[e.component];if(!t)return null;const n=(e.props??{})[t.prop];return typeof n!="string"||n===""?null:{name:n,spec:t}}const Ln={params:{},setParam:()=>{}},Lt=i.createContext(Ln);function _n({value:e,children:t}){return s.jsx(Lt.Provider,{value:e,children:t})}function _t(){return i.useContext(Lt)}function Dt(e){const t={};return e.view&&Ut(e.view,t),t}function ye(e,t){const n=Dt(e),a={};for(const r of Dn(e))r in t?a[r]=t[r]:r in n&&(a[r]=n[r]);return a}function Dn(e){const t=[],n=a=>{const r=Ve(a);if(r)for(const o of r.spec.values){const l=he(r.name,o.suffix);t.includes(l)||t.push(l)}for(const o of a.children??[])n(o)};return e.view&&n(e.view),t}function Ut(e,t){const n=Ve(e);if(n){const a=e.props??{};for(const r of n.spec.values){const o=a[r.valueProp];typeof o=="string"&&o!==""&&(t[he(n.name,r.suffix)]=o)}}for(const a of e.children??[])Ut(a,t)}const at=e=>Array.isArray(e)?e.filter(t=>typeof t=="string"):[];function rt({label:e,state:t}){return s.jsxs("li",{"data-state":t,className:"flex items-center gap-2 text-sm",children:[t==="done"&&s.jsx("span",{"aria-hidden":"true",className:"text-[hsl(var(--success))]",children:"✓"}),s.jsx("span",{className:t==="done"?"text-muted-foreground line-through":void 0,children:e})]})}function Un({n:e}){const t=m(e,"now"),n=at(P(e).done),a=at(P(e).next),r=m(e,"step");return s.jsx(ge,{children:s.jsxs("section",{"data-testid":"ap-progress",className:"flex flex-col gap-3 p-6",children:[s.jsx("p",{"data-testid":"ap-progress-now",className:"text-sm font-medium",children:t}),(n.length>0||a.length>0)&&s.jsxs("ul",{className:"flex flex-col gap-1.5",children:[n.map((o,l)=>s.jsx(rt,{label:o,state:"done"},`done-${l}`)),a.map((o,l)=>s.jsx(rt,{label:o,state:"next"},`next-${l}`))]}),r&&s.jsx("p",{className:"text-xs text-muted-foreground",children:r})]})})}function qn(e){return Array.isArray(e)?e.filter(t=>!!t&&typeof t.value=="string"&&typeof t.label=="string"):[]}function Fn({n:e}){const t=JSON.stringify([m(e,"prompt"),m(e,"kind"),P(e).choices??null]);return s.jsx(Vn,{n:e},t)}function Vn({n:e}){const{answer:t,busy:n}=le(),a=wn(),{answered:r}=Fe(),o=a!==null&&r.has(a),l=m(e,"prompt"),d=m(e,"kind")==="choice"?"choice":"text",f=m(e,"placeholder"),p=m(e,"submitLabel","Answer"),u=qn(P(e).choices),c=i.useId(),[h,b]=i.useState(""),[x,g]=i.useState(!1),[w,C]=i.useState(!1),[N,M]=i.useState(!1);if(w||o)return s.jsx("p",{"data-testid":"ap-question-sent",children:"Sent — waiting for the agent."});const D=h.trim()===""||x||!!n;function j(v){v.preventDefault(),!D&&(g(!0),M(!1),t(h).then(()=>C(!0)).catch($=>{console.error("agentui: ap:question answer failed",$),M(!0)}).finally(()=>g(!1)))}return s.jsx(ge,{children:s.jsx(Pe,{className:"pt-6",children:s.jsxs("form",{"data-testid":"ap-question",onSubmit:j,className:"flex flex-col gap-3",children:[s.jsx(oe,{htmlFor:d==="text"?c:void 0,className:"font-normal text-foreground",children:l}),d==="choice"?s.jsx("div",{className:"flex flex-col gap-2",children:u.map(v=>s.jsxs(oe,{className:"flex items-center gap-2 font-normal",children:[s.jsx("input",{type:"radio",name:c,value:v.value,checked:h===v.value,disabled:x||!!n,onChange:()=>b(v.value),className:"h-4 w-4 border-input text-primary focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"}),v.label]},v.value))}):s.jsx("textarea",{id:c,placeholder:f,value:h,disabled:x||!!n,onChange:v=>b(v.target.value),className:"flex min-h-16 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50"}),s.jsx(B,{type:"submit",disabled:D,className:"self-start",children:p}),N&&s.jsx("p",{role:"alert",className:"text-xs text-destructive",children:"Could not send your answer. Try again."})]})})})}const ot={idle:"bg-muted-foreground",running:"bg-[hsl(var(--success))] animate-pulse",paused:"bg-[hsl(var(--warning))]",ended:"bg-muted-foreground",unwatched:"bg-[hsl(var(--warning))]"};function Bn(e){if(e==="")return null;const t=new Date(e);return Number.isNaN(t.getTime())?null:t.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}function Hn({n:e}){const t=m(e,"state"),n=ot[t]??ot.idle,a=m(e,"since"),r=Bn(a);return s.jsxs("div",{"data-testid":"ap-status","data-state":t,role:"status",title:a||void 0,className:"flex items-center gap-2 text-sm font-medium",children:[s.jsx("span",{"aria-hidden":"true",className:L("inline-block h-2 w-2 shrink-0 rounded-full",n)}),s.jsxs("span",{children:[m(e,"text"),r!==null&&s.jsxs(s.Fragment,{children:[" ",s.jsx("time",{dateTime:a,children:r})]})]})]})}function qt(e,t,n){return t.includes(e)?e:n}const Wn=["default","secondary","destructive","outline"],Kn=["default","secondary","destructive","outline","ghost","link"],ue={none:"gap-0",sm:"gap-2",md:"gap-4",lg:"gap-6"},it={start:"items-start",center:"items-center",end:"items-end",stretch:"items-stretch"},Ne=e=>`apui-${e}`,zn=e=>e==="right"?"text-right":e==="center"?"text-center":void 0,Yn=e=>e==="right"?"text-right tabular-nums":e==="center"?"text-center":void 0;function Jn({n:e}){const{params:t,setParam:n}=_t(),a=m(e,"param"),r=a!=="",o=m(e,"value"),l=r?t[a]??o:o,d=m(e,"placeholder");return s.jsx("div",{className:"flex flex-col gap-1",children:s.jsxs("select",{disabled:!r,className:L("h-9 rounded-md border border-input bg-transparent px-3 text-sm",!r&&"text-muted-foreground"),value:l,onChange:r?f=>n(a,f.target.value):void 0,children:[d&&s.jsx("option",{value:"",disabled:!0,hidden:!0,children:d}),(P(e).options??[]).map(f=>s.jsx("option",{value:f.value,children:f.label??f.value},f.value))]})})}function lt(e){return e===""||e.includes("T")?e:`${e}T00:00:00Z`}function ct(e){const t=e.indexOf("T");return t===-1?e:e.slice(0,t)}function Gn({n:e}){const{params:t,setParam:n}=_t(),a=m(e,"param");if(!(a!==""))return s.jsxs(B,{variant:"secondary",disabled:!0,children:[m(e,"from")||"start"," → ",m(e,"to")||"end"]});const o=he(a,"from"),l=he(a,"to"),d=t[o]??m(e,"from"),f=t[l]??m(e,"to");return s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx(Ae,{type:"date","aria-label":"From date",value:ct(d),onChange:p=>n(o,lt(p.target.value)),className:"h-9 w-auto"}),s.jsx("span",{className:"text-muted-foreground","aria-hidden":"true",children:"→"}),s.jsx(Ae,{type:"date","aria-label":"To date",value:ct(f),onChange:p=>n(l,lt(p.target.value)),className:"h-9 w-auto"})]})}function Be({text:e}){return e?s.jsx("span",{"data-testid":"agent-ui-action-status",className:"text-xs text-muted-foreground",children:e}):null}function Xn({n:e,columns:t,rows:n}){const{states:a,invoke:r}=le(),o=m(e,"rowAction"),l=o!=="",d=l?a[o]??{phase:"idle"}:{phase:"idle"},f=ie(d.phase);return n.length===0?s.jsx("p",{className:"py-6 text-center text-sm text-muted-foreground",children:m(e,"empty","Nothing to show.")}):s.jsxs("div",{className:"overflow-x-auto",children:[s.jsxs(os,{children:[s.jsx(is,{children:s.jsxs(Je,{children:[t.map(p=>s.jsx(Ge,{className:zn(p.align),children:p.header??p.key},p.key)),l&&s.jsx(Ge,{className:"w-px"})]})}),s.jsx(ls,{children:n.map((p,u)=>s.jsxs(Je,{children:[t.map(c=>s.jsx(Xe,{className:Yn(c.align),children:String(p[c.key]??"")},c.key)),l&&s.jsx(Xe,{className:"text-right",children:s.jsx(B,{variant:"ghost",size:"sm",disabled:f,"data-testid":"agent-ui-row-action",onClick:()=>r(o,Qn(p)),children:m(e,"rowActionLabel","Details")})})]},u))})]}),s.jsx(Be,{text:l?d.message??null:null})]})}function Se(e,t){if(e==null)return[];if(!Array.isArray(e))throw new TypeError(`${t} must be an array`);return e}function Qn(e){const t={};for(const[n,a]of Object.entries(e))typeof a=="string"?t[n]=a:(typeof a=="number"&&Number.isFinite(a)||typeof a=="boolean")&&(t[n]=String(a));return t}function Zn({n:e}){const{states:t,invoke:n,busy:a}=le(),r=m(e,"action"),o=r!=="",l=o?t[r]??{phase:"idle"}:{phase:"idle"},d=!o||ie(l.phase)||!!a||!!P(e).disabled;return s.jsxs("div",{className:"flex flex-col gap-1",children:[s.jsx(B,{variant:qt(m(e,"variant"),Kn,"default"),disabled:d,onClick:o?()=>n(r,void 0):void 0,children:m(e,"label")}),s.jsx(Be,{text:De(l)})]})}function ea({n:e}){const{states:t,invoke:n,busy:a}=le(),r=m(e,"action"),o=r!=="",l=o?t[r]??{phase:"idle"}:{phase:"idle"},d=!o||ie(l.phase)||!!a||!!P(e).disabled,f=P(e).fields??[],p=P(e).values??{},[u,c]=i.useState(()=>({...p}));return s.jsxs("form",{className:"flex flex-col gap-3",onSubmit:h=>{h.preventDefault(),o&&n(r,Object.fromEntries(f.map(b=>[b.name,u[b.name]??""])))},children:[f.map(h=>s.jsxs("div",{className:"flex flex-col gap-1",children:[s.jsx(oe,{htmlFor:Ne(h.name),children:h.label??h.name}),h.kind==="textarea"?s.jsx("textarea",{id:Ne(h.name),name:h.name,placeholder:h.placeholder,disabled:d,value:u[h.name]??"",onChange:b=>c(x=>({...x,[h.name]:b.target.value})),className:"flex min-h-16 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50"}):s.jsx(Ae,{id:Ne(h.name),name:h.name,type:h.kind==="number"?"number":"text",placeholder:h.placeholder,disabled:d,value:u[h.name]??"",onChange:b=>c(x=>({...x,[h.name]:b.target.value}))})]},h.name)),s.jsx(B,{type:"submit",disabled:d,children:m(e,"submitLabel","Submit")}),s.jsx(Be,{text:De(l)})]})}function ta(e){const t=Ue(e);return t===null?null:`/session-view/${encodeURIComponent(t[0])}/${encodeURIComponent(t[1])}`}function sa(e,t){const n=s.jsx("ol",{className:"flex w-full items-center","data-testid":"agent-ui-steps",children:t.map((a,r)=>{const o=a.state==="done"||a.state==="active"?a.state:"upcoming",l=r===t.length-1;return s.jsxs("li",{className:L("flex items-center",!l&&"flex-1"),"aria-current":o==="active"?"step":void 0,children:[s.jsxs("div",{className:"flex flex-col items-center gap-1.5",children:[s.jsx("span",{className:L("flex h-7 w-7 items-center justify-center rounded-full border text-xs font-semibold tabular-nums transition-colors",o==="done"&&"border-[hsl(var(--primary))] bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))]",o==="active"&&"border-[hsl(var(--primary))] text-[hsl(var(--primary))] ring-2 ring-[hsl(var(--primary))]/30",o==="upcoming"&&"border-border text-muted-foreground"),children:o==="done"?"✓":r+1}),s.jsx("span",{className:L("whitespace-nowrap text-xs",o==="active"?"font-medium text-foreground":"text-muted-foreground"),children:a.label??""})]}),!l&&s.jsx("span",{className:L("mx-2 mb-5 h-px flex-1 transition-colors",o==="done"?"bg-[hsl(var(--primary))]":"bg-border"),"aria-hidden":"true"})]},r)})});return P(e).pinned?s.jsx("div",{"data-testid":"agent-ui-steps-pinned",className:"sticky top-0 z-10 -mx-4 bg-background px-4 py-2",children:n}):n}function na({node:e,steps:t}){const{layout:n,selectedStep:a,selectStep:r}=Rt();return n!=="rail"?sa(e,t):s.jsx("ol",{className:"flex flex-col","data-testid":"agent-ui-steps","aria-label":"Steps",children:t.map((o,l)=>{const d=o.state==="done"||o.state==="active"?o.state:"upcoming",f=typeof o.id=="string"&&o.id!==""?o.id:null,p=f!==null&&f===a;return s.jsxs("li",{"data-testid":"agent-ui-rail-step","data-step-id":f??void 0,"data-selected":p?"true":void 0,className:"relative",children:[s.jsxs("button",{type:"button",onClick:()=>f!==null&&r(f),disabled:f===null,"aria-current":d==="active"?"step":void 0,"aria-pressed":p,className:L("flex w-full items-start gap-2.5 rounded-md px-2 py-1.5 text-left transition-colors hover:bg-muted/40",p&&"bg-muted/60"),children:[s.jsx("span",{className:L("mt-0.5 flex h-5 w-5 shrink-0 items-center justify-center rounded-full border text-[10px] font-semibold tabular-nums",d==="done"&&"border-[hsl(var(--primary))] bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))]",d==="active"&&"border-[hsl(var(--primary))] text-[hsl(var(--primary))] ring-2 ring-[hsl(var(--primary))]/30",d==="upcoming"&&"border-border text-muted-foreground"),children:d==="done"?"✓":l+1}),s.jsxs("span",{className:"min-w-0",children:[s.jsx("span",{className:L("block text-sm",d==="active"?"font-medium text-foreground":d==="upcoming"?"text-muted-foreground":"text-foreground"),children:o.label??""}),o.summary?s.jsx("span",{className:"block truncate text-xs text-muted-foreground",children:o.summary}):null]})]}),ls.jsx("div",{className:L("flex",m(e,"direction")==="horizontal"?"flex-row":"flex-col",ue[m(e,"gap","md")]??ue.md,it[m(e,"align","start")]??it.start),children:(e.children??[]).map(t)}),"ap:status":e=>s.jsx(Hn,{n:e}),"ap:grid":(e,t)=>{const n=typeof P(e).columns=="number"?P(e).columns:0,a=n>0?Math.min(Math.max(Math.trunc(n),1),12):0;return s.jsx("div",{className:L("grid",ue[m(e,"gap","md")]??ue.md),style:{gridTemplateColumns:a>0?`repeat(${a}, minmax(0, 1fr))`:"repeat(auto-fit, minmax(16rem, 1fr))"},children:(e.children??[]).map(t)})},"ap:card":(e,t)=>{const n=!!(m(e,"title")||m(e,"description"));return s.jsxs(ge,{children:[n&&s.jsxs(bt,{children:[m(e,"title")&&s.jsx(wt,{children:m(e,"title")}),m(e,"description")&&s.jsx(rs,{children:m(e,"description")})]}),s.jsx(Pe,{className:n?void 0:"pt-6",children:(e.children??[]).map(t)})]})},"ap:collapsible":(e,t)=>s.jsx(Ct,{title:m(e,"title"),collapsed:!!P(e).collapsed,testId:"ap-collapsible",children:(e.children??[]).map(t)}),"ap:heading":e=>{const t=Math.min(Math.max(Number(P(e).level)||2,1),4),n=`h${t}`,a={1:"text-2xl",2:"text-xl",3:"text-lg",4:"text-base"}[t]??"text-xl";return s.jsx(n,{className:L(a,"font-semibold text-foreground"),children:m(e,"text")})},"ap:text":e=>s.jsx("p",{className:L(m(e,"variant")==="muted"&&"text-muted-foreground",m(e,"variant")==="mono"&&"font-mono","text-sm"),children:m(e,"text")}),"ap:markdown":e=>s.jsx(_e,{children:m(e,"body")}),"ap:metric":e=>s.jsxs("div",{className:"flex flex-col gap-1",children:[s.jsx("span",{className:"text-xs uppercase tracking-wide text-muted-foreground",children:m(e,"label")}),s.jsx("span",{className:"text-2xl font-semibold tabular-nums",children:m(e,"value")}),m(e,"delta")&&s.jsx("span",{className:L("text-xs tabular-nums",m(e,"trend")==="up"&&"text-[hsl(var(--success))]",m(e,"trend")==="down"&&"text-destructive",m(e,"trend")!=="up"&&m(e,"trend")!=="down"&&"text-muted-foreground"),children:m(e,"delta")}),m(e,"caption")&&s.jsx("span",{className:"text-xs text-muted-foreground",children:m(e,"caption")})]}),"ap:progress":e=>s.jsx(Un,{n:e}),"ap:question":e=>s.jsx(Fn,{n:e}),"ap:notice":e=>s.jsx(Tn,{n:e}),"ap:table":e=>{const t=Se(P(e).columns,"ap:table.columns"),n=Se(P(e).rows,"ap:table.rows");return s.jsx(Xn,{n:e,columns:t,rows:n})},"ap:badge":e=>s.jsx(Ds,{variant:qt(m(e,"variant"),Wn,"default"),children:m(e,"text")}),"ap:alert":e=>{const t=m(e,"severity");return s.jsxs(W,{variant:t==="error"?"destructive":"default",className:t==="warning"?"border-warning/50 text-warning [&>svg]:text-warning":void 0,children:[m(e,"title")&&s.jsx(Y,{children:m(e,"title")}),m(e,"body")&&s.jsx(J,{children:m(e,"body")})]})},"ap:empty":e=>s.jsxs("div",{className:"flex flex-col items-center gap-1 py-10 text-center",children:[s.jsx("p",{className:"text-sm font-medium",children:m(e,"title","Nothing here yet")}),m(e,"body")&&s.jsx("p",{className:"text-xs text-muted-foreground",children:m(e,"body")})]}),"ap:steps":e=>{const t=Se(P(e).steps,"ap:steps.steps");return t.forEach((n,a)=>{if(typeof n!="object"||n===null)throw new TypeError(`ap:steps.steps[${a}] must be an object`)}),s.jsx(na,{node:e,steps:t})},"ap:skeleton":e=>s.jsxs("div",{className:"flex flex-col gap-2 py-4","data-testid":"ap-skeleton","aria-busy":"true","aria-live":"polite",children:[m(e,"label")&&s.jsx("p",{className:"text-xs text-muted-foreground",children:m(e,"label")}),s.jsx("div",{className:"h-4 w-1/3 animate-pulse rounded bg-muted"}),s.jsx("div",{className:"h-4 w-full animate-pulse rounded bg-muted"}),s.jsx("div",{className:"h-4 w-5/6 animate-pulse rounded bg-muted"}),!m(e,"label")&&s.jsx("span",{className:"sr-only",children:"Loading…"})]}),"ap:error":e=>s.jsxs(W,{variant:"destructive",children:[s.jsx(Y,{children:m(e,"title","Something went wrong")}),m(e,"body")&&s.jsx(J,{children:m(e,"body")})]}),"ap:chart":e=>{const t=P(e).series??[],n=P(e).data??[],a=m(e,"xKey"),r=m(e,"kind","line");if(n.length===0||t.length===0)return s.jsx("p",{className:"py-6 text-center text-sm text-muted-foreground",children:"No data to chart."});const o=s.jsx(Ns,{stroke:"hsl(var(--border))",strokeDasharray:"3 3",vertical:!1}),l=s.jsx(Ss,{dataKey:a,stroke:"hsl(var(--muted-foreground))",tickLine:!1,axisLine:!1}),d=s.jsx(ks,{stroke:"hsl(var(--muted-foreground))",tickLine:!1,axisLine:!1,width:40}),f=s.jsx(zs,{});return r==="bar"?s.jsx(je,{children:s.jsxs(gs,{data:n,children:[o,l,d,f,t.map((p,u)=>s.jsx(vs,{dataKey:p.key,name:p.label??p.key,fill:de(u)},p.key))]})}):r==="area"?s.jsx(je,{children:s.jsxs(bs,{data:n,children:[o,l,d,f,t.map((p,u)=>s.jsx(ws,{type:"monotone",dataKey:p.key,name:p.label??p.key,stroke:de(u),fill:de(u),fillOpacity:.25},p.key))]})}):s.jsx(je,{children:s.jsxs(js,{data:n,children:[o,l,d,f,t.map((p,u)=>s.jsx(ys,{type:"monotone",dataKey:p.key,name:p.label??p.key,stroke:de(u),strokeWidth:2,dot:!1},p.key))]})})},"ap:chat":e=>s.jsx(Qs,{n:e}),"ap:tabs":(e,t)=>{const n=P(e).tabs??[],a=e.children??[];return n.length===0?s.jsx(s.Fragment,{children:a.map(t)}):s.jsxs(ts,{defaultValue:m(e,"value")||n[0].value,children:[s.jsx(ss,{children:n.map(r=>s.jsx(ns,{value:r.value,children:r.label??r.value},r.value))}),n.map((r,o)=>{const d=o===n.length-1?a.slice(o):a.slice(o,o+1);return s.jsx(as,{value:r.value,children:d.map((f,p)=>t(f,`${r.value}-${p}`))},r.value)})]})},"ap:raw_html":()=>s.jsxs(W,{children:[s.jsx(Y,{children:"Embedded content"}),s.jsx(J,{children:"This section renders once the sandboxed content view is available."})]}),"ap:session_view":e=>{const t=ta(P(e).sessionRef);return t===null?s.jsx(W,{children:"Session view unavailable: no valid session reference."}):s.jsx("iframe",{src:t,title:"Session view",style:{width:"100%",height:"600px",border:"0"}})},"ap:agentlink":e=>(qe(e),s.jsx(ln,{n:e})),"ap:attachment":e=>s.jsx(mn,{n:e}),"ap:button":e=>s.jsx(Zn,{n:e}),"ap:select":e=>s.jsx(Jn,{n:e}),"ap:daterange":e=>s.jsx(Gn,{n:e}),"ap:form":e=>s.jsx(ea,{n:e}),"oap:generative":(e,t)=>{var n;return s.jsx(jn,{name:m(e,"name"),title:typeof((n=e.props)==null?void 0:n.title)=="string"?e.props.title:void 0,children:(e.children??[]).map(t)})},"oap:page":(e,t)=>s.jsx(On,{node:e,renderChild:t})};function ra({type:e}){return s.jsxs(W,{variant:"destructive",children:[s.jsx(Y,{children:"Cannot render this section"}),s.jsxs(J,{children:["Unknown component ",s.jsx("code",{className:"font-mono",children:e}),". Reload the page; if it persists, this view needs an update."]})]})}function oa({type:e}){return s.jsxs(W,{variant:"destructive",children:[s.jsx(Y,{children:"Cannot render this section"}),s.jsxs(J,{children:["The ",s.jsx("code",{className:"font-mono",children:e})," section could not be displayed. The rest of this view is unaffected."]})]})}const ia=e=>(t,n)=>Ft(t,n,e);function Ft(e,t,n){const a=aa[e.component];if(!a)return n==null||n(e.component),s.jsx(ra,{type:e.component},t);try{return i.cloneElement(a(e,ia(n)),{key:t})}catch(r){return console.error(`agentui: failed to render ${e.component}`,r),n==null||n(e.component),s.jsx(oa,{type:e.component},t)}}function la(e,t,n){return`${e}/${t.join(".")}#${n}`}function ca(e,t){return Vt(e,ne(e)??"",[],t)}function Vt(e,t,n,a){var c;const r=(c=e.children)==null?void 0:c.map((h,b)=>{const x=ne(h);return Vt(h,x??t,x!==null?[]:[...n,b],a)});if(!e.bindings)return{...e,children:r};const o={...e.props};let l=null,d=null,f=null;for(const h of Object.keys(e.bindings).sort()){const b=a[la(t,n,h)]??{status:"loading"};if(b.status==="error"){l===null&&(l=b.message);continue}if(b.status==="needs_input"){d===null&&(d=b.message);continue}if(b.status==="waking"){f===null&&(f=b.message);continue}if(b.status==="loading"){f===null&&(f="");continue}o[h]=b.value}if(l===null&&d===null&&f===null)return{...e,props:o,children:r};const u=l!==null?{component:"ap:error",props:{title:"Cannot load this section",body:l}}:f!==null?{component:"ap:skeleton",props:f===""?{}:{label:f}}:{component:"ap:empty",props:{title:"Nothing to show yet",body:d}};return Ve(e)?{component:"ap:stack",props:{gap:"sm"},children:[{...e,props:o,children:r},u]}:u}const xe="p.";function dt(e){const t={};return new URLSearchParams(e).forEach((a,r)=>{if(!r.startsWith(xe))return;const o=r.slice(xe.length);o!==""&&(t[o]=a)}),t}function da(e,t){const n=new URLSearchParams(e);for(const r of Array.from(n.keys()))r.startsWith(xe)&&n.delete(r);for(const r of Object.keys(t).sort())n.set(xe+r,t[r]);const a=n.toString();return a===""?"":`?${a}`}function ua({open:e,variant:t,text:n,replySeq:a,onReply:r,onDismiss:o}){const[l,d]=i.useState(""),[f,p]=i.useState(!1),[u,c]=i.useState(!1);i.useEffect(()=>{d(""),c(!1)},[a]);const h=l.trim()===""||f;function b(x){x.preventDefault(),!h&&(p(!0),c(!1),r(l).catch(g=>{console.error("agentui: reply modal send failed",g),c(!0)}).finally(()=>p(!1)))}return s.jsx(Oe,{open:e,onOpenChange:x=>{x||o()},children:s.jsxs(Me,{"data-testid":"agent-ui-reply-modal","data-variant":t,children:[s.jsx(Le,{children:t==="paused"?s.jsxs(s.Fragment,{children:[s.jsx(pe,{children:"The agent paused"}),s.jsx(me,{children:"It replied and stopped without asking anything. Send a message to continue."})]}):s.jsxs(s.Fragment,{children:[s.jsx(pe,{children:"The agent is waiting for your reply"}),s.jsx(me,{children:"Your reply goes to this session's conversation, just as if you had typed it there."})]})}),s.jsx("div",{className:"max-h-48 overflow-y-auto text-sm",children:s.jsx(_e,{children:n})}),s.jsxs("form",{onSubmit:b,className:"flex flex-col gap-3",children:[s.jsx("textarea",{"aria-label":"Your reply",value:l,disabled:f,onChange:x=>d(x.target.value),placeholder:t==="paused"?"Tell it how to continue…":void 0,className:"flex min-h-20 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50"}),u&&s.jsx("p",{role:"alert",className:"text-xs text-destructive",children:"Could not send your reply. Try again."}),s.jsxs(cs,{children:[s.jsx(B,{type:"button",variant:"ghost",onClick:o,disabled:f,children:"Later"}),s.jsx(B,{type:"submit",disabled:h,children:f?"Sending…":t==="paused"?"Continue":"Reply"})]})]})]})})}function fa(e){var t;return e.turnActive?e.composingUpdate?"Composing a page update…":(t=e.activity)!=null&&t.compactLine?e.activity.compactLine:e.notice?e.notice:"Working…":null}function pa(e){switch(e){case"done":return"done";case"in_progress":return"current";default:return"next"}}function ma({label:e,state:t,live:n}){return s.jsxs("li",{"data-state":t,className:"flex items-center gap-2 text-xs",children:[t==="done"&&s.jsx("span",{"aria-hidden":"true",className:"text-[hsl(var(--success))]",children:"✓"}),t==="current"&&s.jsx(ve,{className:L("h-3 w-3 shrink-0 text-primary",n&&"animate-spin"),"aria-hidden":"true"}),s.jsx("span",{className:L(t==="done"&&"text-muted-foreground line-through",t==="next"&&"text-muted-foreground"),children:e})]})}function ha({signals:e}){var a;if(!e.turnActive&&e.plan===null)return null;const t=fa(e),n=((a=e.plan)==null?void 0:a.items)??[];return s.jsxs("section",{"data-testid":"agent-ui-default-progress","aria-live":"polite",className:"flex flex-col gap-2 border-b border-border bg-card/40 px-4 py-2",children:[t!==null&&s.jsxs("p",{"data-testid":"agent-ui-progress-now","data-composing":e.composingUpdate?"true":void 0,className:"flex items-center gap-2 text-xs font-medium text-foreground",children:[!e.composingUpdate&&s.jsx(ve,{className:"h-3 w-3 shrink-0 animate-spin text-muted-foreground","aria-hidden":"true"}),t]}),n.length>0&&s.jsx("ul",{className:"flex flex-col gap-1",children:n.map((r,o)=>s.jsx(ma,{label:r.label,state:pa(r.status),live:e.turnActive},`${o}-${r.id}`))})]})}const Bt="$transport",xa="This view's data could not be loaded. Check your connection and reload.";function ut(e){return{status:"error",message:e}}class ke extends Error{constructor(t,n){super(`agent-ui bindings request failed (${t})`),this.name="BindingsRequestError",this.authored=n,this.status=t}}const ga=410;async function va(e){try{const t=await e.json();return typeof(t==null?void 0:t.error)=="string"?t.error:""}catch{return""}}const ba=250,wa=2e3,ja=15;function ya(e,t,n,a,r){const[o,l]=i.useState({}),[d,f]=i.useState(!1),p=i.useRef(r);p.current=r;const u=i.useRef(0),c=i.useRef(!0),[h,b]=i.useState(0),x=i.useRef(0),g=i.useRef(null);return i.useEffect(()=>{let w=!0;u.current+=1;const C=u.current,N=()=>w&&C===u.current,M=new AbortController,D=c.current?0:ba;c.current=!1;const j=setTimeout(()=>{D>0&&f(!0),fetch(`/agent-ui/${encodeURIComponent(e)}/${encodeURIComponent(t)}/bindings`,{method:"POST",credentials:"same-origin",headers:{"Content-Type":"application/json"},body:JSON.stringify({params:n}),signal:M.signal}).then(async v=>{if(!v.ok)throw new ke(v.status,await va(v));return await v.json()}).then(v=>{if(!N())return;const $={};let k=!1;for(const[y,T]of Object.entries(v.bindings??{})){if(T.status==="ok"){$[y]={status:"ok",value:T.value};continue}if(T.status==="needs_input"){$[y]={status:"needs_input",message:T.message??"Choose a value above to load this data."};continue}if(T.status==="waking"){$[y]={status:"waking",message:T.message??"Waking this agent…"},k=!0;continue}$[y]={status:"error",message:T.message??"This view's data is not available."}}l($),k&&x.current{w&&(l(y=>y),b(y=>y+1))},wa)):k?l(y=>{const T={};for(const[U,H]of Object.entries(y))T[U]=H.status==="waking"?{status:"error",message:"the agent for this session isn't responding"}:H;return T}):x.current=0,f(!1)}).catch(v=>{var k;if(M.signal.aborted||!N())return;f(!1),console.error("agent-ui bindings: request failed",v),v instanceof ke&&v.status===ga&&((k=p.current)==null||k.call(p));const $=v instanceof ke&&v.authored!==""?v.authored:xa;l(y=>{const T={};for(const U of Object.keys(y))T[U]=ut($);return T[Bt]=ut($),T})})},D);return()=>{w=!1,clearTimeout(j),M.abort(),g.current!==null&&(clearTimeout(g.current),g.current=null)}},[e,t,JSON.stringify(n),a,h]),{states:o,refreshing:d}}const Na=2e4,Sa=5*6e4,ft=["pointerdown","keydown","scroll","wheel"];function ka({send:e,enabled:t=!0}){const n=i.useRef(e);n.current=e,i.useEffect(()=>{if(!t||typeof window>"u"||typeof document>"u")return;let a=Date.now();const r=()=>{a=Date.now()};for(const d of ft)window.addEventListener(d,r,{passive:!0});const o=()=>document.visibilityState!=="visible"||typeof document.hasFocus=="function"&&!document.hasFocus()?!1:Date.now()-a{o()&&n.current()},Na);return()=>{window.clearInterval(l);for(const d of ft)window.removeEventListener(d,r)}},[t])}function Ca(e,t){return e.replace(/\{([^{}]*)\}/g,(n,a)=>a!==""&&Object.hasOwn(t,a)?t[a]:n)}const Ra=2e3,Ta="This action may not have completed. Check your connection, then check the result before retrying.",Aa="Live updates for this view are unavailable right now.";function Ea(e,t,n){return`${e.protocol==="https:"?"wss:":"ws:"}//${e.host}/agent-ui/${encodeURIComponent(t)}/${encodeURIComponent(n)}/live`}function pt(e){return{phase:e.state,requestId:e.requestId,message:e.message,approvalAddressedToViewer:e.approvalAddressedToViewer}}function Ce(e){return!ie(e)}function $a(e,t){return e!==void 0&&e.phase===t.phase&&e.requestId===t.requestId&&e.message===t.message&&!!e.approvalAddressedToViewer==!!t.approvalAddressedToViewer}function Ia(e,t,n,a,r,o=[]){const[l,d]=i.useState({}),[f,p]=i.useState(null),u=i.useRef(!0),c=i.useRef(n);c.current=n;const h=i.useRef(a);h.current=a;const b=i.useRef(r);b.current=r;const x=i.useRef(o);x.current=o;const g=i.useRef(l);g.current=l;const w=i.useRef(new Set),C=i.useRef(null),N=i.useRef(0),M=i.useRef({});i.useEffect(()=>(u.current=!0,()=>{u.current=!1}),[]),i.useEffect(()=>{let j=null,v,$=!1,k=0;const y=O=>{N.current+=1,M.current[O]=N.current},T=O=>{if(!Ce(O.state))return!1;const A=g.current[O.action];return A===void 0||!Ce(A.phase)},U=O=>{const A=new Set,K={};let z=!1,se=!1;for(const q of O){if(A.has(q.action)||(A.add(q.action),w.current.has(q.action)))continue;T(q)&&(z=!0);const te=pt(q);$a(g.current[q.action],te)||(se=!0),K[q.action]=te,y(q.action)}se&&(d(q=>({...q,...K})),z&&h.current())},H=O=>{const A=T(O);y(O.action),d(K=>({...K,[O.action]:pt(O)})),A&&h.current()},ee=O=>{let A;try{A=JSON.parse(O)}catch(K){console.error("agent-ui live: malformed frame",{ns:e,name:t,err:K});return}if(u.current){if(A.type==="snapshot"){p(null),U(A.actions??[]);return}if(A.type==="event"&&A.action){H(A.action);return}if(A.type==="error"){console.error("agent-ui live: server reported live updates unavailable",{ns:e,name:t,msg:A}),p(A.message||Aa);return}if(A.type==="view"){if(!A.declaration||typeof A.declaration.view!="object"||A.declaration.view===null||typeof A.declaration.view.component!="string"){console.error("agent-ui live: malformed view frame; keeping the previous declaration",{ns:e,name:t,msg:A});return}b.current(A.declaration,A.agentParams,A.hook);return}console.error("agent-ui live: unhandled frame",{ns:e,name:t,msg:A})}},G=()=>{$||(k+=1,console.error("agent-ui live: socket closed; reconnecting",{ns:e,name:t,attempt:k}),v=window.setTimeout(X,Ra))},X=()=>{if(!$){try{j=new WebSocket(Ea(window.location,e,t))}catch(O){console.error("agent-ui live: failed to open socket",{ns:e,name:t,err:O}),G();return}j.onopen=()=>{k=0},C.current=j,j.onmessage=O=>ee(O.data),j.onerror=()=>{},j.onclose=G}};return X(),()=>{$=!0,v&&window.clearTimeout(v),j&&j.close(),C.current=null}},[e,t]),ka({enabled:!0,send:i.useCallback(()=>{const j=C.current;if(!(!j||j.readyState!==WebSocket.OPEN))try{j.send(JSON.stringify({type:"presence"}))}catch(v){console.error("agent-ui live: presence heartbeat send failed",{ns:e,name:t,err:v})}},[e,t])});const D=i.useCallback((j,v)=>{if(w.current.has(j))return;w.current.add(j),N.current+=1;const $=N.current;d(y=>({...y,[j]:{phase:"submitted"}}));const k=x.current.find(y=>y.name===j);if(k!=null&&k.prompt){jt(e,t,Ca(k.prompt,{...c.current,...v??{}})).then(()=>{var y;u.current&&(d(T=>({...T,[j]:{phase:"succeeded",message:"Asked the agent."}})),(y=h.current)==null||y.call(h))}).catch(y=>{console.error("agent-ui actions: asking the agent failed",{ns:e,name:t,action:j,err:y}),u.current&&d(T=>({...T,[j]:{phase:"failed",message:"Could not reach the agent."}}))}).finally(()=>{w.current.delete(j)});return}fetch(`/agent-ui/${encodeURIComponent(e)}/${encodeURIComponent(t)}/actions`,{method:"POST",credentials:"same-origin",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:j,params:c.current,inputs:v})}).then(async y=>{if(!y.ok)throw new Error(`agent-ui actions: request failed (${y.status})`);return await y.json()}).then(y=>{if(!u.current||(M.current[j]??0)>$)return;const T=y.state;d(U=>{var H;return{...U,[j]:{phase:T,requestId:y.requestId,message:y.message,approvalAddressedToViewer:(H=U[j])==null?void 0:H.approvalAddressedToViewer}}}),Ce(T)&&h.current()}).catch(y=>{console.error("agent-ui actions: invoke failed",{ns:e,name:t,action:j,err:y}),u.current&&d(T=>{var U;return{...T,[j]:{phase:"failed",message:Ta,approvalAddressedToViewer:(U=T[j])==null?void 0:U.approvalAddressedToViewer}}})}).finally(()=>{w.current.delete(j)})},[e,t]);return{states:l,invoke:D,liveError:f}}const Pa={approvals:[],trustEvents:[]},Oa=4e3;function Ma(e,t){if(e===t)return!0;if(e.approvals.length!==t.approvals.length||e.trustEvents.length!==t.trustEvents.length)return!1;for(let n=0;nLa(t,n),[t,n]),d=i.useMemo(()=>{const b=new Map;for(const[x,g]of In(e==null?void 0:e.view))g.state==="done"&&b.set(x,g.title??g.label);return b},[e==null?void 0:e.view]),f=i.useMemo(()=>({composed:new Set((e==null?void 0:e.agentComposed)??[]),updated:a,stale:l,waiting:r,answered:new Set((e==null?void 0:e.answered)??[]),collapsed:d}),[e==null?void 0:e.agentComposed,e==null?void 0:e.answered,a,l,r,d]),p=[],u=e!=null&&e.view?Ft(ca(e.view,t),void 0,b=>p.push(b)):null,c=p.length>0?p[0]:null;if(i.useEffect(()=>{c!==null&&o(c)},[c,o]),!(e!=null&&e.view))return s.jsx("div",{className:"p-4 text-sm text-muted-foreground",children:"This agent has not declared any content for this session."});const h=t[Bt];return s.jsx(vn,{value:f,children:s.jsxs("div",{"data-testid":"agent-ui-root",className:L("flex flex-col gap-2 p-4 mx-auto",xn(e==null?void 0:e.view)==="rail"?"max-w-6xl":"max-w-3xl"),"aria-busy":l.has("")||void 0,children:[(h==null?void 0:h.status)==="error"&&s.jsxs(W,{variant:"destructive",children:[s.jsx(Y,{children:"Data unavailable"}),s.jsx(J,{children:h.message})]}),s.jsxs("div",{className:L("relative",l.has("")&&"opacity-60 transition-opacity"),children:[u,l.has("")&&s.jsxs("div",{"data-testid":"agent-ui-region-refreshing",className:"pointer-events-none absolute right-2 top-2 flex items-center gap-1.5 text-[11px] text-muted-foreground",children:[s.jsx(ve,{className:"h-3.5 w-3.5 animate-spin","aria-hidden":"true"}),s.jsx("span",{children:"Updating…"})]})]})]})})}function Da(){const[e,t]=i.useState(()=>new Map),n=i.useRef(new Map),a=i.useCallback(r=>{t(l=>new Map(l).set(r,Date.now()));const o=n.current.get(r);o!==void 0&&clearTimeout(o),n.current.set(r,setTimeout(()=>{n.current.delete(r),t(l=>{if(!l.has(r))return l;const d=new Map(l);return d.delete(r),d})},Oa))},[]);return i.useEffect(()=>{const r=n.current;return()=>{for(const o of r.values())clearTimeout(o);r.clear()}},[]),{updatedHooks:e,markUpdated:a}}function Ua({ns:e,name:t,declaration:n,agentParams:a,shown:r,onChromeSignals:o,onSessionEnded:l}){var Ke,ze;const[d,f]=i.useState(null),p=i.useCallback(S=>{const E=`render-error:${S}`;f(I=>(I==null?void 0:I.id)===E?I:{kind:"hard_error",id:E})},[]),[u,c]=i.useState(n),h=Us(),{questionShowing:b,progressShowing:x,waiting:g}=i.useMemo(()=>{const S=En(u==null?void 0:u.view,"ap:question"),E=new Set((u==null?void 0:u.answered)??[]),I=new Set([...S].filter(V=>!E.has(V)));return{questionShowing:I.size>0||$n(u==null?void 0:u.view)||$e(u==null?void 0:u.view,"ap:notice"),progressShowing:$e(u==null?void 0:u.view,"ap:progress"),waiting:I}},[u==null?void 0:u.view,u==null?void 0:u.answered]),[w,C]=i.useState(0),[N,M]=i.useState(()=>{const E={...Dt(u),...a??{}};return typeof window>"u"?E:ye(u,{...E,...dt(window.location.search)})}),D=i.useRef(new Set(typeof window>"u"?[]:Object.keys(dt(window.location.search)))),j=i.useCallback((S,E)=>{D.current.add(S),M(I=>I[S]===E?I:{...I,[S]:E})},[]),v=i.useCallback((S,E)=>{M(I=>{const V={...I};let Q=!1;for(const[we,Ye]of Object.entries(ye(E,S)))D.current.has(we)||V[we]===Ye||(V[we]=Ye,Q=!0);return Q?V:I})},[]);i.useEffect(()=>{if(typeof window>"u")return;const S=da(window.location.search,N);S!==window.location.search&&window.history.replaceState(window.history.state,"",`${window.location.pathname}${S}${window.location.hash}`)},[N]);const $=i.useMemo(()=>({params:N,setParam:j}),[N,j]),k=i.useMemo(()=>({ns:e,name:t}),[e,t]),[y,T]=i.useState(0),U=i.useCallback(()=>{T(S=>S+1)},[]),{updatedHooks:H,markUpdated:ee}=Da(),G=i.useRef(JSON.stringify(n)),X=i.useCallback((S,E,I)=>{E&&Object.keys(E).length>0&&v(E,S),I&&ee(I);const V=JSON.stringify(S);V!==G.current&&(G.current=V,c(S),M(Q=>ye(S,Q)),T(Q=>Q+1))},[v,ee]),{states:O,invoke:A,liveError:K}=Ia(e,t,N,U,X,(u==null?void 0:u.actions)??[]),z=i.useCallback(S=>jt(e,t,S),[e,t]),se=i.useMemo(()=>({states:O,invoke:A,answer:z,busy:h.turnActive}),[O,A,z,h.turnActive]),{states:q,refreshing:te}=ya(e,t,N,y,l),ce=Object.entries(O).filter(([,S])=>S.phase==="awaiting_approval").map(([S,E])=>`${S}:${E.requestId??""}:${E.approvalAddressedToViewer?"1":"0"}`).sort().join("|"),{approvalNotices:ae,approvalTrustEvents:R}=i.useMemo(()=>{const S=[],E=[];for(const[I,V]of Object.entries(O)){if(V.phase!=="awaiting_approval")continue;const Q=V.requestId??I;S.push({id:Q,label:V.approvalAddressedToViewer?"Your approval is needed to continue.":"Waiting on approval from someone else.",addressedToViewer:!!V.approvalAddressedToViewer}),V.approvalAddressedToViewer&&E.push({kind:"approval_addressed_to_viewer",id:Q})}return{approvalNotices:S,approvalTrustEvents:E}},[ce]),_=i.useMemo(()=>({approvals:ae,trustEvents:[d,...R]}),[ae,R,d]);i.useEffect(()=>{o==null||o(_)},[_,o]);const F=((Ke=h.lastAgentReply)==null?void 0:Ke.seq)??0,Yt=r&&(h.awaitingReply||h.pausedIdle)&&h.lastAgentReply!==null&&F>w&&!b&&!h.ended,Jt=i.useCallback(async S=>{await z(S),C(F)},[z,F]),Gt=i.useCallback(()=>C(F),[F]),[He,be]=i.useState(null),We=qs(e,t,be),Xt=i.useCallback((S,E,I)=>{be(null),We(S,E,I)},[We]),[Qt,Zt]=i.useState({}),es=i.useCallback(S=>{if(S.type!=="interaction_decision_rejected")return;const E=S.payload.payload;h.pendingInteractions.some(I=>I.requestRef===E.requestRef)&&(be(Fs(E)),Zt(I=>({...I,[E.requestRef]:(I[E.requestRef]??0)+1})))},[h.pendingInteractions]);return yt(es),s.jsx(cn,{value:k,children:s.jsx(_n,{value:$,children:s.jsx(Gs,{value:se,children:s.jsxs("div",{className:"flex min-h-full flex-col",children:[!x&&s.jsx(ha,{signals:h}),K!==null&&s.jsx("div",{className:"px-4 pt-4 max-w-3xl mx-auto","data-testid":"agent-ui-live-error",children:s.jsxs(W,{variant:"destructive",children:[s.jsx(Y,{children:"Live updates unavailable"}),s.jsx(J,{children:K})]})}),r&&h.pendingInteractions.length>0&&s.jsxs("section",{"data-testid":"agent-ui-decisions","aria-label":"Needs your decision",className:"flex flex-col gap-2 border-b border-border bg-card/60 px-3 py-2",children:[s.jsx("p",{className:"text-xs font-medium text-muted-foreground",children:"Needs your decision"}),h.pendingInteractions.map(S=>s.jsx(Vs,{request:S,onDecision:Xt},`${S.requestRef}:${Qt[S.requestRef]??0}`)),He&&s.jsx("p",{role:"alert",className:"text-xs text-destructive",children:He})]}),s.jsx(_a,{declaration:u,states:q,refreshing:te,updatedHooks:H,waiting:g,onRenderError:p}),s.jsx(ua,{open:Yt,variant:h.awaitingReply?"asked":"paused",text:((ze=h.lastAgentReply)==null?void 0:ze.text)??"",replySeq:F,onReply:Jt,onDismiss:Gt})]})})})})}function qa(e,t){switch(e){case"attached":return{text:"Resumed your session.",Icon:Qe};case"asleep":return{text:"Your session is asleep; it resumes when you send a message.",Icon:Ps};case"ended":return{text:t?`This session has ended: ${t}`:"This session has ended. You can start a new one.",Icon:Is};default:return{text:"Connected to your session.",Icon:Qe}}}function Ht(e){return e==="collapsed"}function mt(e,t,n,a){a&&(e.defaultPrevented||e.button!==0||e.metaKey||e.ctrlKey||e.shiftKey||e.altKey||(e.preventDefault(),a(t,n)))}function ht(e,t,n,a){e.currentTarget.href=re(t,n,a)}function xt(e){const t="inline-flex items-center gap-1.5 rounded px-2.5 py-1 text-[12px] font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring";return e?`${t} bg-secondary text-secondary-foreground`:`${t} text-muted-foreground hover:bg-accent/50 hover:text-foreground`}function re(e,t,n){const a=new URLSearchParams(typeof window>"u"?"":window.location.search);return a.delete("new"),a.delete("ns"),a.delete("agentClass"),a.delete("prompt"),a.set("session",`${e}/${t}`),a.set("view",n),`/sessions?${a.toString()}`}function Fa(e){return{collapsed:Ht(e),userToggled:!1,trustRevealed:!1}}function Va(e,t){switch(t.type){case"ui_requested":return e.userToggled||e.trustRevealed||e.collapsed===t.collapsed?e:{...e,collapsed:t.collapsed};case"user_toggled":return{collapsed:!e.collapsed,userToggled:!0,trustRevealed:!1};case"trust_event":return{...e,collapsed:!1,trustRevealed:!0}}}function Ba({ns:e,name:t,subject:n,sessionOrigin:a,endedReason:r,currentView:o,offersAgentUI:l,onSelectView:d,initialState:f,trustEvents:p,approvals:u,headerActions:c,sidebar:h,children:b}){const x=e!==void 0&&t!==void 0?{ns:e,name:t}:null,g=qa(a??"",r),[w,C]=i.useReducer(Va,f,Fa),N=w.collapsed;i.useEffect(()=>{C({type:"ui_requested",collapsed:Ht(f)})},[f]);const M=i.useRef(new Set),D=(p??[]).flatMap(v=>v?[v.id]:[]);i.useEffect(()=>{const v=D.filter($=>!M.current.has($));if(v.length!==0){for(const $ of v)M.current.add($);C({type:"trust_event"})}},[D.join("|")]);function j(){C({type:"user_toggled"})}return s.jsxs("div",{className:"h-screen flex flex-col bg-background text-foreground",children:[s.jsxs("header",{className:"flex items-center gap-2.5 px-3 py-2 min-h-[52px] bg-card border-b border-border",children:[s.jsx(B,{type:"button",variant:"ghost",size:"icon","aria-expanded":!N,"aria-label":N?"Show chrome":"Hide chrome","data-testid":"session-shell-chrome-toggle",onClick:j,children:N?s.jsx(Cs,{className:"h-4 w-4","aria-hidden":"true"}):s.jsx(Rs,{className:"h-4 w-4","aria-hidden":"true"})}),x&&s.jsxs("div",{className:"flex items-center gap-2 min-w-0",hidden:N,children:[s.jsx(g.Icon,{className:"h-3.5 w-3.5 text-muted-foreground shrink-0","aria-hidden":"true"}),s.jsx("span",{className:"text-[13px] text-muted-foreground truncate",title:g.text,"data-testid":"session-shell-session-origin",children:g.text})]}),s.jsxs("div",{className:"ml-auto flex items-center gap-2 shrink-0",children:[c&&s.jsx("div",{className:"flex items-center gap-1","data-testid":"session-shell-header-actions",hidden:N,children:c}),s.jsxs("div",{className:"flex items-center gap-2 min-w-0",hidden:N,children:[s.jsx(Ts,{className:"h-4 w-4 text-muted-foreground shrink-0","aria-hidden":"true"}),s.jsxs("span",{className:"text-[13px] font-medium truncate","data-testid":"session-shell-identity",children:["Acting as ",n]})]})]})]}),s.jsxs("div",{className:"flex items-center gap-2 px-3 py-1 min-h-[36px] border-b border-border bg-card/60 text-[12px] text-muted-foreground","data-testid":"session-shell-approval-surface",hidden:N,children:[u&&u.length>0&&s.jsxs(s.Fragment,{children:[s.jsx(As,{className:"h-3.5 w-3.5 shrink-0","aria-hidden":"true"}),s.jsx("ul",{className:"flex flex-col gap-0.5",children:u.map(v=>s.jsx("li",{children:v.label},v.id))})]}),x&&s.jsxs("div",{className:"ml-auto flex items-center gap-0.5 rounded-md border border-border bg-background/60 p-0.5 shrink-0","data-testid":"session-shell-view-tabs",children:[l&&s.jsxs("a",{href:re(x.ns,x.name,"ui"),"aria-current":o==="ui"?"page":void 0,"data-testid":"session-shell-agent-view-switch",className:xt(o==="ui"),onMouseDown:v=>ht(v,x.ns,x.name,"ui"),onClick:v=>mt(v,"ui",re(x.ns,x.name,"ui"),d),children:[s.jsx(Es,{className:"h-3.5 w-3.5","aria-hidden":"true"}),"Agent view"]}),s.jsxs("a",{href:re(x.ns,x.name,"chat"),"aria-current":o==="chat"?"page":void 0,"data-testid":"session-shell-chat-escape-hatch",className:xt(o==="chat"),onMouseDown:v=>ht(v,x.ns,x.name,"chat"),onClick:v=>mt(v,"chat",re(x.ns,x.name,"chat"),d),children:[s.jsx($s,{className:"h-3.5 w-3.5","aria-hidden":"true"}),"Chat"]})]})]}),s.jsxs("div",{className:"flex-1 min-h-0 flex",children:[s.jsx("aside",{className:h?"w-64 shrink-0 min-h-0 overflow-y-auto border-r border-border bg-card/40":"w-0 shrink-0 min-h-0 overflow-hidden","data-testid":"session-shell-sidebar",hidden:N,children:h}),s.jsx("main",{className:"flex min-h-0 flex-1 flex-col overflow-y-auto","data-testid":"session-shell-content-region",children:b})]})]})}function Ha(e){const t=e;if(!t||typeof t.ns!="string"||typeof t.name!="string"||typeof t.href!="string"||!t.href)throw new Error("the server's answer did not address a session");return{ns:t.ns,name:t.name,href:t.href}}class fe extends Error{constructor(t,n){super(t),this.name="StartError",this.indeterminate=n}}async function Wt(e,t){let n;try{n=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})}catch(a){throw console.error("sessions: start request did not complete",{url:e,err:a}),new fe("We could not confirm whether that session started. Reload your sessions before trying again.",!0)}if(!n.ok){let a="";try{const r=await n.json();a=typeof(r==null?void 0:r.error)=="string"?r.error:""}catch{a=""}throw console.error("sessions: start request failed",{url:e,status:n.status}),new fe(a||"That session could not be started right now.",!1)}try{return Ha(await n.json())}catch{throw console.error("sessions: start succeeded but its answer could not be addressed",{url:e}),new fe("That session started, but we could not open it. Reload your sessions to find it.",!0)}}function Kt(e){return!(e instanceof fe)||e.indeterminate}const Wa="This server cannot start new sessions for that agent. You can still open the sessions you already have with it, or ask an administrator to enable starting here.",Ka=" — cannot start here";function za(e){const t=new Map;for(const n of e)t.set(n.title,(t.get(n.title)??0)+1);return e.map(n=>{const a=(t.get(n.title)??0)>1?`${n.title} (in ${n.ns})`:n.title;return n.startable?a:a+Ka})}function zt(e){window.location.assign(e)}function Ya(){return s.jsx("p",{className:"text-sm text-muted-foreground","data-testid":"session-shell-no-startable-classes",children:"You do not have access to any agents yet. Access arrives by being added to a session someone else started, or through a channel an agent is connected to."})}function Ja({classes:e,onNavigate:t=zt,openInitially:n=!1,preselect:a,initialPrompt:r}){const[o,l]=i.useState(n),d=a?e.findIndex(k=>k.ns===a.ns&&k.class===a.agentClass):-1,[f,p]=i.useState(!1),u=a!==void 0&&d===-1&&!f,[c,h]=i.useState(d===-1?0:d),[b,x]=i.useState(r??""),[g,w]=i.useState(!1),[C,N]=i.useState(null);if(e.length===0)return null;const M=e[Math.min(c,e.length-1)],D=za(e),j=!M.startable,v=M.offersUI===!0;async function $(){w(!0),N(null);try{const k=await Wt("/sessions/api/start",{ns:M.ns,agentClass:M.class,prompt:b});t(v?`${k.href}&view=ui`:k.href)}catch(k){N(k.message),Kt(k)||w(!1)}}return s.jsxs(s.Fragment,{children:[s.jsx(B,{type:"button",size:"sm","data-testid":"session-shell-new-session",onClick:()=>{N(null),l(!0)},children:"+ New session"}),s.jsx(Oe,{open:o,onOpenChange:l,children:s.jsxs(Me,{children:[s.jsxs(Le,{children:[s.jsx(pe,{children:"Start a new session"}),s.jsx(me,{children:v?"Pick an agent. This one opens its own view.":"Pick an agent and say what you need."})]}),s.jsxs("div",{className:"flex flex-col gap-3",children:[u&&s.jsx("p",{className:"text-sm text-destructive","data-testid":"session-shell-preselect-refused",children:"You can't start that agent from here."}),s.jsxs("div",{className:"flex flex-col gap-1",children:[s.jsx(oe,{htmlFor:"new-session-class",children:"Agent"}),s.jsx("select",{id:"new-session-class",className:"rounded-md border border-input bg-background px-3 py-2 text-sm","data-testid":"session-shell-new-session-class",value:c,onChange:k=>{h(Number(k.target.value)),p(!0)},children:e.map((k,y)=>s.jsx("option",{value:y,children:D[y]},`${k.ns}/${k.class}`))})]}),v?s.jsxs("details",{className:"flex flex-col gap-1","data-testid":"session-shell-new-session-prompt-disclosure",children:[s.jsx("summary",{className:"cursor-pointer text-sm text-muted-foreground",children:"Add a message (optional — otherwise the agent is just told you opened the view)"}),s.jsx("textarea",{id:"new-session-prompt",rows:3,"aria-label":"Message",className:"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm","data-testid":"session-shell-new-session-prompt",value:b,onChange:k=>x(k.target.value)})]}):s.jsxs("div",{className:"flex flex-col gap-1",children:[s.jsx(oe,{htmlFor:"new-session-prompt",children:"Message"}),s.jsx("textarea",{id:"new-session-prompt",rows:4,className:"rounded-md border border-input bg-background px-3 py-2 text-sm","data-testid":"session-shell-new-session-prompt",value:b,onChange:k=>x(k.target.value)})]}),j&&s.jsx("p",{className:"text-sm text-muted-foreground","data-testid":"session-shell-new-session-unstartable",children:Wa}),C&&s.jsx("p",{className:"text-sm text-destructive","data-testid":"session-shell-new-session-error",children:C}),s.jsx("div",{className:"flex justify-end",children:s.jsx(B,{type:"button","data-testid":"session-shell-new-session-submit",disabled:g||j||u||!v&&b.trim()==="",onClick:()=>void $(),children:g?v?"Opening…":"Starting…":v?"Open UI":"Start session"})})]})]})})]})}function Ga({ns:e,name:t,onNavigate:n=zt}){const[a,r]=i.useState(!1),[o,l]=i.useState(null);async function d(){r(!0),l(null);try{const f=await Wt(`/agent-ui/${encodeURIComponent(e)}/${encodeURIComponent(t)}/start`,{prompt:"Continue where we left off."});n(f.href)}catch(f){l(f.message),Kt(f)||r(!1)}}return s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx(B,{type:"button",size:"sm",variant:"outline","data-testid":"session-shell-start-replacement",disabled:a,onClick:()=>void d(),children:a?"Starting…":"Start a new session"}),o&&s.jsx("span",{className:"text-sm text-destructive","data-testid":"session-shell-start-replacement-error",children:o})]})}async function Xa(e,t){const n=await fetch(`/sessions/api/${encodeURIComponent(e)}/${encodeURIComponent(t)}/detail`);if(!n.ok)throw console.error("sessions: load session detail failed",{ns:e,name:t,status:n.status}),new Error(n.status===403?"you do not have access to this session":n.status===401?"you are no longer signed in":"these settings could not be loaded right now");return await n.json()}function Z({label:e,value:t,children:n}){return s.jsxs("div",{className:"flex items-start justify-between gap-4 py-1.5 text-sm",children:[s.jsx("span",{className:"shrink-0 text-muted-foreground",children:e}),s.jsx("span",{className:"break-all text-right font-mono text-[13px]",children:n??t})]})}function Qa({ns:e,name:t,open:n,onOpenChange:a}){const[r,o]=i.useState(null),[l,d]=i.useState(null);return i.useEffect(()=>{if(!n)return;let f=!1;return o(null),d(null),Xa(e,t).then(p=>{f||o(p)}).catch(p=>{f||d(p.message||"these settings could not be loaded right now")}),()=>{f=!0}},[n,e,t]),s.jsx(Oe,{open:n,onOpenChange:a,children:s.jsxs(Me,{children:[s.jsxs(Le,{children:[s.jsx(pe,{children:"Session details"}),s.jsx(me,{children:"Resolved settings for this conversation."})]}),l?s.jsxs("div",{className:"text-sm text-destructive","data-testid":"session-shell-session-info-error",children:["Couldn't load details: ",l]}):r?s.jsxs("div",{className:"divide-y divide-border",children:[s.jsx(Z,{label:"Agent class",value:r.agentClass}),s.jsx(Z,{label:"Model",children:r.model.name?s.jsx(Ks,{model:`${r.model.provider||"?"}/${r.model.name}`}):"not resolved"}),s.jsx(Z,{label:"Max tokens",value:r.maxTokens?String(r.maxTokens):"—"}),s.jsx(Z,{label:"Max turns",value:r.maxTurns?String(r.maxTurns):"—"}),s.jsx(Z,{label:"Max duration",value:r.maxDuration||"—"}),s.jsx(Z,{label:"Owner",value:r.owner}),s.jsx(Z,{label:"Phase",value:r.phase||"—"}),s.jsx(Z,{label:"Created",value:new Date(r.createdAt).toLocaleString()})]}):s.jsx("div",{className:"text-sm text-muted-foreground",children:"Loading…"})]})})}function Za(e,t=Date.now()){if(!e)return"";const n=Date.parse(e);if(Number.isNaN(n))return"";const a=Math.max(0,Math.floor((t-n)/1e3));if(a<60)return"just now";const r=Math.floor(a/60);if(r<60)return`${r}m`;const o=Math.floor(r/60);return o<24?`${o}h`:`${Math.floor(o/24)}d`}function er(e,t){return`/sessions?session=${encodeURIComponent(`${e}/${t}`)}`}function tr(e){const t=[];return e&&(e.unavailable>0&&t.push(e.unavailable===1?"1 session could not be loaded and is not shown.":`${e.unavailable} sessions could not be loaded and are not shown.`),e.truncated&&t.push("Showing your most recent sessions only."),e.bootstrapUnavailable&&t.push("Some agents may be missing from New chat. Try again in a moment.")),t}function sr(e){const t=e.lastIndexOf("-");return t>0&&tc.ns===n&&c.name===a,f=e.filter(c=>c.ended&&!d(c)).length,p=o?e:e.filter(c=>!c.ended||d(c)),u=new Map;for(const c of p)u.set(c.title,(u.get(c.title)??0)+1);return s.jsxs("nav",{className:"flex flex-col","aria-label":"Your sessions","data-testid":"session-shell-session-list",children:[r.length>0&&s.jsx("div",{className:"px-3 py-2 text-[11px] text-muted-foreground border-b border-border","data-testid":"session-shell-list-notices",children:r.map(c=>s.jsx("div",{children:c},c))}),e.length===0?s.jsx("div",{className:"px-3 py-4 text-[12px] text-muted-foreground","data-testid":"session-shell-empty-list",children:"You have no sessions yet."}):p.length===0?s.jsx("div",{className:"px-3 py-4 text-[12px] text-muted-foreground","data-testid":"session-shell-empty-list",children:"No active sessions."}):s.jsx("ul",{className:"flex flex-col",children:p.map(c=>{const h=d(c),b=(u.get(c.title)??0)>1,x=c.startedAt?Za(c.startedAt):"";return s.jsx("li",{children:s.jsxs("a",{href:er(c.ns,c.name),"aria-current":h?"page":void 0,"data-testid":`session-shell-session-row-${c.ns}/${c.name}`,className:`flex flex-col gap-0.5 px-3 py-2 border-b border-border hover:bg-surface-2 ${h?"bg-surface-active shadow-[inset_3px_0_0_hsl(var(--state))]":""}`,children:[s.jsxs("span",{className:"flex items-baseline gap-1.5 min-w-0",children:[s.jsx("span",{className:"text-[13px] font-medium truncate",children:c.title}),b&&s.jsx("span",{className:"shrink-0 font-mono text-[10px] text-muted-foreground","data-testid":`session-shell-session-row-tag-${c.ns}/${c.name}`,children:sr(c.name)})]}),s.jsxs("span",{className:"flex items-center gap-1.5 text-[11px] text-muted-foreground",children:[c.awaitingHuman?s.jsx(Os,{className:"h-3 w-3 shrink-0","aria-hidden":"true"}):c.ended?s.jsx(Ms,{className:"h-3 w-3 shrink-0","aria-hidden":"true"}):s.jsx(Ls,{className:"h-3 w-3 shrink-0","aria-hidden":"true"}),s.jsx("span",{className:"truncate","data-testid":`session-shell-session-row-phase-${c.ns}/${c.name}`,children:c.phase}),x&&s.jsxs(s.Fragment,{children:[s.jsx("span",{"aria-hidden":"true",children:"·"}),s.jsx("span",{className:"shrink-0","data-testid":`session-shell-session-row-age-${c.ns}/${c.name}`,children:x})]})]})]})},`${c.ns}/${c.name}`)})}),f>0||o&&e.some(c=>c.ended)?s.jsx("button",{type:"button",onClick:()=>l(c=>!c),"aria-expanded":o,className:"px-3 py-2 text-left text-[11px] text-muted-foreground hover:text-foreground hover:bg-surface-2","data-testid":"session-shell-toggle-ended",children:o?"Hide ended sessions":`Show ${f} ended session${f===1?"":"s"}`}):null]})}function ar(e,t){const n="oap sessions",a=e?`${e} · ${n}`:n;return t>0?`(${t}) ${a}`:a}function gt(){return typeof window<"u"&&"Notification"in window}function rr(e){const[t,n]=i.useState(0);i.useEffect(()=>{e&&n(0)},[e]);const a=i.useRef(!1),r=i.useCallback(()=>{a.current||!gt()||(a.current=!0,Notification.permission==="default"&&Notification.requestPermission())},[]),o=i.useCallback((l,d)=>{if(!e&&(n(f=>f+1),!(!gt()||Notification.permission!=="granted")))try{const f=new Notification(l,{body:d});f.onclick=()=>{window.focus(),f.close()}}catch{}},[e]);return{unread:t,notify:o,requestPermission:r}}function vt(){if(typeof document>"u")return!0;const e=document.visibilityState==="visible",t=typeof document.hasFocus=="function"?document.hasFocus():!0;return e&&t}function or(){const[e,t]=i.useState(vt);return i.useEffect(()=>{const n=()=>t(vt());return document.addEventListener("visibilitychange",n),window.addEventListener("focus",n),window.addEventListener("blur",n),()=>{document.removeEventListener("visibilitychange",n),window.removeEventListener("focus",n),window.removeEventListener("blur",n)}},[]),e}const ir=3e4;function lr(e,t){const n=[];for(const a of e)a.awaitingHuman&&(t&&a.ns===t.ns&&a.name===t.name||n.push({id:`session:${a.ns}/${a.name}`,label:`${a.title} is waiting on a person in another session.`,addressedToViewer:!1}));return n}function cr({selected:e,shown:t,ended:n,onChromeSignals:a,onUserSend:r,onAgentReply:o,onAwaitingDecision:l,onSessionEnded:d,uiEverShownRef:f}){const p=e.view.notice?s.jsx("div",{className:"p-4 max-w-3xl mx-auto","data-testid":"session-shell-view-notice",children:s.jsxs(W,{children:[s.jsx(Y,{children:e.view.notice.title}),s.jsx(J,{children:e.view.notice.message})]})}):null;t==="ui"&&(f.current=!0);const u=e.view.ui,c=u&&f.current?s.jsxs("div",{className:t==="ui"?"h-full":"hidden","data-testid":"session-shell-ui-region",children:[t==="ui"&&p,s.jsx(Ua,{ns:u.ns,name:u.name,declaration:u.declaration,agentParams:u.agentParams,shown:t==="ui",onChromeSignals:a,onSessionEnded:d})]}):null;function h(){var x,g;switch(t){case"ui":return u?null:s.jsxs(s.Fragment,{children:[p,!e.view.unavailable&&Re("agent view shown but no ui or unavailable payload",e),s.jsx(Te,{title:((x=e.view.unavailable)==null?void 0:x.title)??"View unavailable",message:((g=e.view.unavailable)==null?void 0:g.message)??"This agent's view could not be loaded."})]});case"chat":return e.view.chat?s.jsxs(s.Fragment,{children:[p,n&&s.jsx("div",{className:"p-4 max-w-3xl mx-auto","data-testid":"session-shell-replacement-region",children:s.jsx(Ga,{ns:e.view.chat.ns,name:e.view.chat.name})}),s.jsx(Ws,{ns:e.view.chat.ns,name:e.view.chat.name,readOnly:n,onUserSend:r,onSessionEnded:d})]}):s.jsxs(s.Fragment,{children:[p,Re("kind is chat but the view payload is absent",e),s.jsx(Te,{title:"View unavailable",message:"This conversation could not be opened."})]});default:return s.jsxs(s.Fragment,{children:[p,Re("unrecognized shown view",e),s.jsx(Te,{title:"View unavailable",message:"This view could not be shown."})]})}}const b=e.view.chat??{ns:e.ns,name:e.name};return s.jsxs(Bs,{ns:b.ns,name:b.name,children:[s.jsx(dr,{onAgentReply:o,onAwaitingDecision:l,onSessionEnded:d}),s.jsx(Hs,{}),c,h()]},`${b.ns}/${b.name}`)}function dr({onAgentReply:e,onAwaitingDecision:t,onSessionEnded:n}){const a=i.useRef(new Set);return yt(r=>{if(r.type==="user_message"){e(r.payload.text);return}if(r.type==="interaction_request"){const o=r.payload.payload;if(a.current.has(o.requestRef))return;a.current.add(o.requestRef),t(o.lead);return}r.type==="session_ended"&&n()}),null}function Re(e,t){return console.error("sessions: cannot render the selected view",{reason:e,ns:t.ns,name:t.name,kind:t.view.kind}),null}function Te({title:e,message:t}){return s.jsx("div",{className:"p-4 max-w-3xl mx-auto","data-testid":"session-shell-view-unavailable",children:s.jsxs(W,{variant:"destructive",children:[s.jsx(Y,{children:e}),s.jsx(J,{children:t})]})})}function ur(e){var q,te,ce,ae;const{selected:t}=e,[n,a]=i.useState(e.sessions??[]),[r,o]=i.useState(e.notices),[l,d]=i.useState(Pa),[f,p]=i.useState(!1),[u,c]=i.useState(!1),h=or(),{unread:b,notify:x,requestPermission:g}=rr(h),w=i.useCallback(R=>{d(_=>Ma(_,R)?_:R)},[]),C=i.useRef(null);C.current===null&&(C.current=new AbortController);const N=i.useCallback(async R=>{try{const _=await fetch("/sessions/api/sessions",{signal:R});if(!_.ok){console.error("sessions: session-list refresh failed",{status:_.status});return}const F=await _.json();if(R.aborted)return;if(!Array.isArray(F==null?void 0:F.sessions)){console.error("sessions: session-list refresh returned an unexpected body; keeping the current list");return}a(F.sessions),o(F.notices)}catch(_){if(R.aborted)return;console.error("sessions: session-list refresh errored",_)}},[]);i.useEffect(()=>{const R=C.current,_=setInterval(()=>void N(R.signal),ir);return()=>{R.abort(),clearInterval(_)}},[N]);const M=i.useRef(!1),D=i.useCallback(()=>{M.current||(M.current=!0,c(!0),N(C.current.signal))},[N]),j=i.useMemo(()=>[...lr(n,t),...l.approvals],[n,t,l.approvals]),v=i.useMemo(()=>{var R;return(R=n.find(_=>t&&_.ns===t.ns&&_.name===t.name))==null?void 0:R.title},[n,t]),$=i.useRef("oap sessions");$.current=v||"oap sessions",i.useEffect(()=>{document.title=ar(v??null,b)},[v,b]);const k=i.useCallback(R=>{x($.current,R)},[x]),y=i.useCallback(R=>{x(`${$.current} needs your decision`,R)},[x]),T=t?u?"ended":t.sessionOrigin:void 0,U=T==="ended",H=e.canStartSessions&&(((q=e.startableClasses)==null?void 0:q.length)??0)>0,[ee,G]=i.useState(()=>{var R;return((R=e.selected)==null?void 0:R.view.kind)==="chat"?"chat":"ui"}),X=e.selected?`${e.selected.ns}/${e.selected.name}`:"",O=i.useRef(X),A=i.useRef(!1);i.useEffect(()=>{var R;O.current!==X&&(O.current=X,A.current=!1,G(((R=e.selected)==null?void 0:R.view.kind)==="chat"?"chat":"ui"))},[X,(te=e.selected)==null?void 0:te.view.kind]);const K=i.useCallback((R,_)=>{G(R),typeof window<"u"&&window.history.pushState(window.history.state,"",_)},[]);i.useEffect(()=>{if(typeof window>"u")return;const R=()=>{const _=new URLSearchParams(window.location.search).get("view");G(_==="chat"?"chat":"ui")};return window.addEventListener("popstate",R),()=>window.removeEventListener("popstate",R)},[]);const z=i.useMemo(()=>{if(typeof window>"u")return{open:!1};const R=new URLSearchParams(window.location.search),_=R.get("ns")??"",F=R.get("agentClass")??"";return{open:R.get("new")==="1",preselect:_&&F?{ns:_,agentClass:F}:void 0,initialPrompt:R.get("prompt")??void 0}},[]),se=t?{ns:t.ns,name:t.name,sessionOrigin:T??t.sessionOrigin,currentView:ee,onSelectView:K,endedReason:U?t.endedReason:void 0,offersAgentUI:t.offersAgentUI&&!U}:{};return s.jsx(Ba,{...se,subject:e.subject,initialState:(ce=t==null?void 0:t.chrome)==null?void 0:ce.initialState,approvals:j,trustEvents:l.trustEvents,headerActions:H||t?s.jsxs(s.Fragment,{children:[H&&s.jsx(Ja,{classes:e.startableClasses,openInitially:z.open,preselect:z.preselect,initialPrompt:z.initialPrompt}),t&&s.jsxs(s.Fragment,{children:[s.jsx(B,{type:"button",variant:"ghost",size:"icon","aria-label":"Session details","data-testid":"session-shell-session-info",onClick:()=>p(!0),children:s.jsx(_s,{className:"h-4 w-4","aria-hidden":"true"})}),s.jsx(Qa,{ns:t.ns,name:t.name,open:f,onOpenChange:p})]})]}):void 0,sidebar:s.jsx(nr,{sessions:n,notices:r,selectedNs:t==null?void 0:t.ns,selectedName:t==null?void 0:t.name}),children:t?s.jsx(cr,{selected:t,shown:ee,ended:U,onChromeSignals:w,onUserSend:g,onAgentReply:k,onAwaitingDecision:y,onSessionEnded:D,uiEverShownRef:A}):s.jsxs("div",{className:"p-6 flex flex-col gap-3","data-testid":"session-shell-no-selection",children:[s.jsx("span",{className:"text-sm text-muted-foreground",children:"Pick a session to open it."}),(((ae=e.startableClasses)==null?void 0:ae.length)??0)===0&&s.jsx(Ya,{})]})})}ds();us(ur); +import{c as L,A as W,V as Ie,G as Y,a as J,C as ge,b as bt,d as wt,e as Pe,B,M as oe,T as ts,g as ss,h as ns,i as as,W as rs,N as Ae,j as os,k as is,l as Je,n as Ge,o as ls,p as Xe,D as Oe,t as Me,u as Le,v as pe,w as me,x as cs,L as ds,m as us}from"./mount.D4ypHaeQ.js";import{j as s,R as fs,J as ps,r as i,E as ms,O as hs,y as ve,X as xs,P as gs,Q as vs,V as bs,Y as ws,Z as js,_ as ys,$ as Ns,a0 as Ss,a1 as ks,a2 as Cs,a3 as Rs,a4 as Ts,a5 as As,a as Es,a6 as $s,f as Qe,a7 as Is,M as Ps,a8 as Os,a9 as Ms,aa as Ls,ab as _s}from"./vendor.C5MRNvUt.js";import{M as _e}from"./markdown.DHnzytkE.js";import{B as Ds}from"./badge.hXhpY1Si.js";import{s as jt,u as Us,b as qs,i as Fs,c as yt,I as Vs,S as Bs,a as Hs,C as Ws}from"./StartupLine.o9MnUGnk.js";import{M as Ks}from"./model-name.BXiF0QjK.js";const Ze=["hsl(var(--chart-1))","hsl(var(--chart-2))","hsl(var(--chart-3))","hsl(var(--chart-4))","hsl(var(--chart-5))"];function de(e){return Ze[e%Ze.length]}function je({height:e=240,className:t,children:n}){return s.jsx("div",{className:L("w-full text-xs",t),style:{height:e},children:s.jsx(fs,{width:"100%",height:"100%",children:n})})}function zs(e){return s.jsx(ps,{cursor:{stroke:"hsl(var(--border))"},contentStyle:{background:"hsl(var(--popover))",border:"1px solid hsl(var(--border))",borderRadius:"var(--radius)",color:"hsl(var(--popover-foreground))",fontSize:"0.75rem"},...e})}const Ys=new Set(["submitted","awaiting_approval","running"]);function ie(e){return Ys.has(e)}function De(e){if(e.phase==="idle")return null;if(e.phase==="succeeded")return e.message??null;if(e.message)return e.message;switch(e.phase){case"submitted":return"Request submitted.";case"awaiting_approval":return e.approvalAddressedToViewer?"Your approval is needed to continue.":"Waiting on approval from someone else.";case"running":return"In progress.";case"failed":return"The request failed. You can try again.";case"denied":return"The request was denied.";case"expired":return"The approval window expired. You can try again.";case"rate_limited":return"Too many requests right now. Try again shortly.";default:return null}}const Js={states:{},invoke:()=>{},answer:()=>Promise.reject(new Error("agentui: no ActionsProvider"))},Nt=i.createContext(Js);function Gs({value:e,children:t}){return s.jsx(Nt.Provider,{value:e,children:t})}function le(){return i.useContext(Nt)}const P=e=>e.props??{},m=(e,t,n="")=>{const a=P(e)[t];return typeof a=="string"?a:typeof a=="number"?Number.isFinite(a)?String(a):n:typeof a=="boolean"?String(a):n};function Ue(e){if(typeof e!="string")return null;const t=e.split("/");if(t.length!==2)return null;for(const n of t)if(n===""||n==="."||n==="..")return null;return[t[0],t[1]]}function Xs(e){const t=Ue(e);return t===null?null:`/chat-embed/${encodeURIComponent(t[0])}/${encodeURIComponent(t[1])}`}function St({sessionRef:e}){const t=Xs(e);return t===null?s.jsx(W,{children:"Chat unavailable: no valid session reference."}):s.jsx("iframe",{"data-testid":"ap-chat",src:t,title:"Test chat",className:"w-full rounded-md bg-background",style:{height:"520px",border:"0"}})}function Qs({n:e}){return s.jsx(St,{sessionRef:P(e).sessionRef})}const Zs=/^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/;function et(e){return e.length>0&&e.length<=63&&Zs.test(e)}function qe(e){const t=m(e,"namespace"),n=m(e,"agentClass"),a=m(e,"label");if(!et(t))throw new Error(`ap:agentlink: namespace ${JSON.stringify(t)} is not a DNS-1123 label`);if(!et(n))throw new Error(`ap:agentlink: agentClass ${JSON.stringify(n)} is not a DNS-1123 label`);if(a==="")throw new Error("ap:agentlink: label is required");const r=new URLSearchParams({new:"1",ns:t,agentClass:n}),o=m(e,"prompt");return o!==""&&r.set("prompt",o),`/sessions?${r.toString()}`}function en(e,t){return`ap-agentlink:${e}/${t}`}function tt(e){try{return window.sessionStorage.getItem(e)}catch(t){return console.error("agentui: ap:agentlink could not read the remembered test session",t),null}}function tn(e,t){try{window.sessionStorage.setItem(e,t)}catch(n){console.error("agentui: ap:agentlink could not remember the test session",n)}}function sn(e){try{window.sessionStorage.removeItem(e)}catch(t){console.error("agentui: ap:agentlink could not forget the remembered test session",t)}}function nn(e){return`/sessions?${new URLSearchParams({session:e}).toString()}`}function an(e){return typeof e!="string"?null:!e.startsWith("/")||e.startsWith("//")||e.startsWith("/\\")?(console.error("agentui: ap:agentlink refused a start href that is not a same-origin path; using the rebuilt address",e),null):e}const rn="The test could not start.",st="We could not confirm whether that session started. Reload before trying again.";function on({n:e}){const t=qe(e),n=m(e,"namespace"),a=m(e,"agentClass"),r=en(n,a),[o,l]=i.useState(()=>tt(r)),[d,f]=i.useState(null),[p,u]=i.useState(!1),[c,h]=i.useState(null);if(i.useEffect(()=>{const x=tt(r);if(x===null)return;let g=!0;const w=()=>{g&&(sn(r),l(null))},C=Ue(x);if(C===null){w();return}return(async()=>{try{(await fetch(`/sessions/api/${encodeURIComponent(C[0])}/${encodeURIComponent(C[1])}/detail`,{credentials:"same-origin"})).ok||w()}catch(N){console.error("agentui: ap:agentlink could not check the remembered test session",N),w()}})(),()=>{g=!1}},[r]),o!==null)return s.jsxs("div",{className:"flex flex-col gap-2",children:[s.jsx(St,{sessionRef:o}),s.jsx("a",{"data-testid":"ap-agentlink-open-tab",href:d??nn(o),target:"_blank",rel:"noopener noreferrer",className:"self-end text-xs text-[hsl(var(--primary))]",children:"Open in a tab"})]});async function b(){u(!0),h(null);let x;try{x=await fetch("/sessions/api/start",{method:"POST",credentials:"same-origin",headers:{"content-type":"application/json"},body:JSON.stringify({ns:n,agentClass:a,prompt:m(e,"prompt")})})}catch(g){console.error("agentui: ap:agentlink embed start did not complete",g),h({text:st,retryable:!1}),u(!1);return}if(!x.ok){let g="";try{const w=await x.json();g=typeof(w==null?void 0:w.error)=="string"?w.error:""}catch{g=""}console.error("agentui: ap:agentlink embed start was refused",{status:x.status}),h({text:g||rn,retryable:!0}),u(!1);return}try{const g=await x.json();if(!g.ns||!g.name)throw new Error("start answered without a session");const w=`${g.ns}/${g.name}`;tn(r,w),f(an(g.href)),l(w)}catch(g){console.error("agentui: ap:agentlink embed start succeeded but its answer could not be addressed",g),h({text:st,retryable:!1})}finally{u(!1)}}return s.jsxs("div",{className:"flex flex-col gap-2",children:[s.jsx("button",{type:"button","data-testid":"ap-agentlink-embed",onClick:()=>void b(),disabled:p||(c==null?void 0:c.retryable)===!1,className:Ie({variant:"default"}),children:m(e,"label")}),c!==null&&s.jsxs("p",{role:"alert",className:"text-sm text-[hsl(var(--destructive))]",children:[c.text,c.retryable&&s.jsxs(s.Fragment,{children:[" ","Try again, or"," ",s.jsx("a",{href:t,target:"_blank",rel:"noopener noreferrer",className:"underline",children:"open it in a tab"}),"."]})]})]})}function ln({n:e}){return P(e).embed?s.jsx(on,{n:e}):s.jsx("a",{"data-testid":"ap-agentlink",href:qe(e),target:"_blank",rel:"noopener noreferrer",className:Ie({variant:"default"}),children:m(e,"label")})}const kt=i.createContext(null);function cn({value:e,children:t}){return s.jsx(kt.Provider,{value:e,children:t})}function dn(){return i.useContext(kt)}const un="application/vnd.agentprimitives.authzed.com.agent.v1";function fn(e){return e===un?"Agent bundle":e==="text/html"?"Web page":e.startsWith("image/")?"Image":e}function pn(e){const[t,n]=e>=1e6?[e/1e6,"megabyte"]:e>=1e3?[e/1e3,"kilobyte"]:[e,"byte"];return new Intl.NumberFormat(void 0,{style:"unit",unit:n,unitDisplay:"short",maximumFractionDigits:1}).format(t)}function nt({reason:e}){return s.jsxs(W,{variant:"destructive","data-testid":"ap-attachment-unavailable",children:[s.jsx(Y,{children:"Attachment unavailable"}),s.jsx(J,{children:e})]})}function mn({n:e}){const t=dn(),n=m(e,"artifact"),a=m(e,"label"),[r,o]=i.useState(null),[l,d]=i.useState(null);if(i.useEffect(()=>{if(t===null||n==="")return;let p=!1;const u=new URLSearchParams({artifactId:n,sessionRef:`${t.ns}/${t.name}`});return fetch(`/artifact-view/meta?${u.toString()}`,{credentials:"same-origin"}).then(async c=>{if(!c.ok)throw new Error(`${c.status} ${await c.text()}`);return await c.json()}).then(c=>{p||o(c)}).catch(c=>{console.error("agentui: ap:attachment lookup failed",n,c),p||d("This file could not be found in this conversation.")}),()=>{p=!0}},[t,n]),t===null)return s.jsx(nt,{reason:"This page is not attached to a conversation."});if(l!==null)return s.jsx(nt,{reason:l});if(r===null)return s.jsx("div",{"data-testid":"ap-attachment-loading",className:"text-sm text-muted-foreground",children:"Loading file…"});const f=new URLSearchParams({artifactId:n,sessionRef:`${t.ns}/${t.name}`,fn:r.filename||n});return s.jsxs("div",{"data-testid":"ap-attachment",className:"flex items-center justify-between gap-3 rounded-md border border-border px-3 py-2",children:[s.jsxs("div",{className:"min-w-0",children:[s.jsx("div",{className:"truncate text-sm font-medium",children:a||r.filename||r.name}),s.jsxs("div",{className:"text-xs text-muted-foreground",children:[fn(r.mime)," · ",pn(r.size)]})]}),s.jsxs("a",{href:`/artifact-download?${f.toString()}`,download:r.filename||void 0,className:L(Ie({variant:"outline",size:"sm"}),"shrink-0"),"aria-label":`Download ${r.filename||r.name}`,children:[s.jsx(ms,{className:"mr-1.5 h-4 w-4","aria-hidden":"true"}),"Download"]})]})}function Ct({title:e,collapsed:t,testId:n,children:a}){const[r,o]=i.useState(!t);return i.useEffect(()=>{o(!t)},[t]),s.jsxs("details",{"data-testid":n,open:r,className:"w-full",children:[s.jsxs("summary",{className:"flex cursor-pointer select-none items-center gap-2 px-1 py-2 text-sm font-medium [&::-webkit-details-marker]:hidden",onClick:l=>{l.preventDefault(),o(d=>!d)},children:[s.jsx(hs,{className:L("h-4 w-4 shrink-0 transition-transform",r&&"rotate-90"),"aria-hidden":"true"}),e]}),s.jsx("div",{className:"px-1 pb-2",children:a})]})}const hn={layout:"column",selectedStep:null,selectStep:()=>{}},Ee=i.createContext(hn);function Rt(){return i.useContext(Ee)}function xn(e){var t;return(e==null?void 0:e.component)==="oap:page"&&((t=e.props)==null?void 0:t.layout)==="rail"?"rail":"column"}const Tt="oap:generative",gn={composed:new Set,updated:new Map,stale:new Set,waiting:new Set,answered:new Set,collapsed:new Map},At=i.createContext(gn);function vn({value:e,children:t}){return s.jsx(At.Provider,{value:e,children:t})}function Fe(){return i.useContext(At)}function ne(e){var t;return e.component!==Tt?null:typeof((t=e.props)==null?void 0:t.name)=="string"?e.props.name:""}const bn="rounded-md bg-state/[0.05] px-3 py-2",Et=i.createContext(null);function wn(){return i.useContext(Et)}function jn({name:e,title:t,children:n}){const{composed:a,updated:r,stale:o,waiting:l,collapsed:d}=Fe(),{layout:f}=Rt(),p=a.has(e),u=r.has(e),c=o.has(e),h=l.has(e),b=i.Children.count(n)>0,x=d.get(e),g=f!=="rail"&&x!==void 0&&b,w=f==="rail"&&t!==void 0&&t!==""&&b,C=h&&f!=="rail";return s.jsxs("section",{"data-hook":e,"data-agent-composed":p?"true":void 0,"data-hook-updated":u?"true":void 0,"data-hook-waiting":h?"true":void 0,"data-hook-collapsed":g?"true":void 0,"aria-live":"polite","aria-busy":c||void 0,className:L("relative w-full",p&&b&&bn,c&&"opacity-60 transition-opacity"),children:[(C||u||c)&&s.jsxs("div",{"data-testid":"agent-ui-hook-cues",className:"pointer-events-none mb-1 flex min-h-5 items-center justify-between gap-2 text-[11px]",children:[s.jsx("span",{children:C&&s.jsx("span",{"data-testid":"agent-ui-hook-waiting",className:"rounded bg-accent/10 px-1.5 py-0.5 font-medium text-accent-foreground",children:"Waiting on you"})}),u?s.jsx("span",{"data-testid":"agent-ui-hook-updated",className:"rounded bg-accent/10 px-1.5 py-0.5 text-muted-foreground",children:"Updated"}):c?s.jsxs("div",{"data-testid":"agent-ui-hook-refreshing",className:"flex items-center gap-1.5 text-muted-foreground",children:[s.jsx(ve,{className:"h-3.5 w-3.5 animate-spin","aria-hidden":"true"}),s.jsx("span",{children:"Updating…"})]}):null]}),s.jsxs(Et.Provider,{value:e,children:[w&&s.jsx("h3",{"data-testid":"agent-ui-hook-title",className:"mb-2 text-sm font-medium text-foreground",children:t}),g?s.jsx(Ct,{title:x,collapsed:!0,testId:"agent-ui-hook-collapsed",children:n}):n]})]})}const yn=["info","success","warning"],Nn={info:"border-state/40 bg-state/[0.06]",success:"border-success/50 bg-success/[0.08]",warning:"border-warning/50 bg-warning/[0.08]"},Sn=4;function $t(e){return Array.isArray(e)?e.filter(t=>!!t&&typeof t.label=="string"&&typeof t.action=="string"&&t.action!=="").slice(0,Sn):[]}function It(e){const t=m(e,"tone");return yn.includes(t)?t:"info"}function kn(e){return JSON.stringify([m(e,"title"),m(e,"body"),It(e),$t(P(e).buttons)])}const Pt="agentui:notice:dismissed:";function Cn(e){try{return window.localStorage.getItem(Pt+e)==="1"}catch(t){return console.error("agentui: could not read dismissed notices",t),!1}}function Rn(e){try{window.localStorage.setItem(Pt+e,"1")}catch(t){console.error("agentui: could not remember a dismissed notice",t)}}function Tn({n:e}){const t=kn(e);return s.jsx(An,{n:e,identity:t},t)}function An({n:e,identity:t}){const{states:n,invoke:a,busy:r}=le(),[o,l]=i.useState(()=>Cn(t)),[d,f]=i.useState(null);if(o)return null;const p=It(e),u=m(e,"title"),c=$t(P(e).buttons),h=c.some(g=>ie((n[g.action]??{phase:"idle"}).phase)),b=d!==null||h||!!r,x=d!==null?n[d]??{phase:"submitted"}:null;return s.jsxs(ge,{"data-testid":"ap-notice","data-tone":p,className:L("relative",Nn[p]),children:[s.jsx("button",{type:"button","aria-label":"Dismiss",className:"absolute right-2 top-2 rounded p-1 text-muted-foreground hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",onClick:()=>{Rn(t),l(!0)},children:s.jsx(xs,{className:"h-4 w-4","aria-hidden":"true"})}),u&&s.jsx(bt,{className:"pb-2 pr-8",children:s.jsx(wt,{className:"text-base",children:u})}),s.jsxs(Pe,{className:L("flex flex-col gap-3 pr-8",!u&&"pt-6"),children:[s.jsx(_e,{children:m(e,"body")}),c.length>0&&s.jsx("div",{className:"flex flex-wrap gap-2",children:c.map((g,w)=>s.jsx(B,{type:"button",variant:w===0?"default":"secondary",disabled:b,onClick:()=>{f(g.action),a(g.action,void 0)},children:g.label},`${g.action}:${w}`))}),x!==null&&s.jsx("p",{"data-testid":"ap-notice-sent",className:"text-xs text-muted-foreground",children:De(x)??"Sent."})]})]})}function $e(e,t){return e?e.component===t?!0:(e.children??[]).some(n=>$e(n,t)):!1}function En(e,t){const n=new Set,a=(r,o)=>{const l=ne(r)??o;r.component===t&&l!==null&&n.add(l);for(const d of r.children??[])a(d,l)};return e&&a(e,null),n}function $n(e){const t=(n,a)=>{const r=ne(n)??a;return n.component==="ap:question"&&r===null?!0:(n.children??[]).some(o=>t(o,r))};return e?t(e,null):!1}function Ot(e){var o;if(!e)return[];const t=[],n=l=>{l.component==="ap:steps"&&t.push(l);for(const d of l.children??[])n(d)};if(n(e),t.length!==1)return[];const a=(o=t[0].props)==null?void 0:o.steps,r=[];for(const l of Array.isArray(a)?a:[]){if(!l||typeof l.id!="string"||l.id==="")continue;const d=l.state==="done"||l.state==="active"?l.state:"upcoming";r.push({id:l.id,label:typeof l.label=="string"?l.label:l.id,state:d})}return r}function In(e){const t=new Map;if(!e)return t;const n=new Map;for(const r of Ot(e))n.set(r.id,{step:r.id,label:r.label,state:r.state});if(n.size===0)return t;const a=r=>{var d,f;const o=ne(r),l=(d=r.props)==null?void 0:d.step;if(o!==null&&typeof l=="string"){const p=n.get(l);if(p){const u=(f=r.props)==null?void 0:f.title;t.set(o,typeof u=="string"&&u!==""?{...p,title:u}:p)}}for(const p of r.children??[])a(p)};return a(e),t}function Mt(e,t){return e.component===t?!0:(e.children??[]).some(n=>Mt(n,t))}function Pn(e){var n;const t=e.component===Tt?(n=e.props)==null?void 0:n.step:void 0;return typeof t=="string"&&t!==""?t:null}function On({node:e,renderChild:t}){var x;const n=((x=e.props)==null?void 0:x.layout)==="rail"?"rail":"column",a=e.children??[],{waiting:r}=Fe(),o=i.useMemo(()=>Ot(e),[e]),l=i.useMemo(()=>{const g=o.find(C=>C.state==="active");if(g)return g.id;const w=o.filter(C=>C.state==="done");return w.length>0?w[w.length-1].id:o.length>0?o[0].id:null},[o]),[d,f]=i.useState(null);i.useEffect(()=>{f(null)},[l]);const p=d??l,u=i.useMemo(()=>({layout:n,selectedStep:p,selectStep:f}),[n,p]);if(n!=="rail")return s.jsx(Ee.Provider,{value:u,children:s.jsx("div",{className:"flex flex-col gap-2",children:a.map(t)})});const c=a.findIndex(g=>Mt(g,"ap:steps")),h=c>=0?a[c]:null,b=(g,w)=>{if(w===c)return!1;const C=Pn(g);if(C===null||C===p)return!0;const N=ne(g);return N!==null&&r.has(N)};return s.jsx(Ee.Provider,{value:u,children:s.jsxs("div",{className:"grid gap-6 md:grid-cols-[220px_minmax(0,1fr)]",children:[s.jsx("div",{"data-testid":"agent-ui-page-rail",className:"md:sticky md:top-4 md:self-start",children:h?t(h,"rail"):null}),s.jsx("div",{"data-testid":"agent-ui-page-stage",className:"flex min-w-0 flex-col gap-3",children:a.map((g,w)=>b(g,w)?t(g,w):null)})]})})}const Mn={"ap:select":{prop:"param",values:[{valueProp:"value"}]},"ap:daterange":{prop:"param",values:[{suffix:"from",valueProp:"from"},{suffix:"to",valueProp:"to"}]}};function he(e,t){return t?`${e}.${t}`:e}function Ve(e){const t=Mn[e.component];if(!t)return null;const n=(e.props??{})[t.prop];return typeof n!="string"||n===""?null:{name:n,spec:t}}const Ln={params:{},setParam:()=>{}},Lt=i.createContext(Ln);function _n({value:e,children:t}){return s.jsx(Lt.Provider,{value:e,children:t})}function _t(){return i.useContext(Lt)}function Dt(e){const t={};return e.view&&Ut(e.view,t),t}function ye(e,t){const n=Dt(e),a={};for(const r of Dn(e))r in t?a[r]=t[r]:r in n&&(a[r]=n[r]);return a}function Dn(e){const t=[],n=a=>{const r=Ve(a);if(r)for(const o of r.spec.values){const l=he(r.name,o.suffix);t.includes(l)||t.push(l)}for(const o of a.children??[])n(o)};return e.view&&n(e.view),t}function Ut(e,t){const n=Ve(e);if(n){const a=e.props??{};for(const r of n.spec.values){const o=a[r.valueProp];typeof o=="string"&&o!==""&&(t[he(n.name,r.suffix)]=o)}}for(const a of e.children??[])Ut(a,t)}const at=e=>Array.isArray(e)?e.filter(t=>typeof t=="string"):[];function rt({label:e,state:t}){return s.jsxs("li",{"data-state":t,className:"flex items-center gap-2 text-sm",children:[t==="done"&&s.jsx("span",{"aria-hidden":"true",className:"text-[hsl(var(--success))]",children:"✓"}),s.jsx("span",{className:t==="done"?"text-muted-foreground line-through":void 0,children:e})]})}function Un({n:e}){const t=m(e,"now"),n=at(P(e).done),a=at(P(e).next),r=m(e,"step");return s.jsx(ge,{children:s.jsxs("section",{"data-testid":"ap-progress",className:"flex flex-col gap-3 p-6",children:[s.jsx("p",{"data-testid":"ap-progress-now",className:"text-sm font-medium",children:t}),(n.length>0||a.length>0)&&s.jsxs("ul",{className:"flex flex-col gap-1.5",children:[n.map((o,l)=>s.jsx(rt,{label:o,state:"done"},`done-${l}`)),a.map((o,l)=>s.jsx(rt,{label:o,state:"next"},`next-${l}`))]}),r&&s.jsx("p",{className:"text-xs text-muted-foreground",children:r})]})})}function qn(e){return Array.isArray(e)?e.filter(t=>!!t&&typeof t.value=="string"&&typeof t.label=="string"):[]}function Fn({n:e}){const t=JSON.stringify([m(e,"prompt"),m(e,"kind"),P(e).choices??null]);return s.jsx(Vn,{n:e},t)}function Vn({n:e}){const{answer:t,busy:n}=le(),a=wn(),{answered:r}=Fe(),o=a!==null&&r.has(a),l=m(e,"prompt"),d=m(e,"kind")==="choice"?"choice":"text",f=m(e,"placeholder"),p=m(e,"submitLabel","Answer"),u=qn(P(e).choices),c=i.useId(),[h,b]=i.useState(""),[x,g]=i.useState(!1),[w,C]=i.useState(!1),[N,M]=i.useState(!1);if(w||o)return s.jsx("p",{"data-testid":"ap-question-sent",children:"Sent — waiting for the agent."});const D=h.trim()===""||x||!!n;function j(v){v.preventDefault(),!D&&(g(!0),M(!1),t(h).then(()=>C(!0)).catch($=>{console.error("agentui: ap:question answer failed",$),M(!0)}).finally(()=>g(!1)))}return s.jsx(ge,{children:s.jsx(Pe,{className:"pt-6",children:s.jsxs("form",{"data-testid":"ap-question",onSubmit:j,className:"flex flex-col gap-3",children:[s.jsx(oe,{htmlFor:d==="text"?c:void 0,className:"font-normal text-foreground",children:l}),d==="choice"?s.jsx("div",{className:"flex flex-col gap-2",children:u.map(v=>s.jsxs(oe,{className:"flex items-center gap-2 font-normal",children:[s.jsx("input",{type:"radio",name:c,value:v.value,checked:h===v.value,disabled:x||!!n,onChange:()=>b(v.value),className:"h-4 w-4 border-input text-primary focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"}),v.label]},v.value))}):s.jsx("textarea",{id:c,placeholder:f,value:h,disabled:x||!!n,onChange:v=>b(v.target.value),className:"flex min-h-16 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50"}),s.jsx(B,{type:"submit",disabled:D,className:"self-start",children:p}),N&&s.jsx("p",{role:"alert",className:"text-xs text-destructive",children:"Could not send your answer. Try again."})]})})})}const ot={idle:"bg-muted-foreground",running:"bg-[hsl(var(--success))] animate-pulse",paused:"bg-[hsl(var(--warning))]",ended:"bg-muted-foreground",unwatched:"bg-[hsl(var(--warning))]"};function Bn(e){if(e==="")return null;const t=new Date(e);return Number.isNaN(t.getTime())?null:t.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"})}function Hn({n:e}){const t=m(e,"state"),n=ot[t]??ot.idle,a=m(e,"since"),r=Bn(a);return s.jsxs("div",{"data-testid":"ap-status","data-state":t,role:"status",title:a||void 0,className:"flex items-center gap-2 text-sm font-medium",children:[s.jsx("span",{"aria-hidden":"true",className:L("inline-block h-2 w-2 shrink-0 rounded-full",n)}),s.jsxs("span",{children:[m(e,"text"),r!==null&&s.jsxs(s.Fragment,{children:[" ",s.jsx("time",{dateTime:a,children:r})]})]})]})}function qt(e,t,n){return t.includes(e)?e:n}const Wn=["default","secondary","destructive","outline"],Kn=["default","secondary","destructive","outline","ghost","link"],ue={none:"gap-0",sm:"gap-2",md:"gap-4",lg:"gap-6"},it={start:"items-start",center:"items-center",end:"items-end",stretch:"items-stretch"},Ne=e=>`apui-${e}`,zn=e=>e==="right"?"text-right":e==="center"?"text-center":void 0,Yn=e=>e==="right"?"text-right tabular-nums":e==="center"?"text-center":void 0;function Jn({n:e}){const{params:t,setParam:n}=_t(),a=m(e,"param"),r=a!=="",o=m(e,"value"),l=r?t[a]??o:o,d=m(e,"placeholder");return s.jsx("div",{className:"flex flex-col gap-1",children:s.jsxs("select",{disabled:!r,className:L("h-9 rounded-md border border-input bg-transparent px-3 text-sm",!r&&"text-muted-foreground"),value:l,onChange:r?f=>n(a,f.target.value):void 0,children:[d&&s.jsx("option",{value:"",disabled:!0,hidden:!0,children:d}),(P(e).options??[]).map(f=>s.jsx("option",{value:f.value,children:f.label??f.value},f.value))]})})}function lt(e){return e===""||e.includes("T")?e:`${e}T00:00:00Z`}function ct(e){const t=e.indexOf("T");return t===-1?e:e.slice(0,t)}function Gn({n:e}){const{params:t,setParam:n}=_t(),a=m(e,"param");if(!(a!==""))return s.jsxs(B,{variant:"secondary",disabled:!0,children:[m(e,"from")||"start"," → ",m(e,"to")||"end"]});const o=he(a,"from"),l=he(a,"to"),d=t[o]??m(e,"from"),f=t[l]??m(e,"to");return s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx(Ae,{type:"date","aria-label":"From date",value:ct(d),onChange:p=>n(o,lt(p.target.value)),className:"h-9 w-auto"}),s.jsx("span",{className:"text-muted-foreground","aria-hidden":"true",children:"→"}),s.jsx(Ae,{type:"date","aria-label":"To date",value:ct(f),onChange:p=>n(l,lt(p.target.value)),className:"h-9 w-auto"})]})}function Be({text:e}){return e?s.jsx("span",{"data-testid":"agent-ui-action-status",className:"text-xs text-muted-foreground",children:e}):null}function Xn({n:e,columns:t,rows:n}){const{states:a,invoke:r}=le(),o=m(e,"rowAction"),l=o!=="",d=l?a[o]??{phase:"idle"}:{phase:"idle"},f=ie(d.phase);return n.length===0?s.jsx("p",{className:"py-6 text-center text-sm text-muted-foreground",children:m(e,"empty","Nothing to show.")}):s.jsxs("div",{className:"overflow-x-auto",children:[s.jsxs(os,{children:[s.jsx(is,{children:s.jsxs(Je,{children:[t.map(p=>s.jsx(Ge,{className:zn(p.align),children:p.header??p.key},p.key)),l&&s.jsx(Ge,{className:"w-px"})]})}),s.jsx(ls,{children:n.map((p,u)=>s.jsxs(Je,{children:[t.map(c=>s.jsx(Xe,{className:Yn(c.align),children:String(p[c.key]??"")},c.key)),l&&s.jsx(Xe,{className:"text-right",children:s.jsx(B,{variant:"ghost",size:"sm",disabled:f,"data-testid":"agent-ui-row-action",onClick:()=>r(o,Qn(p)),children:m(e,"rowActionLabel","Details")})})]},u))})]}),s.jsx(Be,{text:l?d.message??null:null})]})}function Se(e,t){if(e==null)return[];if(!Array.isArray(e))throw new TypeError(`${t} must be an array`);return e}function Qn(e){const t={};for(const[n,a]of Object.entries(e))typeof a=="string"?t[n]=a:(typeof a=="number"&&Number.isFinite(a)||typeof a=="boolean")&&(t[n]=String(a));return t}function Zn({n:e}){const{states:t,invoke:n,busy:a}=le(),r=m(e,"action"),o=r!=="",l=o?t[r]??{phase:"idle"}:{phase:"idle"},d=!o||ie(l.phase)||!!a||!!P(e).disabled;return s.jsxs("div",{className:"flex flex-col gap-1",children:[s.jsx(B,{variant:qt(m(e,"variant"),Kn,"default"),disabled:d,onClick:o?()=>n(r,void 0):void 0,children:m(e,"label")}),s.jsx(Be,{text:De(l)})]})}function ea({n:e}){const{states:t,invoke:n,busy:a}=le(),r=m(e,"action"),o=r!=="",l=o?t[r]??{phase:"idle"}:{phase:"idle"},d=!o||ie(l.phase)||!!a||!!P(e).disabled,f=P(e).fields??[],p=P(e).values??{},[u,c]=i.useState(()=>({...p}));return s.jsxs("form",{className:"flex flex-col gap-3",onSubmit:h=>{h.preventDefault(),o&&n(r,Object.fromEntries(f.map(b=>[b.name,u[b.name]??""])))},children:[f.map(h=>s.jsxs("div",{className:"flex flex-col gap-1",children:[s.jsx(oe,{htmlFor:Ne(h.name),children:h.label??h.name}),h.kind==="textarea"?s.jsx("textarea",{id:Ne(h.name),name:h.name,placeholder:h.placeholder,disabled:d,value:u[h.name]??"",onChange:b=>c(x=>({...x,[h.name]:b.target.value})),className:"flex min-h-16 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50"}):s.jsx(Ae,{id:Ne(h.name),name:h.name,type:h.kind==="number"?"number":"text",placeholder:h.placeholder,disabled:d,value:u[h.name]??"",onChange:b=>c(x=>({...x,[h.name]:b.target.value}))})]},h.name)),s.jsx(B,{type:"submit",disabled:d,children:m(e,"submitLabel","Submit")}),s.jsx(Be,{text:De(l)})]})}function ta(e){const t=Ue(e);return t===null?null:`/session-view/${encodeURIComponent(t[0])}/${encodeURIComponent(t[1])}`}function sa(e,t){const n=s.jsx("ol",{className:"flex w-full items-center","data-testid":"agent-ui-steps",children:t.map((a,r)=>{const o=a.state==="done"||a.state==="active"?a.state:"upcoming",l=r===t.length-1;return s.jsxs("li",{className:L("flex items-center",!l&&"flex-1"),"aria-current":o==="active"?"step":void 0,children:[s.jsxs("div",{className:"flex flex-col items-center gap-1.5",children:[s.jsx("span",{className:L("flex h-7 w-7 items-center justify-center rounded-full border text-xs font-semibold tabular-nums transition-colors",o==="done"&&"border-[hsl(var(--primary))] bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))]",o==="active"&&"border-[hsl(var(--primary))] text-[hsl(var(--primary))] ring-2 ring-[hsl(var(--primary))]/30",o==="upcoming"&&"border-border text-muted-foreground"),children:o==="done"?"✓":r+1}),s.jsx("span",{className:L("whitespace-nowrap text-xs",o==="active"?"font-medium text-foreground":"text-muted-foreground"),children:a.label??""})]}),!l&&s.jsx("span",{className:L("mx-2 mb-5 h-px flex-1 transition-colors",o==="done"?"bg-[hsl(var(--primary))]":"bg-border"),"aria-hidden":"true"})]},r)})});return P(e).pinned?s.jsx("div",{"data-testid":"agent-ui-steps-pinned",className:"sticky top-0 z-10 -mx-4 bg-background px-4 py-2",children:n}):n}function na({node:e,steps:t}){const{layout:n,selectedStep:a,selectStep:r}=Rt();return n!=="rail"?sa(e,t):s.jsx("ol",{className:"flex flex-col","data-testid":"agent-ui-steps","aria-label":"Steps",children:t.map((o,l)=>{const d=o.state==="done"||o.state==="active"?o.state:"upcoming",f=typeof o.id=="string"&&o.id!==""?o.id:null,p=f!==null&&f===a;return s.jsxs("li",{"data-testid":"agent-ui-rail-step","data-step-id":f??void 0,"data-selected":p?"true":void 0,className:"relative",children:[s.jsxs("button",{type:"button",onClick:()=>f!==null&&r(f),disabled:f===null,"aria-current":d==="active"?"step":void 0,"aria-pressed":p,className:L("flex w-full items-start gap-2.5 rounded-md px-2 py-1.5 text-left transition-colors hover:bg-muted/40",p&&"bg-muted/60"),children:[s.jsx("span",{className:L("mt-0.5 flex h-5 w-5 shrink-0 items-center justify-center rounded-full border text-[10px] font-semibold tabular-nums",d==="done"&&"border-[hsl(var(--primary))] bg-[hsl(var(--primary))] text-[hsl(var(--primary-foreground))]",d==="active"&&"border-[hsl(var(--primary))] text-[hsl(var(--primary))] ring-2 ring-[hsl(var(--primary))]/30",d==="upcoming"&&"border-border text-muted-foreground"),children:d==="done"?"✓":l+1}),s.jsxs("span",{className:"min-w-0",children:[s.jsx("span",{className:L("block text-sm",d==="active"?"font-medium text-foreground":d==="upcoming"?"text-muted-foreground":"text-foreground"),children:o.label??""}),o.summary?s.jsx("span",{className:"block truncate text-xs text-muted-foreground",children:o.summary}):null]})]}),ls.jsx("div",{className:L("flex",m(e,"direction")==="horizontal"?"flex-row":"flex-col",ue[m(e,"gap","md")]??ue.md,it[m(e,"align","start")]??it.start),children:(e.children??[]).map(t)}),"ap:status":e=>s.jsx(Hn,{n:e}),"ap:grid":(e,t)=>{const n=typeof P(e).columns=="number"?P(e).columns:0,a=n>0?Math.min(Math.max(Math.trunc(n),1),12):0;return s.jsx("div",{className:L("grid",ue[m(e,"gap","md")]??ue.md),style:{gridTemplateColumns:a>0?`repeat(${a}, minmax(0, 1fr))`:"repeat(auto-fit, minmax(16rem, 1fr))"},children:(e.children??[]).map(t)})},"ap:card":(e,t)=>{const n=!!(m(e,"title")||m(e,"description"));return s.jsxs(ge,{children:[n&&s.jsxs(bt,{children:[m(e,"title")&&s.jsx(wt,{children:m(e,"title")}),m(e,"description")&&s.jsx(rs,{children:m(e,"description")})]}),s.jsx(Pe,{className:n?void 0:"pt-6",children:(e.children??[]).map(t)})]})},"ap:collapsible":(e,t)=>s.jsx(Ct,{title:m(e,"title"),collapsed:!!P(e).collapsed,testId:"ap-collapsible",children:(e.children??[]).map(t)}),"ap:heading":e=>{const t=Math.min(Math.max(Number(P(e).level)||2,1),4),n=`h${t}`,a={1:"text-2xl",2:"text-xl",3:"text-lg",4:"text-base"}[t]??"text-xl";return s.jsx(n,{className:L(a,"font-semibold text-foreground"),children:m(e,"text")})},"ap:text":e=>s.jsx("p",{className:L(m(e,"variant")==="muted"&&"text-muted-foreground",m(e,"variant")==="mono"&&"font-mono","text-sm"),children:m(e,"text")}),"ap:markdown":e=>s.jsx(_e,{children:m(e,"body")}),"ap:metric":e=>s.jsxs("div",{className:"flex flex-col gap-1",children:[s.jsx("span",{className:"text-xs uppercase tracking-wide text-muted-foreground",children:m(e,"label")}),s.jsx("span",{className:"text-2xl font-semibold tabular-nums",children:m(e,"value")}),m(e,"delta")&&s.jsx("span",{className:L("text-xs tabular-nums",m(e,"trend")==="up"&&"text-[hsl(var(--success))]",m(e,"trend")==="down"&&"text-destructive",m(e,"trend")!=="up"&&m(e,"trend")!=="down"&&"text-muted-foreground"),children:m(e,"delta")}),m(e,"caption")&&s.jsx("span",{className:"text-xs text-muted-foreground",children:m(e,"caption")})]}),"ap:progress":e=>s.jsx(Un,{n:e}),"ap:question":e=>s.jsx(Fn,{n:e}),"ap:notice":e=>s.jsx(Tn,{n:e}),"ap:table":e=>{const t=Se(P(e).columns,"ap:table.columns"),n=Se(P(e).rows,"ap:table.rows");return s.jsx(Xn,{n:e,columns:t,rows:n})},"ap:badge":e=>s.jsx(Ds,{variant:qt(m(e,"variant"),Wn,"default"),children:m(e,"text")}),"ap:alert":e=>{const t=m(e,"severity");return s.jsxs(W,{variant:t==="error"?"destructive":"default",className:t==="warning"?"border-warning/50 text-warning [&>svg]:text-warning":void 0,children:[m(e,"title")&&s.jsx(Y,{children:m(e,"title")}),m(e,"body")&&s.jsx(J,{children:m(e,"body")})]})},"ap:empty":e=>s.jsxs("div",{className:"flex flex-col items-center gap-1 py-10 text-center",children:[s.jsx("p",{className:"text-sm font-medium",children:m(e,"title","Nothing here yet")}),m(e,"body")&&s.jsx("p",{className:"text-xs text-muted-foreground",children:m(e,"body")})]}),"ap:steps":e=>{const t=Se(P(e).steps,"ap:steps.steps");return t.forEach((n,a)=>{if(typeof n!="object"||n===null)throw new TypeError(`ap:steps.steps[${a}] must be an object`)}),s.jsx(na,{node:e,steps:t})},"ap:skeleton":e=>s.jsxs("div",{className:"flex flex-col gap-2 py-4","data-testid":"ap-skeleton","aria-busy":"true","aria-live":"polite",children:[m(e,"label")&&s.jsx("p",{className:"text-xs text-muted-foreground",children:m(e,"label")}),s.jsx("div",{className:"h-4 w-1/3 animate-pulse rounded bg-muted"}),s.jsx("div",{className:"h-4 w-full animate-pulse rounded bg-muted"}),s.jsx("div",{className:"h-4 w-5/6 animate-pulse rounded bg-muted"}),!m(e,"label")&&s.jsx("span",{className:"sr-only",children:"Loading…"})]}),"ap:error":e=>s.jsxs(W,{variant:"destructive",children:[s.jsx(Y,{children:m(e,"title","Something went wrong")}),m(e,"body")&&s.jsx(J,{children:m(e,"body")})]}),"ap:chart":e=>{const t=P(e).series??[],n=P(e).data??[],a=m(e,"xKey"),r=m(e,"kind","line");if(n.length===0||t.length===0)return s.jsx("p",{className:"py-6 text-center text-sm text-muted-foreground",children:"No data to chart."});const o=s.jsx(Ns,{stroke:"hsl(var(--border))",strokeDasharray:"3 3",vertical:!1}),l=s.jsx(Ss,{dataKey:a,stroke:"hsl(var(--muted-foreground))",tickLine:!1,axisLine:!1}),d=s.jsx(ks,{stroke:"hsl(var(--muted-foreground))",tickLine:!1,axisLine:!1,width:40}),f=s.jsx(zs,{});return r==="bar"?s.jsx(je,{children:s.jsxs(gs,{data:n,children:[o,l,d,f,t.map((p,u)=>s.jsx(vs,{dataKey:p.key,name:p.label??p.key,fill:de(u)},p.key))]})}):r==="area"?s.jsx(je,{children:s.jsxs(bs,{data:n,children:[o,l,d,f,t.map((p,u)=>s.jsx(ws,{type:"monotone",dataKey:p.key,name:p.label??p.key,stroke:de(u),fill:de(u),fillOpacity:.25},p.key))]})}):s.jsx(je,{children:s.jsxs(js,{data:n,children:[o,l,d,f,t.map((p,u)=>s.jsx(ys,{type:"monotone",dataKey:p.key,name:p.label??p.key,stroke:de(u),strokeWidth:2,dot:!1},p.key))]})})},"ap:chat":e=>s.jsx(Qs,{n:e}),"ap:tabs":(e,t)=>{const n=P(e).tabs??[],a=e.children??[];return n.length===0?s.jsx(s.Fragment,{children:a.map(t)}):s.jsxs(ts,{defaultValue:m(e,"value")||n[0].value,children:[s.jsx(ss,{children:n.map(r=>s.jsx(ns,{value:r.value,children:r.label??r.value},r.value))}),n.map((r,o)=>{const d=o===n.length-1?a.slice(o):a.slice(o,o+1);return s.jsx(as,{value:r.value,children:d.map((f,p)=>t(f,`${r.value}-${p}`))},r.value)})]})},"ap:raw_html":()=>s.jsxs(W,{children:[s.jsx(Y,{children:"Embedded content"}),s.jsx(J,{children:"This section renders once the sandboxed content view is available."})]}),"ap:session_view":e=>{const t=ta(P(e).sessionRef);return t===null?s.jsx(W,{children:"Session view unavailable: no valid session reference."}):s.jsx("iframe",{src:t,title:"Session view",style:{width:"100%",height:"600px",border:"0"}})},"ap:agentlink":e=>(qe(e),s.jsx(ln,{n:e})),"ap:attachment":e=>s.jsx(mn,{n:e}),"ap:button":e=>s.jsx(Zn,{n:e}),"ap:select":e=>s.jsx(Jn,{n:e}),"ap:daterange":e=>s.jsx(Gn,{n:e}),"ap:form":e=>s.jsx(ea,{n:e}),"oap:generative":(e,t)=>{var n;return s.jsx(jn,{name:m(e,"name"),title:typeof((n=e.props)==null?void 0:n.title)=="string"?e.props.title:void 0,children:(e.children??[]).map(t)})},"oap:page":(e,t)=>s.jsx(On,{node:e,renderChild:t})};function ra({type:e}){return s.jsxs(W,{variant:"destructive",children:[s.jsx(Y,{children:"Cannot render this section"}),s.jsxs(J,{children:["Unknown component ",s.jsx("code",{className:"font-mono",children:e}),". Reload the page; if it persists, this view needs an update."]})]})}function oa({type:e}){return s.jsxs(W,{variant:"destructive",children:[s.jsx(Y,{children:"Cannot render this section"}),s.jsxs(J,{children:["The ",s.jsx("code",{className:"font-mono",children:e})," section could not be displayed. The rest of this view is unaffected."]})]})}const ia=e=>(t,n)=>Ft(t,n,e);function Ft(e,t,n){const a=aa[e.component];if(!a)return n==null||n(e.component),s.jsx(ra,{type:e.component},t);try{return i.cloneElement(a(e,ia(n)),{key:t})}catch(r){return console.error(`agentui: failed to render ${e.component}`,r),n==null||n(e.component),s.jsx(oa,{type:e.component},t)}}function la(e,t,n){return`${e}/${t.join(".")}#${n}`}function ca(e,t){return Vt(e,ne(e)??"",[],t)}function Vt(e,t,n,a){var c;const r=(c=e.children)==null?void 0:c.map((h,b)=>{const x=ne(h);return Vt(h,x??t,x!==null?[]:[...n,b],a)});if(!e.bindings)return{...e,children:r};const o={...e.props};let l=null,d=null,f=null;for(const h of Object.keys(e.bindings).sort()){const b=a[la(t,n,h)]??{status:"loading"};if(b.status==="error"){l===null&&(l=b.message);continue}if(b.status==="needs_input"){d===null&&(d=b.message);continue}if(b.status==="waking"){f===null&&(f=b.message);continue}if(b.status==="loading"){f===null&&(f="");continue}o[h]=b.value}if(l===null&&d===null&&f===null)return{...e,props:o,children:r};const u=l!==null?{component:"ap:error",props:{title:"Cannot load this section",body:l}}:f!==null?{component:"ap:skeleton",props:f===""?{}:{label:f}}:{component:"ap:empty",props:{title:"Nothing to show yet",body:d}};return Ve(e)?{component:"ap:stack",props:{gap:"sm"},children:[{...e,props:o,children:r},u]}:u}const xe="p.";function dt(e){const t={};return new URLSearchParams(e).forEach((a,r)=>{if(!r.startsWith(xe))return;const o=r.slice(xe.length);o!==""&&(t[o]=a)}),t}function da(e,t){const n=new URLSearchParams(e);for(const r of Array.from(n.keys()))r.startsWith(xe)&&n.delete(r);for(const r of Object.keys(t).sort())n.set(xe+r,t[r]);const a=n.toString();return a===""?"":`?${a}`}function ua({open:e,variant:t,text:n,replySeq:a,onReply:r,onDismiss:o}){const[l,d]=i.useState(""),[f,p]=i.useState(!1),[u,c]=i.useState(!1);i.useEffect(()=>{d(""),c(!1)},[a]);const h=l.trim()===""||f;function b(x){x.preventDefault(),!h&&(p(!0),c(!1),r(l).catch(g=>{console.error("agentui: reply modal send failed",g),c(!0)}).finally(()=>p(!1)))}return s.jsx(Oe,{open:e,onOpenChange:x=>{x||o()},children:s.jsxs(Me,{"data-testid":"agent-ui-reply-modal","data-variant":t,children:[s.jsx(Le,{children:t==="paused"?s.jsxs(s.Fragment,{children:[s.jsx(pe,{children:"The agent paused"}),s.jsx(me,{children:"It replied and stopped without asking anything. Send a message to continue."})]}):s.jsxs(s.Fragment,{children:[s.jsx(pe,{children:"The agent is waiting for your reply"}),s.jsx(me,{children:"Your reply goes to this session's conversation, just as if you had typed it there."})]})}),s.jsx("div",{className:"max-h-48 overflow-y-auto text-sm",children:s.jsx(_e,{children:n})}),s.jsxs("form",{onSubmit:b,className:"flex flex-col gap-3",children:[s.jsx("textarea",{"aria-label":"Your reply",value:l,disabled:f,onChange:x=>d(x.target.value),placeholder:t==="paused"?"Tell it how to continue…":void 0,className:"flex min-h-20 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50"}),u&&s.jsx("p",{role:"alert",className:"text-xs text-destructive",children:"Could not send your reply. Try again."}),s.jsxs(cs,{children:[s.jsx(B,{type:"button",variant:"ghost",onClick:o,disabled:f,children:"Later"}),s.jsx(B,{type:"submit",disabled:h,children:f?"Sending…":t==="paused"?"Continue":"Reply"})]})]})]})})}function fa(e){var t;return e.turnActive?e.composingUpdate?"Composing a page update…":(t=e.activity)!=null&&t.compactLine?e.activity.compactLine:e.notice?e.notice:"Working…":null}function pa(e){switch(e){case"done":return"done";case"in_progress":return"current";default:return"next"}}function ma({label:e,state:t,live:n}){return s.jsxs("li",{"data-state":t,className:"flex items-center gap-2 text-xs",children:[t==="done"&&s.jsx("span",{"aria-hidden":"true",className:"text-[hsl(var(--success))]",children:"✓"}),t==="current"&&s.jsx(ve,{className:L("h-3 w-3 shrink-0 text-primary",n&&"animate-spin"),"aria-hidden":"true"}),s.jsx("span",{className:L(t==="done"&&"text-muted-foreground line-through",t==="next"&&"text-muted-foreground"),children:e})]})}function ha({signals:e}){var a;if(!e.turnActive&&e.plan===null)return null;const t=fa(e),n=((a=e.plan)==null?void 0:a.items)??[];return s.jsxs("section",{"data-testid":"agent-ui-default-progress","aria-live":"polite",className:"flex flex-col gap-2 border-b border-border bg-card/40 px-4 py-2",children:[t!==null&&s.jsxs("p",{"data-testid":"agent-ui-progress-now","data-composing":e.composingUpdate?"true":void 0,className:"flex items-center gap-2 text-xs font-medium text-foreground",children:[!e.composingUpdate&&s.jsx(ve,{className:"h-3 w-3 shrink-0 animate-spin text-muted-foreground","aria-hidden":"true"}),t]}),n.length>0&&s.jsx("ul",{className:"flex flex-col gap-1",children:n.map((r,o)=>s.jsx(ma,{label:r.label,state:pa(r.status),live:e.turnActive},`${o}-${r.id}`))})]})}const Bt="$transport",xa="This view's data could not be loaded. Check your connection and reload.";function ut(e){return{status:"error",message:e}}class ke extends Error{constructor(t,n){super(`agent-ui bindings request failed (${t})`),this.name="BindingsRequestError",this.authored=n,this.status=t}}const ga=410;async function va(e){try{const t=await e.json();return typeof(t==null?void 0:t.error)=="string"?t.error:""}catch{return""}}const ba=250,wa=2e3,ja=15;function ya(e,t,n,a,r){const[o,l]=i.useState({}),[d,f]=i.useState(!1),p=i.useRef(r);p.current=r;const u=i.useRef(0),c=i.useRef(!0),[h,b]=i.useState(0),x=i.useRef(0),g=i.useRef(null);return i.useEffect(()=>{let w=!0;u.current+=1;const C=u.current,N=()=>w&&C===u.current,M=new AbortController,D=c.current?0:ba;c.current=!1;const j=setTimeout(()=>{D>0&&f(!0),fetch(`/agent-ui/${encodeURIComponent(e)}/${encodeURIComponent(t)}/bindings`,{method:"POST",credentials:"same-origin",headers:{"Content-Type":"application/json"},body:JSON.stringify({params:n}),signal:M.signal}).then(async v=>{if(!v.ok)throw new ke(v.status,await va(v));return await v.json()}).then(v=>{if(!N())return;const $={};let k=!1;for(const[y,T]of Object.entries(v.bindings??{})){if(T.status==="ok"){$[y]={status:"ok",value:T.value};continue}if(T.status==="needs_input"){$[y]={status:"needs_input",message:T.message??"Choose a value above to load this data."};continue}if(T.status==="waking"){$[y]={status:"waking",message:T.message??"Waking this agent…"},k=!0;continue}$[y]={status:"error",message:T.message??"This view's data is not available."}}l($),k&&x.current{w&&(l(y=>y),b(y=>y+1))},wa)):k?l(y=>{const T={};for(const[U,H]of Object.entries(y))T[U]=H.status==="waking"?{status:"error",message:"the agent for this session isn't responding"}:H;return T}):x.current=0,f(!1)}).catch(v=>{var k;if(M.signal.aborted||!N())return;f(!1),console.error("agent-ui bindings: request failed",v),v instanceof ke&&v.status===ga&&((k=p.current)==null||k.call(p));const $=v instanceof ke&&v.authored!==""?v.authored:xa;l(y=>{const T={};for(const U of Object.keys(y))T[U]=ut($);return T[Bt]=ut($),T})})},D);return()=>{w=!1,clearTimeout(j),M.abort(),g.current!==null&&(clearTimeout(g.current),g.current=null)}},[e,t,JSON.stringify(n),a,h]),{states:o,refreshing:d}}const Na=2e4,Sa=5*6e4,ft=["pointerdown","keydown","scroll","wheel"];function ka({send:e,enabled:t=!0}){const n=i.useRef(e);n.current=e,i.useEffect(()=>{if(!t||typeof window>"u"||typeof document>"u")return;let a=Date.now();const r=()=>{a=Date.now()};for(const d of ft)window.addEventListener(d,r,{passive:!0});const o=()=>document.visibilityState!=="visible"||typeof document.hasFocus=="function"&&!document.hasFocus()?!1:Date.now()-a{o()&&n.current()},Na);return()=>{window.clearInterval(l);for(const d of ft)window.removeEventListener(d,r)}},[t])}function Ca(e,t){return e.replace(/\{([^{}]*)\}/g,(n,a)=>a!==""&&Object.hasOwn(t,a)?t[a]:n)}const Ra=2e3,Ta="This action may not have completed. Check your connection, then check the result before retrying.",Aa="Live updates for this view are unavailable right now.";function Ea(e,t,n){return`${e.protocol==="https:"?"wss:":"ws:"}//${e.host}/agent-ui/${encodeURIComponent(t)}/${encodeURIComponent(n)}/live`}function pt(e){return{phase:e.state,requestId:e.requestId,message:e.message,approvalAddressedToViewer:e.approvalAddressedToViewer}}function Ce(e){return!ie(e)}function $a(e,t){return e!==void 0&&e.phase===t.phase&&e.requestId===t.requestId&&e.message===t.message&&!!e.approvalAddressedToViewer==!!t.approvalAddressedToViewer}function Ia(e,t,n,a,r,o=[]){const[l,d]=i.useState({}),[f,p]=i.useState(null),u=i.useRef(!0),c=i.useRef(n);c.current=n;const h=i.useRef(a);h.current=a;const b=i.useRef(r);b.current=r;const x=i.useRef(o);x.current=o;const g=i.useRef(l);g.current=l;const w=i.useRef(new Set),C=i.useRef(null),N=i.useRef(0),M=i.useRef({});i.useEffect(()=>(u.current=!0,()=>{u.current=!1}),[]),i.useEffect(()=>{let j=null,v,$=!1,k=0;const y=O=>{N.current+=1,M.current[O]=N.current},T=O=>{if(!Ce(O.state))return!1;const A=g.current[O.action];return A===void 0||!Ce(A.phase)},U=O=>{const A=new Set,K={};let z=!1,se=!1;for(const q of O){if(A.has(q.action)||(A.add(q.action),w.current.has(q.action)))continue;T(q)&&(z=!0);const te=pt(q);$a(g.current[q.action],te)||(se=!0),K[q.action]=te,y(q.action)}se&&(d(q=>({...q,...K})),z&&h.current())},H=O=>{const A=T(O);y(O.action),d(K=>({...K,[O.action]:pt(O)})),A&&h.current()},ee=O=>{let A;try{A=JSON.parse(O)}catch(K){console.error("agent-ui live: malformed frame",{ns:e,name:t,err:K});return}if(u.current){if(A.type==="snapshot"){p(null),U(A.actions??[]);return}if(A.type==="event"&&A.action){H(A.action);return}if(A.type==="error"){console.error("agent-ui live: server reported live updates unavailable",{ns:e,name:t,msg:A}),p(A.message||Aa);return}if(A.type==="view"){if(!A.declaration||typeof A.declaration.view!="object"||A.declaration.view===null||typeof A.declaration.view.component!="string"){console.error("agent-ui live: malformed view frame; keeping the previous declaration",{ns:e,name:t,msg:A});return}b.current(A.declaration,A.agentParams,A.hook);return}console.error("agent-ui live: unhandled frame",{ns:e,name:t,msg:A})}},G=()=>{$||(k+=1,console.error("agent-ui live: socket closed; reconnecting",{ns:e,name:t,attempt:k}),v=window.setTimeout(X,Ra))},X=()=>{if(!$){try{j=new WebSocket(Ea(window.location,e,t))}catch(O){console.error("agent-ui live: failed to open socket",{ns:e,name:t,err:O}),G();return}j.onopen=()=>{k=0},C.current=j,j.onmessage=O=>ee(O.data),j.onerror=()=>{},j.onclose=G}};return X(),()=>{$=!0,v&&window.clearTimeout(v),j&&j.close(),C.current=null}},[e,t]),ka({enabled:!0,send:i.useCallback(()=>{const j=C.current;if(!(!j||j.readyState!==WebSocket.OPEN))try{j.send(JSON.stringify({type:"presence"}))}catch(v){console.error("agent-ui live: presence heartbeat send failed",{ns:e,name:t,err:v})}},[e,t])});const D=i.useCallback((j,v)=>{if(w.current.has(j))return;w.current.add(j),N.current+=1;const $=N.current;d(y=>({...y,[j]:{phase:"submitted"}}));const k=x.current.find(y=>y.name===j);if(k!=null&&k.prompt){jt(e,t,Ca(k.prompt,{...c.current,...v??{}})).then(()=>{var y;u.current&&(d(T=>({...T,[j]:{phase:"succeeded",message:"Asked the agent."}})),(y=h.current)==null||y.call(h))}).catch(y=>{console.error("agent-ui actions: asking the agent failed",{ns:e,name:t,action:j,err:y}),u.current&&d(T=>({...T,[j]:{phase:"failed",message:"Could not reach the agent."}}))}).finally(()=>{w.current.delete(j)});return}fetch(`/agent-ui/${encodeURIComponent(e)}/${encodeURIComponent(t)}/actions`,{method:"POST",credentials:"same-origin",headers:{"Content-Type":"application/json"},body:JSON.stringify({action:j,params:c.current,inputs:v})}).then(async y=>{if(!y.ok)throw new Error(`agent-ui actions: request failed (${y.status})`);return await y.json()}).then(y=>{if(!u.current||(M.current[j]??0)>$)return;const T=y.state;d(U=>{var H;return{...U,[j]:{phase:T,requestId:y.requestId,message:y.message,approvalAddressedToViewer:(H=U[j])==null?void 0:H.approvalAddressedToViewer}}}),Ce(T)&&h.current()}).catch(y=>{console.error("agent-ui actions: invoke failed",{ns:e,name:t,action:j,err:y}),u.current&&d(T=>{var U;return{...T,[j]:{phase:"failed",message:Ta,approvalAddressedToViewer:(U=T[j])==null?void 0:U.approvalAddressedToViewer}}})}).finally(()=>{w.current.delete(j)})},[e,t]);return{states:l,invoke:D,liveError:f}}const Pa={approvals:[],trustEvents:[]},Oa=4e3;function Ma(e,t){if(e===t)return!0;if(e.approvals.length!==t.approvals.length||e.trustEvents.length!==t.trustEvents.length)return!1;for(let n=0;nLa(t,n),[t,n]),d=i.useMemo(()=>{const b=new Map;for(const[x,g]of In(e==null?void 0:e.view))g.state==="done"&&b.set(x,g.title??g.label);return b},[e==null?void 0:e.view]),f=i.useMemo(()=>({composed:new Set((e==null?void 0:e.agentComposed)??[]),updated:a,stale:l,waiting:r,answered:new Set((e==null?void 0:e.answered)??[]),collapsed:d}),[e==null?void 0:e.agentComposed,e==null?void 0:e.answered,a,l,r,d]),p=[],u=e!=null&&e.view?Ft(ca(e.view,t),void 0,b=>p.push(b)):null,c=p.length>0?p[0]:null;if(i.useEffect(()=>{c!==null&&o(c)},[c,o]),!(e!=null&&e.view))return s.jsx("div",{className:"p-4 text-sm text-muted-foreground",children:"This agent has not declared any content for this session."});const h=t[Bt];return s.jsx(vn,{value:f,children:s.jsxs("div",{"data-testid":"agent-ui-root",className:L("flex flex-col gap-2 p-4 mx-auto",xn(e==null?void 0:e.view)==="rail"?"max-w-6xl":"max-w-3xl"),"aria-busy":l.has("")||void 0,children:[(h==null?void 0:h.status)==="error"&&s.jsxs(W,{variant:"destructive",children:[s.jsx(Y,{children:"Data unavailable"}),s.jsx(J,{children:h.message})]}),s.jsxs("div",{className:L("relative",l.has("")&&"opacity-60 transition-opacity"),children:[u,l.has("")&&s.jsxs("div",{"data-testid":"agent-ui-region-refreshing",className:"pointer-events-none absolute right-2 top-2 flex items-center gap-1.5 text-[11px] text-muted-foreground",children:[s.jsx(ve,{className:"h-3.5 w-3.5 animate-spin","aria-hidden":"true"}),s.jsx("span",{children:"Updating…"})]})]})]})})}function Da(){const[e,t]=i.useState(()=>new Map),n=i.useRef(new Map),a=i.useCallback(r=>{t(l=>new Map(l).set(r,Date.now()));const o=n.current.get(r);o!==void 0&&clearTimeout(o),n.current.set(r,setTimeout(()=>{n.current.delete(r),t(l=>{if(!l.has(r))return l;const d=new Map(l);return d.delete(r),d})},Oa))},[]);return i.useEffect(()=>{const r=n.current;return()=>{for(const o of r.values())clearTimeout(o);r.clear()}},[]),{updatedHooks:e,markUpdated:a}}function Ua({ns:e,name:t,declaration:n,agentParams:a,shown:r,onChromeSignals:o,onSessionEnded:l}){var Ke,ze;const[d,f]=i.useState(null),p=i.useCallback(S=>{const E=`render-error:${S}`;f(I=>(I==null?void 0:I.id)===E?I:{kind:"hard_error",id:E})},[]),[u,c]=i.useState(n),h=Us(),{questionShowing:b,progressShowing:x,waiting:g}=i.useMemo(()=>{const S=En(u==null?void 0:u.view,"ap:question"),E=new Set((u==null?void 0:u.answered)??[]),I=new Set([...S].filter(V=>!E.has(V)));return{questionShowing:I.size>0||$n(u==null?void 0:u.view)||$e(u==null?void 0:u.view,"ap:notice"),progressShowing:$e(u==null?void 0:u.view,"ap:progress"),waiting:I}},[u==null?void 0:u.view,u==null?void 0:u.answered]),[w,C]=i.useState(0),[N,M]=i.useState(()=>{const E={...Dt(u),...a??{}};return typeof window>"u"?E:ye(u,{...E,...dt(window.location.search)})}),D=i.useRef(new Set(typeof window>"u"?[]:Object.keys(dt(window.location.search)))),j=i.useCallback((S,E)=>{D.current.add(S),M(I=>I[S]===E?I:{...I,[S]:E})},[]),v=i.useCallback((S,E)=>{M(I=>{const V={...I};let Q=!1;for(const[we,Ye]of Object.entries(ye(E,S)))D.current.has(we)||V[we]===Ye||(V[we]=Ye,Q=!0);return Q?V:I})},[]);i.useEffect(()=>{if(typeof window>"u")return;const S=da(window.location.search,N);S!==window.location.search&&window.history.replaceState(window.history.state,"",`${window.location.pathname}${S}${window.location.hash}`)},[N]);const $=i.useMemo(()=>({params:N,setParam:j}),[N,j]),k=i.useMemo(()=>({ns:e,name:t}),[e,t]),[y,T]=i.useState(0),U=i.useCallback(()=>{T(S=>S+1)},[]),{updatedHooks:H,markUpdated:ee}=Da(),G=i.useRef(JSON.stringify(n)),X=i.useCallback((S,E,I)=>{E&&Object.keys(E).length>0&&v(E,S),I&&ee(I);const V=JSON.stringify(S);V!==G.current&&(G.current=V,c(S),M(Q=>ye(S,Q)),T(Q=>Q+1))},[v,ee]),{states:O,invoke:A,liveError:K}=Ia(e,t,N,U,X,(u==null?void 0:u.actions)??[]),z=i.useCallback(S=>jt(e,t,S),[e,t]),se=i.useMemo(()=>({states:O,invoke:A,answer:z,busy:h.turnActive}),[O,A,z,h.turnActive]),{states:q,refreshing:te}=ya(e,t,N,y,l),ce=Object.entries(O).filter(([,S])=>S.phase==="awaiting_approval").map(([S,E])=>`${S}:${E.requestId??""}:${E.approvalAddressedToViewer?"1":"0"}`).sort().join("|"),{approvalNotices:ae,approvalTrustEvents:R}=i.useMemo(()=>{const S=[],E=[];for(const[I,V]of Object.entries(O)){if(V.phase!=="awaiting_approval")continue;const Q=V.requestId??I;S.push({id:Q,label:V.approvalAddressedToViewer?"Your approval is needed to continue.":"Waiting on approval from someone else.",addressedToViewer:!!V.approvalAddressedToViewer}),V.approvalAddressedToViewer&&E.push({kind:"approval_addressed_to_viewer",id:Q})}return{approvalNotices:S,approvalTrustEvents:E}},[ce]),_=i.useMemo(()=>({approvals:ae,trustEvents:[d,...R]}),[ae,R,d]);i.useEffect(()=>{o==null||o(_)},[_,o]);const F=((Ke=h.lastAgentReply)==null?void 0:Ke.seq)??0,Yt=r&&(h.awaitingReply||h.pausedIdle)&&h.lastAgentReply!==null&&F>w&&!b&&!h.ended,Jt=i.useCallback(async S=>{await z(S),C(F)},[z,F]),Gt=i.useCallback(()=>C(F),[F]),[He,be]=i.useState(null),We=qs(e,t,be),Xt=i.useCallback((S,E,I)=>{be(null),We(S,E,I)},[We]),[Qt,Zt]=i.useState({}),es=i.useCallback(S=>{if(S.type!=="interaction_decision_rejected")return;const E=S.payload.payload;h.pendingInteractions.some(I=>I.requestRef===E.requestRef)&&(be(Fs(E)),Zt(I=>({...I,[E.requestRef]:(I[E.requestRef]??0)+1})))},[h.pendingInteractions]);return yt(es),s.jsx(cn,{value:k,children:s.jsx(_n,{value:$,children:s.jsx(Gs,{value:se,children:s.jsxs("div",{className:"flex min-h-full flex-col",children:[!x&&s.jsx(ha,{signals:h}),K!==null&&s.jsx("div",{className:"px-4 pt-4 max-w-3xl mx-auto","data-testid":"agent-ui-live-error",children:s.jsxs(W,{variant:"destructive",children:[s.jsx(Y,{children:"Live updates unavailable"}),s.jsx(J,{children:K})]})}),r&&h.pendingInteractions.length>0&&s.jsxs("section",{"data-testid":"agent-ui-decisions","aria-label":"Needs your decision",className:"flex flex-col gap-2 border-b border-border bg-card/60 px-3 py-2",children:[s.jsx("p",{className:"text-xs font-medium text-muted-foreground",children:"Needs your decision"}),h.pendingInteractions.map(S=>s.jsx(Vs,{request:S,onDecision:Xt},`${S.requestRef}:${Qt[S.requestRef]??0}`)),He&&s.jsx("p",{role:"alert",className:"text-xs text-destructive",children:He})]}),s.jsx(_a,{declaration:u,states:q,refreshing:te,updatedHooks:H,waiting:g,onRenderError:p}),s.jsx(ua,{open:Yt,variant:h.awaitingReply?"asked":"paused",text:((ze=h.lastAgentReply)==null?void 0:ze.text)??"",replySeq:F,onReply:Jt,onDismiss:Gt})]})})})})}function qa(e,t){switch(e){case"attached":return{text:"Resumed your session.",Icon:Qe};case"asleep":return{text:"Your session is asleep; it resumes when you send a message.",Icon:Ps};case"ended":return{text:t?`This session has ended: ${t}`:"This session has ended. You can start a new one.",Icon:Is};default:return{text:"Connected to your session.",Icon:Qe}}}function Ht(e){return e==="collapsed"}function mt(e,t,n,a){a&&(e.defaultPrevented||e.button!==0||e.metaKey||e.ctrlKey||e.shiftKey||e.altKey||(e.preventDefault(),a(t,n)))}function ht(e,t,n,a){e.currentTarget.href=re(t,n,a)}function xt(e){const t="inline-flex items-center gap-1.5 rounded px-2.5 py-1 text-[12px] font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring";return e?`${t} bg-secondary text-secondary-foreground`:`${t} text-muted-foreground hover:bg-accent/50 hover:text-foreground`}function re(e,t,n){const a=new URLSearchParams(typeof window>"u"?"":window.location.search);return a.delete("new"),a.delete("ns"),a.delete("agentClass"),a.delete("prompt"),a.set("session",`${e}/${t}`),a.set("view",n),`/sessions?${a.toString()}`}function Fa(e){return{collapsed:Ht(e),userToggled:!1,trustRevealed:!1}}function Va(e,t){switch(t.type){case"ui_requested":return e.userToggled||e.trustRevealed||e.collapsed===t.collapsed?e:{...e,collapsed:t.collapsed};case"user_toggled":return{collapsed:!e.collapsed,userToggled:!0,trustRevealed:!1};case"trust_event":return{...e,collapsed:!1,trustRevealed:!0}}}function Ba({ns:e,name:t,subject:n,sessionOrigin:a,endedReason:r,currentView:o,offersAgentUI:l,onSelectView:d,initialState:f,trustEvents:p,approvals:u,headerActions:c,sidebar:h,children:b}){const x=e!==void 0&&t!==void 0?{ns:e,name:t}:null,g=qa(a??"",r),[w,C]=i.useReducer(Va,f,Fa),N=w.collapsed;i.useEffect(()=>{C({type:"ui_requested",collapsed:Ht(f)})},[f]);const M=i.useRef(new Set),D=(p??[]).flatMap(v=>v?[v.id]:[]);i.useEffect(()=>{const v=D.filter($=>!M.current.has($));if(v.length!==0){for(const $ of v)M.current.add($);C({type:"trust_event"})}},[D.join("|")]);function j(){C({type:"user_toggled"})}return s.jsxs("div",{className:"h-screen flex flex-col bg-background text-foreground",children:[s.jsxs("header",{className:"flex items-center gap-2.5 px-3 py-2 min-h-[52px] bg-card border-b border-border",children:[s.jsx(B,{type:"button",variant:"ghost",size:"icon","aria-expanded":!N,"aria-label":N?"Show chrome":"Hide chrome","data-testid":"session-shell-chrome-toggle",onClick:j,children:N?s.jsx(Cs,{className:"h-4 w-4","aria-hidden":"true"}):s.jsx(Rs,{className:"h-4 w-4","aria-hidden":"true"})}),x&&s.jsxs("div",{className:"flex items-center gap-2 min-w-0",hidden:N,children:[s.jsx(g.Icon,{className:"h-3.5 w-3.5 text-muted-foreground shrink-0","aria-hidden":"true"}),s.jsx("span",{className:"text-[13px] text-muted-foreground truncate",title:g.text,"data-testid":"session-shell-session-origin",children:g.text})]}),s.jsxs("div",{className:"ml-auto flex items-center gap-2 shrink-0",children:[c&&s.jsx("div",{className:"flex items-center gap-1","data-testid":"session-shell-header-actions",hidden:N,children:c}),s.jsxs("div",{className:"flex items-center gap-2 min-w-0",hidden:N,children:[s.jsx(Ts,{className:"h-4 w-4 text-muted-foreground shrink-0","aria-hidden":"true"}),s.jsxs("span",{className:"text-[13px] font-medium truncate","data-testid":"session-shell-identity",children:["Acting as ",n]})]})]})]}),s.jsxs("div",{className:"flex items-center gap-2 px-3 py-1 min-h-[36px] border-b border-border bg-card/60 text-[12px] text-muted-foreground","data-testid":"session-shell-approval-surface",hidden:N,children:[u&&u.length>0&&s.jsxs(s.Fragment,{children:[s.jsx(As,{className:"h-3.5 w-3.5 shrink-0","aria-hidden":"true"}),s.jsx("ul",{className:"flex flex-col gap-0.5",children:u.map(v=>s.jsx("li",{children:v.label},v.id))})]}),x&&s.jsxs("div",{className:"ml-auto flex items-center gap-0.5 rounded-md border border-border bg-background/60 p-0.5 shrink-0","data-testid":"session-shell-view-tabs",children:[l&&s.jsxs("a",{href:re(x.ns,x.name,"ui"),"aria-current":o==="ui"?"page":void 0,"data-testid":"session-shell-agent-view-switch",className:xt(o==="ui"),onMouseDown:v=>ht(v,x.ns,x.name,"ui"),onClick:v=>mt(v,"ui",re(x.ns,x.name,"ui"),d),children:[s.jsx(Es,{className:"h-3.5 w-3.5","aria-hidden":"true"}),"Agent view"]}),s.jsxs("a",{href:re(x.ns,x.name,"chat"),"aria-current":o==="chat"?"page":void 0,"data-testid":"session-shell-chat-escape-hatch",className:xt(o==="chat"),onMouseDown:v=>ht(v,x.ns,x.name,"chat"),onClick:v=>mt(v,"chat",re(x.ns,x.name,"chat"),d),children:[s.jsx($s,{className:"h-3.5 w-3.5","aria-hidden":"true"}),"Chat"]})]})]}),s.jsxs("div",{className:"flex-1 min-h-0 flex",children:[s.jsx("aside",{className:h?"w-64 shrink-0 min-h-0 overflow-y-auto border-r border-border bg-card/40":"w-0 shrink-0 min-h-0 overflow-hidden","data-testid":"session-shell-sidebar",hidden:N,children:h}),s.jsx("main",{className:"flex min-h-0 flex-1 flex-col overflow-y-auto","data-testid":"session-shell-content-region",children:b})]})]})}function Ha(e){const t=e;if(!t||typeof t.ns!="string"||typeof t.name!="string"||typeof t.href!="string"||!t.href)throw new Error("the server's answer did not address a session");return{ns:t.ns,name:t.name,href:t.href}}class fe extends Error{constructor(t,n){super(t),this.name="StartError",this.indeterminate=n}}async function Wt(e,t){let n;try{n=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)})}catch(a){throw console.error("sessions: start request did not complete",{url:e,err:a}),new fe("We could not confirm whether that session started. Reload your sessions before trying again.",!0)}if(!n.ok){let a="";try{const r=await n.json();a=typeof(r==null?void 0:r.error)=="string"?r.error:""}catch{a=""}throw console.error("sessions: start request failed",{url:e,status:n.status}),new fe(a||"That session could not be started right now.",!1)}try{return Ha(await n.json())}catch{throw console.error("sessions: start succeeded but its answer could not be addressed",{url:e}),new fe("That session started, but we could not open it. Reload your sessions to find it.",!0)}}function Kt(e){return!(e instanceof fe)||e.indeterminate}const Wa="This server cannot start new sessions for that agent. You can still open the sessions you already have with it, or ask an administrator to enable starting here.",Ka=" — cannot start here";function za(e){const t=new Map;for(const n of e)t.set(n.title,(t.get(n.title)??0)+1);return e.map(n=>{const a=(t.get(n.title)??0)>1?`${n.title} (in ${n.ns})`:n.title;return n.startable?a:a+Ka})}function zt(e){window.location.assign(e)}function Ya(){return s.jsx("p",{className:"text-sm text-muted-foreground","data-testid":"session-shell-no-startable-classes",children:"You do not have access to any agents yet. Access arrives by being added to a session someone else started, or through a channel an agent is connected to."})}function Ja({classes:e,onNavigate:t=zt,openInitially:n=!1,preselect:a,initialPrompt:r}){const[o,l]=i.useState(n),d=a?e.findIndex(k=>k.ns===a.ns&&k.class===a.agentClass):-1,[f,p]=i.useState(!1),u=a!==void 0&&d===-1&&!f,[c,h]=i.useState(d===-1?0:d),[b,x]=i.useState(r??""),[g,w]=i.useState(!1),[C,N]=i.useState(null);if(e.length===0)return null;const M=e[Math.min(c,e.length-1)],D=za(e),j=!M.startable,v=M.offersUI===!0;async function $(){w(!0),N(null);try{const k=await Wt("/sessions/api/start",{ns:M.ns,agentClass:M.class,prompt:b});t(v?`${k.href}&view=ui`:k.href)}catch(k){N(k.message),Kt(k)||w(!1)}}return s.jsxs(s.Fragment,{children:[s.jsx(B,{type:"button",size:"sm","data-testid":"session-shell-new-session",onClick:()=>{N(null),l(!0)},children:"+ New session"}),s.jsx(Oe,{open:o,onOpenChange:l,children:s.jsxs(Me,{children:[s.jsxs(Le,{children:[s.jsx(pe,{children:"Start a new session"}),s.jsx(me,{children:v?"Pick an agent. This one opens its own view.":"Pick an agent and say what you need."})]}),s.jsxs("div",{className:"flex flex-col gap-3",children:[u&&s.jsx("p",{className:"text-sm text-destructive","data-testid":"session-shell-preselect-refused",children:"You can't start that agent from here."}),s.jsxs("div",{className:"flex flex-col gap-1",children:[s.jsx(oe,{htmlFor:"new-session-class",children:"Agent"}),s.jsx("select",{id:"new-session-class",className:"rounded-md border border-input bg-background px-3 py-2 text-sm","data-testid":"session-shell-new-session-class",value:c,onChange:k=>{h(Number(k.target.value)),p(!0)},children:e.map((k,y)=>s.jsx("option",{value:y,children:D[y]},`${k.ns}/${k.class}`))})]}),v?s.jsxs("details",{className:"flex flex-col gap-1","data-testid":"session-shell-new-session-prompt-disclosure",children:[s.jsx("summary",{className:"cursor-pointer text-sm text-muted-foreground",children:"Add a message (optional — otherwise the agent is just told you opened the view)"}),s.jsx("textarea",{id:"new-session-prompt",rows:3,"aria-label":"Message",className:"mt-1 w-full rounded-md border border-input bg-background px-3 py-2 text-sm","data-testid":"session-shell-new-session-prompt",value:b,onChange:k=>x(k.target.value)})]}):s.jsxs("div",{className:"flex flex-col gap-1",children:[s.jsx(oe,{htmlFor:"new-session-prompt",children:"Message"}),s.jsx("textarea",{id:"new-session-prompt",rows:4,className:"rounded-md border border-input bg-background px-3 py-2 text-sm","data-testid":"session-shell-new-session-prompt",value:b,onChange:k=>x(k.target.value)})]}),j&&s.jsx("p",{className:"text-sm text-muted-foreground","data-testid":"session-shell-new-session-unstartable",children:Wa}),C&&s.jsx("p",{className:"text-sm text-destructive","data-testid":"session-shell-new-session-error",children:C}),s.jsx("div",{className:"flex justify-end",children:s.jsx(B,{type:"button","data-testid":"session-shell-new-session-submit",disabled:g||j||u||!v&&b.trim()==="",onClick:()=>void $(),children:g?v?"Opening…":"Starting…":v?"Open UI":"Start session"})})]})]})})]})}function Ga({ns:e,name:t,onNavigate:n=zt}){const[a,r]=i.useState(!1),[o,l]=i.useState(null);async function d(){r(!0),l(null);try{const f=await Wt(`/agent-ui/${encodeURIComponent(e)}/${encodeURIComponent(t)}/start`,{prompt:"Continue where we left off."});n(f.href)}catch(f){l(f.message),Kt(f)||r(!1)}}return s.jsxs("div",{className:"flex items-center gap-2",children:[s.jsx(B,{type:"button",size:"sm",variant:"outline","data-testid":"session-shell-start-replacement",disabled:a,onClick:()=>void d(),children:a?"Starting…":"Start a new session"}),o&&s.jsx("span",{className:"text-sm text-destructive","data-testid":"session-shell-start-replacement-error",children:o})]})}async function Xa(e,t){const n=await fetch(`/sessions/api/${encodeURIComponent(e)}/${encodeURIComponent(t)}/detail`);if(!n.ok)throw console.error("sessions: load session detail failed",{ns:e,name:t,status:n.status}),new Error(n.status===403?"you do not have access to this session":n.status===401?"you are no longer signed in":"these settings could not be loaded right now");return await n.json()}function Z({label:e,value:t,children:n}){return s.jsxs("div",{className:"flex items-start justify-between gap-4 py-1.5 text-sm",children:[s.jsx("span",{className:"shrink-0 text-muted-foreground",children:e}),s.jsx("span",{className:"break-all text-right font-mono text-[13px]",children:n??t})]})}function Qa({ns:e,name:t,open:n,onOpenChange:a}){const[r,o]=i.useState(null),[l,d]=i.useState(null);return i.useEffect(()=>{if(!n)return;let f=!1;return o(null),d(null),Xa(e,t).then(p=>{f||o(p)}).catch(p=>{f||d(p.message||"these settings could not be loaded right now")}),()=>{f=!0}},[n,e,t]),s.jsx(Oe,{open:n,onOpenChange:a,children:s.jsxs(Me,{children:[s.jsxs(Le,{children:[s.jsx(pe,{children:"Session details"}),s.jsx(me,{children:"Resolved settings for this conversation."})]}),l?s.jsxs("div",{className:"text-sm text-destructive","data-testid":"session-shell-session-info-error",children:["Couldn't load details: ",l]}):r?s.jsxs("div",{className:"divide-y divide-border",children:[s.jsx(Z,{label:"Agent class",value:r.agentClass}),s.jsx(Z,{label:"Model",children:r.model.name?s.jsx(Ks,{model:`${r.model.provider||"?"}/${r.model.name}`}):"not resolved"}),s.jsx(Z,{label:"Max tokens",value:r.maxTokens?String(r.maxTokens):"—"}),s.jsx(Z,{label:"Max turns",value:r.maxTurns?String(r.maxTurns):"—"}),s.jsx(Z,{label:"Max duration",value:r.maxDuration||"—"}),s.jsx(Z,{label:"Owner",value:r.owner}),s.jsx(Z,{label:"Phase",value:r.phase||"—"}),s.jsx(Z,{label:"Created",value:new Date(r.createdAt).toLocaleString()})]}):s.jsx("div",{className:"text-sm text-muted-foreground",children:"Loading…"})]})})}function Za(e,t=Date.now()){if(!e)return"";const n=Date.parse(e);if(Number.isNaN(n))return"";const a=Math.max(0,Math.floor((t-n)/1e3));if(a<60)return"just now";const r=Math.floor(a/60);if(r<60)return`${r}m`;const o=Math.floor(r/60);return o<24?`${o}h`:`${Math.floor(o/24)}d`}function er(e,t){return`/sessions?session=${encodeURIComponent(`${e}/${t}`)}`}function tr(e){const t=[];return e&&(e.unavailable>0&&t.push(e.unavailable===1?"1 session could not be loaded and is not shown.":`${e.unavailable} sessions could not be loaded and are not shown.`),e.truncated&&t.push("Showing your most recent sessions only."),e.bootstrapUnavailable&&t.push("Some agents may be missing from New chat. Try again in a moment.")),t}function sr(e){const t=e.lastIndexOf("-");return t>0&&tc.ns===n&&c.name===a,f=e.filter(c=>c.ended&&!d(c)).length,p=o?e:e.filter(c=>!c.ended||d(c)),u=new Map;for(const c of p)u.set(c.title,(u.get(c.title)??0)+1);return s.jsxs("nav",{className:"flex flex-col","aria-label":"Your sessions","data-testid":"session-shell-session-list",children:[r.length>0&&s.jsx("div",{className:"px-3 py-2 text-[11px] text-muted-foreground border-b border-border","data-testid":"session-shell-list-notices",children:r.map(c=>s.jsx("div",{children:c},c))}),e.length===0?s.jsx("div",{className:"px-3 py-4 text-[12px] text-muted-foreground","data-testid":"session-shell-empty-list",children:"You have no sessions yet."}):p.length===0?s.jsx("div",{className:"px-3 py-4 text-[12px] text-muted-foreground","data-testid":"session-shell-empty-list",children:"No active sessions."}):s.jsx("ul",{className:"flex flex-col",children:p.map(c=>{const h=d(c),b=(u.get(c.title)??0)>1,x=c.startedAt?Za(c.startedAt):"";return s.jsx("li",{children:s.jsxs("a",{href:er(c.ns,c.name),"aria-current":h?"page":void 0,"data-testid":`session-shell-session-row-${c.ns}/${c.name}`,className:`flex flex-col gap-0.5 px-3 py-2 border-b border-border hover:bg-surface-2 ${h?"bg-surface-active shadow-[inset_3px_0_0_hsl(var(--state))]":""}`,children:[s.jsxs("span",{className:"flex items-baseline gap-1.5 min-w-0",children:[s.jsx("span",{className:"text-[13px] font-medium truncate",children:c.title}),b&&s.jsx("span",{className:"shrink-0 font-mono text-[10px] text-muted-foreground","data-testid":`session-shell-session-row-tag-${c.ns}/${c.name}`,children:sr(c.name)})]}),s.jsxs("span",{className:"flex items-center gap-1.5 text-[11px] text-muted-foreground",children:[c.awaitingHuman?s.jsx(Os,{className:"h-3 w-3 shrink-0","aria-hidden":"true"}):c.ended?s.jsx(Ms,{className:"h-3 w-3 shrink-0","aria-hidden":"true"}):s.jsx(Ls,{className:"h-3 w-3 shrink-0","aria-hidden":"true"}),s.jsx("span",{className:"truncate","data-testid":`session-shell-session-row-phase-${c.ns}/${c.name}`,children:c.phase}),x&&s.jsxs(s.Fragment,{children:[s.jsx("span",{"aria-hidden":"true",children:"·"}),s.jsx("span",{className:"shrink-0","data-testid":`session-shell-session-row-age-${c.ns}/${c.name}`,children:x})]})]})]})},`${c.ns}/${c.name}`)})}),f>0||o&&e.some(c=>c.ended)?s.jsx("button",{type:"button",onClick:()=>l(c=>!c),"aria-expanded":o,className:"px-3 py-2 text-left text-[11px] text-muted-foreground hover:text-foreground hover:bg-surface-2","data-testid":"session-shell-toggle-ended",children:o?"Hide ended sessions":`Show ${f} ended session${f===1?"":"s"}`}):null]})}function ar(e,t){const n="oap sessions",a=e?`${e} · ${n}`:n;return t>0?`(${t}) ${a}`:a}function gt(){return typeof window<"u"&&"Notification"in window}function rr(e){const[t,n]=i.useState(0);i.useEffect(()=>{e&&n(0)},[e]);const a=i.useRef(!1),r=i.useCallback(()=>{a.current||!gt()||(a.current=!0,Notification.permission==="default"&&Notification.requestPermission())},[]),o=i.useCallback((l,d)=>{if(!e&&(n(f=>f+1),!(!gt()||Notification.permission!=="granted")))try{const f=new Notification(l,{body:d});f.onclick=()=>{window.focus(),f.close()}}catch{}},[e]);return{unread:t,notify:o,requestPermission:r}}function vt(){if(typeof document>"u")return!0;const e=document.visibilityState==="visible",t=typeof document.hasFocus=="function"?document.hasFocus():!0;return e&&t}function or(){const[e,t]=i.useState(vt);return i.useEffect(()=>{const n=()=>t(vt());return document.addEventListener("visibilitychange",n),window.addEventListener("focus",n),window.addEventListener("blur",n),()=>{document.removeEventListener("visibilitychange",n),window.removeEventListener("focus",n),window.removeEventListener("blur",n)}},[]),e}const ir=3e4;function lr(e,t){const n=[];for(const a of e)a.awaitingHuman&&(t&&a.ns===t.ns&&a.name===t.name||n.push({id:`session:${a.ns}/${a.name}`,label:`${a.title} is waiting on a person in another session.`,addressedToViewer:!1}));return n}function cr({selected:e,shown:t,ended:n,onChromeSignals:a,onUserSend:r,onAgentReply:o,onAwaitingDecision:l,onSessionEnded:d,uiEverShownRef:f}){const p=e.view.notice?s.jsx("div",{className:"p-4 max-w-3xl mx-auto","data-testid":"session-shell-view-notice",children:s.jsxs(W,{children:[s.jsx(Y,{children:e.view.notice.title}),s.jsx(J,{children:e.view.notice.message})]})}):null;t==="ui"&&(f.current=!0);const u=e.view.ui,c=u&&f.current?s.jsxs("div",{className:t==="ui"?"h-full":"hidden","data-testid":"session-shell-ui-region",children:[t==="ui"&&p,s.jsx(Ua,{ns:u.ns,name:u.name,declaration:u.declaration,agentParams:u.agentParams,shown:t==="ui",onChromeSignals:a,onSessionEnded:d})]}):null;function h(){var x,g;switch(t){case"ui":return u?null:s.jsxs(s.Fragment,{children:[p,!e.view.unavailable&&Re("agent view shown but no ui or unavailable payload",e),s.jsx(Te,{title:((x=e.view.unavailable)==null?void 0:x.title)??"View unavailable",message:((g=e.view.unavailable)==null?void 0:g.message)??"This agent's view could not be loaded."})]});case"chat":return e.view.chat?s.jsxs(s.Fragment,{children:[p,n&&s.jsx("div",{className:"p-4 max-w-3xl mx-auto","data-testid":"session-shell-replacement-region",children:s.jsx(Ga,{ns:e.view.chat.ns,name:e.view.chat.name})}),s.jsx(Ws,{ns:e.view.chat.ns,name:e.view.chat.name,readOnly:n,onUserSend:r,onSessionEnded:d})]}):s.jsxs(s.Fragment,{children:[p,Re("kind is chat but the view payload is absent",e),s.jsx(Te,{title:"View unavailable",message:"This conversation could not be opened."})]});default:return s.jsxs(s.Fragment,{children:[p,Re("unrecognized shown view",e),s.jsx(Te,{title:"View unavailable",message:"This view could not be shown."})]})}}const b=e.view.chat??{ns:e.ns,name:e.name};return s.jsxs(Bs,{ns:b.ns,name:b.name,children:[s.jsx(dr,{onAgentReply:o,onAwaitingDecision:l,onSessionEnded:d}),s.jsx(Hs,{}),c,h()]},`${b.ns}/${b.name}`)}function dr({onAgentReply:e,onAwaitingDecision:t,onSessionEnded:n}){const a=i.useRef(new Set);return yt(r=>{if(r.type==="user_message"){e(r.payload.text);return}if(r.type==="interaction_request"){const o=r.payload.payload;if(a.current.has(o.requestRef))return;a.current.add(o.requestRef),t(o.lead);return}r.type==="session_ended"&&n()}),null}function Re(e,t){return console.error("sessions: cannot render the selected view",{reason:e,ns:t.ns,name:t.name,kind:t.view.kind}),null}function Te({title:e,message:t}){return s.jsx("div",{className:"p-4 max-w-3xl mx-auto","data-testid":"session-shell-view-unavailable",children:s.jsxs(W,{variant:"destructive",children:[s.jsx(Y,{children:e}),s.jsx(J,{children:t})]})})}function ur(e){var q,te,ce,ae;const{selected:t}=e,[n,a]=i.useState(e.sessions??[]),[r,o]=i.useState(e.notices),[l,d]=i.useState(Pa),[f,p]=i.useState(!1),[u,c]=i.useState(!1),h=or(),{unread:b,notify:x,requestPermission:g}=rr(h),w=i.useCallback(R=>{d(_=>Ma(_,R)?_:R)},[]),C=i.useRef(null);C.current===null&&(C.current=new AbortController);const N=i.useCallback(async R=>{try{const _=await fetch("/sessions/api/sessions",{signal:R});if(!_.ok){console.error("sessions: session-list refresh failed",{status:_.status});return}const F=await _.json();if(R.aborted)return;if(!Array.isArray(F==null?void 0:F.sessions)){console.error("sessions: session-list refresh returned an unexpected body; keeping the current list");return}a(F.sessions),o(F.notices)}catch(_){if(R.aborted)return;console.error("sessions: session-list refresh errored",_)}},[]);i.useEffect(()=>{const R=C.current,_=setInterval(()=>void N(R.signal),ir);return()=>{R.abort(),clearInterval(_)}},[N]);const M=i.useRef(!1),D=i.useCallback(()=>{M.current||(M.current=!0,c(!0),N(C.current.signal))},[N]),j=i.useMemo(()=>[...lr(n,t),...l.approvals],[n,t,l.approvals]),v=i.useMemo(()=>{var R;return(R=n.find(_=>t&&_.ns===t.ns&&_.name===t.name))==null?void 0:R.title},[n,t]),$=i.useRef("oap sessions");$.current=v||"oap sessions",i.useEffect(()=>{document.title=ar(v??null,b)},[v,b]);const k=i.useCallback(R=>{x($.current,R)},[x]),y=i.useCallback(R=>{x(`${$.current} needs your decision`,R)},[x]),T=t?u?"ended":t.sessionOrigin:void 0,U=T==="ended",H=e.canStartSessions&&(((q=e.startableClasses)==null?void 0:q.length)??0)>0,[ee,G]=i.useState(()=>{var R;return((R=e.selected)==null?void 0:R.view.kind)==="chat"?"chat":"ui"}),X=e.selected?`${e.selected.ns}/${e.selected.name}`:"",O=i.useRef(X),A=i.useRef(!1);i.useEffect(()=>{var R;O.current!==X&&(O.current=X,A.current=!1,G(((R=e.selected)==null?void 0:R.view.kind)==="chat"?"chat":"ui"))},[X,(te=e.selected)==null?void 0:te.view.kind]);const K=i.useCallback((R,_)=>{G(R),typeof window<"u"&&window.history.pushState(window.history.state,"",_)},[]);i.useEffect(()=>{if(typeof window>"u")return;const R=()=>{const _=new URLSearchParams(window.location.search).get("view");G(_==="chat"?"chat":"ui")};return window.addEventListener("popstate",R),()=>window.removeEventListener("popstate",R)},[]);const z=i.useMemo(()=>{if(typeof window>"u")return{open:!1};const R=new URLSearchParams(window.location.search),_=R.get("ns")??"",F=R.get("agentClass")??"";return{open:R.get("new")==="1",preselect:_&&F?{ns:_,agentClass:F}:void 0,initialPrompt:R.get("prompt")??void 0}},[]),se=t?{ns:t.ns,name:t.name,sessionOrigin:T??t.sessionOrigin,currentView:ee,onSelectView:K,endedReason:U?t.endedReason:void 0,offersAgentUI:t.offersAgentUI&&!U}:{};return s.jsx(Ba,{...se,subject:e.subject,initialState:(ce=t==null?void 0:t.chrome)==null?void 0:ce.initialState,approvals:j,trustEvents:l.trustEvents,headerActions:H||t?s.jsxs(s.Fragment,{children:[H&&s.jsx(Ja,{classes:e.startableClasses,openInitially:z.open,preselect:z.preselect,initialPrompt:z.initialPrompt}),t&&s.jsxs(s.Fragment,{children:[s.jsx(B,{type:"button",variant:"ghost",size:"icon","aria-label":"Session details","data-testid":"session-shell-session-info",onClick:()=>p(!0),children:s.jsx(_s,{className:"h-4 w-4","aria-hidden":"true"})}),s.jsx(Qa,{ns:t.ns,name:t.name,open:f,onOpenChange:p})]})]}):void 0,sidebar:s.jsx(nr,{sessions:n,notices:r,selectedNs:t==null?void 0:t.ns,selectedName:t==null?void 0:t.name}),children:t?s.jsx(cr,{selected:t,shown:ee,ended:U,onChromeSignals:w,onUserSend:g,onAgentReply:k,onAwaitingDecision:y,onSessionEnded:D,uiEverShownRef:A}):s.jsxs("div",{className:"p-6 flex flex-col gap-3","data-testid":"session-shell-no-selection",children:[s.jsx("span",{className:"text-sm text-muted-foreground",children:"Pick a session to open it."}),(((ae=e.startableClasses)==null?void 0:ae.length)??0)===0&&s.jsx(Ya,{})]})})}ds();us(ur); diff --git a/pkg/web/webui/webassets/dist/settings.Bs9xT9hr.js b/pkg/web/webui/webassets/dist/settings.D2ZpUumf.js similarity index 99% rename from pkg/web/webui/webassets/dist/settings.Bs9xT9hr.js rename to pkg/web/webui/webassets/dist/settings.D2ZpUumf.js index f0a6a4ef..7b0d8f94 100644 --- a/pkg/web/webui/webassets/dist/settings.Bs9xT9hr.js +++ b/pkg/web/webui/webassets/dist/settings.D2ZpUumf.js @@ -1,3 +1,3 @@ -import{A as b,a as N,M as v,N as V,B as $,O as se,P as le,Q as ae,R as ne,U as J,j as he,k as ge,l as K,n as _,o as pe,p as I,D as Ge,t as Ue,u as Ke,v as Je,x as Ye,T as ye,g as we,h as Te,i as H,m as qe}from"./mount.BOEH1oNx.js";import{r,j as e}from"./vendor.C5MRNvUt.js";import{B as Ce}from"./badge.CIlGQKPh.js";class ie extends Error{constructor(s,l){super(s),this.status=l}}async function ce(t){if(!t.ok){const s=await t.text();let l=s.trim()||`request failed (${t.status})`;try{const i=JSON.parse(s);i.error&&(l=i.error)}catch{}throw new ie(l,t.status)}return await t.json()}async function ve(t){const s=await fetch(t,{method:"POST"});if(!s.ok){await ce(s);return}}const ue=async t=>ce(await fetch(t)),He=async(t,s)=>ce(await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)})),Ee=async(t,s)=>ce(await fetch(t,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)})),We=t=>ue(`${t}/state`),te=t=>ue(`${t}/config`),Ae=(t,s)=>Ee(`${t}/config`,s),Pe=t=>ue(`${t}/cluster/settings`),De=(t,s)=>He(`${t}/cluster/settings/validate`,s),Me=(t,s)=>Ee(`${t}/cluster/settings`,s),Qe=t=>ue(`${t}/cluster/install-info`);function Fe(t){if(!(t instanceof ie))return null;try{const s=JSON.parse(t.message);if(Array.isArray(s.errors))return s}catch{}return null}function Oe(t){if(!(t instanceof ie))return null;try{const s=JSON.parse(t.message);if(s.validation&&Array.isArray(s.validation.errors))return s}catch{}return null}const Xe=t=>ve(`${t}/kubectl/use`),Ze=t=>ve(`${t}/reveal/config`),Be=t=>ve(`${t}/reveal/logs`);function et(t){const[s,l]=r.useState(null),[i,o]=r.useState(null);return r.useEffect(()=>{let a=!1;We(t).then(u=>{a||(l(u),o(null))}).catch(u=>{a||o(u.message)});const n=new EventSource(`${t}/events`);return n.onmessage=u=>{if(!a)try{l(JSON.parse(u.data)),o(null)}catch{}},n.onerror=()=>{a||o("settings: live update stream stalled")},()=>{a=!0,n.close()}},[t]),{state:s,error:i}}const tt={applied:"Applied","next-start":"Applies at next start",failed:"Failed"},st={applied:"✓","next-start":"⏱",failed:"✕"},lt={model:"Model",password:"Password",ngrok:"ngrok",healthNotifications:"Health notifications"};function Le({outcomes:t}){return t.length===0?null:e.jsx("ul",{"aria-label":"Save results",className:"flex flex-col gap-1 text-sm",children:t.map(s=>e.jsxs("li",{className:"flex items-start gap-2",children:[e.jsx("span",{"aria-hidden":"true",children:st[s.outcome]??"•"}),e.jsxs("span",{children:[e.jsxs("span",{className:"font-medium",children:[lt[s.field]??s.field,":"]})," ",tt[s.outcome]??s.outcome,s.message&&e.jsxs("span",{className:"text-muted-foreground",children:[" — ",s.message]})]})]},s.field))})}const xe=8;function at({apiBase:t,running:s,kubectlCurrent:l}){const[i,o]=r.useState(null),[a,n]=r.useState(null),[u,g]=r.useState(!0),[c,x]=r.useState(""),[w,T]=r.useState(""),[h,P]=r.useState(""),[R,D]=r.useState(null),[d,f]=r.useState(!1),[S,E]=r.useState([]),[y,A]=r.useState(!1),[m,O]=r.useState(null),[Y,U]=r.useState(null);r.useEffect(()=>{let p=!1;return te(t).then(k=>{p||(o(k),g(k.healthNotifications))}).catch(k=>{p||n(k.message)}),()=>{p=!0}},[t]);async function q(){D(null),E([]);const p=w!==""||h!=="";if(p){if(w.lengthg(p.target.checked),className:"h-4 w-4 rounded border-border"}),e.jsx(v,{htmlFor:"general-health-notifications",children:"Notify on cluster health issues"})]})}),e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsx("h3",{className:"text-sm font-medium",children:"Admin password"}),e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(v,{htmlFor:"general-current-password",children:"Current password"}),e.jsx(V,{id:"general-current-password",type:"password",value:c,onChange:p=>x(p.target.value)})]}),e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(v,{htmlFor:"general-new-password",children:"New password"}),e.jsx(V,{id:"general-new-password",type:"password",value:w,onChange:p=>T(p.target.value)}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Must be at least ",xe," characters."]})]}),e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(v,{htmlFor:"general-confirm-password",children:"Confirm new password"}),e.jsx(V,{id:"general-confirm-password",type:"password",value:h,onChange:p=>P(p.target.value)})]})]}),R&&e.jsx(b,{variant:"destructive",children:e.jsx(N,{children:R})}),e.jsx(Le,{outcomes:S}),e.jsx("div",{children:e.jsx($,{onClick:()=>void q(),disabled:d||!i,children:d?"Saving…":"Save general settings"})}),e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsx("h3",{className:"text-sm font-medium",children:"kubectl"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:l?"kubectl is pointing at this cluster.":"kubectl is not pointing at this cluster."}),e.jsxs("div",{children:[e.jsx($,{variant:"outline",onClick:()=>void G(),disabled:!s||y,title:s?void 0:"Start the cluster first.",children:y?"Switching…":"Point kubectl at this cluster"}),!s&&e.jsx("p",{className:"text-xs text-muted-foreground",children:"Start the cluster first."})]}),m&&e.jsx(b,{variant:"destructive",children:e.jsx(N,{children:m})})]}),e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsx("h3",{className:"text-sm font-medium",children:"Diagnostics"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx($,{variant:"outline",onClick:()=>void Q(Ze),children:"Reveal config file"}),e.jsx($,{variant:"outline",onClick:()=>void Q(Be),children:"View logs"})]}),Y&&e.jsx(b,{variant:"destructive",children:e.jsx(N,{children:Y})})]})]})}function nt({apiBase:t,running:s}){const[l,i]=r.useState(null),[o,a]=r.useState(null),[n,u]=r.useState(""),[g,c]=r.useState(""),[x,w]=r.useState(""),[T,h]=r.useState(""),[P,R]=r.useState(!1),[D,d]=r.useState(null),[f,S]=r.useState(!1),[E,y]=r.useState([]);r.useEffect(()=>{let m=!1;return te(t).then(O=>{m||(i(O),u(O.model.provider),w(O.model.name))}).catch(O=>{m||a(O.message)}),()=>{m=!0}},[t]);async function A(){d(null),y([]),S(!0);try{const m=await te(t),O=await Ae(t,{model:{provider:n,apiKey:g,name:x},ngrokAuthToken:P?"":T,clearNgrok:P,healthNotifications:m.healthNotifications});y(O.outcomes),c(""),h(""),R(!1);const Y=await te(t);i(Y)}catch(m){d(m instanceof ie||m instanceof Error?m.message:String(m))}finally{S(!1)}}return e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsx("h2",{className:"text-base font-semibold",children:"Model settings"}),o&&e.jsx(b,{variant:"destructive",children:e.jsx(N,{children:o})}),l&&e.jsxs(e.Fragment,{children:[e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsx(v,{htmlFor:"model-provider",children:"Provider"}),e.jsxs(se,{value:n,onValueChange:u,children:[e.jsx(le,{id:"model-provider",children:e.jsx(ae,{})}),e.jsx(ne,{children:l.providers.map(m=>e.jsx(J,{value:m,children:m},m))})]})]}),e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsx(v,{htmlFor:"model-api-key",children:"API key"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:l.model.apiKeyMasked?l.model.apiKeyMasked:"Not set"}),e.jsx(V,{id:"model-api-key",type:"password",placeholder:"unchanged",value:g,onChange:m=>c(m.target.value)})]}),e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsx(v,{htmlFor:"model-name",children:"Model name"}),e.jsx(V,{id:"model-name",value:x,onChange:m=>w(m.target.value)}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Leave blank to use ",n||"the selected provider","'s recommended default model."]})]}),e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsx("h3",{className:"text-sm font-medium",children:"ngrok"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:l.ngrokConfigured?"Configured":"Not configured"}),e.jsx(v,{htmlFor:"model-ngrok-token",children:"ngrok auth token"}),e.jsx(V,{id:"model-ngrok-token",type:"password",placeholder:"unchanged",value:T,onChange:m=>h(m.target.value),disabled:P}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{id:"model-clear-ngrok",type:"checkbox",checked:P,onChange:m=>R(m.target.checked),className:"h-4 w-4 rounded border-border"}),e.jsx(v,{htmlFor:"model-clear-ngrok",children:"Clear ngrok token"})]})]}),!s&&e.jsx("p",{className:"text-xs text-muted-foreground",children:"Changes apply at the next start — the cluster isn't running."}),D&&e.jsx(b,{variant:"destructive",children:e.jsx(N,{children:D})}),e.jsx(Le,{outcomes:E}),e.jsx("div",{children:e.jsx($,{onClick:()=>void A(),disabled:f,children:f?"Saving…":"Save"})})]})]})}function de({result:t}){return e.jsxs("div",{className:"flex flex-col gap-2",children:[t.errors.map((s,l)=>e.jsx(b,{variant:"destructive",children:e.jsx(N,{children:s})},`err-${l}`)),t.violations.map((s,l)=>e.jsx(b,{children:e.jsxs(N,{className:"flex items-center gap-2",children:[e.jsx(Ce,{variant:s.fatal?"destructive":"secondary",children:s.reason}),e.jsx("span",{children:s.message})]})},`violation-${l}`)),t.effective!==void 0&&e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx("h4",{className:"text-xs font-semibold uppercase text-muted-foreground",children:"Effective settings (preview)"}),e.jsx("pre",{className:"max-h-64 overflow-auto rounded-md border border-border bg-muted/30 p-2 text-xs",children:JSON.stringify(t.effective,null,2)})]})]})}function Ie({drift:t,onTakeOwnership:s,busy:l,afterTakeOwnership:i}){return i?e.jsx(b,{children:e.jsxs(N,{className:"flex flex-col gap-2",children:[e.jsx("p",{children:"Drift remains even after taking full ownership at these paths — a defaulting webhook may be re-adding them:"}),e.jsx("ul",{className:"list-inside list-disc text-xs",children:t.map(o=>e.jsx("li",{children:o},o))})]})}):e.jsx(b,{children:e.jsxs(N,{className:"flex flex-col gap-2",children:[e.jsx("p",{children:"The saved spec differs from the cluster's at these paths — a different field manager may own them (SSA cannot remove a field it doesn't own by omission):"}),e.jsx("ul",{className:"list-inside list-disc text-xs",children:t.map(o=>e.jsx("li",{children:o},o))}),e.jsx("div",{children:e.jsx($,{size:"sm",onClick:s,disabled:l,children:"Take full ownership and re-apply"})})]})})}function $e({dirty:t,busy:s=!1,disabled:l=!1,note:i,onValidate:o,onSave:a,saveLabel:n}){const u=s||l;return e.jsx("div",{className:"flex shrink-0 flex-col gap-2 border-t border-border bg-background py-3",children:e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-x-4 gap-y-2",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx($,{variant:"outline",onClick:o,disabled:u,children:"Validate"}),e.jsx($,{onClick:a,disabled:u,children:n??"Save"}),t&&e.jsx("span",{role:"status",className:"text-xs text-muted-foreground",children:"Unsaved changes"})]}),i&&e.jsx("span",{className:"text-xs text-muted-foreground",children:i})]})})}function Re(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function F(t,s,l){if(s.length===0)throw new Error("updateSpec: path must not be empty");return Ve(t,s,l)}function ee(t,s){let l=t;for(const i of s){if(!Re(l))return;l=l[i]}return l}function Ve(t,s,l){const[i,...o]=s,a={...t};if(o.length===0)return l===void 0?delete a[i]:a[i]=l,a;const n=a[i],u=Re(n)?n:{};return a[i]=Ve(u,o,l),a}function it(t){return t===void 0?"unset":t?"true":"false"}function rt(t){if(t!=="unset")return t==="true"}function ot(t){return t===void 0?"unrestricted":t.length===0?"deny-all":"restricted"}function dt(t){return t.split(` +import{A as b,a as N,M as v,N as V,B as $,O as se,P as le,Q as ae,R as ne,U as J,j as he,k as ge,l as K,n as _,o as pe,p as I,D as Ge,t as Ue,u as Ke,v as Je,x as Ye,T as ye,g as we,h as Te,i as H,m as qe}from"./mount.D4ypHaeQ.js";import{r,j as e}from"./vendor.C5MRNvUt.js";import{B as Ce}from"./badge.hXhpY1Si.js";class ie extends Error{constructor(s,l){super(s),this.status=l}}async function ce(t){if(!t.ok){const s=await t.text();let l=s.trim()||`request failed (${t.status})`;try{const i=JSON.parse(s);i.error&&(l=i.error)}catch{}throw new ie(l,t.status)}return await t.json()}async function ve(t){const s=await fetch(t,{method:"POST"});if(!s.ok){await ce(s);return}}const ue=async t=>ce(await fetch(t)),He=async(t,s)=>ce(await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)})),Ee=async(t,s)=>ce(await fetch(t,{method:"PUT",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)})),We=t=>ue(`${t}/state`),te=t=>ue(`${t}/config`),Ae=(t,s)=>Ee(`${t}/config`,s),Pe=t=>ue(`${t}/cluster/settings`),De=(t,s)=>He(`${t}/cluster/settings/validate`,s),Me=(t,s)=>Ee(`${t}/cluster/settings`,s),Qe=t=>ue(`${t}/cluster/install-info`);function Fe(t){if(!(t instanceof ie))return null;try{const s=JSON.parse(t.message);if(Array.isArray(s.errors))return s}catch{}return null}function Oe(t){if(!(t instanceof ie))return null;try{const s=JSON.parse(t.message);if(s.validation&&Array.isArray(s.validation.errors))return s}catch{}return null}const Xe=t=>ve(`${t}/kubectl/use`),Ze=t=>ve(`${t}/reveal/config`),Be=t=>ve(`${t}/reveal/logs`);function et(t){const[s,l]=r.useState(null),[i,o]=r.useState(null);return r.useEffect(()=>{let a=!1;We(t).then(u=>{a||(l(u),o(null))}).catch(u=>{a||o(u.message)});const n=new EventSource(`${t}/events`);return n.onmessage=u=>{if(!a)try{l(JSON.parse(u.data)),o(null)}catch{}},n.onerror=()=>{a||o("settings: live update stream stalled")},()=>{a=!0,n.close()}},[t]),{state:s,error:i}}const tt={applied:"Applied","next-start":"Applies at next start",failed:"Failed"},st={applied:"✓","next-start":"⏱",failed:"✕"},lt={model:"Model",password:"Password",ngrok:"ngrok",healthNotifications:"Health notifications"};function Le({outcomes:t}){return t.length===0?null:e.jsx("ul",{"aria-label":"Save results",className:"flex flex-col gap-1 text-sm",children:t.map(s=>e.jsxs("li",{className:"flex items-start gap-2",children:[e.jsx("span",{"aria-hidden":"true",children:st[s.outcome]??"•"}),e.jsxs("span",{children:[e.jsxs("span",{className:"font-medium",children:[lt[s.field]??s.field,":"]})," ",tt[s.outcome]??s.outcome,s.message&&e.jsxs("span",{className:"text-muted-foreground",children:[" — ",s.message]})]})]},s.field))})}const xe=8;function at({apiBase:t,running:s,kubectlCurrent:l}){const[i,o]=r.useState(null),[a,n]=r.useState(null),[u,g]=r.useState(!0),[c,x]=r.useState(""),[w,T]=r.useState(""),[h,P]=r.useState(""),[R,D]=r.useState(null),[d,f]=r.useState(!1),[S,E]=r.useState([]),[y,A]=r.useState(!1),[m,O]=r.useState(null),[Y,U]=r.useState(null);r.useEffect(()=>{let p=!1;return te(t).then(k=>{p||(o(k),g(k.healthNotifications))}).catch(k=>{p||n(k.message)}),()=>{p=!0}},[t]);async function q(){D(null),E([]);const p=w!==""||h!=="";if(p){if(w.lengthg(p.target.checked),className:"h-4 w-4 rounded border-border"}),e.jsx(v,{htmlFor:"general-health-notifications",children:"Notify on cluster health issues"})]})}),e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsx("h3",{className:"text-sm font-medium",children:"Admin password"}),e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(v,{htmlFor:"general-current-password",children:"Current password"}),e.jsx(V,{id:"general-current-password",type:"password",value:c,onChange:p=>x(p.target.value)})]}),e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(v,{htmlFor:"general-new-password",children:"New password"}),e.jsx(V,{id:"general-new-password",type:"password",value:w,onChange:p=>T(p.target.value)}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Must be at least ",xe," characters."]})]}),e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(v,{htmlFor:"general-confirm-password",children:"Confirm new password"}),e.jsx(V,{id:"general-confirm-password",type:"password",value:h,onChange:p=>P(p.target.value)})]})]}),R&&e.jsx(b,{variant:"destructive",children:e.jsx(N,{children:R})}),e.jsx(Le,{outcomes:S}),e.jsx("div",{children:e.jsx($,{onClick:()=>void q(),disabled:d||!i,children:d?"Saving…":"Save general settings"})}),e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsx("h3",{className:"text-sm font-medium",children:"kubectl"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:l?"kubectl is pointing at this cluster.":"kubectl is not pointing at this cluster."}),e.jsxs("div",{children:[e.jsx($,{variant:"outline",onClick:()=>void G(),disabled:!s||y,title:s?void 0:"Start the cluster first.",children:y?"Switching…":"Point kubectl at this cluster"}),!s&&e.jsx("p",{className:"text-xs text-muted-foreground",children:"Start the cluster first."})]}),m&&e.jsx(b,{variant:"destructive",children:e.jsx(N,{children:m})})]}),e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsx("h3",{className:"text-sm font-medium",children:"Diagnostics"}),e.jsxs("div",{className:"flex gap-2",children:[e.jsx($,{variant:"outline",onClick:()=>void Q(Ze),children:"Reveal config file"}),e.jsx($,{variant:"outline",onClick:()=>void Q(Be),children:"View logs"})]}),Y&&e.jsx(b,{variant:"destructive",children:e.jsx(N,{children:Y})})]})]})}function nt({apiBase:t,running:s}){const[l,i]=r.useState(null),[o,a]=r.useState(null),[n,u]=r.useState(""),[g,c]=r.useState(""),[x,w]=r.useState(""),[T,h]=r.useState(""),[P,R]=r.useState(!1),[D,d]=r.useState(null),[f,S]=r.useState(!1),[E,y]=r.useState([]);r.useEffect(()=>{let m=!1;return te(t).then(O=>{m||(i(O),u(O.model.provider),w(O.model.name))}).catch(O=>{m||a(O.message)}),()=>{m=!0}},[t]);async function A(){d(null),y([]),S(!0);try{const m=await te(t),O=await Ae(t,{model:{provider:n,apiKey:g,name:x},ngrokAuthToken:P?"":T,clearNgrok:P,healthNotifications:m.healthNotifications});y(O.outcomes),c(""),h(""),R(!1);const Y=await te(t);i(Y)}catch(m){d(m instanceof ie||m instanceof Error?m.message:String(m))}finally{S(!1)}}return e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsx("h2",{className:"text-base font-semibold",children:"Model settings"}),o&&e.jsx(b,{variant:"destructive",children:e.jsx(N,{children:o})}),l&&e.jsxs(e.Fragment,{children:[e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsx(v,{htmlFor:"model-provider",children:"Provider"}),e.jsxs(se,{value:n,onValueChange:u,children:[e.jsx(le,{id:"model-provider",children:e.jsx(ae,{})}),e.jsx(ne,{children:l.providers.map(m=>e.jsx(J,{value:m,children:m},m))})]})]}),e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsx(v,{htmlFor:"model-api-key",children:"API key"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:l.model.apiKeyMasked?l.model.apiKeyMasked:"Not set"}),e.jsx(V,{id:"model-api-key",type:"password",placeholder:"unchanged",value:g,onChange:m=>c(m.target.value)})]}),e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsx(v,{htmlFor:"model-name",children:"Model name"}),e.jsx(V,{id:"model-name",value:x,onChange:m=>w(m.target.value)}),e.jsxs("p",{className:"text-xs text-muted-foreground",children:["Leave blank to use ",n||"the selected provider","'s recommended default model."]})]}),e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsx("h3",{className:"text-sm font-medium",children:"ngrok"}),e.jsx("p",{className:"text-sm text-muted-foreground",children:l.ngrokConfigured?"Configured":"Not configured"}),e.jsx(v,{htmlFor:"model-ngrok-token",children:"ngrok auth token"}),e.jsx(V,{id:"model-ngrok-token",type:"password",placeholder:"unchanged",value:T,onChange:m=>h(m.target.value),disabled:P}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{id:"model-clear-ngrok",type:"checkbox",checked:P,onChange:m=>R(m.target.checked),className:"h-4 w-4 rounded border-border"}),e.jsx(v,{htmlFor:"model-clear-ngrok",children:"Clear ngrok token"})]})]}),!s&&e.jsx("p",{className:"text-xs text-muted-foreground",children:"Changes apply at the next start — the cluster isn't running."}),D&&e.jsx(b,{variant:"destructive",children:e.jsx(N,{children:D})}),e.jsx(Le,{outcomes:E}),e.jsx("div",{children:e.jsx($,{onClick:()=>void A(),disabled:f,children:f?"Saving…":"Save"})})]})]})}function de({result:t}){return e.jsxs("div",{className:"flex flex-col gap-2",children:[t.errors.map((s,l)=>e.jsx(b,{variant:"destructive",children:e.jsx(N,{children:s})},`err-${l}`)),t.violations.map((s,l)=>e.jsx(b,{children:e.jsxs(N,{className:"flex items-center gap-2",children:[e.jsx(Ce,{variant:s.fatal?"destructive":"secondary",children:s.reason}),e.jsx("span",{children:s.message})]})},`violation-${l}`)),t.effective!==void 0&&e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx("h4",{className:"text-xs font-semibold uppercase text-muted-foreground",children:"Effective settings (preview)"}),e.jsx("pre",{className:"max-h-64 overflow-auto rounded-md border border-border bg-muted/30 p-2 text-xs",children:JSON.stringify(t.effective,null,2)})]})]})}function Ie({drift:t,onTakeOwnership:s,busy:l,afterTakeOwnership:i}){return i?e.jsx(b,{children:e.jsxs(N,{className:"flex flex-col gap-2",children:[e.jsx("p",{children:"Drift remains even after taking full ownership at these paths — a defaulting webhook may be re-adding them:"}),e.jsx("ul",{className:"list-inside list-disc text-xs",children:t.map(o=>e.jsx("li",{children:o},o))})]})}):e.jsx(b,{children:e.jsxs(N,{className:"flex flex-col gap-2",children:[e.jsx("p",{children:"The saved spec differs from the cluster's at these paths — a different field manager may own them (SSA cannot remove a field it doesn't own by omission):"}),e.jsx("ul",{className:"list-inside list-disc text-xs",children:t.map(o=>e.jsx("li",{children:o},o))}),e.jsx("div",{children:e.jsx($,{size:"sm",onClick:s,disabled:l,children:"Take full ownership and re-apply"})})]})})}function $e({dirty:t,busy:s=!1,disabled:l=!1,note:i,onValidate:o,onSave:a,saveLabel:n}){const u=s||l;return e.jsx("div",{className:"flex shrink-0 flex-col gap-2 border-t border-border bg-background py-3",children:e.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-x-4 gap-y-2",children:[e.jsxs("div",{className:"flex items-center gap-3",children:[e.jsx($,{variant:"outline",onClick:o,disabled:u,children:"Validate"}),e.jsx($,{onClick:a,disabled:u,children:n??"Save"}),t&&e.jsx("span",{role:"status",className:"text-xs text-muted-foreground",children:"Unsaved changes"})]}),i&&e.jsx("span",{className:"text-xs text-muted-foreground",children:i})]})})}function Re(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function F(t,s,l){if(s.length===0)throw new Error("updateSpec: path must not be empty");return Ve(t,s,l)}function ee(t,s){let l=t;for(const i of s){if(!Re(l))return;l=l[i]}return l}function Ve(t,s,l){const[i,...o]=s,a={...t};if(o.length===0)return l===void 0?delete a[i]:a[i]=l,a;const n=a[i],u=Re(n)?n:{};return a[i]=Ve(u,o,l),a}function it(t){return t===void 0?"unset":t?"true":"false"}function rt(t){if(t!=="unset")return t==="true"}function ot(t){return t===void 0?"unrestricted":t.length===0?"deny-all":"restricted"}function dt(t){return t.split(` `).map(s=>s.trim()).filter(s=>s.length>0)}function ct(t){return(t??[]).join(` `)}function be(t){return{namespace:"agentprimitives-system",name:`model-default-token-${t}`,key:"token"}}function ut(t,s){const l=t.modelCatalog??[],i=l.findIndex(n=>n.name===s.name),o=l.slice();i>=0?o[i]=s:o.push(s);const a=s.default?o.map(n=>n.name===s.name?n:{...n,default:!1}):o;return F(t,["modelCatalog"],a)}function ze(t,s){const l=t.modelCatalog??[];return F(t,["modelCatalog"],l.filter(i=>i.name!==s))}function xt(t,s,l){return ut(ze(t,s),l)}function mt(t){const s=(t==null?void 0:t.rules)??[],l=(t==null?void 0:t.bypass)??[];if(s.length===0&&l.length===0)return"—";let o=s.map(a=>`${a.kind}(min=${a.minStrength||"any"},mode=${a.mode||"approve"})`).join(", ");return l.length>0&&(o+=` · ${l.length} bypass`),o}function ft(t){if(!t)return"—";const s=[];return t.maxFailureThreshold!==void 0&&s.push(`maxFailureThreshold=${t.maxFailureThreshold}`),t.minInitialCoolOff!==void 0&&s.push(`minInitialCoolOff=${t.minInitialCoolOff}`),t.minAction!==void 0&&s.push(`minAction=${t.minAction}`),t.maxCallsPerTurn!==void 0&&s.push(`maxCallsPerTurn=${t.maxCallsPerTurn}`),t.maxCalls!==void 0&&t.window!==void 0&&s.push(`maxCalls=${t.maxCalls}/${t.window}`),t.maxEgressBytes!==void 0&&s.push(`maxEgressBytes=${t.maxEgressBytes}`),t.maxIngressBytes!==void 0&&s.push(`maxIngressBytes=${t.maxIngressBytes}`),s.length===0?"—":s.join(", ")}function ht(t){return t===void 0?"not set":t.length===0?"(none)":t.map(s=>s.id).join(", ")}function gt(t){return t===void 0?"no constraint":t.length===0?"deny-all":t.map(s=>s.name).join(", ")}const pt=["anthropic","openai","openrouter"];function Ne(){return{name:"",provider:"anthropic",isDefault:!1,inputPerMTok:0,outputPerMTok:0,tokenInput:""}}function jt(t){return{name:t.name,provider:t.provider??"anthropic",isDefault:!!t.default,inputPerMTok:t.inputPerMTok??0,outputPerMTok:t.outputPerMTok??0,tokenInput:""}}function ke(t){return t===void 0||t===0?"—":String(t)}function vt({spec:t,onChange:s,tokens:l,onTokensChange:i}){const o=t.modelCatalog??[],[a,n]=r.useState(!1),[u,g]=r.useState(null),[c,x]=r.useState(Ne()),[w,T]=r.useState(null);function h(){g(null),x(Ne()),n(!0)}function P(d){g(d.name),x(jt(d)),n(!0)}function R(){const d=c.name.trim();if(!d)return;const f=u?o.find(A=>A.name===u):void 0,S=(f==null?void 0:f.tokenRef)??be(d),E={...f,name:d,provider:c.provider,default:c.isDefault,inputPerMTok:c.inputPerMTok,outputPerMTok:c.outputPerMTok,tokenRef:S};s(xt(t,u??d,E));const y=c.tokenInput.trim();if(y!==""){const A=l.filter(m=>!(m.namespace===S.namespace&&m.name===S.name&&m.key===S.key));i([...A,{...S,value:y}])}n(!1)}function D(d){s(ze(t,d));const f=o.find(y=>y.name===d),S=(f==null?void 0:f.tokenRef)??be(d),E=l.filter(y=>!(y.namespace===S.namespace&&y.name===S.name&&y.key===S.key));E.length!==l.length&&i(E),T(null)}return e.jsxs("section",{className:"flex flex-col gap-3",children:[e.jsxs("div",{className:"flex items-center justify-between",children:[e.jsx("h3",{className:"text-sm font-medium",children:"Model catalog"}),e.jsx($,{size:"sm",onClick:h,children:"Add model"})]}),e.jsxs(he,{children:[e.jsx(ge,{children:e.jsxs(K,{children:[e.jsx(_,{children:"Name"}),e.jsx(_,{children:"Provider"}),e.jsx(_,{children:"Default"}),e.jsx(_,{children:"Input $/MTok"}),e.jsx(_,{children:"Output $/MTok"}),e.jsx(_,{children:"Actions"})]})}),e.jsxs(pe,{children:[o.length===0&&e.jsx(K,{children:e.jsx(I,{colSpan:6,className:"text-muted-foreground",children:"No catalog entries."})}),o.map(d=>e.jsxs(K,{children:[e.jsx(I,{children:d.name}),e.jsx(I,{children:d.provider||"—"}),e.jsx(I,{children:d.default?"Yes":"No"}),e.jsx(I,{children:ke(d.inputPerMTok)}),e.jsx(I,{children:ke(d.outputPerMTok)}),e.jsx(I,{children:w===d.name?e.jsxs("div",{className:"flex gap-2",children:[e.jsx($,{variant:"destructive",size:"sm",onClick:()=>D(d.name),children:"Confirm delete"}),e.jsx($,{variant:"outline",size:"sm",onClick:()=>T(null),children:"Cancel"})]}):e.jsxs("div",{className:"flex gap-2",children:[e.jsx($,{variant:"outline",size:"sm",onClick:()=>P(d),children:"Edit"}),e.jsx($,{variant:"outline",size:"sm",onClick:()=>T(d.name),children:"Delete"})]})})]},d.name))]})]}),e.jsx(Ge,{open:a,onOpenChange:n,children:e.jsxs(Ue,{children:[e.jsx(Ke,{children:e.jsx(Je,{children:u?"Edit model":"Add model"})}),e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(v,{htmlFor:"catalog-name",children:"Name"}),e.jsx(V,{id:"catalog-name",value:c.name,onChange:d=>x({...c,name:d.target.value})})]}),e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(v,{htmlFor:"catalog-provider",children:"Provider"}),e.jsxs(se,{value:c.provider,onValueChange:d=>x({...c,provider:d}),children:[e.jsx(le,{id:"catalog-provider",children:e.jsx(ae,{})}),e.jsx(ne,{children:pt.map(d=>e.jsx(J,{value:d,children:d},d))})]})]}),e.jsxs("div",{className:"flex items-center gap-2",children:[e.jsx("input",{id:"catalog-default",type:"checkbox",checked:c.isDefault,onChange:d=>x({...c,isDefault:d.target.checked}),className:"h-4 w-4 rounded border-border"}),e.jsx(v,{htmlFor:"catalog-default",children:"Default model"})]}),e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(v,{htmlFor:"catalog-input-price",children:"Input $/MTok"}),e.jsx(V,{id:"catalog-input-price",type:"number",value:c.inputPerMTok,onChange:d=>x({...c,inputPerMTok:Number(d.target.value)||0})})]}),e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(v,{htmlFor:"catalog-output-price",children:"Output $/MTok"}),e.jsx(V,{id:"catalog-output-price",type:"number",value:c.outputPerMTok,onChange:d=>x({...c,outputPerMTok:Number(d.target.value)||0})})]}),e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(v,{htmlFor:"catalog-token",children:"API token"}),e.jsx(V,{id:"catalog-token",type:"password",placeholder:"unchanged",value:c.tokenInput,onChange:d=>x({...c,tokenInput:d.target.value})}),e.jsx("p",{className:"text-xs text-muted-foreground",children:"Leave blank to keep the existing token for this entry."})]})]}),e.jsx(Ye,{children:e.jsx($,{onClick:R,disabled:c.name.trim()==="",children:"Save"})})]})})]})}function W({spec:t,onChange:s,path:l,id:i,label:o,hint:a}){const n=ee(t,l),u=typeof n=="string"?n:"";return e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(v,{htmlFor:i,children:o}),e.jsx(V,{id:i,placeholder:"e.g. 30m",value:u,onChange:g=>{const c=g.target.value;s(F(t,l,c.trim()===""?void 0:c))}}),a&&e.jsx("p",{className:"text-xs text-muted-foreground",children:a})]})}function B({spec:t,onChange:s,path:l,id:i,label:o,hint:a}){const n=ee(t,l),u=typeof n=="number"?n:"";return e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(v,{htmlFor:i,children:o}),e.jsx(V,{id:i,type:"number",value:u,onChange:g=>{const c=g.target.value;if(c.trim()===""){s(F(t,l,void 0));return}const x=Number(c);Number.isNaN(x)||s(F(t,l,x))}}),a&&e.jsx("p",{className:"text-xs text-muted-foreground",children:a})]})}function Se({spec:t,onChange:s,path:l,id:i,label:o,hint:a}){const n=ee(t,l),u=typeof n=="string"?n:"";return e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(v,{htmlFor:i,children:o}),e.jsx(V,{id:i,value:u,onChange:g=>{const c=g.target.value;s(F(t,l,c.trim()===""?void 0:c))}}),a&&e.jsx("p",{className:"text-xs text-muted-foreground",children:a})]})}function oe({spec:t,onChange:s,path:l,id:i,label:o,hint:a}){const n=ee(t,l),u=it(typeof n=="boolean"?n:void 0);return e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(v,{htmlFor:i,children:o}),e.jsxs(se,{value:u,onValueChange:g=>s(F(t,l,rt(g))),children:[e.jsx(le,{id:i,children:e.jsx(ae,{})}),e.jsxs(ne,{children:[e.jsx(J,{value:"unset",children:"Unset (no requirement)"}),e.jsx(J,{value:"true",children:"True"}),e.jsx(J,{value:"false",children:"False"})]})]}),a&&e.jsx("p",{className:"text-xs text-muted-foreground",children:a})]})}function je({id:t,initial:s,onCommit:l}){const[i,o]=r.useState(()=>ct(s));return e.jsx("textarea",{id:t,rows:4,className:"flex w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",value:i,onChange:a=>{o(a.target.value),l(dt(a.target.value))}})}function re({label:t,value:s}){return e.jsxs("div",{className:"flex flex-col gap-0.5 rounded-md border border-border p-3",children:[e.jsx("span",{className:"text-xs font-medium text-muted-foreground",children:t}),e.jsx("span",{className:"text-sm",children:s}),e.jsx("span",{className:"text-xs text-muted-foreground",children:"Edit in Advanced tab"})]})}const bt=[{value:"unset",label:"Unset (no floor)"},{value:"disabled",label:"disabled"},{value:"logging",label:"logging"},{value:"enforcing",label:"enforcing"}];function me({spec:t,onChange:s,path:l,fieldLabel:i,idPrefix:o}){const a=ee(t,l),n=ot(a),u=n!=="unrestricted";return e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx(v,{children:i}),e.jsxs("div",{className:"flex flex-col gap-1 text-sm",children:[e.jsxs("label",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"radio",name:o,checked:!u,onChange:()=>s(F(t,l,void 0))}),i,": Unrestricted"]}),e.jsxs("label",{className:"flex items-center gap-2",children:[e.jsx("input",{type:"radio",name:o,checked:u,onChange:()=>s(F(t,l,a??[]))}),i,": Restrict to list"]})]}),u&&e.jsxs(e.Fragment,{children:[e.jsx(je,{id:`${o}-list`,initial:a??[],onCommit:g=>s(F(t,l,g))}),n==="deny-all"&&e.jsx(b,{variant:"destructive",children:e.jsx(N,{children:"Empty list — deny-all: no entries are permitted."})})]})]})}function Nt({spec:t,onChange:s}){var i,o,a,n,u,g,c;const l=((i=t.limits)==null?void 0:i.minPlanGateMode)||"unset";return e.jsxs("section",{className:"flex flex-col gap-6",children:[e.jsx("h3",{className:"text-sm font-medium",children:"Limits (ceilings)"}),e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsx("h4",{className:"text-xs font-semibold uppercase text-muted-foreground",children:"Budget ceiling"}),e.jsx(B,{spec:t,onChange:s,path:["limits","budget","maxTurns"],id:"limits-budget-max-turns",label:"Ceiling: max turns"}),e.jsx(B,{spec:t,onChange:s,path:["limits","budget","maxTokens"],id:"limits-budget-max-tokens",label:"Ceiling: max tokens"}),e.jsx(W,{spec:t,onChange:s,path:["limits","budget","maxDuration"],id:"limits-budget-max-duration",label:"Ceiling: max duration"}),e.jsx(W,{spec:t,onChange:s,path:["limits","budget","sessionExpiration"],id:"limits-budget-session-expiration",label:"Ceiling: session expiration"}),e.jsx(B,{spec:t,onChange:s,path:["limits","budget","maxDelegatedAgents"],id:"limits-budget-max-delegated-agents",label:"Ceiling: max delegated agents"})]}),e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsx("h4",{className:"text-xs font-semibold uppercase text-muted-foreground",children:"Authz ceiling"}),e.jsx(W,{spec:t,onChange:s,path:["limits","authz","maxApprovalTimeout"],id:"limits-authz-max-approval-timeout",label:"Ceiling: max approval timeout"}),e.jsx(W,{spec:t,onChange:s,path:["limits","authz","maxInformationLeakageApprovalTTL"],id:"limits-authz-max-leakage-ttl",label:"Ceiling: max information-leakage approval TTL"})]}),e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(v,{htmlFor:"limits-min-plan-gate-mode",children:"Minimum plan-gate mode"}),e.jsxs(se,{value:l,onValueChange:x=>s(F(t,["limits","minPlanGateMode"],x==="unset"?void 0:x)),children:[e.jsx(le,{id:"limits-min-plan-gate-mode",children:e.jsx(ae,{})}),e.jsx(ne,{children:bt.map(x=>e.jsx(J,{value:x.value,children:x.label},x.value))})]})]}),e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(v,{htmlFor:"limits-denied-models",children:"Denied models"}),e.jsx(je,{id:"limits-denied-models",initial:((o=t.limits)==null?void 0:o.deniedModels)??[],onCommit:x=>s(F(t,["limits","deniedModels"],x.length>0?x:void 0))})]}),e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(v,{htmlFor:"limits-denied-skills",children:"Denied skills"}),e.jsx(je,{id:"limits-denied-skills",initial:((a=t.limits)==null?void 0:a.deniedSkills)??[],onCommit:x=>s(F(t,["limits","deniedSkills"],x.length>0?x:void 0))})]}),e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsx(oe,{spec:t,onChange:s,path:["limits","allowModelOverride"],id:"limits-allow-model-override",label:"Allow model override",hint:"Top-down grant: nil/false means catalog-only."}),e.jsx(oe,{spec:t,onChange:s,path:["limits","nativeFileHandling"],id:"limits-native-file-handling",label:"Native file handling"}),e.jsx(oe,{spec:t,onChange:s,path:["limits","requireSubagentDigestPins"],id:"limits-require-subagent-digest-pins",label:"Require subagent digest pins"})]}),e.jsxs("div",{className:"flex flex-col gap-4",children:[e.jsx(me,{spec:t,onChange:s,path:["limits","allowedToolkits"],fieldLabel:"Allowed toolkits",idPrefix:"limits-allowed-toolkits"}),e.jsx(me,{spec:t,onChange:s,path:["limits","allowedSkills"],fieldLabel:"Allowed skills",idPrefix:"limits-allowed-skills"}),e.jsx(me,{spec:t,onChange:s,path:["limits","allowedSandboxKinds"],fieldLabel:"Allowed sandbox kinds",idPrefix:"limits-allowed-sandbox-kinds"})]}),e.jsxs("div",{className:"grid grid-cols-1 gap-3 sm:grid-cols-2",children:[e.jsx(re,{label:"Pinning",value:mt((n=t.limits)==null?void 0:n.pinning)}),e.jsx(re,{label:"Tool guard ceiling",value:ft((u=t.limits)==null?void 0:u.toolGuard)}),e.jsx(re,{label:"Content inspectors",value:ht((g=t.limits)==null?void 0:g.contentInspectors)}),e.jsx(re,{label:"Allowed MCP servers",value:gt((c=t.limits)==null?void 0:c.allowedMCPServers)})]})]})}const kt=["anthropic","openai","openrouter"],fe="__none__";function St({spec:t,onChange:s}){var g,c,x,w,T;const l=(c=(g=t.defaults)==null?void 0:g.model)==null?void 0:c.provider,i=((w=(x=t.defaults)==null?void 0:x.model)==null?void 0:w.fromCatalog)||fe,o=(t.modelCatalog??[]).map(h=>h.name),a=(T=t.defaults)==null?void 0:T.reportSessionCost,n=ee(t,["defaults","authz","planGate","mode"]),u=ee(t,["defaults","authz","metaagent","trigger"]);return e.jsxs("section",{className:"flex flex-col gap-6",children:[e.jsx("h3",{className:"text-sm font-medium",children:"Defaults (fallbacks)"}),e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsx("h4",{className:"text-xs font-semibold uppercase text-muted-foreground",children:"Default model"}),e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(v,{htmlFor:"defaults-model-provider",children:"Provider"}),e.jsxs(se,{value:l,onValueChange:h=>s(F(t,["defaults","model","provider"],h)),children:[e.jsx(le,{id:"defaults-model-provider",children:e.jsx(ae,{placeholder:"Select a provider…"})}),e.jsx(ne,{children:kt.map(h=>e.jsx(J,{value:h,children:h},h))})]})]}),e.jsx(Se,{spec:t,onChange:s,path:["defaults","model","name"],id:"defaults-model-name",label:"Model name"}),e.jsxs("div",{className:"flex flex-col gap-1",children:[e.jsx(v,{htmlFor:"defaults-model-from-catalog",children:"From catalog"}),e.jsxs(se,{value:i,onValueChange:h=>s(F(t,["defaults","model","fromCatalog"],h===fe?void 0:h)),children:[e.jsx(le,{id:"defaults-model-from-catalog",children:e.jsx(ae,{})}),e.jsxs(ne,{children:[e.jsx(J,{value:fe,children:"(use provider/name above)"}),o.map(h=>e.jsx(J,{value:h,children:h},h))]})]})]})]}),e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsx("h4",{className:"text-xs font-semibold uppercase text-muted-foreground",children:"Default budget"}),e.jsx(B,{spec:t,onChange:s,path:["defaults","budget","maxTurns"],id:"defaults-budget-max-turns",label:"Default: max turns"}),e.jsx(B,{spec:t,onChange:s,path:["defaults","budget","maxTokens"],id:"defaults-budget-max-tokens",label:"Default: max tokens"}),e.jsx(W,{spec:t,onChange:s,path:["defaults","budget","maxDuration"],id:"defaults-budget-max-duration",label:"Default: max duration"}),e.jsx(W,{spec:t,onChange:s,path:["defaults","budget","sessionExpiration"],id:"defaults-budget-session-expiration",label:"Default: session expiration"}),e.jsx(B,{spec:t,onChange:s,path:["defaults","budget","maxDelegatedAgents"],id:"defaults-budget-max-delegated-agents",label:"Default: max delegated agents"})]}),e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsx("h4",{className:"text-xs font-semibold uppercase text-muted-foreground",children:"Default authz"}),e.jsx(W,{spec:t,onChange:s,path:["defaults","authz","approvalTimeout"],id:"defaults-authz-approval-timeout",label:"Default: approval timeout"}),e.jsx(W,{spec:t,onChange:s,path:["defaults","authz","informationLeakageApprovalTTL"],id:"defaults-authz-leakage-ttl",label:"Default: information-leakage approval TTL"}),e.jsx(B,{spec:t,onChange:s,path:["defaults","authz","scopeMaxLlmLatencyMs"],id:"defaults-authz-scope-max-llm-latency-ms",label:"Default: scope max LLM latency (ms)"}),e.jsxs("div",{className:"flex flex-col gap-0.5 text-xs text-muted-foreground",children:[e.jsxs("span",{children:["Plan-gate mode: ",typeof n=="string"&&n?n:"not set"]}),e.jsxs("span",{children:["Metaagent trigger: ",typeof u=="string"&&u?u:"not set"]}),e.jsx("span",{children:"Edit in Advanced tab"})]})]}),e.jsxs("div",{className:"flex flex-col gap-3",children:[e.jsx(oe,{spec:t,onChange:s,path:["defaults","reportSessionCost"],id:"defaults-report-session-cost",label:"Report session cost",hint:"Unset means on: the end-of-session cost estimate is shown by default."}),e.jsx(Se,{spec:t,onChange:s,path:["defaults","sandbox","kind"],id:"defaults-sandbox-kind",label:"Sandbox kind",hint:'Defaults to "pod" when unset.'})]}),a===void 0&&e.jsx("p",{className:"text-xs text-muted-foreground","data-testid":"report-session-cost-default-note",children:"No value set — cost reporting is ON by default."})]})}const yt=[{id:"catalog",label:"Catalog"},{id:"limits",label:"Limits"},{id:"defaults",label:"Defaults"}];function wt({apiBase:t,running:s}){const[l,i]=r.useState(null),[o,a]=r.useState(null),[n,u]=r.useState({}),[g,c]=r.useState(!1),[x,w]=r.useState([]),[T,h]=r.useState(null),[P,R]=r.useState(!1),[D,d]=r.useState(null),[f,S]=r.useState(null),[E,y]=r.useState(!1),[A,m]=r.useState(null),[O,Y]=r.useState(!1);r.useEffect(()=>{let j=!1;return Pe(t).then(M=>{j||(i(M),u(M.spec??{}),c(!1))}).catch(M=>{j||a(M.message)}),()=>{j=!0}},[t]);async function U(){d(null),R(!0);try{const j=await De(t,{spec:n});h(j)}catch(j){const M=Fe(j);M?h(M):d(j instanceof Error?j.message:String(j))}finally{R(!1)}}async function q(j){m(null),y(!0),Y(j);try{const Z=await Me(t,j?{spec:n,takeOwnership:!0}:{spec:n,tokens:x});S(Z),Z.applied&&(c(!1),j||w([]))}catch(M){const Z=Oe(M);Z?S(Z):m(M instanceof Error?M.message:String(M))}finally{y(!1)}}const G=()=>q(!1),Q=()=>q(!0);function p(j){u(j),c(!0)}function k(j){w(j),c(!0)}const X=g||x.length>0;return e.jsxs("div",{className:"flex h-full flex-col gap-6",children:[e.jsx("h2",{className:"text-base font-semibold",children:"Cluster settings"}),o&&e.jsx(b,{variant:"destructive",children:e.jsx(N,{children:o})}),(l==null?void 0:l.clusterDown)&&e.jsx(b,{variant:"destructive",children:e.jsx(N,{children:"The desktop cluster isn't running. Start it from the General tab to edit cluster settings."})}),l&&!l.clusterDown&&e.jsxs(e.Fragment,{children:[!s&&e.jsx("p",{className:"text-xs text-muted-foreground",children:"The desktop isn't running — Validate still works, but Save will fail until it's back up."}),e.jsxs(ye,{defaultValue:"catalog",orientation:"vertical",className:"flex min-h-0 flex-1 gap-6",children:[e.jsx(we,{className:"h-auto w-40 shrink-0 flex-col items-stretch justify-start gap-1 bg-transparent p-0",children:yt.map(j=>e.jsx(Te,{value:j.id,className:"justify-start data-[state=active]:bg-muted",children:j.label},j.id))}),e.jsxs("div",{className:"min-w-0 flex-1 overflow-y-auto",children:[e.jsx(H,{value:"catalog",className:"mt-0",children:e.jsx(vt,{spec:n,onChange:p,tokens:x,onTokensChange:k})}),e.jsx(H,{value:"limits",className:"mt-0",children:e.jsx(Nt,{spec:n,onChange:p})}),e.jsx(H,{value:"defaults",className:"mt-0",children:e.jsx(St,{spec:n,onChange:p})})]})]}),(D||T||A||f)&&e.jsxs("div",{className:"flex max-h-48 shrink-0 flex-col gap-2 overflow-y-auto",children:[D&&e.jsx(b,{variant:"destructive",children:e.jsx(N,{children:D})}),T&&e.jsx(de,{result:T}),A&&e.jsx(b,{variant:"destructive",children:e.jsx(N,{children:A})}),f&&e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("p",{className:"text-sm",children:f.applied?"Applied.":"Not applied — see validation below."}),e.jsx(de,{result:f.validation}),f.drift&&f.drift.length>0&&e.jsx(Ie,{drift:f.drift,onTakeOwnership:()=>void Q(),busy:E,afterTakeOwnership:O})]})]}),e.jsx($e,{dirty:X,busy:P||E,onValidate:()=>void U(),onSave:()=>void G()})]})]})}const Tt=1e4;function Ct({apiBase:t,running:s}){const[l,i]=r.useState(null),[o,a]=r.useState(null),[n,u]=r.useState(""),[g,c]=r.useState(""),[x,w]=r.useState(null),[T,h]=r.useState(!1),[P,R]=r.useState(null),[D,d]=r.useState(null),[f,S]=r.useState(null),[E,y]=r.useState(!1),[A,m]=r.useState(null),[O,Y]=r.useState(!1),[U,q]=r.useState(!1),G=r.useRef(null);r.useEffect(()=>()=>{G.current&&clearTimeout(G.current)},[]),r.useEffect(()=>{let L=!1;return Pe(t).then(C=>{if(L)return;i(C);const z=C.yaml??"";u(z),c(z)}).catch(C=>{L||a(C.message)}),()=>{L=!0}},[t]);function Q(){G.current&&(clearTimeout(G.current),G.current=null),q(!1)}function p(L){u(L),U&&Q()}async function k(){R(null),h(!0);const L=n;try{const C=await De(t,{yaml:L});w(C),d(L)}catch(C){const z=Fe(C);z?(w(z),d(L)):R(C instanceof Error?C.message:String(C))}finally{h(!1)}}async function X(L){m(null),y(!0),Y(L);try{const z=await Me(t,L?{yaml:n,takeOwnership:!0}:{yaml:n});S(z),z.applied&&c(n)}catch(C){const z=Oe(C);z?S(z):m(C instanceof Error?C.message:String(C))}finally{y(!1)}}const j=()=>X(!0),M=n!==g;function Z(){if(D===n){X(!1);return}if(U){Q(),X(!1);return}q(!0),G.current=setTimeout(()=>q(!1),Tt)}const _e=E?"Applying…":U?"Apply without validating?":"Apply";return e.jsxs("div",{className:"flex h-full flex-col gap-6",children:[e.jsx("h2",{className:"text-base font-semibold",children:"Advanced (raw YAML)"}),o&&e.jsx(b,{variant:"destructive",children:e.jsx(N,{children:o})}),(l==null?void 0:l.clusterDown)&&e.jsx(b,{variant:"destructive",children:e.jsx(N,{children:"The desktop cluster isn't running. Start it from the General tab to edit cluster settings."})}),l&&!l.clusterDown&&e.jsxs(e.Fragment,{children:[!s&&e.jsx("p",{className:"text-xs text-muted-foreground",children:"The desktop isn't running — Validate still works, but Apply will fail until it's back up."}),e.jsx("textarea",{"aria-label":"cluster settings yaml",spellCheck:!1,className:"min-h-0 w-full flex-1 rounded-md border border-border bg-background p-3 font-mono text-xs",value:n,onChange:L=>p(L.target.value)}),U&&e.jsx("p",{className:"text-xs text-muted-foreground",children:"This text hasn't been validated. Click Apply again within 10 seconds to apply it anyway."}),(P||x||A||f)&&e.jsxs("div",{className:"flex max-h-48 shrink-0 flex-col gap-2 overflow-y-auto",children:[P&&e.jsx(b,{variant:"destructive",children:e.jsx(N,{children:P})}),x&&e.jsx(de,{result:x}),A&&e.jsx(b,{variant:"destructive",children:e.jsx(N,{children:A})}),f&&e.jsxs("div",{className:"flex flex-col gap-2",children:[e.jsx("p",{className:"text-sm",children:f.applied?"Applied.":"Not applied — see validation below."}),e.jsx(de,{result:f.validation}),f.drift&&f.drift.length>0&&e.jsx(Ie,{drift:f.drift,onTakeOwnership:()=>void j(),busy:E,afterTakeOwnership:O})]})]}),e.jsx($e,{dirty:M,busy:T||E,onValidate:()=>void k(),onSave:Z,saveLabel:_e})]})]})}function Et({apiBase:t}){const[s,l]=r.useState(null),[i,o]=r.useState(null);return r.useEffect(()=>{let a=!1;return Qe(t).then(n=>{a||l(n)}).catch(n=>{a||o(n.message)}),()=>{a=!0}},[t]),e.jsxs("div",{className:"flex flex-col gap-6",children:[e.jsx("h2",{className:"text-base font-semibold",children:"About"}),i&&e.jsx(b,{variant:"destructive",children:e.jsx(N,{children:i})}),(s==null?void 0:s.clusterDown)&&e.jsx(b,{variant:"destructive",children:e.jsx(N,{children:"The desktop cluster isn't running. Start it from the General tab to see install info."})}),s&&!s.clusterDown&&e.jsxs(e.Fragment,{children:[e.jsxs("section",{className:"flex items-center gap-2","data-testid":"about-cluster-kind",children:[e.jsx("h3",{className:"text-sm font-medium",children:"Cluster kind"}),e.jsx(Ce,{variant:"secondary",children:s.clusterKind})]}),e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsx("h3",{className:"text-sm font-medium",children:"Components"}),e.jsxs(he,{"data-testid":"about-components-table",children:[e.jsx(ge,{children:e.jsxs(K,{children:[e.jsx(_,{children:"Name"}),e.jsx(_,{children:"Image"}),e.jsx(_,{children:"Ready"})]})}),e.jsxs(pe,{children:[s.components.length===0&&e.jsx(K,{children:e.jsx(I,{colSpan:3,className:"text-muted-foreground",children:"No components reported."})}),s.components.map(a=>e.jsxs(K,{children:[e.jsx(I,{children:a.name}),e.jsx(I,{className:"font-mono text-xs",children:a.image}),e.jsx(I,{children:a.ready})]},a.name))]})]})]}),e.jsxs("section",{className:"flex flex-col gap-2",children:[e.jsx("h3",{className:"text-sm font-medium",children:"Operator environment"}),e.jsxs(he,{"data-testid":"about-env-table",children:[e.jsx(ge,{children:e.jsxs(K,{children:[e.jsx(_,{children:"Name"}),e.jsx(_,{children:"Value"})]})}),e.jsxs(pe,{children:[s.operatorEnv.length===0&&e.jsx(K,{children:e.jsx(I,{colSpan:2,className:"text-muted-foreground",children:"No environment variables reported."})}),s.operatorEnv.map(a=>e.jsxs(K,{children:[e.jsx(I,{className:"font-mono text-xs",children:a.name}),e.jsx(I,{className:"font-mono text-xs",children:a.value})]},a.name))]})]})]}),e.jsxs("section",{className:"flex flex-col gap-1","data-testid":"about-node",children:[e.jsx("h3",{className:"text-sm font-medium",children:"Node"}),s.node?e.jsxs("p",{className:"text-sm text-muted-foreground",children:[s.node.name," — kubelet ",s.node.kubeletVersion," —"," ",s.node.ready?"Ready":"Not ready"]}):e.jsx("p",{className:"text-sm text-muted-foreground",children:"No node reported."})]}),e.jsxs("footer",{className:"text-xs text-muted-foreground","data-testid":"about-app-version",children:["oap ",s.appVersion]})]})]})}const At=[{id:"general",label:"General"},{id:"model",label:"Model"},{id:"cluster",label:"Cluster"},{id:"advanced",label:"Advanced"},{id:"about",label:"About"}];function Pt({apiBase:t}){const{state:s,error:l}=et(t);return e.jsxs("div",{className:"mx-auto flex h-screen max-w-3xl flex-col gap-4 p-6",children:[e.jsxs("header",{className:"flex items-center justify-between gap-4",children:[e.jsx("h1",{className:"text-lg font-semibold",children:"Desktop settings"}),e.jsx(Dt,{phase:s==null?void 0:s.phase,step:s==null?void 0:s.step})]}),l&&e.jsx(b,{variant:"destructive",children:e.jsx(N,{children:l})}),e.jsxs(ye,{defaultValue:"general",className:"flex min-h-0 flex-1 flex-col",children:[e.jsx(we,{className:"shrink-0 self-start",children:At.map(i=>e.jsx(Te,{value:i.id,children:i.label},i.id))}),e.jsx(H,{value:"general",className:"min-h-0 flex-1 overflow-y-auto",children:e.jsx(at,{apiBase:t,running:(s==null?void 0:s.running)??!1,kubectlCurrent:(s==null?void 0:s.kubectlCurrent)??!1})}),e.jsx(H,{value:"model",className:"min-h-0 flex-1 overflow-y-auto",children:e.jsx(nt,{apiBase:t,running:(s==null?void 0:s.running)??!1})}),e.jsx(H,{value:"cluster",className:"min-h-0 flex-1",children:e.jsx(wt,{apiBase:t,running:(s==null?void 0:s.running)??!1})}),e.jsx(H,{value:"advanced",className:"min-h-0 flex-1",children:e.jsx(Ct,{apiBase:t,running:(s==null?void 0:s.running)??!1})}),e.jsx(H,{value:"about",className:"min-h-0 flex-1 overflow-y-auto",children:e.jsx(Et,{apiBase:t})})]})]})}function Dt({phase:t,step:s}){return t?e.jsxs("div",{className:"text-sm text-muted-foreground",children:[e.jsx("span",{className:"font-medium text-foreground",children:t}),t==="starting"&&s&&e.jsxs("span",{children:[" — ",s]})]}):null}qe(Pt); diff --git a/pkg/web/webui/webassets/dist/system.DT_ax8I5.js b/pkg/web/webui/webassets/dist/system.BC8KWmm_.js similarity index 94% rename from pkg/web/webui/webassets/dist/system.DT_ax8I5.js rename to pkg/web/webui/webassets/dist/system.BC8KWmm_.js index 96b34fad..24943bc7 100644 --- a/pkg/web/webui/webassets/dist/system.DT_ax8I5.js +++ b/pkg/web/webui/webassets/dist/system.BC8KWmm_.js @@ -1 +1 @@ -import{C as c,b as l,c as x,d as m,e as u,B as f,m as h}from"./mount.BOEH1oNx.js";import{j as e,an as a,ae as g,ag as j,ay as p,az as C,c as N}from"./vendor.C5MRNvUt.js";const b={unauthorized:N,forbidden:C,notFound:p,expired:j,error:g,info:a},w={unauthorized:"text-warning",forbidden:"text-destructive",notFound:"text-muted-foreground",expired:"text-warning",error:"text-destructive",info:"text-primary"};function y({status:n,kind:t,title:d,message:o,actions:r}){const i=b[t]??a;return e.jsx("div",{className:"min-h-screen flex items-center justify-center p-6 bg-background text-foreground",children:e.jsxs(c,{className:"max-w-md w-full",children:[e.jsxs(l,{className:"flex flex-row items-center gap-3",children:[e.jsx(i,{className:x("h-6 w-6 shrink-0",w[t])}),e.jsx(m,{children:d})]}),e.jsxs(u,{className:"space-y-4",children:[e.jsx("p",{className:"text-sm text-muted-foreground",children:o}),r&&r.length>0&&e.jsx("div",{className:"flex gap-2",children:r.map(s=>e.jsx(f,{asChild:!0,variant:"secondary",children:e.jsx("a",{href:s.href,children:s.label})},s.href))}),e.jsxs("p",{className:"text-xs text-muted-foreground/60",children:["Status ",n]})]})]})})}h(y); +import{C as c,b as l,c as x,d as m,e as u,B as f,m as h}from"./mount.D4ypHaeQ.js";import{j as e,an as a,ae as g,ag as j,ay as p,az as C,c as N}from"./vendor.C5MRNvUt.js";const b={unauthorized:N,forbidden:C,notFound:p,expired:j,error:g,info:a},w={unauthorized:"text-warning",forbidden:"text-destructive",notFound:"text-muted-foreground",expired:"text-warning",error:"text-destructive",info:"text-primary"};function y({status:n,kind:t,title:d,message:o,actions:r}){const i=b[t]??a;return e.jsx("div",{className:"min-h-screen flex items-center justify-center p-6 bg-background text-foreground",children:e.jsxs(c,{className:"max-w-md w-full",children:[e.jsxs(l,{className:"flex flex-row items-center gap-3",children:[e.jsx(i,{className:x("h-6 w-6 shrink-0",w[t])}),e.jsx(m,{children:d})]}),e.jsxs(u,{className:"space-y-4",children:[e.jsx("p",{className:"text-sm text-muted-foreground",children:o}),r&&r.length>0&&e.jsx("div",{className:"flex gap-2",children:r.map(s=>e.jsx(f,{asChild:!0,variant:"secondary",children:e.jsx("a",{href:s.href,children:s.label})},s.href))}),e.jsxs("p",{className:"text-xs text-muted-foreground/60",children:["Status ",n]})]})]})})}h(y); diff --git a/test/e2e/bronzethread/testdata/browser-login-secret-source/bundle.json b/test/e2e/bronzethread/testdata/browser-login-secret-source/bundle.json index a6b9f5b2..a060113b 100644 --- a/test/e2e/bronzethread/testdata/browser-login-secret-source/bundle.json +++ b/test/e2e/bronzethread/testdata/browser-login-secret-source/bundle.json @@ -1,6 +1,6 @@ { "name": "browser-login-secret-source", - "description": "The headline Phase C proof: a credentialed sign-in driven through the REAL browser driver end to end — the filler fills a stored login with no secret reaching the model, acting is gated on a web_host#act plan-gate slot, ONE approval covers the whole acting phase, and the run reaches a cookie-gated protected page.\n\nTHE SITE IS STATEFUL (test/testbrowser.ServeLoginSite, selected by this bundle's LOGIN_SITE marker): GET / is a real sign-in form; POST /signin checks the credentials, sets a session cookie, and 303-redirects to /protected; /protected shows PROTECTED-CONTENT-SIGNED-IN only WITH that cookie. So reaching the sentinel proves the credentialed round trip actually happened, not that a scripted reply said so.\n\nTHE CREDENTIAL NEVER REACHES THE MODEL. The two web_type calls carry {{login.host.docker.internal.username}} / {{login.host.docker.internal.password}} placeholders; the filler substitutes the real values strictly inside the type tool's Execute, AFTER the loop recorded the raw placeholder args. The fixture password is \"s3cr3t-fixture\" (test/testbrowser.LoginPassword) and lastToolResultNotContains pins it absent from every type result, the protected-page read, and agentReplyNotContains pins it absent from the delivered reply. The type result is a bare \"typed into ref eN\" status — never the value.\n\nONE APPROVAL, MANY ACTING CALLS (the carried C3 durability check). The acting sequence makes FOUR web_host#act calls on the same host — type username, type password, click submit, then click Continue on the protected page — and approvalPrompts is 1: the single plan-gate card that approves the signin phase binds the web_host slot, and every acting call after it runs on that grant. A regression that re-prompted per call would auto-approve (tool_approval is in autoApprove deliberately) and surface here as a count of 2+, not a hang. planGate.approvalPrompts:1 and the recorded authz decision web_host:host=2Edocker=2Einternal#act = allowed are the airtight form: the escaped host id is C-R4's chain (spicedb_escape, dots are illegal in a SpiceDB object id), and an allow could only have come from the slot grant the approval wrote — this fixture ships no owner tuple for web_host.\n\nThe AgentClass REFERENCES the toolbox (spec.browserToolboxes) — mandatory, because a web_host slot can only be declared by a referencing class (pkg/controllers/agentclass/browser_slot.go). That makes the operator stand up a per-session browser pod and hold the runner until it is Ready; the e2e harness fakes that readiness (no kubelet in envtest) and the reconciler resolves the login catalog from the directCredentials `secret` identity itself.\n\nEverything is asserted on the TOOL RESULT, never the reply.", + "description": "The headline Phase C proof: a credentialed sign-in driven through the REAL browser driver end to end — the filler fills a stored login with no secret reaching the model, acting is gated on a web_host#act plan-gate slot, ONE approval covers the whole acting phase, and the run reaches a cookie-gated protected page.\n\nTHE SITE IS STATEFUL (test/testbrowser.ServeLoginSite, selected by this bundle's LOGIN_SITE marker): GET / is a real sign-in form; POST /signin checks the credentials, sets a session cookie, and 303-redirects to /protected; /protected shows PROTECTED-CONTENT-SIGNED-IN only WITH that cookie. So reaching the sentinel proves the credentialed round trip actually happened, not that a scripted reply said so.\n\nTHE CREDENTIAL NEVER REACHES THE MODEL. The two web_type calls carry {{login.host.docker.internal.username}} / {{login.host.docker.internal.password}} placeholders; the filler substitutes the real values strictly inside the type tool's Execute, AFTER the loop recorded the raw placeholder args. The fixture password is \"s3cr3t-fixture\" (test/testbrowser.LoginPassword) and lastToolResultNotContains pins it absent from every type result, the protected-page read, and agentReplyNotContains pins it absent from the delivered reply. The type result is a bare \"typed into ref eN\" status — never the value.\n\nONE APPROVAL, MANY ACTING CALLS (the carried C3 durability check). The acting sequence makes FOUR web_host#act calls on the same host — type username, type password, click submit, then click Continue on the protected page — and approvalPrompts is 1: the single plan-gate card that approves the signin phase binds the web_host slot, and every acting call after it runs on that grant. A regression that re-prompted per call would auto-approve (tool_approval is in autoApprove deliberately) and surface here as a count of 2+, not a hang. planGate.approvalPrompts:1 and the recorded authz decision web_host:host=2Edocker=2Einternal#act = allowed are the airtight form: the escaped host id is C-R4's chain (spicedb_escape, dots are illegal in a SpiceDB object id), and an allow could only have come from the slot grant the approval wrote — this fixture ships no owner tuple for web_host.\n\nThe AgentClass REFERENCES the toolbox (spec.browserToolboxes) — mandatory, because a web_host slot can only be declared by a referencing class (pkg/controllers/agentclass/browser_slot.go). That makes the operator stand up a per-session browser pod and hold the runner until it is Ready; the e2e harness fakes that readiness (no kubelet in envtest) and the reconciler resolves the login catalog from the directCredentials `secret` identity itself.\n\nEverything is asserted on the TOOL RESULT, never the reply.\n\nPHASE D PROOF: the single web_host#act plan-gate card this run publishes also carries a redacted page screenshot. The e2e in-process Loop now wires a real client.Client (test/e2e/inprocess_runner_factory.go, scoped to this one consumer — see its comment there for why it does not also turn on MCP-UI widget persistence), so storeScreenshotArtifact can actually Create the ArtifactRender{Kind:\"image\"} CR instead of failing closed to text-only. approvalScreenshotAttached asserts the published interaction_request's Screenshot.RenderName is non-empty — proving the capture→redact→store→attach path ran for real against the live browser session behind this sign-in, not just that the unit/integration tests for each stage pass in isolation.", "agentDir": "testdata/browser-login-secret-source/manifests", "agentClass": "browser-login-secret-source", @@ -99,6 +99,7 @@ "agentReplyNotContains": ["s3cr3t-fixture"], "toolsCalled": ["web_navigate", "web_read", "web_type", "web_click", "web_wait_for"], "approvalPrompts": 1, + "approvalScreenshotAttached": true, "authz": { "decisions": { "web_host:host=2Edocker=2Einternal#act": "allowed" diff --git a/test/e2e/inprocess_runner_factory.go b/test/e2e/inprocess_runner_factory.go index be0635c2..93e07898 100644 --- a/test/e2e/inprocess_runner_factory.go +++ b/test/e2e/inprocess_runner_factory.go @@ -2026,6 +2026,23 @@ func (f *InProcessRunnerFactory) buildLoop(sess *spiceboxv1alpha1.AgentSession, // reaches the provider natively could never pass. ArtifactReader: env.ArtifactReader, + // Client mirrors internal/cmd/runner/main.go's identical field: the real + // manager-cached client over this test's envtest apiserver (f.K8s, the + // SAME client the placeholder-pod and RunnerEnv.Client wiring above + // already use). Wiring it here is scoped to exactly one consumer this + // harness previously left dark: browser_screenshot.go's + // storeScreenshotArtifact, which fails closed ("no k8s client wired") + // and ships every browser approval/human-step card text-only without + // it. It does NOT also turn on applyUIResource's widget-persistence + // path (loop.go's uiResourceDeps{Client: l.Client, Artifacts: + // l.Artifacts, ...}) — that path gates on BOTH deps.Client AND + // deps.Artifacts being non-nil, and Artifacts is deliberately left + // unset below, so every other e2e scenario's widget behavior is + // unchanged by this field. nil only for a factory built directly in a + // unit test with no K8s set (f.K8s itself defaults to nil there), + // which is exactly today's pre-existing fallback. + Client: f.K8s, + // LabelStore is the same instance threaded into every MCPTool // in buildMCPTools above. The Loop's approval-emit path // snapshots it into the outbound ToolApprovalRequestPayload. diff --git a/test/e2e/threadrun/driver.go b/test/e2e/threadrun/driver.go index 79ceb06b..e67af7c6 100644 --- a/test/e2e/threadrun/driver.go +++ b/test/e2e/threadrun/driver.go @@ -480,6 +480,7 @@ func Run(t *testing.T, dir string, b bt.Bundle) *e2e.Harness { // wantSessionPhaseFor is "" and this is a no-op. checkSessionPhase(t, h, b) checkApprovalPromptCount(t, h, b) + checkApprovalScreenshotAttached(t, h, b) checkSystemPrompt(t, h, b) checkTriggerStatus(t, h, b) checkChannelPosts(t, h, b) @@ -1497,6 +1498,30 @@ func checkApprovalPromptCount(t *testing.T, h *e2e.Harness, b bt.Bundle) { "published interaction approval prompts") } +// checkApprovalScreenshotAttached asserts that at least one published +// interaction approval prompt carries a non-empty +// InteractionRequestPayload.Screenshot.RenderName (Assertions. +// ApprovalScreenshotAttached). This reads the recorded PAYLOAD, not the +// reply — a scripted turn says the same words whether or not the redacted +// page screenshot (Phase D of the browser-approval-screenshots feature) rode +// along with the card, so only the payload itself can prove it attached. +func checkApprovalScreenshotAttached(t *testing.T, h *e2e.Harness, b bt.Bundle) { + t.Helper() + if !b.Assert.ApprovalScreenshotAttached { + return + } + prompts := h.PublishedApprovalPrompts() + found := false + for _, p := range prompts { + if p.Payload.Screenshot != nil && p.Payload.Screenshot.RenderName != "" { + found = true + break + } + } + assert.True(t, found, + "expected at least one published approval prompt to carry a non-empty Screenshot.RenderName (got %d prompts)", len(prompts)) +} + // checkPlanGate evaluates the plan-gate assertions against the recorded log. func checkPlanGate(t *testing.T, h *e2e.Harness, b bt.Bundle) { t.Helper()