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