@copilotkit/web-inspector 1.70.0 → 1.70.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/components/learning-view.cjs +1415 -0
  2. package/dist/components/learning-view.cjs.map +1 -0
  3. package/dist/components/learning-view.mjs +1415 -0
  4. package/dist/components/learning-view.mjs.map +1 -0
  5. package/dist/index.cjs +1437 -609
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.d.cts +64 -27
  8. package/dist/index.d.cts.map +1 -1
  9. package/dist/index.d.mts +64 -27
  10. package/dist/index.d.mts.map +1 -1
  11. package/dist/index.mjs +1440 -612
  12. package/dist/index.mjs.map +1 -1
  13. package/dist/index.umd.js +3224 -734
  14. package/dist/index.umd.js.map +1 -1
  15. package/dist/lib/home-briefing.cjs +19 -5
  16. package/dist/lib/home-briefing.cjs.map +1 -1
  17. package/dist/lib/home-briefing.mjs +19 -6
  18. package/dist/lib/home-briefing.mjs.map +1 -1
  19. package/dist/lib/inspector-learning.cjs +37 -0
  20. package/dist/lib/inspector-learning.cjs.map +1 -0
  21. package/dist/lib/inspector-learning.mjs +36 -0
  22. package/dist/lib/inspector-learning.mjs.map +1 -0
  23. package/dist/lib/learning-setup.cjs +83 -0
  24. package/dist/lib/learning-setup.cjs.map +1 -0
  25. package/dist/lib/learning-setup.mjs +78 -0
  26. package/dist/lib/learning-setup.mjs.map +1 -0
  27. package/dist/lib/persistence.cjs +56 -3
  28. package/dist/lib/persistence.cjs.map +1 -1
  29. package/dist/lib/persistence.mjs +54 -4
  30. package/dist/lib/persistence.mjs.map +1 -1
  31. package/dist/lib/telemetry.cjs +65 -0
  32. package/dist/lib/telemetry.cjs.map +1 -1
  33. package/dist/lib/telemetry.d.cts.map +1 -1
  34. package/dist/lib/telemetry.d.mts.map +1 -1
  35. package/dist/lib/telemetry.mjs +56 -1
  36. package/dist/lib/telemetry.mjs.map +1 -1
  37. package/dist/package.cjs +1 -1
  38. package/dist/package.mjs +1 -1
  39. package/dist/styles/generated.cjs +1 -1
  40. package/dist/styles/generated.cjs.map +1 -1
  41. package/dist/styles/generated.mjs +1 -1
  42. package/dist/styles/generated.mjs.map +1 -1
  43. package/package.json +5 -3
package/dist/index.mjs CHANGED
@@ -1,14 +1,17 @@
1
1
  import generated_default from "./styles/generated.mjs";
2
2
  import inspector_logo_default from "./assets/inspector-logo.mjs";
3
3
  import inspector_logo_kite_default from "./assets/inspector-logo-kite.mjs";
4
+ import { deriveLearningViewState } from "./components/learning-view.mjs";
4
5
  import { applyAnchorPosition, centerContext, clampSize, constrainToViewport, keepPositionWithinViewport, updateAnchorFromPosition, updateSizeFromElement } from "./lib/context-helpers.mjs";
5
- import { clearLegacyAnnouncementReadState, isValidAnchor, isValidDockMode, isValidPosition, isValidSize, loadAnnouncementPulsedTimestamp, loadAnnouncementReadTimestamp, loadInspectorState, saveAnnouncementPulsedTimestamp, saveAnnouncementReadTimestamp, saveInspectorState } from "./lib/persistence.mjs";
6
+ import { INSPECTOR_DISMISSAL_MAX_DURATION_MS, clearLegacyAnnouncementReadState, isValidAnchor, isValidDockMode, isValidPosition, isValidSize, loadAnnouncementPulsedTimestamp, loadAnnouncementReadTimestamp, loadInspectorDismissedUntil, loadInspectorState, saveAnnouncementPulsedTimestamp, saveAnnouncementReadTimestamp, saveInspectorDismissedUntil, saveInspectorState } from "./lib/persistence.mjs";
7
+ import { clearLearningSetupMarker, learningSetupMarkerMatches, readLearningSetupMarker, subscribeToLearningSetupMarker, writeLearningSetupMarker } from "./lib/learning-setup.mjs";
8
+ import { InspectorLearningUnsupportedError, fetchInspectorLearning } from "./lib/inspector-learning.mjs";
6
9
  import { buildPopOutFeatures, ensureBrandFont, openPopOutWindow } from "./lib/pop-out.mjs";
7
10
  import { projectInspectorMetadata } from "./lib/inspector-metadata.mjs";
8
- import { buildHomeModel, runtimeConnectionNeedsAttention } from "./lib/home-briefing.mjs";
11
+ import { buildHomeModel, homeFeatureImplementationPrompt, runtimeConnectionNeedsAttention } from "./lib/home-briefing.mjs";
9
12
  import { INSPECTOR_GROUPS, INSPECTOR_NAV_SECTIONS, getGroupForMenu, isInspectorMenuKey, shouldUseIconRail } from "./lib/inspector-nav.mjs";
10
13
  import { selectVisibleRealThreadId } from "./lib/thread-selection.mjs";
11
- import { TELEMETRY_DOCS_URL, ensureTelemetryDistinctId, getRuntimeUrlType, getTelemetryDistinctIdForUrl, maybeShowDisclosure, trackErrorSignalViewed, trackHomeCtaClicked, trackHomePromptCopied, trackHomeStoryBeatSelected, trackHomeViewed, trackInspectorOpened, trackMemoriesTabClicked, trackMetadataActionClicked, trackMetadataModuleViewed, trackTalkToEngineerClicked, trackThreadsEmptyEnabledViewed, trackThreadsEnabledViewed, trackThreadsExampleSelected, trackThreadsExampleTourCompleted, trackThreadsExampleTourDismissed, trackThreadsExampleTourReopened, trackThreadsExampleTourStarted, trackThreadsExampleTourStepViewed, trackThreadsExampleViewed, trackThreadsIntelligenceSignupClicked, trackThreadsLockedViewed, trackThreadsTabClicked, trackThreadsTalkToEngineerClicked, trackThreadsTryFromHereClicked, trackWhatsNewClicked, trackWhatsNewSignalViewed, trackWhatsNewViewed } from "./lib/telemetry.mjs";
14
+ import { TELEMETRY_DOCS_URL, ensureTelemetryDistinctId, getRuntimeUrlType, getTelemetryDistinctIdForUrl, learningCountBucket, learningDurationBucket, maybeShowDisclosure, trackErrorSignalViewed, trackHomeCtaClicked, trackHomeFeaturePromptClicked, trackHomePromptCopied, trackHomeStoryBeatSelected, trackHomeViewed, trackInspectorOpened, trackLearningEvidenceOpened, trackLearningPageChanged, trackLearningPaneViewed, trackLearningSetupPromptClicked, trackLearningSkillToggled, trackLearningSnapshotLoaded, trackLearningWebAppOpened, trackMemoriesTabClicked, trackMetadataActionClicked, trackMetadataModuleViewed, trackTalkToEngineerClicked, trackThreadsEmptyEnabledViewed, trackThreadsEnabledViewed, trackThreadsExampleSelected, trackThreadsExampleTourCompleted, trackThreadsExampleTourDismissed, trackThreadsExampleTourReopened, trackThreadsExampleTourStarted, trackThreadsExampleTourStepViewed, trackThreadsExampleViewed, trackThreadsIntelligenceSignupClicked, trackThreadsLockedViewed, trackThreadsTabClicked, trackThreadsTalkToEngineerClicked, trackThreadsTryFromHereClicked, trackWhatsNewClicked, trackWhatsNewSignalViewed, trackWhatsNewViewed } from "./lib/telemetry.mjs";
12
15
  import { createOnboardingPrompt, createOnboardingRunId } from "./lib/onboarding-prompt.mjs";
13
16
  import { LitElement, css, html, nothing, render, unsafeCSS } from "lit";
14
17
  import { marked } from "marked";
@@ -111,20 +114,15 @@ const EVENT_ERROR_GUIDANCE = {
111
114
  * an announcement, and it would double the spoken length.
112
115
  */
113
116
  const PILL_SUBLINE_LABEL = "Open Inspector for details";
114
- const HUD_OPEN_INSPECTOR_LABEL = "Open Inspector";
115
- const HUD_THREADS_OFF_LABEL = "Turn on Threads";
116
- const HUD_THREADS_ON_LABEL = "Threads on";
117
- const HUD_INTELLIGENCE_OFF_LABEL = "Turn on Intelligence";
118
- const HUD_INTELLIGENCE_ON_LABEL = "Intelligence connected";
119
- const HUD_THREADS_OFF_DETAIL = "Inspect conversations from this app.";
120
- const HUD_THREADS_ON_DETAIL = "Threads is on. Opens the Threads view.";
121
- const HUD_INTELLIGENCE_OFF_DETAIL = "Connect Intelligence to use Threads and Learning.";
122
- const HUD_INTELLIGENCE_ON_DETAIL = "Intelligence is connected. Opens Home.";
123
- const HUD_LEARNING_OFF_LABEL = "Turn on Learning";
124
- const HUD_LEARNING_ON_LABEL = "Learning on";
125
- const HUD_LEARNING_OFF_DETAIL = "Connect Intelligence to use Learning.";
126
- const HUD_LEARNING_ON_DETAIL = "Learning is on. Opens the Learning view.";
127
- const HUD_OPEN_INSPECTOR_DETAIL = "Same as clicking the circle. Opens the full Inspector.";
117
+ const HUD_INSPECTOR_LABEL = "CopilotKit Inspector";
118
+ const HUD_ANNOUNCEMENT_TITLE_LIMIT = 80;
119
+ const HUD_THREADS_LABEL = "Rich Threads";
120
+ const HUD_LEARNING_LABEL = "Automatic Learning";
121
+ const HUD_LEARN_MORE_LABEL = "Click to learn more";
122
+ const INSPECTOR_DISMISSAL_MS = {
123
+ day: 1440 * 60 * 1e3,
124
+ week: INSPECTOR_DISMISSAL_MAX_DURATION_MS
125
+ };
128
126
  const LAUNCHER_SIGNALS = {
129
127
  "whats-new": {
130
128
  tone: "news",
@@ -242,22 +240,24 @@ const THREAD_LIST_DEBOUNCE_MS = 300;
242
240
  const LAUNCHER_BASE_LABEL = "Web Inspector";
243
241
  const EDGE_MARGIN = 16;
244
242
  /** HUD card plus the hover bridge. Used to pick left vs right. */
245
- const LAUNCHER_HUD_WIDTH = 248;
243
+ const LAUNCHER_HUD_WIDTH = 258;
246
244
  /**
247
245
  * One page-load preview of the launcher's feature HUD.
248
246
  *
249
- * The card arrives after the host page has had a beat to settle. Its four rows
250
- * then come online in order, stay readable, and leave together. Nothing is
251
- * persisted: a new Inspector element means a new preview.
247
+ * The card arrives after the host page has had a beat to settle. Its feature
248
+ * contents then arrive from top to bottom, stay readable, and leave together.
249
+ * Nothing is persisted: a new Inspector element means a new preview.
252
250
  */
253
251
  const LAUNCHER_HUD_INTRO_MS = {
254
252
  delay: 500,
255
253
  duration: 3400,
256
- rowStart: 180,
257
- rowStagger: 170,
258
- rowDuration: 300,
254
+ waterfallStart: 180,
255
+ waterfallStagger: 170,
256
+ waterfallDuration: 300,
259
257
  blockedRetry: 250
260
258
  };
259
+ /** Return the staggered reveal delay for one launcher HUD layer. */
260
+ const launcherHudWaterfallDelay = (introIndex) => `${LAUNCHER_HUD_INTRO_MS.waterfallStart + introIndex * LAUNCHER_HUD_INTRO_MS.waterfallStagger}ms`;
261
261
  const DRAG_THRESHOLD = 6;
262
262
  const MIN_WINDOW_WIDTH = 880;
263
263
  const MIN_WINDOW_WIDTH_DOCKED_LEFT = 640;
@@ -286,17 +286,7 @@ function createPlaygroundThreadId() {
286
286
  return globalThis.crypto?.randomUUID?.() ?? `playground-${Date.now()}`;
287
287
  }
288
288
  const THREADS_DOCS_URL = "https://docs.copilotkit.ai/threads";
289
- const THREADS_RUNTIME_SETUP_DOCS_URL = "https://docs.copilotkit.ai/backend/runtime-endpoints#enable-rich-threads-routes";
290
- const THREADS_RUNTIME_SETUP_PROMPT = [
291
- `Read ${THREADS_RUNTIME_SETUP_DOCS_URL} and finish setting up Rich Threads in this repository.`,
292
- "",
293
- "First inspect the repository's agent instructions, installed CopilotKit versions, Runtime adapter, frontend provider, route or proxy setup, and existing authentication. Preserve the current framework and deployment model. Preserve existing authentication middleware and access checks on every Runtime route.",
294
- "",
295
- "Follow the guide to enable the multi-route Runtime, align the frontend transport, scope identifyUser to the existing server-verified signed-in application user, and expose the full Runtime subtree for GET, POST, PATCH, and DELETE. Never use a fixed demo identity in production. If no trusted user identity exists, stop and ask me which auth source to use.",
296
- "",
297
- "Start the app and verify GET {basePath}/info reports threadEndpoints.list, inspect, mutations, and realtimeMetadata as true. Run focused tests, lint, and typecheck. Report the files changed, commands run, and verification result. If blocked, explain the missing input; do not invent setup."
298
- ].join("\n");
299
- const SELF_HOSTED_INTELLIGENCE_URL = "https://docs.copilotkit.ai/premium/self-hosting";
289
+ const SELF_HOSTED_INTELLIGENCE_URL = "https://docs.copilotkit.ai/intelligence/self-hosting";
300
290
  const INTELLIGENCE_STORY_BEATS = [
301
291
  {
302
292
  id: "threads",
@@ -401,6 +391,52 @@ const INTELLIGENCE_STORY_CHAIN = [
401
391
  ];
402
392
  const THREADS_EXAMPLE_OVERVIEW_VIDEO_URL = "https://cdn.copilotkit.ai/corp-site/videos/copilotkit-generative-ui-agentic-frontend-demo.webm";
403
393
  const THREADS_EXAMPLE_OVERVIEW_VIDEO_FALLBACK = "The demo video is unavailable. Use the example threads to explore Messages, AG-UI Events, and State.";
394
+ const THREADS_LOCKED_VIDEO_URL = "https://www.loom.com/embed/79817778d29e490c97225127d2f17b3a?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true&hide_speed=true";
395
+ const LEARNING_LOCKED_VIDEO_URL = "https://www.loom.com/embed/2978fbfe42324e509057ac5fd46b7a70?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true&hide_speed=true";
396
+ const THREADS_LOCKED_FEATURE_OUTLINE = [
397
+ {
398
+ icon: "MessagesSquare",
399
+ title: "The whole conversation comes back",
400
+ description: "Rich Threads restores the complete interaction, not just a transcript. Messages, tool calls, shared state, generated interfaces, and supported files return together when a user reopens the thread."
401
+ },
402
+ {
403
+ icon: "LayoutGrid",
404
+ title: "Generated UI stays in the thread",
405
+ description: "Cards, charts, A2UI surfaces, MCP Apps, and tool renderers remain part of the conversation. The demo above shows a generated spending chart returning after a reload."
406
+ },
407
+ {
408
+ icon: "RefreshCw",
409
+ title: "Return without starting over",
410
+ description: "Users can move across sessions and devices while thread lists stay synchronized across open tabs. Rich Threads replays missed events and reconnects to work already in progress."
411
+ },
412
+ {
413
+ icon: "Server",
414
+ title: "Infrastructure you do not have to rebuild",
415
+ description: "CopilotKit handles durable event storage, replay, synchronization, lifecycle APIs, and thread locks on one portable AG-UI history model. Use CopilotKit Cloud or deploy Intelligence in your own Kubernetes environment."
416
+ }
417
+ ];
418
+ const LEARNING_LOCKED_FEATURE_OUTLINE = [
419
+ {
420
+ icon: "History",
421
+ title: "Memory across sessions",
422
+ description: "Keep useful facts, preferences, and decisions after the thread closes. Learning gives future conversations the context they need without asking users to repeat themselves."
423
+ },
424
+ {
425
+ icon: "Search",
426
+ title: "Recall by meaning",
427
+ description: "Surface relevant memories by what they mean, not by an exact phrase. Your agent can bring the right context into a new interaction even when the user asks in a completely different way."
428
+ },
429
+ {
430
+ icon: "Layers",
431
+ title: "Built-in structure",
432
+ description: "Turn raw interactions into organized topical, episodic, and operational knowledge. Learning separates enduring facts from individual experiences and useful instructions automatically."
433
+ },
434
+ {
435
+ icon: "Eye",
436
+ title: "Full visibility",
437
+ description: "Inspect exactly what your agent learned and trace each memory back to the threads that shaped it. Review the stored context instead of treating memory like a black box."
438
+ }
439
+ ];
404
440
  const THREADS_EXAMPLE_TOUR_STORAGE_KEY = "cpk:inspector:threads-example-tour:v1";
405
441
  const THREADS_EXAMPLE_AGENT_ID = "threads-feature";
406
442
  /** Keep one row per thread id when flattening per-agent stores. */
@@ -4866,6 +4902,21 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
4866
4902
  this._memoryUnsub = null;
4867
4903
  this._memorySubscribed = false;
4868
4904
  this._memoryStoreUnsupported = false;
4905
+ this.learningSnapshot = null;
4906
+ this.learningSnapshotScope = null;
4907
+ this.learningProjectIdentity = null;
4908
+ this.learningLoading = false;
4909
+ this.learningRefreshing = false;
4910
+ this.learningError = null;
4911
+ this.learningSupported = false;
4912
+ this.learningRequestGeneration = 0;
4913
+ this.learningAbortController = null;
4914
+ this.learningPollTimer = null;
4915
+ this.learningPollFailureCount = 0;
4916
+ this.learningSetupMarker = null;
4917
+ this.learningSetupUnsubscribe = null;
4918
+ this.learningPromptCopyState = "idle";
4919
+ this.learningViewedState = null;
4869
4920
  this._recallResults = null;
4870
4921
  this._recallLoading = false;
4871
4922
  this._recallError = null;
@@ -5023,11 +5074,12 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
5023
5074
  this.pillTimeoutId = null;
5024
5075
  this.launcherHudOpen = false;
5025
5076
  this.launcherHudSide = "left";
5026
- this.launcherHudHelp = null;
5027
5077
  this.launcherHudCloseTimer = null;
5028
5078
  this.launcherHudIntro = false;
5029
5079
  this.launcherHudIntroStartTimer = null;
5030
5080
  this.launcherHudIntroEndTimer = null;
5081
+ this.inspectorDismissedUntil = null;
5082
+ this.inspectorDismissalTimer = null;
5031
5083
  this.hudLandingMenu = null;
5032
5084
  this.pillOutcome = null;
5033
5085
  this.viewedNewsSignalIds = /* @__PURE__ */ new Set();
@@ -5055,9 +5107,9 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
5055
5107
  this.threadsExampleOverviewVideoPlayAttemptGeneration = 0;
5056
5108
  this.threadsExampleOverviewVideoPlayPromise = null;
5057
5109
  this.threadsExampleOverviewVideoPlayOnNextBind = false;
5058
- this.threadsSetupPromptCopyState = "idle";
5059
- this.threadsSetupPromptCopyResetTimeoutId = null;
5060
- this.threadsSetupPromptCopyGeneration = 0;
5110
+ this.homeFeaturePromptCopyState = null;
5111
+ this.homeFeaturePromptCopyResetTimeoutId = null;
5112
+ this.homeFeaturePromptCopyGeneration = 0;
5061
5113
  this.contextState = {
5062
5114
  button: {
5063
5115
  position: {
@@ -5101,9 +5153,158 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
5101
5153
  this.resizeEdge = "se";
5102
5154
  this.isResizing = false;
5103
5155
  this.customTabIcons = { threads: `<svg class="h-3.5 w-3.5" width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M9.04167 15C8.29167 15 7.65972 14.7431 7.14583 14.2292C6.63194 13.7153 6.375 13.0972 6.375 12.375C6.375 11.3194 6.80208 10.3646 7.65625 9.51042C8.51042 8.65625 9.57639 8.125 10.8542 7.91667C10.8125 7.41667 10.6875 7.03819 10.4792 6.78125C10.2708 6.52431 9.98611 6.39583 9.625 6.39583C9.20833 6.39583 8.75694 6.56944 8.27083 6.91667C7.78472 7.26389 7.20833 7.83333 6.54167 8.625C5.45833 9.91667 4.66319 10.7569 4.15625 11.1458C3.64931 11.5347 3.10417 11.7292 2.52083 11.7292C1.8125 11.7292 1.21528 11.4653 0.729167 10.9375C0.243056 10.4097 0 9.77083 0 9.02083C0 8.27083 0.163194 7.50347 0.489583 6.71875C0.815972 5.93403 1.36806 4.99306 2.14583 3.89583C2.40972 3.53472 2.60417 3.22917 2.72917 2.97917C2.85417 2.72917 2.91667 2.52778 2.91667 2.375C2.91667 2.27778 2.89931 2.20486 2.86458 2.15625C2.82986 2.10764 2.77778 2.08333 2.70833 2.08333C2.56944 2.08333 2.39583 2.17014 2.1875 2.34375C1.97917 2.51736 1.73611 2.78472 1.45833 3.14583L0 1.66667C0.444444 1.125 0.895833 0.711806 1.35417 0.427083C1.8125 0.142361 2.26389 0 2.70833 0C3.34722 0 3.88889 0.222222 4.33333 0.666667C4.77778 1.11111 5 1.66667 5 2.33333C5 2.73611 4.89583 3.18056 4.6875 3.66667C4.47917 4.15278 4.13194 4.73611 3.64583 5.41667C3.11806 6.16667 2.72569 6.82639 2.46875 7.39583C2.21181 7.96528 2.08333 8.46528 2.08333 8.89583C2.08333 9.13194 2.12153 9.31597 2.19792 9.44792C2.27431 9.57986 2.38194 9.64583 2.52083 9.64583C2.65972 9.64583 2.78125 9.60764 2.88542 9.53125C2.98958 9.45486 3.18056 9.27083 3.45833 8.97917C3.63889 8.78472 3.85417 8.54514 4.10417 8.26042C4.35417 7.97569 4.65972 7.625 5.02083 7.20833C5.89583 6.16667 6.6875 5.42361 7.39583 4.97917C8.10417 4.53472 8.84722 4.3125 9.625 4.3125C10.5556 4.3125 11.3194 4.625 11.9167 5.25C12.5139 5.875 12.8542 6.72917 12.9375 7.8125H15V9.89583H12.9375C12.8264 11.4514 12.4201 12.691 11.7188 13.6146C11.0174 14.5382 10.125 15 9.04167 15ZM9.08333 12.9167C9.52778 12.9167 9.90278 12.6632 10.2083 12.1562C10.5139 11.6493 10.7222 10.9444 10.8333 10.0417C10.1944 10.1944 9.63889 10.4965 9.16667 10.9479C8.69444 11.3993 8.45833 11.8472 8.45833 12.2917C8.45833 12.4861 8.51389 12.6389 8.625 12.75C8.73611 12.8611 8.88889 12.9167 9.08333 12.9167Z" fill="currentColor"/></svg>` };
5156
+ this.refreshLearningSnapshot = async (options = {}) => {
5157
+ const core = this.core;
5158
+ const runtimeUrl = core?.runtimeUrl;
5159
+ this.learningSupported = Boolean(core?.inspectorLearning);
5160
+ if (!core || !runtimeUrl || !this.learningSupported) {
5161
+ this.clearLearningSnapshot();
5162
+ this.requestUpdate();
5163
+ this.trackLearningViewState();
5164
+ return;
5165
+ }
5166
+ this.cancelLearningPoll();
5167
+ const startedAt = performance.now();
5168
+ let loadOutcome = "failure";
5169
+ let loadedSkills = 0;
5170
+ let loadedInsights = 0;
5171
+ let loadedPendingThreads = 0;
5172
+ let resetSkillsPage = false;
5173
+ let resetInsightsPage = false;
5174
+ const previousSnapshot = this.learningSnapshot;
5175
+ const agentId = this.getLearningAgentId();
5176
+ const requestContext = `${runtimeUrl.replace(/\/+$/u, "")}|${agentId ?? ""}`;
5177
+ if (this.learningSnapshotScope && !this.learningSnapshotScope.startsWith(`${requestContext}|`)) this.clearLearningSnapshot();
5178
+ const generation = ++this.learningRequestGeneration;
5179
+ this.learningAbortController?.abort();
5180
+ const controller = new AbortController();
5181
+ this.learningAbortController = controller;
5182
+ const preserve = options.preserve === true && this.learningSnapshot !== null;
5183
+ this.learningLoading = !preserve;
5184
+ this.learningRefreshing = preserve;
5185
+ this.learningError = null;
5186
+ this.requestUpdate();
5187
+ try {
5188
+ const snapshot = await fetchInspectorLearning({
5189
+ runtimeUrl,
5190
+ runtimeTransport: core.runtimeTransport,
5191
+ request: {
5192
+ ...agentId ? { agentId } : {},
5193
+ skillsPage: options.skillsPage ?? this.learningSnapshot?.skillsPage.page ?? 1,
5194
+ insightsPage: options.insightsPage ?? this.learningSnapshot?.insightsPage.page ?? 1
5195
+ },
5196
+ fetch: core.ɵruntimeFetch,
5197
+ headers: core.headers,
5198
+ credentials: core.credentials,
5199
+ signal: controller.signal
5200
+ });
5201
+ if (generation !== this.learningRequestGeneration) return;
5202
+ if (snapshot.pendingThreadCount > 0 && !snapshot.links.runs || snapshot.pendingCandidateCount > 0 && !snapshot.links.candidates) throw new Error("Learning snapshot is missing a required web-app link.");
5203
+ const containerId = snapshot.configuration.state === "configured" ? snapshot.configuration.container.id : "";
5204
+ const previousContainerId = previousSnapshot?.configuration.state === "configured" ? previousSnapshot.configuration.container.id : "";
5205
+ const scopeChanged = previousSnapshot !== null && (previousSnapshot.projectKey !== snapshot.projectKey || previousContainerId !== containerId);
5206
+ const isBackgroundRefresh = options.skillsPage === void 0 && options.insightsPage === void 0;
5207
+ resetSkillsPage = Boolean(isBackgroundRefresh && previousSnapshot && previousSnapshot.skillsPage.page > 1 && (scopeChanged || JSON.stringify([previousSnapshot.skillsPage.total, previousSnapshot.skillsPage.items.map((skill) => [skill.id, skill.revision])]) !== JSON.stringify([snapshot.skillsPage.total, snapshot.skillsPage.items.map((skill) => [skill.id, skill.revision])])));
5208
+ resetInsightsPage = Boolean(isBackgroundRefresh && previousSnapshot && previousSnapshot.insightsPage.page > 1 && (scopeChanged || JSON.stringify([previousSnapshot.insightsPage.total, previousSnapshot.insightsPage.items.map((insight) => insight.id)]) !== JSON.stringify([snapshot.insightsPage.total, snapshot.insightsPage.items.map((insight) => insight.id)])));
5209
+ this.learningSnapshot = snapshot;
5210
+ loadOutcome = "success";
5211
+ loadedSkills = snapshot.skillsPage.total;
5212
+ loadedInsights = snapshot.insightsPage.total;
5213
+ loadedPendingThreads = snapshot.pendingThreadCount;
5214
+ this.learningSnapshotScope = `${requestContext}|${snapshot.projectKey}|${containerId}`;
5215
+ this.learningError = null;
5216
+ this.learningPollFailureCount = 0;
5217
+ if (snapshot.configuration.state === "configured") {
5218
+ clearLearningSetupMarker();
5219
+ this.learningSetupMarker = null;
5220
+ }
5221
+ } catch (error) {
5222
+ if (generation !== this.learningRequestGeneration || controller.signal.aborted) return;
5223
+ if (error instanceof InspectorLearningUnsupportedError) {
5224
+ loadOutcome = "unsupported";
5225
+ this.learningSupported = false;
5226
+ this.learningSnapshot = null;
5227
+ } else {
5228
+ this.learningError = error instanceof Error ? error.message : "Learning data is unavailable.";
5229
+ this.learningPollFailureCount += 1;
5230
+ }
5231
+ } finally {
5232
+ if (generation === this.learningRequestGeneration) {
5233
+ this.learningLoading = false;
5234
+ this.learningRefreshing = false;
5235
+ this.learningAbortController = null;
5236
+ if (!core.telemetryDisabled) trackLearningSnapshotLoaded({
5237
+ outcome: loadOutcome,
5238
+ duration_bucket: learningDurationBucket(performance.now() - startedAt),
5239
+ skills_bucket: learningCountBucket(loadedSkills),
5240
+ insights_bucket: learningCountBucket(loadedInsights),
5241
+ pending_threads_bucket: learningCountBucket(loadedPendingThreads)
5242
+ });
5243
+ this.scheduleLearningPoll();
5244
+ this.requestUpdate();
5245
+ this.trackLearningViewState();
5246
+ if (resetSkillsPage || resetInsightsPage) this.refreshLearningSnapshot({
5247
+ preserve: true,
5248
+ ...resetSkillsPage ? { skillsPage: 1 } : {},
5249
+ ...resetInsightsPage ? { insightsPage: 1 } : {}
5250
+ });
5251
+ }
5252
+ }
5253
+ };
5254
+ this.copyFeaturePromptToClipboard = async (service, event, onboardingRunId = createOnboardingRunId()) => {
5255
+ const clipboard = this.getClipboard(event);
5256
+ if (!clipboard?.writeText) return false;
5257
+ try {
5258
+ await clipboard.writeText(homeFeatureImplementationPrompt(service, { onboardingRunId }));
5259
+ return true;
5260
+ } catch {
5261
+ return false;
5262
+ }
5263
+ };
5264
+ this.handleLearningSetupCopy = async (event) => {
5265
+ const service = this.getHomeFeaturePromptTarget("threads");
5266
+ if (!service || !this.core?.runtimeUrl) return;
5267
+ const copied = await this.copyFeaturePromptToClipboard(service, event, this.getOnboardingRunId());
5268
+ if (!this.core.telemetryDisabled) trackLearningSetupPromptClicked({ outcome: copied ? "success" : "failure" });
5269
+ if (!copied) {
5270
+ this.learningPromptCopyState = "error";
5271
+ this.requestUpdate();
5272
+ return;
5273
+ }
5274
+ this.learningPromptCopyState = "copied";
5275
+ this.learningSetupMarker = writeLearningSetupMarker({
5276
+ runtimeUrl: this.core.runtimeUrl,
5277
+ agentId: this.getLearningAgentId()
5278
+ });
5279
+ this.selectedMenu = "memories";
5280
+ this.persistState();
5281
+ this.requestUpdate();
5282
+ this.refreshLearningSnapshot({ preserve: false });
5283
+ };
5284
+ this.handleLearningPage = (event) => {
5285
+ const { section, page } = event.detail;
5286
+ const currentPage = section === "skills" ? this.learningSnapshot?.skillsPage.page ?? 1 : this.learningSnapshot?.insightsPage.page ?? 1;
5287
+ if (!this.core?.telemetryDisabled) trackLearningPageChanged({
5288
+ section,
5289
+ direction: page < currentPage ? "previous" : "next"
5290
+ });
5291
+ this.refreshLearningSnapshot({
5292
+ preserve: true,
5293
+ ...section === "skills" ? { skillsPage: page } : { insightsPage: page }
5294
+ });
5295
+ };
5296
+ this.handleLearningEvidence = (event) => {
5297
+ this.focusThread({
5298
+ threadId: event.detail.threadId,
5299
+ ...event.detail.messageId ? { messageId: event.detail.messageId } : {}
5300
+ });
5301
+ };
5104
5302
  this.handleDocumentVisibilityChange = () => {
5105
5303
  this.accountCtaMotionPaused = document.visibilityState !== "visible";
5106
- if (document.visibilityState === "visible" && !this.isOpen) this.flushPendingSignalPulse();
5304
+ this.refreshInspectorDismissalState();
5305
+ if (document.visibilityState === "visible" && !this.isOpen && !this.isInspectorDismissed) this.flushPendingSignalPulse();
5306
+ if (document.visibilityState === "visible" && this.isOpen && this.selectedMenu === "memories") this.refreshLearningSnapshot({ preserve: true });
5307
+ else this.cancelLearningPoll();
5107
5308
  this.requestUpdate();
5108
5309
  };
5109
5310
  this.handlePillClick = (event) => {
@@ -5143,21 +5344,33 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
5143
5344
  this.handleHudActionClick = (event, row) => {
5144
5345
  event.preventDefault();
5145
5346
  event.stopPropagation();
5146
- this.hudLandingMenu = row === "inspector" ? null : row === "threads" ? "threads" : row === "learning" ? "memories" : "home";
5347
+ this.hudLandingMenu = row === "threads" ? "threads" : row === "learning" ? "memories" : "home";
5147
5348
  this.closeLauncherHud();
5148
5349
  this.openInspector("floating_button");
5149
5350
  };
5150
- this.handleHudHelpClick = (event, row) => {
5151
- event.preventDefault();
5152
- event.stopPropagation();
5153
- this.launcherHudHelp = this.launcherHudHelp === row ? null : row;
5154
- this.requestUpdate();
5155
- };
5156
5351
  this.handleHudRowClick = (event, row) => {
5157
5352
  const target = event.target;
5158
- if (target instanceof Element && target.closest(".cpk-launcher-hud__help, [data-cpk-hud-action]")) return;
5353
+ if (target instanceof Element && target.closest(".cpk-launcher-hud__controls, [data-cpk-hud-action]")) return;
5159
5354
  this.handleHudActionClick(event, row);
5160
5355
  };
5356
+ this.handleHudNewsClick = (event) => {
5357
+ event.preventDefault();
5358
+ event.stopPropagation();
5359
+ this.hudLandingMenu = WHATS_NEW_MENU_KEY;
5360
+ this.closeLauncherHud();
5361
+ this.openInspector("floating_button");
5362
+ };
5363
+ this.handleHudNewsDismissClick = (event) => {
5364
+ event.preventDefault();
5365
+ event.stopPropagation();
5366
+ this.clearNewsSignal();
5367
+ this.activeRoot.querySelector(".console-button")?.focus({ preventScroll: true });
5368
+ };
5369
+ this.handleHudDismissDayClick = (event) => {
5370
+ event.preventDefault();
5371
+ event.stopPropagation();
5372
+ this.dismissInspectorFor("day");
5373
+ };
5161
5374
  this.handleSidebarToggle = () => {
5162
5375
  this.sidebarRailTooltip = null;
5163
5376
  this.sidebarCollapsed = !this.sidebarCollapsed;
@@ -5200,6 +5413,22 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
5200
5413
  this.applyEventErrorLanding(key);
5201
5414
  this.requestUpdate();
5202
5415
  };
5416
+ this.handleHomeFeaturePromptCopy = async (service, event) => {
5417
+ const generation = this.homeFeaturePromptCopyGeneration += 1;
5418
+ if (this.homeFeaturePromptCopyResetTimeoutId !== null) {
5419
+ window.clearTimeout(this.homeFeaturePromptCopyResetTimeoutId);
5420
+ this.homeFeaturePromptCopyResetTimeoutId = null;
5421
+ }
5422
+ this.homeFeaturePromptCopyState = null;
5423
+ this.requestUpdate();
5424
+ const onboardingRunId = createOnboardingRunId();
5425
+ if (!this.core?.telemetryDisabled) trackHomeFeaturePromptClicked({
5426
+ feature_id: service.id,
5427
+ onboarding_run_id: onboardingRunId
5428
+ });
5429
+ if (await this.copyFeaturePromptToClipboard(service, event, onboardingRunId)) this.showHomeFeaturePromptCopyState(service.id, "copied", generation);
5430
+ else this.showHomeFeaturePromptCopyState(service.id, "error", generation);
5431
+ };
5203
5432
  this.handleIntelligencePromptCopy = async (event) => {
5204
5433
  this.clearIntelligencePromptReset();
5205
5434
  const runId = this.getOnboardingRunId();
@@ -5679,26 +5908,6 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
5679
5908
  }
5680
5909
  this.playThreadsExampleOverviewVideo(video, lifecycleGeneration);
5681
5910
  };
5682
- this.handleThreadsSetupPromptCopy = async (event) => {
5683
- const generation = this.threadsSetupPromptCopyGeneration += 1;
5684
- if (this.threadsSetupPromptCopyResetTimeoutId !== null) {
5685
- window.clearTimeout(this.threadsSetupPromptCopyResetTimeoutId);
5686
- this.threadsSetupPromptCopyResetTimeoutId = null;
5687
- }
5688
- this.threadsSetupPromptCopyState = "idle";
5689
- this.requestUpdate();
5690
- const clipboard = this.getClipboard(event);
5691
- if (!clipboard?.writeText) {
5692
- this.showThreadsSetupPromptCopyState("error", generation);
5693
- return;
5694
- }
5695
- try {
5696
- await clipboard.writeText(THREADS_RUNTIME_SETUP_PROMPT);
5697
- this.showThreadsSetupPromptCopyState("copied", generation);
5698
- } catch {
5699
- this.showThreadsSetupPromptCopyState("error", generation);
5700
- }
5701
- };
5702
5911
  this.handleClearEvents = () => {
5703
5912
  if (this.selectedContext === "all-agents") {
5704
5913
  this.agentEvents.clear();
@@ -6044,9 +6253,6 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
6044
6253
  getThreadsDocsUrl() {
6045
6254
  return this.appendRefParam(THREADS_DOCS_URL, "cpk-inspector-threads");
6046
6255
  }
6047
- getThreadsRuntimeSetupDocsUrl() {
6048
- return this.appendRefParam(THREADS_RUNTIME_SETUP_DOCS_URL, "cpk-inspector-threads");
6049
- }
6050
6256
  getThreadsIntelligenceSignupUrl() {
6051
6257
  return this.appendRefParam(INTELLIGENCE_SIGNUP_URL, "cpk-inspector-threads");
6052
6258
  }
@@ -6074,6 +6280,7 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
6074
6280
  this._threadsByAgent.set(agentId, threads);
6075
6281
  this.rebuildFlattenedThreads();
6076
6282
  this.autoSelectLatestThread();
6283
+ if (this.selectedMenu === "memories" && this.shouldPollLearningSetup() && !this.learningLoading && !this.learningRefreshing) this.refreshLearningSnapshot({ preserve: true });
6077
6284
  this.requestUpdate();
6078
6285
  });
6079
6286
  const statusSub = store.select(createThreadStoreStatusSelector()).subscribe(({ error, isLoading }) => {
@@ -6254,6 +6461,8 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
6254
6461
  this.clearAllEventErrors();
6255
6462
  const supportsInspectorMetadata = this.coreSupportsInspectorMetadata(core);
6256
6463
  this.updateInspectorMetadataProjection(this.readCoreInspectorMetadata(core));
6464
+ this.learningSupported = core.inspectorLearning;
6465
+ this.learningProjectIdentity = JSON.stringify(this.inspectorMetadataProjection.identity ?? null);
6257
6466
  this.coreSubscriber = {
6258
6467
  onRuntimeConnectionStatusChanged: ({ status }) => {
6259
6468
  this.runtimeStatus = status;
@@ -6261,16 +6470,22 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
6261
6470
  const threadCapabilityWasEnabled = this.threadCapabilityEnabled === true;
6262
6471
  this.synchronizeThreadCapability();
6263
6472
  if (status === "connected") {
6473
+ this.learningSupported = core.inspectorLearning;
6264
6474
  if (!core.telemetryDisabled) {
6265
6475
  ensureTelemetryDistinctId();
6266
6476
  maybeShowDisclosure();
6267
6477
  }
6268
6478
  this.flushPendingWhatsNewTelemetry();
6479
+ if (this.isOpen && this.selectedMenu === "memories") {
6480
+ this.clearLearningSnapshot();
6481
+ this.refreshLearningSnapshot({ preserve: false });
6482
+ }
6269
6483
  if (threadCapabilityWasEnabled && this.areThreadEndpointsAvailable()) for (const agentId of this._ownedThreadStores.keys()) this.refreshOwnedThreadStore(agentId);
6270
6484
  } else {
6271
6485
  this._threadsByAgent.clear();
6272
6486
  this._threads = [];
6273
6487
  this.clearInspectorUsageRefresh();
6488
+ this.clearLearningSnapshot();
6274
6489
  }
6275
6490
  this.requestUpdate();
6276
6491
  },
@@ -6285,6 +6500,12 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
6285
6500
  ...supportsInspectorMetadata ? { onInspectorMetadataChanged: ({ inspectorMetadata }) => {
6286
6501
  if (this._core !== core) return;
6287
6502
  this.updateInspectorMetadataProjection(inspectorMetadata);
6503
+ const identity = JSON.stringify(this.inspectorMetadataProjection.identity ?? null);
6504
+ if (identity !== this.learningProjectIdentity) {
6505
+ this.learningProjectIdentity = identity;
6506
+ this.clearLearningSnapshot();
6507
+ if (this.isOpen && this.selectedMenu === "memories") this.refreshLearningSnapshot({ preserve: false });
6508
+ }
6288
6509
  this.requestUpdate();
6289
6510
  } } : {},
6290
6511
  onError: ({ code, error, context }) => {
@@ -6444,6 +6665,64 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
6444
6665
  this._recallQuery = "";
6445
6666
  this.requestUpdate();
6446
6667
  }
6668
+ getLearningAgentId() {
6669
+ if (this.selectedContext !== "all-agents" && this.core?.agents[this.selectedContext]) return this.selectedContext;
6670
+ return null;
6671
+ }
6672
+ isLearningSetupActive() {
6673
+ const runtimeUrl = this.core?.runtimeUrl;
6674
+ if (!runtimeUrl) return false;
6675
+ return learningSetupMarkerMatches(this.learningSetupMarker, runtimeUrl, this.getLearningAgentId());
6676
+ }
6677
+ trackLearningViewState() {
6678
+ if (!this.isOpen || this.selectedMenu !== "memories" || this.core?.telemetryDisabled) return;
6679
+ const state = deriveLearningViewState({
6680
+ supported: this.learningSupported,
6681
+ loading: this.learningLoading,
6682
+ error: this.learningError,
6683
+ snapshot: this.learningSnapshot,
6684
+ setupActive: this.isLearningSetupActive()
6685
+ });
6686
+ if (state === this.learningViewedState) return;
6687
+ this.learningViewedState = state;
6688
+ trackLearningPaneViewed({ state });
6689
+ }
6690
+ cancelLearningPoll() {
6691
+ if (this.learningPollTimer !== null) {
6692
+ clearTimeout(this.learningPollTimer);
6693
+ this.learningPollTimer = null;
6694
+ }
6695
+ }
6696
+ shouldPollLearningSetup() {
6697
+ if (!this.isOpen || this.selectedMenu !== "memories" || document.visibilityState !== "visible" || !this.learningSupported) return false;
6698
+ const snapshot = this.learningSnapshot;
6699
+ if (!snapshot) return this.isLearningSetupActive();
6700
+ if (snapshot.configuration.state === "not_configured") return this.isLearningSetupActive();
6701
+ return snapshot.configuration.state === "configured" && !snapshot.run.hasEverSucceeded && !snapshot.run.hasActiveRun && snapshot.pendingThreadCount === 0 && snapshot.skillsPage.total === 0 && snapshot.insightsPage.total === 0;
6702
+ }
6703
+ scheduleLearningPoll() {
6704
+ this.cancelLearningPoll();
6705
+ if (!this.shouldPollLearningSetup()) return;
6706
+ const delay = this.learningPollFailureCount === 0 ? 5e3 : this.learningPollFailureCount === 1 ? 1e4 : 3e4;
6707
+ this.learningPollTimer = setTimeout(() => {
6708
+ this.learningPollTimer = null;
6709
+ this.refreshLearningSnapshot({ preserve: true });
6710
+ }, delay);
6711
+ }
6712
+ clearLearningSnapshot() {
6713
+ this.cancelLearningRequest();
6714
+ this.learningSnapshot = null;
6715
+ this.learningSnapshotScope = null;
6716
+ this.learningError = null;
6717
+ this.learningLoading = false;
6718
+ this.learningRefreshing = false;
6719
+ this.cancelLearningPoll();
6720
+ }
6721
+ cancelLearningRequest() {
6722
+ this.learningRequestGeneration += 1;
6723
+ this.learningAbortController?.abort();
6724
+ this.learningAbortController = null;
6725
+ }
6447
6726
  detachFromCore() {
6448
6727
  this.threadCapabilityGeneration += 1;
6449
6728
  this.threadCapabilityEnabled = null;
@@ -6470,6 +6749,8 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
6470
6749
  this._recallLoading = false;
6471
6750
  this._recallError = null;
6472
6751
  this._recallQuery = "";
6752
+ this.clearLearningSnapshot();
6753
+ this.learningSupported = false;
6473
6754
  this.coreSubscriber = null;
6474
6755
  this.runtimeStatus = null;
6475
6756
  this.cancelThreadRefreshDebounce();
@@ -6496,6 +6777,7 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
6496
6777
  this.eventCounter = 0;
6497
6778
  }
6498
6779
  processAgentsChanged(agents) {
6780
+ const previousLearningAgentId = this.getLearningAgentId();
6499
6781
  this.synchronizeThreadCapability();
6500
6782
  const seenAgentIds = /* @__PURE__ */ new Set();
6501
6783
  for (const agent of Object.values(agents)) {
@@ -6511,6 +6793,15 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
6511
6793
  this.agentStates.delete(agentId);
6512
6794
  }
6513
6795
  this.updateContextOptions(seenAgentIds);
6796
+ const learningAgentId = this.getLearningAgentId();
6797
+ if (learningAgentId && this.core?.runtimeUrl && this.learningSetupMarker?.agentId === null && learningSetupMarkerMatches(this.learningSetupMarker, this.core.runtimeUrl, null)) this.learningSetupMarker = writeLearningSetupMarker({
6798
+ runtimeUrl: this.core.runtimeUrl,
6799
+ agentId: learningAgentId
6800
+ });
6801
+ if (previousLearningAgentId !== learningAgentId && this.isOpen && this.selectedMenu === "memories") {
6802
+ this.clearLearningSnapshot();
6803
+ this.refreshLearningSnapshot({ preserve: false });
6804
+ }
6514
6805
  this.refreshToolsSnapshot();
6515
6806
  this.requestUpdate();
6516
6807
  }
@@ -8095,56 +8386,66 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
8095
8386
 
8096
8387
  .cpk-launcher-hud {
8097
8388
  --hud-fill: var(--cpk-inspector-surface-dark);
8098
- --hud-line: rgb(190 194 255 / 0.5);
8389
+ --hud-line: rgb(190 194 255 / 0.38);
8390
+ --hud-accent: #b8adf5;
8391
+ --hud-accent-soft: rgb(184 173 245 / 0.13);
8392
+ --hud-hover-fill: #252231;
8099
8393
  --hud-blur: blur(12px) saturate(1.2);
8394
+ --hud-card-gap: 8px;
8395
+ --hud-dismiss-day-height: 32px;
8100
8396
  position: absolute;
8101
- top: 0;
8102
8397
  z-index: 4;
8103
- padding-right: 14px;
8398
+ width: 258px;
8104
8399
  pointer-events: none;
8105
8400
  opacity: 0;
8106
8401
  visibility: hidden;
8107
- transform: translateX(8px);
8108
8402
  transition:
8109
8403
  opacity 160ms ease,
8110
8404
  transform 200ms cubic-bezier(0.16, 1, 0.3, 1);
8111
8405
  }
8112
8406
 
8407
+ .cpk-launcher-hud[data-cpk-hud-vertical="top"] {
8408
+ top: 0;
8409
+ bottom: auto;
8410
+ }
8411
+
8412
+ .cpk-launcher-hud[data-cpk-hud-vertical="bottom"] {
8413
+ top: auto;
8414
+ bottom: 0;
8415
+ }
8416
+
8113
8417
  .cpk-launcher-hud[data-cpk-hud-side="left"] {
8114
8418
  right: 100%;
8419
+ left: auto;
8115
8420
  padding-right: 14px;
8116
- padding-left: 0;
8421
+ transform: translateX(8px);
8117
8422
  }
8118
8423
 
8119
8424
  .cpk-launcher-hud[data-cpk-hud-side="right"] {
8120
8425
  left: 100%;
8121
8426
  right: auto;
8122
- padding-right: 0;
8123
8427
  padding-left: 14px;
8124
8428
  transform: translateX(-8px);
8125
8429
  }
8126
8430
 
8127
- .console-button-wrapper[data-cpk-hud="open"]
8128
- .cpk-launcher-hud[data-cpk-hud-side="right"] {
8431
+ .console-button-wrapper[data-cpk-hud="open"] .cpk-launcher-hud {
8129
8432
  transform: none;
8130
8433
  }
8131
8434
 
8132
8435
  .cpk-launcher-hud__card {
8133
8436
  position: relative;
8134
- width: 228px;
8135
- padding: 4px;
8136
- border: 1px dotted var(--hud-line);
8137
- border-radius: var(--cpk-inspector-shell-radius);
8138
- background: var(--hud-fill);
8437
+ display: grid;
8438
+ width: 244px;
8439
+ gap: var(--hud-card-gap);
8139
8440
  color: #fff;
8140
- backdrop-filter: var(--hud-blur);
8141
- -webkit-backdrop-filter: var(--hud-blur);
8142
- box-shadow: 0 8px 20px rgb(1 5 7 / 0.18);
8143
8441
  }
8144
8442
 
8145
8443
  .cpk-launcher-hud[data-color-scheme="light"] {
8146
8444
  --hud-fill: #fff;
8147
- --hud-line: #d8d8e8;
8445
+ --hud-line: #ddd6f4;
8446
+ --hud-accent: #6757b0;
8447
+ --hud-accent-soft: #f1edff;
8448
+ --hud-hover-fill: #f1edff;
8148
8449
  }
8149
8450
 
8150
8451
  .cpk-launcher-hud[data-color-scheme="light"] .cpk-launcher-hud__card {
@@ -8154,205 +8455,543 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
8154
8455
  .cpk-launcher-hud__arrow {
8155
8456
  position: absolute;
8156
8457
  top: calc(var(--cpk-launcher-size) / 2);
8157
- z-index: 1;
8458
+ z-index: 2;
8158
8459
  width: 10px;
8159
8460
  height: 10px;
8160
8461
  border: 0;
8161
- /* The card frosts the page behind it, so it reads lighter than the
8162
- raw fill. Mix a little white so the arrow matches the glass card
8163
- without going lighter than the HUD. */
8164
- background: color-mix(in srgb, var(--hud-fill) 88%, white 12%);
8165
- transform: translateY(-50%) rotate(45deg);
8462
+ background: var(--hud-fill);
8463
+ transform: rotate(45deg);
8464
+ transition: background 120ms ease;
8166
8465
  }
8167
8466
 
8168
8467
  .cpk-launcher-hud[data-cpk-hud-side="left"] .cpk-launcher-hud__arrow {
8169
8468
  right: 9px;
8469
+ border-top: 1px solid var(--hud-line);
8470
+ border-right: 1px solid var(--hud-line);
8170
8471
  }
8171
8472
 
8172
8473
  .cpk-launcher-hud[data-cpk-hud-side="right"] .cpk-launcher-hud__arrow {
8173
8474
  left: 9px;
8475
+ border-bottom: 1px solid var(--hud-line);
8476
+ border-left: 1px solid var(--hud-line);
8174
8477
  }
8175
8478
 
8176
- .cpk-launcher-hud__list {
8177
- margin: 0;
8178
- padding: 0;
8179
- list-style: none;
8479
+ .cpk-launcher-hud[data-cpk-hud-vertical="top"] .cpk-launcher-hud__arrow {
8480
+ top: calc(var(--cpk-launcher-size) / 2 - 5px);
8180
8481
  }
8181
8482
 
8182
- .cpk-launcher-hud__list + .cpk-launcher-hud__list {
8183
- margin-top: 4px;
8184
- padding-top: 4px;
8185
- border-top: 1px dotted var(--hud-line);
8483
+ .cpk-launcher-hud[data-cpk-hud-vertical="bottom"]
8484
+ .cpk-launcher-hud__arrow {
8485
+ top: auto;
8486
+ bottom: calc(var(--cpk-launcher-size) / 2 - 5px);
8186
8487
  }
8187
8488
 
8188
- .cpk-launcher-hud__row {
8189
- position: relative;
8190
- display: grid;
8191
- grid-template-columns: 1fr 28px;
8192
- align-items: start;
8193
- border-radius: 7px;
8194
- cursor: pointer;
8489
+ /* A bottom-anchored HUD can end with the narrower dismissal bubble.
8490
+ Keep the pointer attached to the full-width feature panel instead of
8491
+ letting it float in the empty space beside that final action. */
8492
+ .cpk-launcher-hud[data-cpk-hud-vertical="bottom"]:has(
8493
+ .cpk-launcher-hud__dismiss-day
8494
+ )
8495
+ .cpk-launcher-hud__arrow {
8496
+ bottom: calc(
8497
+ var(--hud-dismiss-day-height) + var(--hud-card-gap) + 2px
8498
+ );
8195
8499
  }
8196
8500
 
8197
- .cpk-launcher-hud__row + .cpk-launcher-hud__row {
8198
- margin-top: 1px;
8501
+ .cpk-launcher-hud__list {
8502
+ margin: 0;
8503
+ padding: 0;
8504
+ list-style: none;
8199
8505
  }
8200
8506
 
8201
- .cpk-launcher-hud__row:hover,
8202
- .cpk-launcher-hud__row:focus-within,
8203
- .cpk-launcher-hud__row[data-cpk-hud-help="open"] {
8204
- background: rgb(255 255 255 / 0.06);
8507
+ .cpk-launcher-hud__masthead {
8508
+ position: relative;
8509
+ z-index: 1;
8510
+ margin-top: 6px;
8511
+ padding: 0;
8512
+ border: 1px solid var(--hud-line);
8513
+ border-radius: var(--cpk-inspector-shell-radius);
8514
+ background: var(--hud-fill);
8515
+ backdrop-filter: var(--hud-blur);
8516
+ -webkit-backdrop-filter: var(--hud-blur);
8517
+ box-shadow: 0 10px 28px rgb(46 37 91 / 0.16);
8518
+ transition: background 120ms ease;
8205
8519
  }
8206
8520
 
8207
- .cpk-launcher-hud[data-color-scheme="light"] .cpk-launcher-hud__row:hover,
8208
- .cpk-launcher-hud[data-color-scheme="light"]
8209
- .cpk-launcher-hud__row:focus-within,
8210
- .cpk-launcher-hud[data-color-scheme="light"]
8211
- .cpk-launcher-hud__row[data-cpk-hud-help="open"] {
8212
- background: #f0f0f4;
8521
+ .cpk-launcher-hud__news-wrap {
8522
+ position: relative;
8523
+ margin: 0;
8213
8524
  }
8214
8525
 
8215
- .cpk-launcher-hud__action {
8526
+ .cpk-launcher-hud__news {
8527
+ position: relative;
8216
8528
  display: flex;
8217
- gap: 8px;
8218
- min-height: 32px;
8219
- align-items: center;
8220
- padding: 6px 8px;
8529
+ width: 100%;
8530
+ min-width: 0;
8531
+ flex-direction: column;
8532
+ align-items: flex-start;
8533
+ padding: 18px 12px 11px;
8221
8534
  border: 0;
8222
- border-radius: 7px;
8535
+ border-radius: calc(var(--cpk-inspector-shell-radius) - 1px);
8223
8536
  background: transparent;
8224
8537
  color: #fff;
8225
8538
  font-family: inherit;
8226
- font-size: 12px;
8227
- font-weight: 600;
8539
+ line-height: 1;
8228
8540
  text-align: start;
8229
8541
  cursor: pointer;
8230
8542
  }
8231
8543
 
8232
- .cpk-launcher-hud[data-color-scheme="light"] .cpk-launcher-hud__action {
8233
- color: #010507;
8544
+ .cpk-launcher-hud__news:hover,
8545
+ .cpk-launcher-hud__news:focus-visible {
8546
+ background: transparent;
8234
8547
  }
8235
8548
 
8236
- /* Stretch the row action over the whole tab, including the detail
8237
- copy. The help mark sits above this layer. */
8238
- .cpk-launcher-hud__action::after {
8239
- content: "";
8240
- position: absolute;
8241
- inset: 0;
8549
+ .cpk-launcher-hud__masthead:has(.cpk-launcher-hud__news:hover),
8550
+ .cpk-launcher-hud__masthead:has(.cpk-launcher-hud__news:focus-visible),
8551
+ .cpk-launcher-hud:has(.cpk-launcher-hud__news:hover)
8552
+ .cpk-launcher-hud__arrow,
8553
+ .cpk-launcher-hud:has(.cpk-launcher-hud__news:focus-visible)
8554
+ .cpk-launcher-hud__arrow {
8555
+ background: var(--hud-hover-fill);
8242
8556
  }
8243
8557
 
8244
- .cpk-launcher-hud__check {
8245
- flex: none;
8246
- width: 14px;
8247
- height: 14px;
8248
- color: #34d399;
8558
+ .cpk-launcher-hud__news:focus-visible {
8559
+ outline: 2px solid #bec2ff;
8560
+ outline-offset: 1px;
8249
8561
  }
8250
8562
 
8251
- .cpk-launcher-hud__help {
8252
- position: relative;
8253
- z-index: 1;
8563
+ .cpk-launcher-hud__news-title {
8564
+ display: block;
8565
+ font-size: 12px;
8566
+ font-weight: 650;
8567
+ line-height: 1.32;
8568
+ overflow-wrap: anywhere;
8569
+ white-space: normal;
8570
+ }
8571
+
8572
+ .cpk-launcher-hud__news-label {
8573
+ position: absolute;
8574
+ top: -9px;
8575
+ left: 12px;
8254
8576
  display: inline-flex;
8255
- width: 28px;
8256
- height: 32px;
8577
+ min-height: 20px;
8578
+ align-items: center;
8579
+ padding: 3px 8px;
8580
+ border-radius: 6px;
8581
+ background: #7563c7;
8582
+ color: #fff;
8583
+ box-shadow: 0 3px 8px rgb(46 37 91 / 0.18);
8584
+ font-size: 9px;
8585
+ font-weight: 700;
8586
+ line-height: 1;
8587
+ }
8588
+
8589
+ .cpk-launcher-hud__news-dismiss {
8590
+ position: absolute;
8591
+ top: -1px;
8592
+ right: 2px;
8593
+ z-index: 2;
8594
+ display: inline-flex;
8595
+ width: 20px;
8596
+ height: 20px;
8257
8597
  align-items: center;
8258
8598
  justify-content: center;
8259
8599
  padding: 0;
8260
8600
  border: 0;
8601
+ border-radius: 4px;
8261
8602
  background: transparent;
8262
- color: rgb(255 255 255 / 0.78);
8263
- font-size: 12px;
8264
- font-weight: 600;
8603
+ color: rgb(255 255 255 / 0.68);
8265
8604
  cursor: pointer;
8266
8605
  }
8267
8606
 
8268
- .cpk-launcher-hud__help span {
8269
- display: inline-flex;
8270
- width: 16px;
8271
- height: 16px;
8272
- align-items: center;
8273
- justify-content: center;
8274
- border: 1px dotted rgb(190 194 255 / 0.55);
8275
- border-radius: 50%;
8276
- line-height: 1;
8607
+ .cpk-launcher-hud__news-dismiss:hover,
8608
+ .cpk-launcher-hud__news-dismiss:focus-visible {
8609
+ background: var(--hud-accent-soft);
8610
+ color: #fff;
8277
8611
  }
8278
8612
 
8279
- .cpk-launcher-hud[data-color-scheme="light"] .cpk-launcher-hud__help {
8280
- color: #68686e;
8613
+ .cpk-launcher-hud[data-color-scheme="light"]
8614
+ .cpk-launcher-hud__news-dismiss {
8615
+ color: #6e697c;
8281
8616
  }
8282
8617
 
8283
- .cpk-launcher-hud__help:focus-visible,
8284
- .cpk-launcher-hud__action:focus-visible {
8618
+ .cpk-launcher-hud[data-color-scheme="light"]
8619
+ .cpk-launcher-hud__news-dismiss:hover,
8620
+ .cpk-launcher-hud[data-color-scheme="light"]
8621
+ .cpk-launcher-hud__news-dismiss:focus-visible {
8622
+ color: #27233a;
8623
+ }
8624
+
8625
+ .cpk-launcher-hud__news-dismiss:focus-visible {
8285
8626
  outline: 2px solid #bec2ff;
8286
8627
  outline-offset: 1px;
8287
8628
  }
8288
8629
 
8289
- .cpk-launcher-hud__detail {
8290
- grid-column: 1 / -1;
8291
- max-height: 0;
8630
+ .cpk-launcher-hud__news-dismiss svg {
8631
+ width: 7px;
8632
+ height: 7px;
8633
+ }
8634
+
8635
+ .cpk-launcher-hud[data-color-scheme="light"] .cpk-launcher-hud__news {
8636
+ color: #17131f;
8637
+ }
8638
+
8639
+ .cpk-launcher-hud__dismiss-day {
8640
+ position: relative;
8641
+ z-index: 1;
8642
+ display: flex;
8643
+ width: auto;
8644
+ min-height: var(--hud-dismiss-day-height);
8645
+ align-items: center;
8646
+ justify-content: center;
8647
+ justify-self: center;
8648
+ gap: 6px;
8292
8649
  margin: 0;
8293
- padding: 0 8px;
8294
- overflow: hidden;
8295
- color: rgb(255 255 255 / 0.78);
8296
- font-size: 11px;
8297
- font-weight: 400;
8298
- line-height: 1.4;
8299
- opacity: 0;
8300
- pointer-events: none;
8301
- transform: translateY(-6px);
8650
+ padding: 7px 13px;
8651
+ border: 1px solid var(--hud-line);
8652
+ border-radius: var(--cpk-inspector-shell-radius);
8653
+ background: var(--hud-fill);
8654
+ color: #c9cad3;
8655
+ box-shadow: 0 8px 20px rgb(17 14 29 / 0.18);
8656
+ font-family: inherit;
8657
+ font-size: 10px;
8658
+ font-weight: 650;
8659
+ line-height: 1.2;
8660
+ cursor: pointer;
8302
8661
  transition:
8303
- max-height 200ms cubic-bezier(0.16, 1, 0.3, 1),
8304
- opacity 150ms ease-out,
8305
- transform 200ms cubic-bezier(0.16, 1, 0.3, 1),
8306
- padding-bottom 200ms cubic-bezier(0.16, 1, 0.3, 1);
8662
+ border-color 120ms ease,
8663
+ background 120ms ease,
8664
+ color 120ms ease;
8307
8665
  }
8308
8666
 
8309
- .cpk-launcher-hud[data-color-scheme="light"] .cpk-launcher-hud__detail {
8310
- color: #68686e;
8667
+ .cpk-launcher-hud__dismiss-day:hover,
8668
+ .cpk-launcher-hud__dismiss-day:focus-visible {
8669
+ border-color: var(--hud-accent);
8670
+ background: var(--hud-hover-fill);
8671
+ color: #f3f4f8;
8311
8672
  }
8312
8673
 
8313
- .cpk-launcher-hud__row:hover .cpk-launcher-hud__detail,
8314
- .cpk-launcher-hud__row:focus-within .cpk-launcher-hud__detail,
8315
- .cpk-launcher-hud__row[data-cpk-hud-help="open"]
8316
- .cpk-launcher-hud__detail {
8317
- max-height: 72px;
8318
- padding: 0 8px 7px;
8319
- opacity: 1;
8320
- transform: none;
8674
+ .cpk-launcher-hud__dismiss-day:focus-visible {
8675
+ outline: 2px solid #bec2ff;
8676
+ outline-offset: 1px;
8321
8677
  }
8322
8678
 
8323
- @media (prefers-reduced-motion: reduce) {
8324
- .cpk-launcher-hud,
8325
- .cpk-launcher-hud__detail {
8326
- transition: none;
8327
- }
8679
+ .cpk-launcher-hud__dismiss-day svg {
8680
+ width: 12px;
8681
+ height: 12px;
8328
8682
  }
8329
8683
 
8330
- /*
8331
- * On mount, borrow the hover HUD for one short introduction. The card
8332
- * establishes the destination first; its rows then resolve in order so
8333
- * the eye can count the available features instead of receiving one
8334
- * undifferentiated block. Only opacity and transform move.
8335
- */
8336
- @keyframes cpk-launcher-hud-intro {
8337
- 0% {
8338
- opacity: 0;
8339
- transform: translateX(8px);
8340
- }
8341
- 8%,
8342
- 88% {
8343
- opacity: 1;
8344
- transform: none;
8345
- }
8346
- 100% {
8347
- opacity: 0;
8348
- transform: translateX(4px);
8349
- }
8684
+ .cpk-launcher-hud[data-color-scheme="light"]
8685
+ .cpk-launcher-hud__dismiss-day {
8686
+ box-shadow: 0 8px 20px rgb(46 37 91 / 0.12);
8687
+ color: #5f6068;
8350
8688
  }
8351
8689
 
8352
- @keyframes cpk-launcher-hud-intro-right {
8353
- 0% {
8354
- opacity: 0;
8355
- transform: translateX(-8px);
8690
+ .cpk-launcher-hud[data-color-scheme="light"]
8691
+ .cpk-launcher-hud__dismiss-day:hover,
8692
+ .cpk-launcher-hud[data-color-scheme="light"]
8693
+ .cpk-launcher-hud__dismiss-day:focus-visible {
8694
+ color: #36373d;
8695
+ }
8696
+
8697
+ .cpk-launcher-hud__feature-list {
8698
+ position: relative;
8699
+ z-index: 1;
8700
+ padding: 5px;
8701
+ border: 1px solid var(--hud-line);
8702
+ border-radius: var(--cpk-inspector-shell-radius);
8703
+ background: var(--hud-fill);
8704
+ backdrop-filter: var(--hud-blur);
8705
+ -webkit-backdrop-filter: var(--hud-blur);
8706
+ box-shadow: 0 10px 28px rgb(46 37 91 / 0.16);
8707
+ }
8708
+
8709
+ .cpk-launcher-hud__row {
8710
+ position: relative;
8711
+ display: grid;
8712
+ grid-template-columns: minmax(0, 1fr) auto;
8713
+ align-items: center;
8714
+ min-height: 54px;
8715
+ border-radius: 9px;
8716
+ cursor: pointer;
8717
+ }
8718
+
8719
+ .cpk-launcher-hud__row + .cpk-launcher-hud__row {
8720
+ border-top: 1px solid var(--hud-line);
8721
+ border-radius: 0 0 9px 9px;
8722
+ }
8723
+
8724
+ .cpk-launcher-hud__row:hover,
8725
+ .cpk-launcher-hud__row:focus-within {
8726
+ background: rgb(255 255 255 / 0.06);
8727
+ }
8728
+
8729
+ .cpk-launcher-hud[data-color-scheme="light"] .cpk-launcher-hud__row:hover,
8730
+ .cpk-launcher-hud[data-color-scheme="light"] .cpk-launcher-hud__row:focus-within {
8731
+ background: #f7f5ff;
8732
+ }
8733
+
8734
+ .cpk-launcher-hud__primary {
8735
+ position: relative;
8736
+ display: flex;
8737
+ min-width: 0;
8738
+ }
8739
+
8740
+ .cpk-launcher-hud__action {
8741
+ display: flex;
8742
+ width: 100%;
8743
+ gap: 8px;
8744
+ min-height: 52px;
8745
+ align-items: center;
8746
+ padding: 7px 4px;
8747
+ border: 0;
8748
+ border-radius: 9px;
8749
+ background: transparent;
8750
+ color: #fff;
8751
+ font-family: inherit;
8752
+ font-size: 12px;
8753
+ font-weight: 600;
8754
+ text-align: start;
8755
+ cursor: pointer;
8756
+ }
8757
+
8758
+ .cpk-launcher-hud__label {
8759
+ min-width: 0;
8760
+ }
8761
+
8762
+ .cpk-launcher-hud__feature-icon {
8763
+ display: inline-flex;
8764
+ width: 28px;
8765
+ height: 32px;
8766
+ flex: none;
8767
+ align-items: center;
8768
+ justify-content: center;
8769
+ background: transparent;
8770
+ color: var(--hud-accent);
8771
+ }
8772
+
8773
+ .cpk-launcher-hud__feature-icon svg {
8774
+ width: 17px;
8775
+ height: 17px;
8776
+ stroke-width: 1.8;
8777
+ }
8778
+
8779
+ .cpk-launcher-hud[data-color-scheme="light"] .cpk-launcher-hud__action {
8780
+ color: #010507;
8781
+ }
8782
+
8783
+ /* Stretch the row action over the whole tab. The icon controls sit
8784
+ above this layer and keep their own focused interactions. */
8785
+ .cpk-launcher-hud__action::after {
8786
+ content: "";
8787
+ position: absolute;
8788
+ inset: 0;
8789
+ }
8790
+
8791
+ .cpk-launcher-hud__controls {
8792
+ position: relative;
8793
+ z-index: 1;
8794
+ display: flex;
8795
+ gap: 0;
8796
+ align-items: center;
8797
+ padding-right: 5px;
8798
+ }
8799
+
8800
+ .cpk-launcher-hud__learn-more {
8801
+ display: inline-flex;
8802
+ width: 24px;
8803
+ height: 44px;
8804
+ align-items: center;
8805
+ justify-content: center;
8806
+ padding: 0;
8807
+ border: 0;
8808
+ background: transparent;
8809
+ color: rgb(190 194 255 / 0.72);
8810
+ cursor: pointer;
8811
+ }
8812
+
8813
+ .cpk-launcher-hud__learn-more:hover,
8814
+ .cpk-launcher-hud__learn-more:focus-visible {
8815
+ color: #fff;
8816
+ }
8817
+
8818
+ .cpk-launcher-hud[data-color-scheme="light"]
8819
+ .cpk-launcher-hud__learn-more {
8820
+ color: #777080;
8821
+ }
8822
+
8823
+ .cpk-launcher-hud[data-color-scheme="light"]
8824
+ .cpk-launcher-hud__learn-more:hover,
8825
+ .cpk-launcher-hud[data-color-scheme="light"]
8826
+ .cpk-launcher-hud__learn-more:focus-visible {
8827
+ color: #4b416b;
8828
+ }
8829
+
8830
+ .cpk-launcher-hud__learn-more svg {
8831
+ width: 16px;
8832
+ height: 16px;
8833
+ stroke-width: 1.8;
8834
+ }
8835
+
8836
+ .cpk-launcher-hud__toggle {
8837
+ display: inline-flex;
8838
+ width: 38px;
8839
+ height: 44px;
8840
+ align-items: center;
8841
+ justify-content: center;
8842
+ padding: 0;
8843
+ border: 0;
8844
+ background: transparent;
8845
+ color: rgb(255 255 255 / 0.78);
8846
+ font-size: 12px;
8847
+ font-weight: 600;
8848
+ cursor: pointer;
8849
+ }
8850
+
8851
+ .cpk-launcher-hud__toggle:disabled {
8852
+ cursor: not-allowed;
8853
+ opacity: 1;
8854
+ }
8855
+
8856
+ .cpk-launcher-hud__toggle-track {
8857
+ position: relative;
8858
+ display: block;
8859
+ width: 34px;
8860
+ height: 20px;
8861
+ border: 1px solid rgb(190 194 255 / 0.38);
8862
+ border-radius: 999px;
8863
+ background: rgb(255 255 255 / 0.08);
8864
+ transition:
8865
+ border-color 120ms ease,
8866
+ background 120ms ease;
8867
+ }
8868
+
8869
+ .cpk-launcher-hud__toggle-track::after {
8870
+ content: "";
8871
+ position: absolute;
8872
+ top: 2px;
8873
+ left: 2px;
8874
+ width: 14px;
8875
+ height: 14px;
8876
+ border-radius: 50%;
8877
+ background: #8c8e99;
8878
+ transition:
8879
+ background 120ms ease,
8880
+ transform 120ms ease;
8881
+ }
8882
+
8883
+ .cpk-launcher-hud__toggle[data-enabled="true"]
8884
+ .cpk-launcher-hud__toggle-track {
8885
+ border-color: var(--hud-accent);
8886
+ background: color-mix(in srgb, var(--hud-accent) 76%, transparent);
8887
+ }
8888
+
8889
+ .cpk-launcher-hud__toggle[data-enabled="true"]
8890
+ .cpk-launcher-hud__toggle-track::after {
8891
+ background: #fff;
8892
+ transform: translateX(14px);
8893
+ }
8894
+
8895
+ .cpk-launcher-hud[data-color-scheme="light"]
8896
+ .cpk-launcher-hud__toggle-track {
8897
+ border-color: #c9c9d2;
8898
+ background: #e7e7ec;
8899
+ }
8900
+
8901
+ .cpk-launcher-hud[data-color-scheme="light"]
8902
+ .cpk-launcher-hud__toggle-track::after {
8903
+ background: #777780;
8904
+ }
8905
+
8906
+ .cpk-launcher-hud[data-color-scheme="light"]
8907
+ .cpk-launcher-hud__toggle[data-enabled="true"]
8908
+ .cpk-launcher-hud__toggle-track {
8909
+ border-color: #6757b0;
8910
+ background: #7563c7;
8911
+ }
8912
+
8913
+ .cpk-launcher-hud[data-color-scheme="light"]
8914
+ .cpk-launcher-hud__toggle[data-enabled="true"]
8915
+ .cpk-launcher-hud__toggle-track::after {
8916
+ background: #fff;
8917
+ }
8918
+
8919
+ .cpk-launcher-hud__toggle:focus-visible,
8920
+ .cpk-launcher-hud__learn-more:focus-visible,
8921
+ .cpk-launcher-hud__action:focus-visible {
8922
+ outline: 2px solid #bec2ff;
8923
+ outline-offset: 1px;
8924
+ }
8925
+
8926
+ .cpk-launcher-hud__tooltip {
8927
+ position: absolute;
8928
+ top: 50%;
8929
+ z-index: 30;
8930
+ width: max-content;
8931
+ max-width: min(220px, 52vw);
8932
+ padding: 7px 9px;
8933
+ border: 1px solid #3a3d49;
8934
+ border-radius: 4px;
8935
+ background: #15171e;
8936
+ color: #f3f4f8;
8937
+ box-shadow: 0 8px 20px rgb(1 5 7 / 0.18);
8938
+ font-size: 10px;
8939
+ font-weight: 500;
8940
+ line-height: 1.45;
8941
+ opacity: 0;
8942
+ pointer-events: none;
8943
+ transform: translate(3px, -50%);
8944
+ white-space: normal;
8945
+ transition:
8946
+ opacity 120ms ease,
8947
+ transform 120ms ease;
8948
+ }
8949
+
8950
+ .cpk-launcher-hud__row:has(.cpk-launcher-hud__learn-more:hover)
8951
+ .cpk-launcher-hud__tooltip,
8952
+ .cpk-launcher-hud__row:has(.cpk-launcher-hud__learn-more:focus-visible)
8953
+ .cpk-launcher-hud__tooltip {
8954
+ opacity: 1;
8955
+ transform: translate(0, -50%);
8956
+ }
8957
+
8958
+ .cpk-launcher-hud[data-cpk-hud-side="left"] .cpk-launcher-hud__tooltip {
8959
+ right: calc(100% + 8px);
8960
+ left: auto;
8961
+ }
8962
+
8963
+ .cpk-launcher-hud[data-cpk-hud-side="right"] .cpk-launcher-hud__tooltip {
8964
+ right: auto;
8965
+ left: calc(100% + 8px);
8966
+ transform: translate(-3px, -50%);
8967
+ }
8968
+
8969
+ .cpk-launcher-hud[data-cpk-hud-side="right"]
8970
+ .cpk-launcher-hud__row:has(.cpk-launcher-hud__learn-more:hover)
8971
+ .cpk-launcher-hud__tooltip,
8972
+ .cpk-launcher-hud[data-cpk-hud-side="right"]
8973
+ .cpk-launcher-hud__row:has(.cpk-launcher-hud__learn-more:focus-visible)
8974
+ .cpk-launcher-hud__tooltip {
8975
+ transform: translate(0, -50%);
8976
+ }
8977
+
8978
+ @media (prefers-reduced-motion: reduce) {
8979
+ .cpk-launcher-hud,
8980
+ .cpk-launcher-hud__tooltip {
8981
+ transition: none;
8982
+ }
8983
+ }
8984
+
8985
+ /*
8986
+ * On mount, borrow the hover HUD for one short introduction. The card
8987
+ * establishes the destination first; notification, features, and hide
8988
+ * action then fall into place from top to bottom. Only opacity and
8989
+ * transform move.
8990
+ */
8991
+ @keyframes cpk-launcher-hud-intro {
8992
+ 0% {
8993
+ opacity: 0;
8994
+ transform: translateY(-4px);
8356
8995
  }
8357
8996
  8%,
8358
8997
  88% {
@@ -8361,14 +9000,14 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
8361
9000
  }
8362
9001
  100% {
8363
9002
  opacity: 0;
8364
- transform: translateX(-4px);
9003
+ transform: translateY(3px);
8365
9004
  }
8366
9005
  }
8367
9006
 
8368
- @keyframes cpk-launcher-hud-row-online {
9007
+ @keyframes cpk-launcher-hud-waterfall {
8369
9008
  from {
8370
9009
  opacity: 0;
8371
- transform: translateY(4px);
9010
+ transform: translateY(-8px);
8372
9011
  }
8373
9012
  to {
8374
9013
  opacity: 1;
@@ -8376,43 +9015,33 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
8376
9015
  }
8377
9016
  }
8378
9017
 
8379
- @keyframes cpk-launcher-hud-check-online {
8380
- from {
8381
- opacity: 0;
8382
- transform: scale(0.65);
8383
- }
8384
- to {
8385
- opacity: 1;
8386
- transform: scale(1);
8387
- }
8388
- }
8389
-
8390
9018
  .cpk-launcher-hud[data-cpk-hud-intro="true"] {
8391
9019
  animation: cpk-launcher-hud-intro var(--cpk-launcher-hud-intro-duration)
8392
9020
  cubic-bezier(0.16, 1, 0.3, 1) both;
8393
9021
  }
8394
9022
 
8395
- .cpk-launcher-hud[data-cpk-hud-intro="true"][data-cpk-hud-side="right"] {
8396
- animation-name: cpk-launcher-hud-intro-right;
8397
- }
8398
-
8399
- .cpk-launcher-hud[data-cpk-hud-intro="true"] .cpk-launcher-hud__row {
8400
- animation: cpk-launcher-hud-row-online
8401
- var(--cpk-launcher-hud-row-duration) cubic-bezier(0.16, 1, 0.3, 1)
8402
- both;
8403
- animation-delay: var(--cpk-hud-row-delay);
8404
- }
8405
-
8406
- .cpk-launcher-hud[data-cpk-hud-intro="true"] .cpk-launcher-hud__check {
8407
- animation: cpk-launcher-hud-check-online 220ms
9023
+ .cpk-launcher-hud[data-cpk-hud-intro="true"]
9024
+ :is(
9025
+ .cpk-launcher-hud__masthead,
9026
+ .cpk-launcher-hud__feature-list,
9027
+ .cpk-launcher-hud__row,
9028
+ .cpk-launcher-hud__dismiss-day
9029
+ ) {
9030
+ animation: cpk-launcher-hud-waterfall
9031
+ var(--cpk-launcher-hud-waterfall-duration)
8408
9032
  cubic-bezier(0.16, 1, 0.3, 1) both;
8409
- animation-delay: calc(var(--cpk-hud-row-delay) + 90ms);
9033
+ animation-delay: var(--cpk-hud-waterfall-delay);
8410
9034
  }
8411
9035
 
8412
9036
  @media (prefers-reduced-motion: reduce) {
8413
9037
  .cpk-launcher-hud[data-cpk-hud-intro="true"],
8414
- .cpk-launcher-hud[data-cpk-hud-intro="true"] .cpk-launcher-hud__row,
8415
- .cpk-launcher-hud[data-cpk-hud-intro="true"] .cpk-launcher-hud__check {
9038
+ .cpk-launcher-hud[data-cpk-hud-intro="true"]
9039
+ :is(
9040
+ .cpk-launcher-hud__masthead,
9041
+ .cpk-launcher-hud__feature-list,
9042
+ .cpk-launcher-hud__row,
9043
+ .cpk-launcher-hud__dismiss-day
9044
+ ) {
8416
9045
  animation: none !important;
8417
9046
  opacity: 1;
8418
9047
  transform: none;
@@ -8456,15 +9085,15 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
8456
9085
  }
8457
9086
 
8458
9087
  .inspector-account-strip {
8459
- background: linear-gradient(
8460
- 90deg,
8461
- #ffffff 0%,
8462
- #f3f1ff 58%,
8463
- #eefbf7 100%
8464
- ) !important;
9088
+ background: #f7f6fd !important;
8465
9089
  color: #010507 !important;
8466
9090
  }
8467
9091
 
9092
+ .inspector-window[data-color-scheme="dark"] .drag-handle,
9093
+ .inspector-window[data-color-scheme="dark"] .inspector-account-strip {
9094
+ background: #15171e !important;
9095
+ }
9096
+
8468
9097
  /* ── Tab buttons ─────────────────────────────────────────────── */
8469
9098
  /*
8470
9099
  * Named classes owned by this component — no Tailwind conflict.
@@ -8524,6 +9153,11 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
8524
9153
  height: 100%;
8525
9154
  object-fit: cover;
8526
9155
  }
9156
+ .cpk-threads-overview-video-embed {
9157
+ width: 100%;
9158
+ height: 100%;
9159
+ border: 0;
9160
+ }
8527
9161
 
8528
9162
  /* ── Header controls on the branded account strip ──────────── */
8529
9163
  .drag-handle > div[data-inspector-account-strip] button {
@@ -8827,11 +9461,18 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
8827
9461
  const viteHot = import.meta.hot;
8828
9462
  if (viteHot) viteHot.on("vite:beforeUpdate", this.handleAppBeforeUnload);
8829
9463
  this.hydrateStateFromStorageEarly();
9464
+ this.learningSetupMarker = readLearningSetupMarker();
9465
+ this.learningSetupUnsubscribe = subscribeToLearningSetupMarker((marker) => {
9466
+ this.learningSetupMarker = marker;
9467
+ this.requestUpdate();
9468
+ this.scheduleLearningPoll();
9469
+ });
9470
+ this.refreshInspectorDismissalState();
8830
9471
  this.subscribeToSystemColorScheme();
8831
9472
  this.exampleTourDismissed = this.readThreadsExampleTourDismissed();
8832
9473
  clearLegacyAnnouncementReadState();
8833
9474
  this.tryAutoAttachCore();
8834
- this.ensureAnnouncementLoading();
9475
+ if (!this.isInspectorDismissed) this.ensureAnnouncementLoading();
8835
9476
  this.subscribeToInspectorThreadBridge();
8836
9477
  }
8837
9478
  this.requestUpdate();
@@ -8857,17 +9498,21 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
8857
9498
  }
8858
9499
  this.clearIconRailContextCloseTimer();
8859
9500
  this.unsubscribeFromInspectorThreadBridge();
9501
+ this.learningSetupUnsubscribe?.();
9502
+ this.learningSetupUnsubscribe = null;
9503
+ this.clearLearningSnapshot();
8860
9504
  this.stopIntelligenceStory();
8861
9505
  this.clearIntelligencePromptReset();
8862
- this.threadsSetupPromptCopyGeneration += 1;
8863
- if (this.threadsSetupPromptCopyResetTimeoutId !== null) {
8864
- window.clearTimeout(this.threadsSetupPromptCopyResetTimeoutId);
8865
- this.threadsSetupPromptCopyResetTimeoutId = null;
9506
+ this.homeFeaturePromptCopyGeneration += 1;
9507
+ if (this.homeFeaturePromptCopyResetTimeoutId !== null) {
9508
+ window.clearTimeout(this.homeFeaturePromptCopyResetTimeoutId);
9509
+ this.homeFeaturePromptCopyResetTimeoutId = null;
8866
9510
  }
8867
- this.threadsSetupPromptCopyState = "idle";
9511
+ this.homeFeaturePromptCopyState = null;
8868
9512
  this.stopSignalPulse();
8869
9513
  this.cancelGestureTail();
8870
9514
  this.cancelLauncherHudIntro();
9515
+ this.clearInspectorDismissalTimer();
8871
9516
  this.cancelThreadRefreshDebounce();
8872
9517
  this.clearInspectorUsageRefresh();
8873
9518
  this.cleanupThreadsExampleOverviewVideo();
@@ -8902,11 +9547,13 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
8902
9547
  this.applyAnchorPosition("button");
8903
9548
  if (this.dockMode === "floating") if (this.hasCustomPosition.window) this.applyAnchorPosition("window");
8904
9549
  else this.centerContext("window");
8905
- this.ensureAnnouncementLoading();
9550
+ if (this.isInspectorDismissed) this.persistState();
9551
+ else this.ensureAnnouncementLoading();
8906
9552
  this.updateHostTransform(this.isOpen ? "window" : "button");
8907
- this.scheduleLauncherHudIntro();
9553
+ if (!this.isInspectorDismissed) this.scheduleLauncherHudIntro();
8908
9554
  }
8909
9555
  render() {
9556
+ if (this.isInspectorDismissed) return nothing;
8910
9557
  return this.isOpen ? html`
8911
9558
  <div data-inspector-portal-anchor></div>
8912
9559
  ` : this.renderButton();
@@ -8999,7 +9646,7 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
8999
9646
  aria-expanded=${this.launcherHudOpen ? "true" : "false"}
9000
9647
  aria-controls=${this.launcherHudOpen ? "cpk-launcher-hud" : nothing}
9001
9648
  aria-label=${signal && signal.tone === "error" ? `${LAUNCHER_BASE_LABEL}, ${signal.accessibleLabel}` : LAUNCHER_BASE_LABEL}
9002
- title=${activeSignal === NEWS_SIGNAL_ID ? `${WHATS_NEW_VIEW_LABEL} — unread` : nothing}
9649
+ title=${HUD_INSPECTOR_LABEL}
9003
9650
  data-drag-context="button"
9004
9651
  data-cpk-signal=${signal ? signal.tone : nothing}
9005
9652
  data-cpk-signal-pulsing=${activeSignal !== null && this.pulsingSignal === activeSignal ? "true" : nothing}
@@ -9084,14 +9731,78 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
9084
9731
  </span>
9085
9732
  `;
9086
9733
  }
9734
+ /** Whether a persisted temporary dismissal is still active. */
9735
+ get isInspectorDismissed() {
9736
+ return this.inspectorDismissedUntil !== null && this.inspectorDismissedUntil > Date.now();
9737
+ }
9738
+ /** Cancel the timer that restores Inspector after a temporary dismissal. */
9739
+ clearInspectorDismissalTimer() {
9740
+ if (this.inspectorDismissalTimer === null) return;
9741
+ clearTimeout(this.inspectorDismissalTimer);
9742
+ this.inspectorDismissalTimer = null;
9743
+ }
9744
+ /** Schedule Inspector to return just after its persisted deadline. */
9745
+ scheduleInspectorDismissalExpiry() {
9746
+ this.clearInspectorDismissalTimer();
9747
+ if (this.inspectorDismissedUntil === null) return;
9748
+ const delay = Math.max(0, this.inspectorDismissedUntil - Date.now() + 25);
9749
+ this.inspectorDismissalTimer = setTimeout(() => {
9750
+ this.inspectorDismissalTimer = null;
9751
+ this.refreshInspectorDismissalState();
9752
+ }, delay);
9753
+ }
9754
+ /** Reconcile this tab with host-scoped dismissal state from other ports. */
9755
+ refreshInspectorDismissalState() {
9756
+ const hadDismissal = this.inspectorDismissedUntil !== null;
9757
+ this.inspectorDismissedUntil = loadInspectorDismissedUntil();
9758
+ this.clearInspectorDismissalTimer();
9759
+ if (this.inspectorDismissedUntil !== null) {
9760
+ this.closePopOut();
9761
+ this.closeInspector();
9762
+ this.scheduleInspectorDismissalExpiry();
9763
+ if (!hadDismissal) this.requestUpdate();
9764
+ return;
9765
+ }
9766
+ if (!hadDismissal || !this.isConnected) return;
9767
+ this.ensureAnnouncementLoading();
9768
+ this.requestUpdate();
9769
+ this.updateComplete.then(() => {
9770
+ if (!this.isConnected || this.isInspectorDismissed) return;
9771
+ this.measureContext("button");
9772
+ this.applyAnchorPosition("button");
9773
+ this.scheduleLauncherHudIntro();
9774
+ this.flushPendingSignalPulse();
9775
+ });
9776
+ }
9777
+ /** Hide Inspector for a supported duration and persist it for this host. */
9778
+ dismissInspectorFor(duration) {
9779
+ const now = Date.now();
9780
+ const until = now + INSPECTOR_DISMISSAL_MS[duration];
9781
+ saveInspectorDismissedUntil(until, now);
9782
+ this.inspectorDismissedUntil = until;
9783
+ this.scheduleInspectorDismissalExpiry();
9784
+ this.settingsOpen = false;
9785
+ this.closeLauncherHud();
9786
+ this.stopSignalPulse();
9787
+ this.cancelGestureTail();
9788
+ this.cancelLauncherHudIntro();
9789
+ this.closePopOut();
9790
+ if (this.isOpen) {
9791
+ this.closeInspector();
9792
+ return;
9793
+ }
9794
+ this.persistState();
9795
+ this.requestUpdate();
9796
+ }
9087
9797
  isLauncherHudBlocked() {
9088
- return this.gestureSignal !== null;
9798
+ return this.gestureSignal !== null || this.isInspectorDismissed;
9089
9799
  }
9090
9800
  scheduleLauncherHudIntro(delay = LAUNCHER_HUD_INTRO_MS.delay) {
9801
+ if (this.isInspectorDismissed) return;
9091
9802
  if (this.launcherHudIntroStartTimer !== null) clearTimeout(this.launcherHudIntroStartTimer);
9092
9803
  this.launcherHudIntroStartTimer = setTimeout(() => {
9093
9804
  this.launcherHudIntroStartTimer = null;
9094
- if (!this.isConnected || this.isOpen) return;
9805
+ if (!this.isConnected || this.isOpen || this.isInspectorDismissed) return;
9095
9806
  if (this.isLauncherHudBlocked()) {
9096
9807
  this.scheduleLauncherHudIntro(LAUNCHER_HUD_INTRO_MS.blockedRetry);
9097
9808
  return;
@@ -9104,7 +9815,6 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
9104
9815
  this.launcherHudIntroEndTimer = null;
9105
9816
  this.launcherHudIntro = false;
9106
9817
  this.launcherHudOpen = false;
9107
- this.launcherHudHelp = null;
9108
9818
  this.requestUpdate();
9109
9819
  }, LAUNCHER_HUD_INTRO_MS.duration);
9110
9820
  }, delay);
@@ -9155,67 +9865,78 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
9155
9865
  clearTimeout(this.launcherHudCloseTimer);
9156
9866
  this.launcherHudCloseTimer = null;
9157
9867
  }
9158
- if (!this.launcherHudOpen && this.launcherHudHelp === null) return;
9868
+ if (!this.launcherHudOpen) return;
9159
9869
  this.launcherHudOpen = false;
9160
- this.launcherHudHelp = null;
9161
9870
  this.requestUpdate();
9162
9871
  }
9163
- renderHudCheck() {
9164
- return html`
9165
- <svg
9166
- class="cpk-launcher-hud__check"
9167
- viewBox="0 0 16 16"
9168
- aria-hidden="true"
9169
- focusable="false"
9170
- data-cpk-hud-check
9171
- >
9172
- <path
9173
- fill="none"
9174
- stroke="currentColor"
9175
- stroke-width="2"
9176
- stroke-linecap="round"
9177
- stroke-linejoin="round"
9178
- d="M3 8.5 6.5 12 13 4.5"
9179
- />
9180
- </svg>
9181
- `;
9872
+ getUnreadAnnouncementTitle() {
9873
+ if (!this.newsSignalArmed || !this.announcementLoaded) return null;
9874
+ const title = this.announcementPreviewText?.trim() || "New in CopilotKit";
9875
+ const titleCharacters = Array.from(title);
9876
+ return titleCharacters.length > HUD_ANNOUNCEMENT_TITLE_LIMIT ? `${titleCharacters.slice(0, HUD_ANNOUNCEMENT_TITLE_LIMIT).join("").trimEnd()}...` : title;
9182
9877
  }
9183
9878
  renderHudRow(args) {
9184
- const helpOpen = this.launcherHudHelp === args.id;
9185
9879
  const detailId = `cpk-hud-detail-${args.id}`;
9186
9880
  return html`
9187
9881
  <li
9188
9882
  class="cpk-launcher-hud__row"
9189
9883
  data-cpk-hud-row=${args.id}
9190
- data-cpk-hud-help=${helpOpen ? "open" : nothing}
9191
- style=${styleMap({
9192
- "--cpk-hud-row-index": `${args.introIndex}`,
9193
- "--cpk-hud-row-delay": `${LAUNCHER_HUD_INTRO_MS.rowStart + args.introIndex * LAUNCHER_HUD_INTRO_MS.rowStagger}ms`
9194
- })}
9884
+ data-cpk-hud-action-kind="navigate"
9885
+ style=${styleMap({ "--cpk-hud-waterfall-delay": launcherHudWaterfallDelay(args.introIndex) })}
9195
9886
  @click=${(event) => this.handleHudRowClick(event, args.id)}
9196
9887
  >
9197
- <button
9198
- type="button"
9199
- class="cpk-launcher-hud__action"
9200
- data-cpk-hud-action
9201
- aria-describedby=${detailId}
9202
- @click=${(event) => this.handleHudActionClick(event, args.id)}
9203
- @pointerdown=${(event) => event.stopPropagation()}
9204
- >
9205
- ${args.connected ? this.renderHudCheck() : nothing}${args.label}
9206
- </button>
9207
- <button
9208
- type="button"
9209
- class="cpk-launcher-hud__help"
9210
- aria-expanded=${helpOpen ? "true" : "false"}
9211
- aria-controls=${detailId}
9212
- aria-label=${`About ${args.label}`}
9213
- @click=${(event) => this.handleHudHelpClick(event, args.id)}
9214
- @pointerdown=${(event) => event.stopPropagation()}
9215
- >
9216
- <span aria-hidden="true">?</span>
9217
- </button>
9218
- <p class="cpk-launcher-hud__detail" id=${detailId}>${args.detail}</p>
9888
+ <span class="cpk-launcher-hud__primary">
9889
+ <button
9890
+ type="button"
9891
+ class="cpk-launcher-hud__action"
9892
+ data-cpk-hud-action
9893
+ aria-label=${`Open ${args.label} in Inspector`}
9894
+ @click=${(event) => this.handleHudActionClick(event, args.id)}
9895
+ @pointerdown=${(event) => event.stopPropagation()}
9896
+ >
9897
+ <span
9898
+ class="cpk-launcher-hud__feature-icon"
9899
+ data-cpk-hud-icon=${args.id}
9900
+ aria-hidden="true"
9901
+ >${this.renderIcon(args.icon)}</span
9902
+ >
9903
+ <span class="cpk-launcher-hud__label">${args.label}</span>
9904
+ </button>
9905
+ <span
9906
+ class="cpk-launcher-hud__tooltip"
9907
+ id=${detailId}
9908
+ role="tooltip"
9909
+ >${HUD_LEARN_MORE_LABEL}</span
9910
+ >
9911
+ </span>
9912
+ <span class="cpk-launcher-hud__controls">
9913
+ <button
9914
+ type="button"
9915
+ class="cpk-launcher-hud__learn-more"
9916
+ data-cpk-hud-learn-more=${args.id}
9917
+ aria-label=${`Learn more about ${args.label}`}
9918
+ aria-describedby=${detailId}
9919
+ @click=${(event) => this.handleHudActionClick(event, args.id)}
9920
+ @pointerdown=${(event) => event.stopPropagation()}
9921
+ >
9922
+ ${this.renderIcon("CircleHelp")}
9923
+ </button>
9924
+ <button
9925
+ type="button"
9926
+ class="cpk-launcher-hud__toggle"
9927
+ data-cpk-hud-toggle=${args.id}
9928
+ data-enabled=${args.connected ? "true" : "false"}
9929
+ aria-label=${args.connected ? `${args.label} is enabled` : `Open ${args.label} in Inspector`}
9930
+ ?disabled=${args.connected}
9931
+ @click=${(event) => this.handleHudActionClick(event, args.id)}
9932
+ @pointerdown=${(event) => event.stopPropagation()}
9933
+ >
9934
+ <span
9935
+ class="cpk-launcher-hud__toggle-track"
9936
+ aria-hidden="true"
9937
+ ></span>
9938
+ </button>
9939
+ </span>
9219
9940
  </li>
9220
9941
  `;
9221
9942
  }
@@ -9224,53 +9945,92 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
9224
9945
  const homeModel = this.getHomeModel();
9225
9946
  const threadsOn = homeModel.services.some((service) => service.id === "threads" && service.enabled);
9226
9947
  const learningOn = homeModel.services.some((service) => service.id === "memory" && service.enabled);
9227
- const intelligenceOn = homeModel.hero.connection === "connected";
9948
+ const announcementTitle = this.getUnreadAnnouncementTitle();
9949
+ const featureBlockIntroIndex = announcementTitle ? 1 : 0;
9228
9950
  return html`
9229
9951
  <div
9230
9952
  class="cpk-launcher-hud"
9231
9953
  id="cpk-launcher-hud"
9232
9954
  data-cpk-launcher-hud
9233
9955
  data-cpk-hud-side=${this.launcherHudSide}
9956
+ data-cpk-hud-vertical=${this.contextState.button.anchor.vertical}
9234
9957
  data-cpk-hud-intro=${this.launcherHudIntro ? "true" : nothing}
9235
9958
  data-color-scheme=${this.colorScheme}
9236
9959
  style=${styleMap({
9237
9960
  "--cpk-launcher-hud-intro-duration": `${LAUNCHER_HUD_INTRO_MS.duration}ms`,
9238
- "--cpk-launcher-hud-row-duration": `${LAUNCHER_HUD_INTRO_MS.rowDuration}ms`
9961
+ "--cpk-launcher-hud-waterfall-duration": `${LAUNCHER_HUD_INTRO_MS.waterfallDuration}ms`
9239
9962
  })}
9240
9963
  >
9241
9964
  <span class="cpk-launcher-hud__arrow" aria-hidden="true"></span>
9242
9965
  <div class="cpk-launcher-hud__card">
9243
- <ul class="cpk-launcher-hud__list" role="list">
9244
- ${this.renderHudRow({
9245
- id: "inspector",
9246
- label: HUD_OPEN_INSPECTOR_LABEL,
9247
- detail: HUD_OPEN_INSPECTOR_DETAIL,
9248
- introIndex: 0
9249
- })}
9250
- </ul>
9251
- <ul class="cpk-launcher-hud__list" role="list">
9966
+ ${announcementTitle ? html`
9967
+ <div
9968
+ class="cpk-launcher-hud__masthead"
9969
+ style=${styleMap({ "--cpk-hud-waterfall-delay": launcherHudWaterfallDelay(0) })}
9970
+ >
9971
+ <div class="cpk-launcher-hud__news-wrap">
9972
+ <button
9973
+ type="button"
9974
+ class="cpk-launcher-hud__news"
9975
+ data-cpk-hud-news
9976
+ aria-label=${`Open new notification: ${announcementTitle}`}
9977
+ @click=${this.handleHudNewsClick}
9978
+ @pointerdown=${(event) => event.stopPropagation()}
9979
+ >
9980
+ <span
9981
+ class="cpk-launcher-hud__news-label"
9982
+ data-cpk-hud-news-label
9983
+ aria-hidden="true"
9984
+ >New</span
9985
+ >
9986
+ <span class="cpk-launcher-hud__news-title"
9987
+ >${announcementTitle}</span
9988
+ >
9989
+ </button>
9990
+ <button
9991
+ type="button"
9992
+ class="cpk-launcher-hud__news-dismiss"
9993
+ data-cpk-hud-news-dismiss
9994
+ aria-label="Dismiss notification"
9995
+ @click=${this.handleHudNewsDismissClick}
9996
+ @pointerdown=${(event) => event.stopPropagation()}
9997
+ >
9998
+ ${this.renderIcon("X")}
9999
+ </button>
10000
+ </div>
10001
+ </div>
10002
+ ` : nothing}
10003
+ <ul
10004
+ class="cpk-launcher-hud__list cpk-launcher-hud__feature-list"
10005
+ role="list"
10006
+ style=${styleMap({ "--cpk-hud-waterfall-delay": launcherHudWaterfallDelay(featureBlockIntroIndex) })}
10007
+ >
9252
10008
  ${this.renderHudRow({
9253
10009
  id: "threads",
9254
- label: threadsOn ? HUD_THREADS_ON_LABEL : HUD_THREADS_OFF_LABEL,
9255
- detail: threadsOn ? HUD_THREADS_ON_DETAIL : HUD_THREADS_OFF_DETAIL,
10010
+ label: HUD_THREADS_LABEL,
10011
+ icon: "MessageSquare",
9256
10012
  connected: threadsOn,
9257
- introIndex: 1
9258
- })}
9259
- ${this.renderHudRow({
9260
- id: "intelligence",
9261
- label: intelligenceOn ? HUD_INTELLIGENCE_ON_LABEL : HUD_INTELLIGENCE_OFF_LABEL,
9262
- detail: intelligenceOn ? HUD_INTELLIGENCE_ON_DETAIL : HUD_INTELLIGENCE_OFF_DETAIL,
9263
- connected: intelligenceOn,
9264
- introIndex: 2
10013
+ introIndex: featureBlockIntroIndex + 1
9265
10014
  })}
9266
10015
  ${this.renderHudRow({
9267
10016
  id: "learning",
9268
- label: learningOn ? HUD_LEARNING_ON_LABEL : HUD_LEARNING_OFF_LABEL,
9269
- detail: learningOn ? HUD_LEARNING_ON_DETAIL : HUD_LEARNING_OFF_DETAIL,
10017
+ label: HUD_LEARNING_LABEL,
10018
+ icon: "Brain",
9270
10019
  connected: learningOn,
9271
- introIndex: 3
10020
+ introIndex: featureBlockIntroIndex + 2
9272
10021
  })}
9273
10022
  </ul>
10023
+ <button
10024
+ type="button"
10025
+ class="cpk-launcher-hud__dismiss-day"
10026
+ data-cpk-dismiss-inspector="day"
10027
+ style=${styleMap({ "--cpk-hud-waterfall-delay": launcherHudWaterfallDelay(featureBlockIntroIndex + 3) })}
10028
+ @click=${this.handleHudDismissDayClick}
10029
+ @pointerdown=${(event) => event.stopPropagation()}
10030
+ >
10031
+ <span aria-hidden="true">${this.renderIcon("Clock")}</span>
10032
+ Hide Inspector for a day
10033
+ </button>
9274
10034
  </div>
9275
10035
  </div>
9276
10036
  `;
@@ -9491,7 +10251,7 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
9491
10251
  type: lastRuntimeEvent.type,
9492
10252
  timestamp: lastRuntimeEvent.timestamp
9493
10253
  } : void 0,
9494
- memoriesOn: this._memoriesAvailable,
10254
+ memoriesOn: this._memorySubscribed && !this._memoriesLoading && this._memoriesAvailable,
9495
10255
  a2uiOn: this._core?.a2uiEnabled === true,
9496
10256
  openGenUiOn: this._core?.openGenerativeUIEnabled === true,
9497
10257
  suggestionsOn: this._core?.suggestions === true,
@@ -9899,23 +10659,67 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
9899
10659
  renderHomeFeatures(model) {
9900
10660
  const enabledServices = model.services.filter((service) => service.enabled);
9901
10661
  const disabledServices = model.services.filter((service) => !service.enabled);
9902
- const renderService = (service) => html`
9903
- <a
10662
+ const renderService = (service) => {
10663
+ const copyState = this.homeFeaturePromptCopyState?.serviceId === service.id ? this.homeFeaturePromptCopyState.state : "idle";
10664
+ const stateDescription = `${service.label} is ${service.enabled ? "enabled in your runtime" : "not enabled in your runtime"}`;
10665
+ const copyLabel = copyState === "copied" ? "Copied" : copyState === "error" ? "Copy failed" : "Copy prompt";
10666
+ const copyTitle = copyLabel;
10667
+ return html`
10668
+ <div
9904
10669
  class="inspector-home-feature"
9905
10670
  data-inspector-service=${service.id}
9906
10671
  data-state=${service.enabled ? "on" : "off"}
9907
- href=${this.appendRefParam(service.docsUrl, "cpk-inspector-home")}
9908
- target="_blank"
9909
- rel="noopener noreferrer"
9910
- aria-label="Learn more about ${service.label}, currently ${service.enabled ? "on" : "off"}"
10672
+ role="listitem"
9911
10673
  >
9912
- <span>${service.label}</span>
9913
- <small>${service.enabled ? "On" : "Off"}</small>
9914
- <span class="inspector-home-feature-arrow" aria-hidden="true">
9915
- ${this.renderIcon("ArrowUpRight")}
10674
+ <span
10675
+ class="inspector-home-feature-status"
10676
+ role="img"
10677
+ aria-label=${stateDescription}
10678
+ title=${stateDescription}
10679
+ >
10680
+ <span aria-hidden="true"></span>
9916
10681
  </span>
9917
- </a>
10682
+ <a
10683
+ class="inspector-home-feature-label"
10684
+ data-inspector-home-feature-docs=${service.id}
10685
+ href=${this.appendRefParam(service.docsUrl, "cpk-inspector-home")}
10686
+ target="_blank"
10687
+ rel="noopener noreferrer"
10688
+ aria-label="Open ${service.label} documentation in a new tab"
10689
+ >
10690
+ <span>${service.label}</span>
10691
+ <span class="inspector-home-feature-label-icon" aria-hidden="true"
10692
+ >${this.renderIcon("ArrowUpRight")}</span
10693
+ >
10694
+ </a>
10695
+ <span class="inspector-home-feature-actions">
10696
+ ${service.enabled ? nothing : html`
10697
+ <button
10698
+ type="button"
10699
+ class="inspector-home-feature-action inspector-system-health-url"
10700
+ data-inspector-home-feature-prompt=${service.id}
10701
+ data-copy-state=${copyState}
10702
+ data-full-value=${copyTitle}
10703
+ aria-label="${copyLabel} for ${service.label}"
10704
+ @click=${(event) => this.handleHomeFeaturePromptCopy(service, event)}
10705
+ >
10706
+ <span class="inspector-home-feature-action-icon" aria-hidden="true"
10707
+ >${this.renderIcon(copyState === "copied" ? "Check" : "Bot")}</span
10708
+ >
10709
+ <span class="inspector-home-feature-action-label"
10710
+ >${copyTitle}</span
10711
+ >
10712
+ </button>
10713
+ `}
10714
+ ${service.enabled ? nothing : html`
10715
+ <span class="sr-only" aria-live="polite">
10716
+ ${copyState === "copied" ? `${service.label} implementation prompt copied.` : copyState === "error" ? `Could not copy the ${service.label} implementation prompt.` : ""}
10717
+ </span>
10718
+ `}
10719
+ </span>
10720
+ </div>
9918
10721
  `;
10722
+ };
9919
10723
  return html`
9920
10724
  <section
9921
10725
  class="inspector-home-section inspector-home-features"
@@ -9924,7 +10728,7 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
9924
10728
  <header class="inspector-home-section-header">
9925
10729
  <h2 class="inspector-home-section-title">Features</h2>
9926
10730
  <span>
9927
- ${enabledServices.length} active, ${disabledServices.length} off
10731
+ ${enabledServices.length} enabled, ${disabledServices.length} available
9928
10732
  </span>
9929
10733
  </header>
9930
10734
  ${model.services.length === 0 ? html`
@@ -9936,13 +10740,13 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
9936
10740
  <section
9937
10741
  class="inspector-home-feature-group"
9938
10742
  data-feature-state-group="active"
9939
- aria-label="Active features"
10743
+ aria-label="Enabled features"
9940
10744
  >
9941
10745
  <header class="inspector-home-feature-group-header">
9942
- <strong>Active</strong>
10746
+ <strong>Enabled</strong>
9943
10747
  <span>${enabledServices.length}</span>
9944
10748
  </header>
9945
- <div class="inspector-home-feature-list">
10749
+ <div class="inspector-home-feature-list" role="list">
9946
10750
  ${enabledServices.length > 0 ? enabledServices.map(renderService) : html`
9947
10751
  <p class="inspector-home-feature-group-empty">None enabled</p>
9948
10752
  `}
@@ -9951,13 +10755,13 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
9951
10755
  <section
9952
10756
  class="inspector-home-feature-group"
9953
10757
  data-feature-state-group="available"
9954
- aria-label="Available features"
10758
+ aria-label="Features available to add"
9955
10759
  >
9956
10760
  <header class="inspector-home-feature-group-header">
9957
- <strong>Available</strong>
10761
+ <strong>Available to add</strong>
9958
10762
  <span>${disabledServices.length}</span>
9959
10763
  </header>
9960
- <div class="inspector-home-feature-list">
10764
+ <div class="inspector-home-feature-list" role="list">
9961
10765
  ${disabledServices.length > 0 ? disabledServices.map(renderService) : html`
9962
10766
  <p class="inspector-home-feature-group-empty">Everything is active</p>
9963
10767
  `}
@@ -9966,6 +10770,47 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
9966
10770
  </div>
9967
10771
  `}
9968
10772
  </section>
10773
+ `;
10774
+ }
10775
+ showHomeFeaturePromptCopyState(serviceId, state, generation) {
10776
+ if (!this.isConnected || generation !== this.homeFeaturePromptCopyGeneration) return;
10777
+ if (this.homeFeaturePromptCopyResetTimeoutId !== null) window.clearTimeout(this.homeFeaturePromptCopyResetTimeoutId);
10778
+ this.homeFeaturePromptCopyState = {
10779
+ serviceId,
10780
+ state
10781
+ };
10782
+ this.requestUpdate();
10783
+ this.homeFeaturePromptCopyResetTimeoutId = window.setTimeout(() => {
10784
+ if (!this.isConnected || generation !== this.homeFeaturePromptCopyGeneration) return;
10785
+ this.homeFeaturePromptCopyState = null;
10786
+ this.homeFeaturePromptCopyResetTimeoutId = null;
10787
+ this.requestUpdate();
10788
+ }, 2e3);
10789
+ }
10790
+ getHomeFeaturePromptTarget(serviceId) {
10791
+ return this.getHomeModel().services.find((service) => service.id === serviceId);
10792
+ }
10793
+ renderFeatureSetupPrompt(serviceId, className, options) {
10794
+ const service = this.getHomeFeaturePromptTarget(serviceId);
10795
+ if (!service) return nothing;
10796
+ const copyState = options?.copyState ?? (this.homeFeaturePromptCopyState?.serviceId === service.id ? this.homeFeaturePromptCopyState.state : "idle");
10797
+ const label = copyState === "copied" ? "Copied" : copyState === "error" ? "Copy blocked" : "Copy setup prompt";
10798
+ return html`
10799
+ <button
10800
+ type="button"
10801
+ class=${className}
10802
+ data-inspector-feature-setup-prompt=${service.id}
10803
+ data-inspector-threads-setup-prompt=${service.id === "threads" ? "" : nothing}
10804
+ data-copy-state=${copyState}
10805
+ aria-label=${copyState === "copied" ? `${service.label} setup prompt copied` : copyState === "error" ? `Could not copy the ${service.label} setup prompt. Try again` : `Copy setup prompt for ${service.label}`}
10806
+ @click=${(event) => options?.onClick ? options.onClick(event) : this.handleHomeFeaturePromptCopy(service, event)}
10807
+ >
10808
+ ${this.renderIcon(copyState === "copied" ? "Check" : "Copy")}
10809
+ ${label}
10810
+ </button>
10811
+ <span class="sr-only" aria-live="polite">
10812
+ ${copyState === "copied" ? `${service.label} setup prompt copied.` : copyState === "error" ? `Could not copy the ${service.label} setup prompt.` : ""}
10813
+ </span>
9969
10814
  `;
9970
10815
  }
9971
10816
  handleHomeHeroCta(action) {
@@ -10961,6 +11806,7 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
10961
11806
  this.draggedDuringInteraction = false;
10962
11807
  }
10963
11808
  openInspector(source, options = {}) {
11809
+ if (this.isInspectorDismissed) return;
10964
11810
  if (options.threadId) this.focusThread(options);
10965
11811
  if (this.isPoppedOut) return;
10966
11812
  if (this.isOpen) return;
@@ -10972,10 +11818,8 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
10972
11818
  this.closeLauncherHud();
10973
11819
  const hudMenu = this.hudLandingMenu;
10974
11820
  this.hudLandingMenu = null;
10975
- if (hudMenu) {
10976
- this.selectedMenu = hudMenu;
10977
- this.lastSelectedMenuByGroup[getGroupForMenu(hudMenu)] = hudMenu;
10978
- } else if (activeSignalAtOpen !== null && source === "floating_button") {
11821
+ if (hudMenu) this.handleMenuSelect(hudMenu);
11822
+ else if (activeSignalAtOpen !== null && source === "floating_button") {
10979
11823
  const landing = LAUNCHER_SIGNALS[activeSignalAtOpen].landingTarget;
10980
11824
  this.selectedMenu = landing;
10981
11825
  this.lastSelectedMenuByGroup[getGroupForMenu(landing)] = landing;
@@ -10985,6 +11829,7 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
10985
11829
  }
10986
11830
  this.ensureAnnouncementLoading();
10987
11831
  this.isOpen = true;
11832
+ if (this.selectedMenu === "memories") this.refreshLearningSnapshot({ preserve: this.learningSnapshot !== null });
10988
11833
  this.cancelGestureTail();
10989
11834
  this.persistState();
10990
11835
  this.trackOpened(source, hadUnseenAnnouncement, firstOpen, activeSignalAtOpen);
@@ -11002,6 +11847,9 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
11002
11847
  if (this.isPoppedOut) return;
11003
11848
  if (!this.isOpen) return;
11004
11849
  this.isOpen = false;
11850
+ this.cancelLearningPoll();
11851
+ this.cancelLearningRequest();
11852
+ this.learningViewedState = null;
11005
11853
  if (this.dockMode !== "floating") this.removeDockStyles();
11006
11854
  this.persistState();
11007
11855
  this.updateHostTransform("button");
@@ -11849,6 +12697,40 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
11849
12697
  </a>
11850
12698
  </div>
11851
12699
  </section>
12700
+
12701
+ <section
12702
+ class="inspector-settings-section"
12703
+ aria-labelledby="inspector-settings-visibility-title"
12704
+ >
12705
+ <div class="inspector-settings-section-heading">
12706
+ <span class="inspector-settings-section-icon" aria-hidden="true">
12707
+ ${this.renderIcon("EyeOff")}
12708
+ </span>
12709
+ <div>
12710
+ <h2 id="inspector-settings-visibility-title">Visibility</h2>
12711
+ <p>Temporarily hide the Inspector on this domain.</p>
12712
+ </div>
12713
+ </div>
12714
+
12715
+ <div class="inspector-settings-visibility">
12716
+ <div>
12717
+ <h3>Take a break from the Inspector</h3>
12718
+ <p>
12719
+ Hide the Inspector for seven days. It will return automatically
12720
+ when the week is over.
12721
+ </p>
12722
+ </div>
12723
+ <button
12724
+ type="button"
12725
+ class="inspector-settings-dismiss"
12726
+ data-cpk-dismiss-inspector="week"
12727
+ @click=${() => this.dismissInspectorFor("week")}
12728
+ >
12729
+ <span aria-hidden="true">${this.renderIcon("Clock")}</span>
12730
+ Hide Inspector for one week
12731
+ </button>
12732
+ </div>
12733
+ </section>
11852
12734
  </div>
11853
12735
  `;
11854
12736
  }
@@ -11869,15 +12751,11 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
11869
12751
  });
11870
12752
  }
11871
12753
  getVisibleInspectorMetadataAction() {
11872
- const { threadsFooterAction, lockedAction } = this.inspectorMetadataProjection;
11873
- if (threadsFooterAction && !this.settingsOpen && this.selectedMenu === "threads") return {
12754
+ const { threadsFooterAction } = this.inspectorMetadataProjection;
12755
+ if (threadsFooterAction && !this.settingsOpen && this.selectedMenu === "threads" && this.areThreadEndpointsAvailable()) return {
11874
12756
  action: threadsFooterAction,
11875
12757
  placement: "threads-footer"
11876
12758
  };
11877
- if (lockedAction && !this.settingsOpen && this.selectedMenu === "threads" && !this.areThreadEndpointsAvailable()) return {
11878
- action: lockedAction,
11879
- placement: "locked"
11880
- };
11881
12759
  }
11882
12760
  /** Return paired stable navigation keys, or neither for an invalid leaf. */
11883
12761
  getMetadataTelemetryNavigation() {
@@ -11978,8 +12856,8 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
11978
12856
  else if (state === "empty_enabled") trackThreadsEmptyEnabledViewed(props);
11979
12857
  else trackThreadsEnabledViewed(props);
11980
12858
  }
11981
- shouldRenderExampleThreads(locked, displayThreads, threadsErrorMessage, threadsLoading) {
11982
- return locked || !threadsErrorMessage && !threadsLoading && displayThreads.length === 0;
12859
+ shouldRenderExampleThreads(displayThreads, threadsErrorMessage, threadsLoading) {
12860
+ return !threadsErrorMessage && !threadsLoading && displayThreads.length === 0;
11983
12861
  }
11984
12862
  isExampleThreadId(threadId) {
11985
12863
  return THREADS_EXAMPLE_THREADS.some((thread) => thread.id === threadId);
@@ -12390,82 +13268,112 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
12390
13268
  ` : nothing}
12391
13269
  `;
12392
13270
  }
12393
- /** Show a copy result briefly and announce it to assistive technology. */
12394
- showThreadsSetupPromptCopyState(state, generation) {
12395
- if (!this.isConnected || generation !== this.threadsSetupPromptCopyGeneration) return;
12396
- if (this.threadsSetupPromptCopyResetTimeoutId !== null) window.clearTimeout(this.threadsSetupPromptCopyResetTimeoutId);
12397
- this.threadsSetupPromptCopyState = state;
12398
- this.requestUpdate();
12399
- this.threadsSetupPromptCopyResetTimeoutId = window.setTimeout(() => {
12400
- if (!this.isConnected || generation !== this.threadsSetupPromptCopyGeneration) return;
12401
- this.threadsSetupPromptCopyState = "idle";
12402
- this.threadsSetupPromptCopyResetTimeoutId = null;
12403
- this.requestUpdate();
12404
- }, 2e3);
12405
- }
12406
- renderThreadsExampleOverview(locked) {
12407
- const lockedCopy = locked ? this.getThreadsLockedCopy() : void 0;
12408
- const { lockedAction } = this.inspectorMetadataProjection;
13271
+ renderThreadsExampleOverview() {
12409
13272
  const onboardingAction = this.getThreadsEmptyOnboardingAction();
12410
13273
  return html`
12411
13274
  <div class="cpk-threads-overview">
12412
13275
  <div class="cpk-threads-overview-content">
12413
13276
  <h2 class="cpk-threads-overview-title">
12414
- ${lockedCopy?.heading ?? "Threads are persistent, inspectable conversations"}
13277
+ Threads are persistent, inspectable conversations
12415
13278
  </h2>
12416
13279
  ${this.renderThreadsExampleOverviewVideo()}
12417
13280
  <p class="cpk-threads-overview-copy">
12418
- ${lockedCopy?.description ?? "Take a tour with the example threads in the sidebar. Then, start chatting in your app to create the first real thread."}
13281
+ Take a tour with the example threads in the sidebar. Then, start
13282
+ chatting in your app to create the first real thread.
12419
13283
  </p>
12420
- ${locked ? this.renderRuntimeEntitlementDiagnostic(this.getRuntimeEntitlementDiagnostic()) : nothing}
12421
13284
  <div class="cpk-threads-overview-actions">
12422
- ${locked ? html`
12423
- ${this.inspectorMetadataProjection.licenseState === "valid" ? html`
12424
- <button
12425
- data-inspector-threads-setup-prompt
12426
- type="button"
12427
- aria-label=${this.threadsSetupPromptCopyState === "copied" ? "Setup prompt copied" : this.threadsSetupPromptCopyState === "error" ? "Copy setup prompt failed. Try again" : "Copy setup prompt for your coding agent"}
12428
- @click=${this.handleThreadsSetupPromptCopy}
12429
- >
12430
- ${this.renderIcon(this.threadsSetupPromptCopyState === "copied" ? "Check" : "Copy")}
12431
- ${this.threadsSetupPromptCopyState === "copied" ? "Copied" : this.threadsSetupPromptCopyState === "error" ? "Copy blocked" : "Copy prompt for your agent"}
12432
- </button>
12433
- <a
12434
- data-inspector-threads-setup-link
12435
- href=${this.getThreadsRuntimeSetupDocsUrl()}
12436
- target="_blank"
12437
- rel="noopener"
12438
- aria-label="Open setup guide (opens in a new tab)"
12439
- >
12440
- Open setup guide
12441
- </a>
12442
- <span
12443
- class="sr-only"
12444
- data-inspector-threads-setup-copy-status
12445
- aria-live="polite"
12446
- >${this.threadsSetupPromptCopyState === "copied" ? "Setup prompt copied." : this.threadsSetupPromptCopyState === "error" ? "Setup prompt copy failed. Open the setup guide and copy it manually." : ""}</span
12447
- >
12448
- ` : nothing}
12449
- ${lockedAction ? this.renderInspectorAction(lockedAction, "locked") : nothing}
12450
- ` : html`
12451
- <a
12452
- href=${this.getThreadsDocsUrl()}
12453
- target="_blank"
12454
- rel="noopener"
12455
- class="cpk-threads-overview-action cpk-threads-overview-action-primary"
12456
- >
12457
- Learn how Threads work
12458
- </a>
12459
- <a
12460
- href=${onboardingAction.href}
12461
- target="_blank"
12462
- rel="noopener"
12463
- class="cpk-threads-overview-action cpk-threads-overview-action-secondary"
12464
- >
12465
- ${onboardingAction.label}
12466
- </a>
12467
- `}
13285
+ <a
13286
+ href=${this.getThreadsDocsUrl()}
13287
+ target="_blank"
13288
+ rel="noopener"
13289
+ class="cpk-threads-overview-action cpk-threads-overview-action-primary"
13290
+ >
13291
+ Learn how Threads work
13292
+ </a>
13293
+ <a
13294
+ href=${onboardingAction.href}
13295
+ target="_blank"
13296
+ rel="noopener"
13297
+ class="cpk-threads-overview-action cpk-threads-overview-action-secondary"
13298
+ >
13299
+ ${onboardingAction.label}
13300
+ </a>
13301
+ </div>
13302
+ </div>
13303
+ </div>
13304
+ `;
13305
+ }
13306
+ renderLockedFeatureOverview({ serviceId, featureName, heading, description, videoUrl, videoTitle, outlineItems, setupPrompt }) {
13307
+ return html`
13308
+ <div
13309
+ class="cpk-locked-feature"
13310
+ data-inspector-locked-feature=${serviceId}
13311
+ >
13312
+ <div class="cpk-locked-feature-layout">
13313
+ <div class="cpk-locked-feature-hero">
13314
+ <div class="cpk-locked-feature-copy">
13315
+ <div class="cpk-locked-feature-name">
13316
+ <span class="cpk-locked-feature-icon" aria-hidden="true">
13317
+ ${serviceId === "threads" ? unsafeHTML(this.customTabIcons.threads) : this.renderIcon("Brain")}
13318
+ </span>
13319
+ ${featureName}
13320
+ </div>
13321
+ <h2 class="cpk-locked-feature-title">${heading}</h2>
13322
+ <p class="cpk-locked-feature-description">${description}</p>
13323
+ <div class="cpk-threads-overview-actions">
13324
+ ${this.renderFeatureSetupPrompt(setupPrompt?.serviceId ?? serviceId, "inspector-account-cta cpk-locked-feature-setup-cta", setupPrompt ? {
13325
+ copyState: setupPrompt.copyState,
13326
+ onClick: setupPrompt.onClick
13327
+ } : void 0)}
13328
+ <a
13329
+ data-inspector-locked-feature-talk=${serviceId}
13330
+ href=${this.getTalkToEngineerUrl()}
13331
+ target="_blank"
13332
+ rel="noopener noreferrer"
13333
+ aria-label="Talk to an Engineer (opens in a new tab)"
13334
+ class="cpk-threads-overview-action cpk-threads-overview-action-secondary"
13335
+ @click=${this.handleThreadsTalkToEngineerClick}
13336
+ >
13337
+ Talk to an Engineer
13338
+ </a>
13339
+ </div>
13340
+ </div>
13341
+ <div class="cpk-locked-feature-media">
13342
+ <div class="cpk-threads-overview-video-frame cpk-locked-feature-video">
13343
+ <iframe
13344
+ class="cpk-threads-overview-video-embed"
13345
+ data-inspector-feature-video=${serviceId}
13346
+ src=${videoUrl}
13347
+ title=${videoTitle}
13348
+ loading="lazy"
13349
+ allow="fullscreen; picture-in-picture"
13350
+ allowfullscreen
13351
+ ></iframe>
13352
+ </div>
13353
+ </div>
12468
13354
  </div>
13355
+ <section
13356
+ class="cpk-locked-feature-outline"
13357
+ data-inspector-feature-outline=${serviceId}
13358
+ aria-label="${featureName} capabilities"
13359
+ >
13360
+ <div class="cpk-locked-feature-outline-list">
13361
+ ${outlineItems.map((item) => html`
13362
+ <section class="cpk-locked-feature-outline-item">
13363
+ <h3>
13364
+ <span
13365
+ class="cpk-locked-feature-outline-icon"
13366
+ aria-hidden="true"
13367
+ >
13368
+ ${this.renderIcon(item.icon)}
13369
+ </span>
13370
+ ${item.title}
13371
+ </h3>
13372
+ <p>${item.description}</p>
13373
+ </section>
13374
+ `)}
13375
+ </div>
13376
+ </section>
12469
13377
  </div>
12470
13378
  </div>
12471
13379
  `;
@@ -12523,56 +13431,6 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
12523
13431
  </div>
12524
13432
  </div>
12525
13433
  </div>
12526
- `;
12527
- }
12528
- renderThreadsLockedBackgroundMockup() {
12529
- return html`
12530
- <div aria-hidden="true" class="cpk-locked-preview">
12531
- <div class="cpk-locked-preview-sidebar">
12532
- ${[
12533
- {
12534
- width: 74,
12535
- accent: true
12536
- },
12537
- { width: 92 },
12538
- { width: 68 },
12539
- { width: 84 },
12540
- { width: 58 },
12541
- { width: 76 }
12542
- ].map((row) => html`
12543
- <div
12544
- class="cpk-locked-preview-row"
12545
- data-accent=${row.accent ? "true" : "false"}
12546
- >
12547
- <div
12548
- class="cpk-locked-preview-bar cpk-locked-preview-row-title"
12549
- style="--preview-width: ${row.width}%;"
12550
- ></div>
12551
- <div
12552
- class="cpk-locked-preview-bar cpk-locked-preview-row-line"
12553
- ></div>
12554
- <div
12555
- class="cpk-locked-preview-bar cpk-locked-preview-row-line"
12556
- ></div>
12557
- </div>
12558
- `)}
12559
- </div>
12560
- <div class="cpk-locked-preview-main">
12561
- <div class="cpk-locked-preview-bar cpk-locked-preview-heading"></div>
12562
- <div class="cpk-locked-preview-bar cpk-locked-preview-copy"></div>
12563
- <div class="cpk-locked-preview-bar cpk-locked-preview-copy"></div>
12564
- <div class="cpk-locked-preview-cards">
12565
- <div class="cpk-locked-preview-card"></div>
12566
- <div class="cpk-locked-preview-card"></div>
12567
- </div>
12568
- <div
12569
- class="cpk-locked-preview-bar cpk-locked-preview-footer-line"
12570
- ></div>
12571
- <div
12572
- class="cpk-locked-preview-bar cpk-locked-preview-footer-line"
12573
- ></div>
12574
- </div>
12575
- </div>
12576
13434
  `;
12577
13435
  }
12578
13436
  getThreadsLockedCopy() {
@@ -12581,89 +13439,18 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
12581
13439
  heading: "Finish setting up Rich Threads",
12582
13440
  description: "Copy this prompt into your coding agent to finish the setup."
12583
13441
  };
12584
- case "none": return {
12585
- heading: "Enable Intelligence to inspect Threads.",
12586
- description: "Persist conversations and inspect saved thread history from the Inspector."
13442
+ case "none":
13443
+ case "unknown": return {
13444
+ heading: "Production-grade chat threads without the complexity. Self hostable.",
13445
+ description: "Chat threads that go beyond text with generative UI and multimodal inputs, built to replay missed events and stay in sync across tabs, sessions, and devices."
12587
13446
  };
12588
13447
  case "expired": return {
12589
13448
  heading: "Renew Intelligence to inspect Threads.",
12590
13449
  description: "Your Intelligence access has expired. Renew it to inspect saved thread history."
12591
13450
  };
12592
- case "unknown": return {
12593
- heading: "Threads are unavailable.",
12594
- description: "This runtime does not expose Threads for the Inspector."
12595
- };
12596
13451
  }
12597
13452
  }
12598
13453
  /**
12599
- * Prefer the Runtime's structured entitlement diagnostic and derive a
12600
- * compatibility diagnostic only when an older Core exposes legacy status.
12601
- */
12602
- getRuntimeEntitlementDiagnostic() {
12603
- const runtimeEntitlements = this.core?.runtimeEntitlements;
12604
- if (runtimeEntitlements) return runtimeEntitlements.status === "ready" ? { status: runtimeEntitlements.status } : {
12605
- status: runtimeEntitlements.status,
12606
- error: runtimeEntitlements.error
12607
- };
12608
- switch (this.core?.licenseStatus) {
12609
- case "valid": return { status: "ready" };
12610
- case "expired": return {
12611
- status: "degraded",
12612
- error: {
12613
- code: "legacy_license_expired",
12614
- message: "Legacy Runtime license has expired.",
12615
- retryable: false
12616
- }
12617
- };
12618
- case "expiring": return {
12619
- status: "degraded",
12620
- error: {
12621
- code: "legacy_license_expiring",
12622
- message: "Legacy Runtime license is expiring.",
12623
- retryable: false
12624
- }
12625
- };
12626
- case "invalid": return {
12627
- status: "misconfigured",
12628
- error: {
12629
- code: "legacy_license_invalid",
12630
- message: "Legacy Runtime license is invalid.",
12631
- retryable: false
12632
- }
12633
- };
12634
- case "none":
12635
- case "unknown": return { status: "unavailable" };
12636
- default: return null;
12637
- }
12638
- }
12639
- /** Render exact Runtime entitlement correlation details without gating UI. */
12640
- renderRuntimeEntitlementDiagnostic(diagnostic) {
12641
- if (!diagnostic) return nothing;
12642
- return html`
12643
- <div
12644
- role="status"
12645
- data-runtime-entitlement-status=${diagnostic.status}
12646
- style="
12647
- margin: -8px auto 18px;
12648
- max-width: 380px;
12649
- font-size: 11px;
12650
- line-height: 1.5;
12651
- color: #57575b;
12652
- "
12653
- >
12654
- <div style="font-weight: 600;">
12655
- Runtime entitlement: ${diagnostic.status}
12656
- </div>
12657
- ${diagnostic.error ? html`
12658
- <div>${diagnostic.error.message}</div>
12659
- <div>Code: ${diagnostic.error.code}</div>
12660
- ${diagnostic.error.requestId ? html`<div>Request ID: ${diagnostic.error.requestId}</div>` : nothing}
12661
- ${diagnostic.error.traceId ? html`<div>Trace ID: ${diagnostic.error.traceId}</div>` : nothing}
12662
- ` : nothing}
12663
- </div>
12664
- `;
12665
- }
12666
- /**
12667
13454
  * Renders the realtime-connection indicator in the memory-store header.
12668
13455
  * Only `"connected"` shows the live (green-dot) state; `"connecting"` shows a
12669
13456
  * muted amber "reconnecting" and `"unavailable"` a muted grey "offline", so
@@ -12698,43 +13485,64 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
12698
13485
  `;
12699
13486
  }
12700
13487
  renderMemoriesView() {
12701
- if (!this.core?.intelligence || !this._memoriesAvailable) return html`
12702
- <div class="cpk-memory-locked">
12703
- ${this.renderThreadsLockedBackgroundMockup()}
12704
- <div aria-hidden="true" class="cpk-memory-locked-scrim"></div>
12705
- <div class="cpk-memory-locked-content">
12706
- <div aria-hidden="true" class="cpk-memory-locked-icon-wrap">
12707
- <div class="cpk-memory-locked-icon">
12708
- ${this.renderIcon("Lock")}
12709
- </div>
12710
- </div>
12711
- <h2 class="cpk-memory-locked-title">Learning</h2>
12712
- <p class="cpk-memory-locked-copy">
12713
- ${this._memoryStoreUnsupported ? "Learning is unavailable in this version of the @copilotkit SDK. Upgrade @copilotkit/core (and @copilotkit/react) to a version that supports long-term memory." : "Learning turns durable information from agent interactions into reusable context. It isn't enabled on this deployment."}
12714
- </p>
12715
- <div class="cpk-memory-locked-actions">
12716
- <a
12717
- href=${this.getTalkToEngineerUrl()}
12718
- target="_blank"
12719
- rel="noopener"
12720
- class="cpk-memory-locked-action"
12721
- @click=${this.handleThreadsTalkToEngineerClick}
12722
- >
12723
- Talk to an Engineer
12724
- </a>
12725
- <a
12726
- href=${this.getIntelligenceSignupUrl()}
12727
- target="_blank"
12728
- rel="noopener"
12729
- class="cpk-memory-locked-action cpk-memory-locked-action-secondary"
12730
- @click=${this.handleThreadsIntelligenceSignupClick}
12731
- >
12732
- Sign up for Intelligence
12733
- </a>
12734
- </div>
12735
- </div>
12736
- </div>
12737
- `;
13488
+ if (deriveLearningViewState({
13489
+ supported: this.learningSupported,
13490
+ loading: this.learningLoading,
13491
+ error: this.learningError,
13492
+ snapshot: this.learningSnapshot,
13493
+ setupActive: this.isLearningSetupActive()
13494
+ }) === "landing") return this.renderLockedFeatureOverview({
13495
+ serviceId: "memory",
13496
+ featureName: "Learning",
13497
+ heading: "Turn every interaction into reusable context.",
13498
+ description: "Learning captures durable information from agent interactions and brings it back when it matters, so your product gets more useful over time.",
13499
+ videoUrl: LEARNING_LOCKED_VIDEO_URL,
13500
+ videoTitle: "CopilotKit Learning overview",
13501
+ outlineItems: LEARNING_LOCKED_FEATURE_OUTLINE,
13502
+ setupPrompt: {
13503
+ serviceId: "threads",
13504
+ copyState: this.learningPromptCopyState,
13505
+ onClick: (event) => void this.handleLearningSetupCopy(event)
13506
+ }
13507
+ });
13508
+ return html`
13509
+ <cpk-learning-view
13510
+ data-color-scheme=${this.colorScheme}
13511
+ .supported=${this.learningSupported}
13512
+ .loading=${this.learningLoading}
13513
+ .refreshing=${this.learningRefreshing}
13514
+ .error=${this.learningError}
13515
+ .snapshot=${this.learningSnapshot}
13516
+ .setupActive=${this.isLearningSetupActive()}
13517
+ .copyState=${this.learningPromptCopyState}
13518
+ .setupPrompt=${this.getHomeFeaturePromptTarget("threads") ? homeFeatureImplementationPrompt(this.getHomeFeaturePromptTarget("threads"), { onboardingRunId: this.getOnboardingRunId() }) : ""}
13519
+ @learning-retry=${() => this.refreshLearningSnapshot({ preserve: this.learningSnapshot !== null })}
13520
+ @learning-copy-setup=${(event) => this.handleLearningSetupCopy(event)}
13521
+ @learning-page=${(event) => this.handleLearningPage(event)}
13522
+ @learning-open-evidence=${(event) => this.handleLearningEvidence(event)}
13523
+ @learning-evidence-opened=${() => {
13524
+ if (!this.core?.telemetryDisabled) trackLearningEvidenceOpened();
13525
+ }}
13526
+ @learning-skill-toggle=${(event) => {
13527
+ if (!this.core?.telemetryDisabled) trackLearningSkillToggled({ action: event.detail.action });
13528
+ }}
13529
+ @learning-web-link=${(event) => {
13530
+ if (!this.core?.telemetryDisabled) trackLearningWebAppOpened({ category: event.detail.category });
13531
+ }}
13532
+ ></cpk-learning-view>
13533
+ `;
13534
+ }
13535
+ /** Legacy Memory rendering kept isolated while published Memory APIs remain. */
13536
+ renderLegacyMemoriesView() {
13537
+ if (!this.getHomeModel().services.some((service) => service.id === "memory" && service.enabled)) return this.renderLockedFeatureOverview({
13538
+ serviceId: "memory",
13539
+ featureName: "Learning",
13540
+ heading: this._memoryStoreUnsupported ? "Upgrade to enable Learning" : "Turn every interaction into reusable context.",
13541
+ description: this._memoryStoreUnsupported ? "Learning requires a newer version of @copilotkit/core and @copilotkit/react. Copy the setup prompt to upgrade and add long-term memory." : "Learning captures durable information from agent interactions and brings it back when it matters, so your product gets more useful over time.",
13542
+ videoUrl: LEARNING_LOCKED_VIDEO_URL,
13543
+ videoTitle: "CopilotKit Learning overview",
13544
+ outlineItems: LEARNING_LOCKED_FEATURE_OUTLINE
13545
+ });
12738
13546
  if (this._memoriesError && this._memories.length === 0) return html`
12739
13547
  <div
12740
13548
  style="
@@ -12945,16 +13753,27 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
12945
13753
  `;
12946
13754
  }
12947
13755
  renderThreadsView() {
12948
- const locked = !this.areThreadEndpointsAvailable();
13756
+ if (!this.areThreadEndpointsAvailable()) {
13757
+ this.trackThreadsViewStateOnce("locked");
13758
+ const lockedCopy = this.getThreadsLockedCopy();
13759
+ return this.renderLockedFeatureOverview({
13760
+ serviceId: "threads",
13761
+ featureName: "Rich Threads",
13762
+ heading: lockedCopy.heading,
13763
+ description: lockedCopy.description,
13764
+ videoUrl: THREADS_LOCKED_VIDEO_URL,
13765
+ videoTitle: "Rich Threads overview",
13766
+ outlineItems: THREADS_LOCKED_FEATURE_OUTLINE
13767
+ });
13768
+ }
12949
13769
  const { displayThreads, threadsErrorMessage, threadsLoading } = this.getActiveThreadsState();
12950
- const loadingWithoutRows = !locked && threadsLoading && !threadsErrorMessage && displayThreads.length === 0;
12951
- const showingExamples = this.shouldRenderExampleThreads(locked, displayThreads, threadsErrorMessage, threadsLoading);
12952
- const visibleThreads = !locked && (threadsErrorMessage || loadingWithoutRows) ? [] : showingExamples ? THREADS_EXAMPLE_THREADS : displayThreads;
13770
+ const loadingWithoutRows = threadsLoading && !threadsErrorMessage && displayThreads.length === 0;
13771
+ const showingExamples = this.shouldRenderExampleThreads(displayThreads, threadsErrorMessage, threadsLoading);
13772
+ const visibleThreads = threadsErrorMessage || loadingWithoutRows ? [] : showingExamples ? THREADS_EXAMPLE_THREADS : displayThreads;
12953
13773
  if (showingExamples) this.trackThreadsExampleViewedOnce();
12954
13774
  const selectedThread = this.selectedThreadId != null ? visibleThreads.find((t) => t.id === this.selectedThreadId) ?? null : null;
12955
13775
  const selectedThreadIsLocalExample = selectedThread !== null && selectedThread.id === this.selectedLocalExampleThreadId;
12956
- if (locked) this.trackThreadsViewStateOnce("locked");
12957
- else if (!threadsErrorMessage && (!threadsLoading || displayThreads.length > 0)) this.trackThreadsViewStateOnce(displayThreads.length === 0 ? "empty_enabled" : "enabled");
13776
+ if (!threadsErrorMessage && (!threadsLoading || displayThreads.length > 0)) this.trackThreadsViewStateOnce(displayThreads.length === 0 ? "empty_enabled" : "enabled");
12958
13777
  return html`
12959
13778
  <div
12960
13779
  style="display:flex;height:100%;overflow:hidden;flex-direction:column;"
@@ -12992,7 +13811,7 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
12992
13811
  <div
12993
13812
  style="flex:1;min-width:0;overflow:hidden;display:flex;position:relative;"
12994
13813
  >
12995
- ${!locked && threadsErrorMessage ? html`
13814
+ ${threadsErrorMessage ? html`
12996
13815
  <div
12997
13816
  role="alert"
12998
13817
  style="
@@ -13055,7 +13874,7 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
13055
13874
  this.handleTryFromHere(event.detail);
13056
13875
  }}
13057
13876
  ></cpk-thread-details>
13058
- ${selectedThreadIsLocalExample ? this.renderThreadsExampleTour() : nothing}` : showingExamples ? this.renderThreadsExampleOverview(locked) : html`
13877
+ ${selectedThreadIsLocalExample ? this.renderThreadsExampleTour() : nothing}` : showingExamples ? this.renderThreadsExampleOverview() : html`
13059
13878
  <div
13060
13879
  style="
13061
13880
  flex: 1;
@@ -13747,8 +14566,13 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
13747
14566
  }
13748
14567
  if (key === "playground" && !this.playgroundAgent) this.startPlaygroundSession(false);
13749
14568
  if (key === "memories") {
13750
- this.ensureMemorySubscription();
14569
+ this.learningSupported = Boolean(this.core?.inspectorLearning);
14570
+ if (previousMenu !== "memories" || this.learningSnapshot === null) this.refreshLearningSnapshot({ preserve: previousMenu === "memories" });
13751
14571
  if (previousMenu !== "memories" && !this.core?.telemetryDisabled) trackMemoriesTabClicked(this.getMemoriesTelemetryProps());
14572
+ } else if (previousMenu === "memories") {
14573
+ this.learningViewedState = null;
14574
+ this.cancelLearningPoll();
14575
+ this.cancelLearningRequest();
13752
14576
  }
13753
14577
  if (key === "home" && previousMenu !== "home") this.homeViewedThisOpen = false;
13754
14578
  if (key === "ag-ui-events" || key === "agents") {
@@ -13782,6 +14606,10 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
13782
14606
  this.expandedRows.clear();
13783
14607
  this.autoSelectLatestThread();
13784
14608
  if (this.selectedMenu === "playground") this.startPlaygroundSession(false);
14609
+ else if (this.selectedMenu === "memories") {
14610
+ this.clearLearningSnapshot();
14611
+ this.refreshLearningSnapshot({ preserve: false });
14612
+ }
13785
14613
  }
13786
14614
  this.contextMenuOpen = false;
13787
14615
  this.persistState();
@@ -14509,12 +15337,12 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
14509
15337
  /**
14510
15338
  * Requests one beat for a signal, running it now or deferring it.
14511
15339
  *
14512
- * There is a single pending slot and four reasons a beat cannot land. All
14513
- * four are the same situation — "cannot land now, run later" — and treating
15340
+ * There is a single pending slot and five reasons a beat cannot land. All
15341
+ * five are the same situation — "cannot land now, run later" — and treating
14514
15342
  * them alike is the point: three separate behaviours for one situation would
14515
15343
  * not survive a third signal.
14516
15344
  *
14517
- * Reason 3 is not cosmetic. Starting a beat while one runs does not restart
15345
+ * Reason 4 is not cosmetic. Starting a beat while one runs does not restart
14518
15346
  * the animation, because the attribute it binds to does not change value and
14519
15347
  * the pseudo-element selectors match on attribute *presence*; the running
14520
15348
  * beat would merely change colour mid-flight. A failure that arms during an
@@ -14523,11 +15351,11 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
14523
15351
  *
14524
15352
  * A failure's beat is followed by a pill, and the whole 3.4-second gesture
14525
15353
  * holds this one slot for its full duration. That is not a second scheduling
14526
- * concept: reason 3 already says "another beat is running", and a gesture is
15354
+ * concept: reason 4 already says "another beat is running", and a gesture is
14527
15355
  * simply a longer beat.
14528
15356
  */
14529
15357
  startSignalPulse(key) {
14530
- if (this.isOpen || typeof document !== "undefined" && document.visibilityState !== "visible" || this.gestureSlotSignal !== null && this.gestureSlotSignal !== key || this.getActiveLauncherSignal() !== key) {
15358
+ if (this.isOpen || this.isInspectorDismissed || typeof document !== "undefined" && document.visibilityState !== "visible" || this.gestureSlotSignal !== null && this.gestureSlotSignal !== key || this.getActiveLauncherSignal() !== key) {
14531
15359
  const pending = this.pendingPulseSignal;
14532
15360
  if (pending === null || LAUNCHER_SIGNALS[key].priority >= LAUNCHER_SIGNALS[pending].priority) this.pendingPulseSignal = key;
14533
15361
  this.requestUpdate();
@@ -14592,7 +15420,7 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
14592
15420
  }
14593
15421
  /**
14594
15422
  * The signal holding the single gesture slot: a beat in flight, or the pill
14595
- * and spoken sentence that follow it. One slot, not two — see reason 3 in
15423
+ * and spoken sentence that follow it. One slot, not two — see reason 4 in
14596
15424
  * `startSignalPulse`.
14597
15425
  */
14598
15426
  get gestureSlotSignal() {