@copilotkit/web-inspector 1.69.2 → 1.70.0

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.
package/dist/index.mjs CHANGED
@@ -8,7 +8,8 @@ import { projectInspectorMetadata } from "./lib/inspector-metadata.mjs";
8
8
  import { buildHomeModel, runtimeConnectionNeedsAttention } from "./lib/home-briefing.mjs";
9
9
  import { INSPECTOR_GROUPS, INSPECTOR_NAV_SECTIONS, getGroupForMenu, isInspectorMenuKey, shouldUseIconRail } from "./lib/inspector-nav.mjs";
10
10
  import { selectVisibleRealThreadId } from "./lib/thread-selection.mjs";
11
- import { TELEMETRY_DOCS_URL, ensureTelemetryDistinctId, getRuntimeUrlType, getTelemetryDistinctIdForUrl, maybeShowDisclosure, trackErrorSignalViewed, trackHomeCtaClicked, trackHomeViewed, trackInspectorOpened, trackMemoriesTabClicked, trackMetadataActionClicked, trackMetadataModuleViewed, trackTalkToEngineerClicked, trackThreadsEmptyEnabledViewed, trackThreadsEnabledViewed, trackThreadsExampleSelected, trackThreadsExampleTourCompleted, trackThreadsExampleTourDismissed, trackThreadsExampleTourReopened, trackThreadsExampleTourStarted, trackThreadsExampleTourStepViewed, trackThreadsExampleViewed, trackThreadsIntelligenceSignupClicked, trackThreadsLockedViewed, trackThreadsTabClicked, trackThreadsTalkToEngineerClicked, trackWhatsNewClicked, trackWhatsNewSignalViewed, trackWhatsNewViewed } from "./lib/telemetry.mjs";
11
+ import { TELEMETRY_DOCS_URL, ensureTelemetryDistinctId, getRuntimeUrlType, getTelemetryDistinctIdForUrl, maybeShowDisclosure, trackErrorSignalViewed, trackHomeCtaClicked, trackHomePromptCopied, trackHomeStoryBeatSelected, trackHomeViewed, trackInspectorOpened, trackMemoriesTabClicked, trackMetadataActionClicked, trackMetadataModuleViewed, trackTalkToEngineerClicked, trackThreadsEmptyEnabledViewed, trackThreadsEnabledViewed, trackThreadsExampleSelected, trackThreadsExampleTourCompleted, trackThreadsExampleTourDismissed, trackThreadsExampleTourReopened, trackThreadsExampleTourStarted, trackThreadsExampleTourStepViewed, trackThreadsExampleViewed, trackThreadsIntelligenceSignupClicked, trackThreadsLockedViewed, trackThreadsTabClicked, trackThreadsTalkToEngineerClicked, trackThreadsTryFromHereClicked, trackWhatsNewClicked, trackWhatsNewSignalViewed, trackWhatsNewViewed } from "./lib/telemetry.mjs";
12
+ import { createOnboardingPrompt, createOnboardingRunId } from "./lib/onboarding-prompt.mjs";
12
13
  import { LitElement, css, html, nothing, render, unsafeCSS } from "lit";
13
14
  import { marked } from "marked";
14
15
  import { styleMap } from "lit/directives/style-map.js";
@@ -242,6 +243,21 @@ const LAUNCHER_BASE_LABEL = "Web Inspector";
242
243
  const EDGE_MARGIN = 16;
243
244
  /** HUD card plus the hover bridge. Used to pick left vs right. */
244
245
  const LAUNCHER_HUD_WIDTH = 248;
246
+ /**
247
+ * One page-load preview of the launcher's feature HUD.
248
+ *
249
+ * The card arrives after the host page has had a beat to settle. Its four rows
250
+ * then come online in order, stay readable, and leave together. Nothing is
251
+ * persisted: a new Inspector element means a new preview.
252
+ */
253
+ const LAUNCHER_HUD_INTRO_MS = {
254
+ delay: 500,
255
+ duration: 3400,
256
+ rowStart: 180,
257
+ rowStagger: 170,
258
+ rowDuration: 300,
259
+ blockedRetry: 250
260
+ };
245
261
  const DRAG_THRESHOLD = 6;
246
262
  const MIN_WINDOW_WIDTH = 880;
247
263
  const MIN_WINDOW_WIDTH_DOCKED_LEFT = 640;
@@ -281,6 +297,108 @@ const THREADS_RUNTIME_SETUP_PROMPT = [
281
297
  "Start the app and verify GET {basePath}/info reports threadEndpoints.list, inspect, mutations, and realtimeMetadata as true. Run focused tests, lint, and typecheck. Report the files changed, commands run, and verification result. If blocked, explain the missing input; do not invent setup."
282
298
  ].join("\n");
283
299
  const SELF_HOSTED_INTELLIGENCE_URL = "https://docs.copilotkit.ai/premium/self-hosting";
300
+ const INTELLIGENCE_STORY_BEATS = [
301
+ {
302
+ id: "threads",
303
+ label: "Threads",
304
+ duration: 6500,
305
+ lead: "You only see this session. Your users have all the others.",
306
+ support: "Rich Threads keep every conversation and its state, so you can open the one that broke instead of reproducing it."
307
+ },
308
+ {
309
+ id: "learning",
310
+ label: "Learning",
311
+ duration: 6e3,
312
+ lead: "Your users already told you what to fix.",
313
+ support: "Learning reads the runs behind those threads and finds the patterns — every Insight linked to the messages that back it."
314
+ },
315
+ {
316
+ id: "skill",
317
+ label: "Skills",
318
+ duration: 5500,
319
+ lead: "An Insight becomes a skill you own.",
320
+ support: "A SKILL.md built from that evidence — yours to review, edit and ship with your project."
321
+ },
322
+ {
323
+ id: "intelligence",
324
+ label: "Intelligence",
325
+ duration: 6e3,
326
+ lead: "Every round of real use leaves your agent better.",
327
+ support: "Approve a skill, pull it into your project, and the next run starts from what already worked."
328
+ }
329
+ ];
330
+ /**
331
+ * The threads the first beat shows.
332
+ *
333
+ * One of them failed, because that is the row a developer actually wants and
334
+ * the reason durable threads are worth paying for. It is a user's thread that
335
+ * went wrong, not a demo of our agent failing — the distinction matters for a
336
+ * card that has to argue for the product.
337
+ */
338
+ const INTELLIGENCE_STORY_THREADS = [
339
+ {
340
+ title: "Reschedule the Tuesday sync",
341
+ meta: "2 min ago",
342
+ failed: false
343
+ },
344
+ {
345
+ title: "Book time with the design team",
346
+ meta: "18 min ago",
347
+ failed: false
348
+ },
349
+ {
350
+ title: "Booked the wrong slot",
351
+ meta: "Needs a look",
352
+ failed: true
353
+ }
354
+ ];
355
+ /** The three rules the story derives, shown verbatim across all three beats. */
356
+ const INTELLIGENCE_STORY_RULES = [
357
+ "Check both calendars.",
358
+ "Propose several times.",
359
+ "Ask before booking."
360
+ ];
361
+ /**
362
+ * The raw thread signals the first beat collapses into those rules.
363
+ *
364
+ * Kept at real-message length and varied on purpose — these have to read as
365
+ * things people actually typed, not as three tidy bullet points. The longest
366
+ * one truncates in a narrow panel, which is honest: it is an excerpt.
367
+ */
368
+ const INTELLIGENCE_STORY_SIGNALS = [
369
+ "Check our calendars and find a time for both of us.",
370
+ "Could you share a few options?",
371
+ "Ask me before you book it."
372
+ ];
373
+ const INTELLIGENCE_STORY_SKILL_FILE = "meeting-scheduling/SKILL.md";
374
+ /**
375
+ * How long the copied confirmation stands before the button invites a second
376
+ * press. Longer than the 2s the Threads setup prompt uses, because this state
377
+ * also carries an instruction that has to be read, not just an acknowledgement.
378
+ */
379
+ const PROMPT_COPY_RESET_MS = 4e3;
380
+ const INTELLIGENCE_STORY_CHAIN = [
381
+ {
382
+ icon: "MessagesSquare",
383
+ name: "Threads",
384
+ detail: "Every conversation"
385
+ },
386
+ {
387
+ icon: "Lightbulb",
388
+ name: "Insights",
389
+ detail: "Backed by evidence"
390
+ },
391
+ {
392
+ icon: "FileText",
393
+ name: "Skills",
394
+ detail: "You approve"
395
+ },
396
+ {
397
+ icon: "Wand2",
398
+ name: "Your agent",
399
+ detail: "Starts from what worked"
400
+ }
401
+ ];
284
402
  const THREADS_EXAMPLE_OVERVIEW_VIDEO_URL = "https://cdn.copilotkit.ai/corp-site/videos/copilotkit-generative-ui-agentic-frontend-demo.webm";
285
403
  const THREADS_EXAMPLE_OVERVIEW_VIDEO_FALLBACK = "The demo video is unavailable. Use the example threads to explore Messages, AG-UI Events, and State.";
286
404
  const THREADS_EXAMPLE_TOUR_STORAGE_KEY = "cpk:inspector:threads-example-tour:v1";
@@ -347,6 +465,29 @@ const AGENT_EVENT_TYPES = [
347
465
  "ACTIVITY_SNAPSHOT",
348
466
  "ACTIVITY_DELTA"
349
467
  ];
468
+ const EMPTY_INSPECTOR_MESSAGES = [];
469
+ function textFromUnknownContent(content) {
470
+ if (typeof content === "string") return content;
471
+ if (Array.isArray(content)) {
472
+ const parts = [];
473
+ for (const part of content) {
474
+ if (typeof part === "string") {
475
+ parts.push(part);
476
+ continue;
477
+ }
478
+ if (typeof part === "object" && part !== null && "text" in part) {
479
+ const text = part.text;
480
+ if (typeof text === "string") parts.push(text);
481
+ }
482
+ }
483
+ return parts.join("");
484
+ }
485
+ if (typeof content === "object" && content !== null && "text" in content) {
486
+ const text = content.text;
487
+ if (typeof text === "string") return text;
488
+ }
489
+ return "";
490
+ }
350
491
  /**
351
492
  * Map core.tools (the registry INCLUDING disabled tools) into Capabilities-tab
352
493
  * frontend-tool rows. Pure: no DOM, no `this`. Reads current on/off state from
@@ -605,13 +746,6 @@ function highlightedJson(obj) {
605
746
  const cached = highlightedJsonCache.get(obj);
606
747
  if (cached !== void 0) return cached;
607
748
  }
608
- const colors = {
609
- key: "#5558B2",
610
- str: "#087653",
611
- num: "#8a5900",
612
- bool: "#c0333a",
613
- nil: "#68686e"
614
- };
615
749
  const json = JSON.stringify(obj, null, 2);
616
750
  if (!json) return "";
617
751
  const parts = [];
@@ -621,11 +755,11 @@ function highlightedJson(obj) {
621
755
  while ((match = re.exec(json)) !== null) {
622
756
  parts.push(escapeHtml(json.slice(lastIndex, match.index)));
623
757
  const m = match[0];
624
- let color = colors.num;
625
- if (m.startsWith("\"")) color = m.trimEnd().endsWith(":") ? colors.key : colors.str;
626
- else if (m === "true" || m === "false") color = colors.bool;
627
- else if (m === "null") color = colors.nil;
628
- parts.push(`<span style="color:${color}">${escapeHtml(m)}</span>`);
758
+ let token = "num";
759
+ if (m.startsWith("\"")) token = m.trimEnd().endsWith(":") ? "key" : "str";
760
+ else if (m === "true" || m === "false") token = "bool";
761
+ else if (m === "null") token = "nil";
762
+ parts.push(`<span class="cpk-json-token cpk-json-token--${token}">${escapeHtml(m)}</span>`);
629
763
  lastIndex = match.index + m.length;
630
764
  }
631
765
  parts.push(escapeHtml(json.slice(lastIndex)));
@@ -650,31 +784,23 @@ function renderHighlightedJsonBlock(value, options = {}) {
650
784
  ${unsafeHTML(highlightedJson(parsed))}</pre
651
785
  >`;
652
786
  }
653
- function eventColors(type) {
654
- if (type.startsWith("TEXT_MESSAGE")) return {
655
- bg: "#EEE6FE",
656
- fg: "#57575B"
657
- };
658
- if (type.startsWith("TOOL_CALL")) return {
659
- bg: "rgba(133,236,206,0.15)",
660
- fg: "#087653"
661
- };
662
- if (type.startsWith("STATE")) return {
663
- bg: "rgba(190,194,255,0.102)",
664
- fg: "#5558B2"
665
- };
666
- if (type === "RUN_ERROR" || type === "ERROR") return {
667
- bg: "rgba(250,95,103,0.13)",
668
- fg: "#c0333a"
669
- };
670
- if (type.startsWith("RUN_") || type.startsWith("STEP_")) return {
671
- bg: "rgba(255,172,77,0.2)",
672
- fg: "#8a5900"
673
- };
674
- return {
675
- bg: "#F7F7F9",
676
- fg: "#68686e"
677
- };
787
+ function humanizeEventType(type) {
788
+ const words = type.trim().split(/[_\s]+/).filter(Boolean).map((word) => word.toLowerCase());
789
+ if (words.length === 0) return "Event";
790
+ const [first = "event", ...rest] = words;
791
+ return [`${first.charAt(0).toUpperCase()}${first.slice(1)}`, ...rest].join(" ");
792
+ }
793
+ function messageTitle(role) {
794
+ const normalized = role.trim() || "message";
795
+ return `${`${normalized.charAt(0).toUpperCase()}${normalized.slice(1).toLowerCase()}`} message`;
796
+ }
797
+ function eventCategory(type) {
798
+ if (type === "RUN_ERROR" || type === "ERROR") return "error";
799
+ if (type.startsWith("TEXT_MESSAGE")) return "message";
800
+ if (type.startsWith("TOOL_CALL")) return "tool";
801
+ if (type.startsWith("STATE") || type.startsWith("MESSAGES")) return "state";
802
+ if (type.startsWith("RUN_") || type.startsWith("STEP_")) return "run";
803
+ return "event";
678
804
  }
679
805
  function formatTimestamp(ts) {
680
806
  const date = typeof ts === "number" ? new Date(ts) : new Date(ts);
@@ -1076,11 +1202,15 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
1076
1202
  this.threadInspectionAvailable = false;
1077
1203
  this.agentStateInput = null;
1078
1204
  this.agentEventsInput = [];
1205
+ this.agentMessagesInput = EMPTY_INSPECTOR_MESSAGES;
1079
1206
  this.liveMessageVersion = 0;
1080
1207
  this.viewInAppMode = "hidden";
1081
1208
  this.viewInAppError = null;
1082
1209
  this.focusMessageId = null;
1083
1210
  this.focusRequestId = 0;
1211
+ this.tryFromHereAvailable = false;
1212
+ this.tryFromHereBusy = false;
1213
+ this.tryFromHereError = null;
1084
1214
  this._tab = "timeline";
1085
1215
  this._fetchedMetadata = null;
1086
1216
  this._conversation = [];
@@ -1140,6 +1270,15 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
1140
1270
  if (target.hasPointerCapture(this._dividerPointerId)) target.releasePointerCapture(this._dividerPointerId);
1141
1271
  this._dividerResizing = false;
1142
1272
  };
1273
+ this.onTryFromHere = (event) => {
1274
+ event.preventDefault();
1275
+ if (!this.tryFromHereAvailable || this.tryFromHereBusy) return;
1276
+ this.dispatchEvent(new CustomEvent("tryFromHere", {
1277
+ detail: this.threadId,
1278
+ bubbles: true,
1279
+ composed: true
1280
+ }));
1281
+ };
1143
1282
  }
1144
1283
  static {
1145
1284
  this.properties = {
@@ -1151,11 +1290,15 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
1151
1290
  threadInspectionAvailable: { attribute: false },
1152
1291
  agentStateInput: { attribute: false },
1153
1292
  agentEventsInput: { attribute: false },
1293
+ agentMessagesInput: { attribute: false },
1154
1294
  liveMessageVersion: { attribute: false },
1155
1295
  viewInAppMode: { attribute: false },
1156
1296
  viewInAppError: { attribute: false },
1157
1297
  focusMessageId: { attribute: false },
1158
1298
  focusRequestId: { attribute: false },
1299
+ tryFromHereAvailable: { attribute: false },
1300
+ tryFromHereBusy: { attribute: false },
1301
+ tryFromHereError: { attribute: false },
1159
1302
  _tab: { state: true },
1160
1303
  _fetchedMetadata: { state: true },
1161
1304
  _conversation: { state: true },
@@ -1232,7 +1375,7 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
1232
1375
  return JSON.stringify(Object.entries(headers).sort(([leftKey], [rightKey]) => leftKey.localeCompare(rightKey)));
1233
1376
  }
1234
1377
  renderTabContent(id) {
1235
- if (id === "timeline") return this.renderTimeline();
1378
+ if (id === "timeline") return this.withMessagesToolbar(this.renderTimeline());
1236
1379
  if (id === "state") return this.renderState();
1237
1380
  return this.renderEvents();
1238
1381
  }
@@ -1295,6 +1438,11 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
1295
1438
  display: flex;
1296
1439
  flex-direction: row;
1297
1440
  overflow: hidden;
1441
+ --cpk-json-key: #3d408f;
1442
+ --cpk-json-str: #0b6b4c;
1443
+ --cpk-json-num: #8a5900;
1444
+ --cpk-json-bool: #c0333a;
1445
+ --cpk-json-nil: #57575b;
1298
1446
  }
1299
1447
 
1300
1448
  .cpk-td {
@@ -1419,11 +1567,25 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
1419
1567
  flex-shrink: 0;
1420
1568
  }
1421
1569
 
1422
- .cpk-td__metadata-strip {
1570
+ .cpk-td__chrome-actions {
1571
+ margin-inline-start: auto;
1423
1572
  display: flex;
1573
+ flex-wrap: wrap;
1424
1574
  align-items: center;
1575
+ justify-content: flex-end;
1425
1576
  gap: 6px;
1426
- flex-wrap: wrap;
1577
+ padding-inline: 8px;
1578
+ min-width: 0;
1579
+ }
1580
+
1581
+ .cpk-td__chrome-actions + .cpk-td__panel-toggle {
1582
+ margin-inline-start: 0;
1583
+ }
1584
+
1585
+ .cpk-td__metadata-strip {
1586
+ display: flex;
1587
+ flex-direction: column;
1588
+ gap: 8px;
1427
1589
  padding: 10px 16px;
1428
1590
  border-bottom: 1px solid #e9e9ef;
1429
1591
  background: #fbfbfd;
@@ -1432,19 +1594,22 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
1432
1594
 
1433
1595
  .cpk-td__metadata-pills {
1434
1596
  display: flex;
1597
+ align-items: center;
1435
1598
  gap: 6px;
1436
- flex: 1;
1437
- flex-wrap: wrap;
1599
+ width: 100%;
1438
1600
  min-width: 0;
1601
+ flex-wrap: nowrap;
1439
1602
  }
1440
1603
 
1441
1604
  .cpk-td__metadata-pill {
1442
1605
  display: inline-flex;
1443
1606
  align-items: center;
1444
- gap: 5px;
1445
- max-width: 220px;
1446
- padding: 3px 7px;
1447
- border: 1px solid #e9e9ef;
1607
+ gap: 6px;
1608
+ flex: 1 1 0;
1609
+ min-width: 0;
1610
+ height: 24px;
1611
+ padding: 0 8px;
1612
+ border: 1px solid #dbdbe5;
1448
1613
  border-radius: 6px;
1449
1614
  background: #ffffff;
1450
1615
  color: #57575b;
@@ -1460,20 +1625,17 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
1460
1625
  }
1461
1626
 
1462
1627
  .cpk-td__metadata-value {
1628
+ min-width: 0;
1463
1629
  overflow: hidden;
1464
1630
  text-overflow: ellipsis;
1631
+ white-space: nowrap;
1465
1632
  }
1466
1633
 
1634
+ .cpk-td__metadata-value--wrap,
1467
1635
  .cpk-td__metadata-pill--wrap {
1468
- max-width: 100%;
1469
- white-space: normal;
1470
- }
1471
-
1472
- .cpk-td__metadata-value--wrap {
1473
- overflow: visible;
1474
- text-overflow: clip;
1475
- white-space: normal;
1476
- overflow-wrap: anywhere;
1636
+ overflow: hidden;
1637
+ text-overflow: ellipsis;
1638
+ white-space: nowrap;
1477
1639
  }
1478
1640
 
1479
1641
  .cpk-td__view-in-app {
@@ -1484,11 +1646,18 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
1484
1646
  border-radius: 6px;
1485
1647
  background: #5558b2;
1486
1648
  color: #ffffff;
1487
- font-family: "Plus Jakarta Sans", sans-serif;
1488
- font-size: 11px;
1649
+ font-family: "Spline Sans Mono", monospace;
1650
+ font-size: 10px;
1489
1651
  font-weight: 600;
1490
- padding: 5px 10px;
1652
+ line-height: 1.2;
1653
+ min-height: 24px;
1654
+ padding: 3px 8px;
1491
1655
  cursor: pointer;
1656
+ transition:
1657
+ transform 160ms cubic-bezier(0.23, 1, 0.32, 1),
1658
+ background 120ms ease,
1659
+ color 120ms ease,
1660
+ border-color 120ms ease;
1492
1661
  }
1493
1662
 
1494
1663
  .cpk-td__view-in-app:focus-visible {
@@ -1496,6 +1665,10 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
1496
1665
  outline-offset: 2px;
1497
1666
  }
1498
1667
 
1668
+ .cpk-td__view-in-app:active {
1669
+ transform: scale(0.96);
1670
+ }
1671
+
1499
1672
  .cpk-td__view-in-app--stop {
1500
1673
  background: #ffffff;
1501
1674
  color: #5558b2;
@@ -1507,6 +1680,65 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
1507
1680
  font-size: 11px;
1508
1681
  }
1509
1682
 
1683
+ @media (prefers-reduced-motion: reduce) {
1684
+ .cpk-td__view-in-app {
1685
+ transition: none;
1686
+ }
1687
+
1688
+ .cpk-td__view-in-app:active {
1689
+ transform: none;
1690
+ }
1691
+ }
1692
+
1693
+ .cpk-td__try-from-here {
1694
+ display: inline-flex;
1695
+ align-items: center;
1696
+ gap: 4px;
1697
+ margin-inline-start: auto;
1698
+ padding: 6px 10px;
1699
+ border: 1px solid #dbdbe5;
1700
+ border-radius: 8px;
1701
+ background: #ffffff;
1702
+ color: #36363a;
1703
+ font-family: "Spline Sans Mono", monospace;
1704
+ font-size: 11px;
1705
+ font-weight: 600;
1706
+ line-height: 1.2;
1707
+ cursor: pointer;
1708
+ }
1709
+
1710
+ .cpk-td__try-from-here-icon {
1711
+ display: block;
1712
+ flex-shrink: 0;
1713
+ }
1714
+
1715
+ :host([dir="rtl"]) .cpk-td__try-from-here-icon {
1716
+ scale: -1 1;
1717
+ }
1718
+
1719
+ .cpk-td__try-from-here:hover:not(:disabled) {
1720
+ border-color: rgba(85, 88, 178, 0.38);
1721
+ background: #f7f7ff;
1722
+ color: #010507;
1723
+ }
1724
+
1725
+ .cpk-td__try-from-here:focus-visible {
1726
+ outline: 2px solid #a78bfa;
1727
+ outline-offset: 1px;
1728
+ }
1729
+
1730
+ .cpk-td__try-from-here:disabled {
1731
+ cursor: not-allowed;
1732
+ opacity: 0.55;
1733
+ }
1734
+
1735
+ .cpk-td__try-from-here-error {
1736
+ flex-basis: 100%;
1737
+ color: #c0333a;
1738
+ font-size: 11px;
1739
+ line-height: 1.4;
1740
+ }
1741
+
1510
1742
  /*
1511
1743
  * Each tab's content is wrapped in this panel so the keep-mounted
1512
1744
  * inactive panels can be hidden via display:none without disturbing
@@ -1703,15 +1935,16 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
1703
1935
  .cpk-td__tool-pre {
1704
1936
  margin: 0;
1705
1937
  font-family: "Spline Sans Mono", monospace;
1706
- font-size: 10px;
1938
+ font-size: 12px;
1707
1939
  background: #f7f7f9;
1708
- padding: 6px 8px;
1709
- border-radius: 5px;
1940
+ padding: 10px 12px;
1941
+ border-radius: 6px;
1710
1942
  overflow-x: auto;
1711
1943
  white-space: pre-wrap;
1712
- word-break: break-all;
1944
+ overflow-wrap: anywhere;
1945
+ word-break: normal;
1713
1946
  color: #010507;
1714
- line-height: 1.6;
1947
+ line-height: 1.65;
1715
1948
  }
1716
1949
 
1717
1950
  /* ── Tool call group ─────────────────────────────────────────────── */
@@ -1764,12 +1997,31 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
1764
1997
 
1765
1998
  /* ── Interaction timeline ───────────────────────────────────────── */
1766
1999
  .cpk-td__timeline-item {
1767
- border: 1px solid #e9e9ef;
1768
- border-radius: 7px;
1769
- background: #ffffff;
2000
+ border: 1px solid transparent;
2001
+ border-radius: 10px;
2002
+ background: transparent;
1770
2003
  overflow: hidden;
1771
2004
  }
1772
2005
 
2006
+ .cpk-td__timeline-item--run,
2007
+ .cpk-td__timeline-item--state,
2008
+ .cpk-td__timeline-item--event,
2009
+ .cpk-td__timeline-item--tool,
2010
+ .cpk-td__event--run,
2011
+ .cpk-td__event--event,
2012
+ .cpk-td__event--state,
2013
+ .cpk-td__event--message,
2014
+ .cpk-td__event--tool {
2015
+ border-color: #dbdbe5;
2016
+ background: #ffffff;
2017
+ }
2018
+
2019
+ .cpk-td__timeline-item--message {
2020
+ border-color: #dbdbe5;
2021
+ background: #ffffff;
2022
+ box-shadow: 0 1px 2px #0105070d;
2023
+ }
2024
+
1773
2025
  .cpk-td__timeline-item--warning {
1774
2026
  border-color: rgba(250, 95, 103, 0.35);
1775
2027
  background: rgba(250, 95, 103, 0.04);
@@ -1779,29 +2031,72 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
1779
2031
  display: flex;
1780
2032
  align-items: center;
1781
2033
  gap: 8px;
1782
- padding: 7px 10px;
2034
+ padding: 6px 10px;
2035
+ background: transparent;
2036
+ }
2037
+
2038
+ .cpk-td__timeline-item--message .cpk-td__timeline-header {
2039
+ padding: 10px 12px;
1783
2040
  background: #f7f7f9;
1784
2041
  }
1785
2042
 
2043
+ .cpk-td__timeline-item--user .cpk-td__timeline-header {
2044
+ background: #bec2ff1a;
2045
+ }
2046
+
2047
+ .cpk-td__timeline-item--assistant .cpk-td__timeline-header {
2048
+ background: #85ecce1a;
2049
+ }
2050
+
1786
2051
  .cpk-td__timeline-kind {
2052
+ display: inline-flex;
2053
+ align-items: center;
2054
+ padding: 4px 8px;
2055
+ border-radius: 999px;
2056
+ background: #f0f0f4;
2057
+ color: #57575b;
1787
2058
  font-family: "Spline Sans Mono", monospace;
1788
- font-size: 9px;
2059
+ font-size: 10px;
1789
2060
  font-weight: 600;
2061
+ letter-spacing: 0.04em;
2062
+ line-height: 1.2;
1790
2063
  text-transform: uppercase;
1791
- color: #5558b2;
2064
+ flex-shrink: 0;
2065
+ }
2066
+
2067
+ .cpk-td__timeline-item--message .cpk-td__timeline-kind {
2068
+ background: #bec2ff33;
2069
+ color: #010507;
2070
+ }
2071
+
2072
+ .cpk-td__timeline-item--assistant .cpk-td__timeline-kind {
2073
+ background: #85ecce4d;
2074
+ color: #010507;
2075
+ }
2076
+
2077
+ .cpk-td__timeline-item--warning .cpk-td__timeline-kind {
2078
+ background: rgba(250, 95, 103, 0.16);
2079
+ color: #c0333a;
1792
2080
  }
1793
2081
 
1794
2082
  .cpk-td__timeline-title {
1795
2083
  flex: 1;
1796
2084
  min-width: 0;
2085
+ font-family: "Plus Jakarta Sans", sans-serif;
1797
2086
  font-size: 12px;
1798
2087
  font-weight: 500;
1799
- color: #010507;
2088
+ color: #57575b;
1800
2089
  overflow: hidden;
1801
2090
  text-overflow: ellipsis;
1802
2091
  white-space: nowrap;
1803
2092
  }
1804
2093
 
2094
+ .cpk-td__timeline-item--message .cpk-td__timeline-title {
2095
+ font-size: 13px;
2096
+ font-weight: 600;
2097
+ color: #010507;
2098
+ }
2099
+
1805
2100
  .cpk-td__timeline-time {
1806
2101
  font-family: "Spline Sans Mono", monospace;
1807
2102
  font-size: 9px;
@@ -1812,6 +2107,7 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
1812
2107
  .cpk-td__timeline-body {
1813
2108
  margin: 0;
1814
2109
  padding: 0 10px 9px;
2110
+ font-family: "Plus Jakarta Sans", sans-serif;
1815
2111
  font-size: 12px;
1816
2112
  line-height: 1.55;
1817
2113
  color: #57575b;
@@ -1819,21 +2115,28 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
1819
2115
  word-break: break-word;
1820
2116
  }
1821
2117
 
2118
+ .cpk-td__timeline-item--message .cpk-td__timeline-body {
2119
+ padding: 0 12px 12px;
2120
+ font-size: 13px;
2121
+ color: #010507;
2122
+ }
2123
+
1822
2124
  .cpk-td__timeline-toolbar {
1823
2125
  display: flex;
2126
+ flex-wrap: wrap;
2127
+ align-items: center;
1824
2128
  gap: 6px;
1825
- margin-left: auto;
1826
2129
  }
1827
2130
 
1828
2131
  .cpk-td__timeline-bulk-toggle {
1829
2132
  margin: 0;
1830
- padding: 4px 8px;
1831
- border: 1px solid #dcdce8;
1832
- border-radius: 7px;
2133
+ padding: 6px 10px;
2134
+ border: 1px solid #dbdbe5;
2135
+ border-radius: 8px;
1833
2136
  background: #ffffff;
1834
2137
  color: #36363a;
1835
2138
  cursor: pointer;
1836
- font-family: "Inter", sans-serif;
2139
+ font-family: "Spline Sans Mono", monospace;
1837
2140
  font-size: 11px;
1838
2141
  font-weight: 600;
1839
2142
  line-height: 1.2;
@@ -1908,84 +2211,6 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
1908
2211
  }
1909
2212
  }
1910
2213
 
1911
- @keyframes cpk-playground-message-enter {
1912
- from {
1913
- opacity: 0;
1914
- filter: blur(2px);
1915
- transform: translateY(4px);
1916
- }
1917
- to {
1918
- opacity: 1;
1919
- filter: blur(0);
1920
- transform: translateY(0);
1921
- }
1922
- }
1923
-
1924
- @keyframes cpk-playground-thinking {
1925
- 0%,
1926
- 60%,
1927
- 100% {
1928
- opacity: 0.28;
1929
- transform: translateY(0);
1930
- }
1931
- 30% {
1932
- opacity: 1;
1933
- transform: translateY(-2px);
1934
- }
1935
- }
1936
-
1937
- .cpk-playground-root {
1938
- container-type: inline-size;
1939
- }
1940
-
1941
- .cpk-playground-message-enter {
1942
- animation: cpk-playground-message-enter 0.24s cubic-bezier(0.16, 1, 0.3, 1)
1943
- both;
1944
- }
1945
-
1946
- .cpk-playground-thinking-dot {
1947
- animation: cpk-playground-thinking 1.2s ease-in-out infinite;
1948
- }
1949
-
1950
- .cpk-playground-thinking-dot:nth-child(2) {
1951
- animation-delay: 0.12s;
1952
- }
1953
-
1954
- .cpk-playground-thinking-dot:nth-child(3) {
1955
- animation-delay: 0.24s;
1956
- }
1957
-
1958
- .cpk-playground-reasoning summary::-webkit-details-marker {
1959
- display: none;
1960
- }
1961
-
1962
- .cpk-playground-reasoning[open] .cpk-playground-reasoning-chevron {
1963
- transform: rotate(90deg);
1964
- }
1965
-
1966
- @container (max-width: 560px) {
1967
- .cpk-playground-header {
1968
- align-items: stretch;
1969
- }
1970
-
1971
- .cpk-playground-actions {
1972
- width: 100%;
1973
- }
1974
-
1975
- .cpk-playground-thread-select {
1976
- min-width: 0;
1977
- max-width: none;
1978
- flex: 1;
1979
- }
1980
- }
1981
-
1982
- @media (prefers-reduced-motion: reduce) {
1983
- .cpk-playground-message-enter,
1984
- .cpk-playground-thinking-dot {
1985
- animation: none;
1986
- }
1987
- }
1988
-
1989
2214
  .cpk-td__genui {
1990
2215
  display: flex;
1991
2216
  flex-direction: column;
@@ -2027,8 +2252,9 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
2027
2252
  /* ── AG-UI Events ────────────────────────────────────────────────── */
2028
2253
  .cpk-td__event {
2029
2254
  flex-shrink: 0;
2030
- border: 1px solid #e9e9ef;
2031
- border-radius: 7px;
2255
+ border: 1px solid #dbdbe5;
2256
+ border-radius: 10px;
2257
+ background: #ffffff;
2032
2258
  overflow: hidden;
2033
2259
  /*
2034
2260
  * content-visibility: auto lets the browser skip layout + paint for
@@ -2044,48 +2270,89 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
2044
2270
  contain-intrinsic-size: 0 80px;
2045
2271
  }
2046
2272
 
2273
+ .cpk-td__event--error {
2274
+ border-color: rgba(250, 95, 103, 0.35);
2275
+ background: rgba(250, 95, 103, 0.04);
2276
+ }
2277
+
2047
2278
  .cpk-td__event-header {
2048
2279
  display: flex;
2049
- justify-content: space-between;
2050
2280
  align-items: center;
2051
- padding: 5px 10px;
2281
+ gap: 8px;
2282
+ padding: 6px 10px;
2283
+ background: transparent;
2052
2284
  }
2053
2285
 
2054
2286
  .cpk-td__event-type {
2287
+ display: inline-flex;
2288
+ align-items: center;
2289
+ padding: 4px 8px;
2290
+ border-radius: 999px;
2291
+ background: #f0f0f4;
2292
+ color: #010507;
2055
2293
  font-family: "Spline Sans Mono", monospace;
2056
- font-size: 9px;
2057
- font-weight: 500;
2058
- text-transform: uppercase;
2294
+ font-size: 10px;
2295
+ font-weight: 600;
2296
+ letter-spacing: 0.02em;
2297
+ line-height: 1.2;
2298
+ }
2299
+
2300
+ .cpk-td__event--message .cpk-td__event-type {
2301
+ background: #bec2ff33;
2302
+ }
2303
+
2304
+ .cpk-td__event--tool .cpk-td__event-type {
2305
+ background: #85ecce4d;
2306
+ }
2307
+
2308
+ .cpk-td__event--error .cpk-td__event-type {
2309
+ background: rgba(250, 95, 103, 0.16);
2310
+ color: #c0333a;
2059
2311
  }
2060
2312
 
2061
2313
  .cpk-td__event-time {
2314
+ margin-inline-start: auto;
2062
2315
  font-family: "Spline Sans Mono", monospace;
2063
2316
  font-size: 9px;
2064
2317
  color: #68686e;
2318
+ flex-shrink: 0;
2065
2319
  }
2066
2320
 
2067
- .cpk-td__event-payload {
2068
- margin: 0;
2069
- font-family: "Spline Sans Mono", monospace;
2070
- font-size: 10px;
2071
- line-height: 1.6;
2072
- white-space: pre-wrap;
2073
- word-break: break-all;
2074
- color: #57575b;
2075
- padding: 8px 10px;
2076
- border-top: 1px solid #e9e9ef;
2077
- }
2078
-
2079
- /* ── JSON block (agent state) ────────────────────────────────────── */
2321
+ .cpk-td__event-payload,
2080
2322
  .cpk-td__json-block,
2081
2323
  .cpk-json-block {
2082
2324
  margin: 0;
2325
+ padding: 10px 12px;
2326
+ border-top: 1px solid #dbdbe5;
2327
+ background: #f7f7f9;
2083
2328
  font-family: "Spline Sans Mono", monospace;
2084
- font-size: 11px;
2085
- line-height: 1.8;
2329
+ font-size: 12px;
2330
+ line-height: 1.65;
2086
2331
  white-space: pre-wrap;
2087
- word-break: break-all;
2088
- color: #57575b;
2332
+ overflow-wrap: anywhere;
2333
+ word-break: normal;
2334
+ color: #010507;
2335
+ overflow: auto;
2336
+ }
2337
+
2338
+ .cpk-json-token--key {
2339
+ color: var(--cpk-json-key);
2340
+ }
2341
+
2342
+ .cpk-json-token--str {
2343
+ color: var(--cpk-json-str);
2344
+ }
2345
+
2346
+ .cpk-json-token--num {
2347
+ color: var(--cpk-json-num);
2348
+ }
2349
+
2350
+ .cpk-json-token--bool {
2351
+ color: var(--cpk-json-bool);
2352
+ }
2353
+
2354
+ .cpk-json-token--nil {
2355
+ color: var(--cpk-json-nil);
2089
2356
  }
2090
2357
 
2091
2358
  /* ── Resize divider ──────────────────────────────────────────────── */
@@ -2184,6 +2451,11 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
2184
2451
 
2185
2452
  :host([data-color-scheme="dark"]) {
2186
2453
  color-scheme: dark;
2454
+ --cpk-json-key: #bec2ff;
2455
+ --cpk-json-str: #85ecce;
2456
+ --cpk-json-num: #ffac4d;
2457
+ --cpk-json-bool: #fa5f67;
2458
+ --cpk-json-nil: #afafb7;
2187
2459
  }
2188
2460
 
2189
2461
  :host([data-color-scheme="dark"]) .cpk-td {
@@ -2195,6 +2467,7 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
2195
2467
  :host([data-color-scheme="dark"]) .cpk-td__panel-toggle,
2196
2468
  :host([data-color-scheme="dark"]) .cpk-td__metadata-strip,
2197
2469
  :host([data-color-scheme="dark"]) .cpk-td__metadata-pill,
2470
+ :host([data-color-scheme="dark"]) .cpk-td__try-from-here,
2198
2471
  :host([data-color-scheme="dark"]) .cpk-td__tool-block,
2199
2472
  :host([data-color-scheme="dark"]) .cpk-td__tool-header,
2200
2473
  :host([data-color-scheme="dark"]) .cpk-td__tool-body,
@@ -2212,6 +2485,7 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
2212
2485
  }
2213
2486
 
2214
2487
  :host([data-color-scheme="dark"]) .cpk-td__metadata-pill,
2488
+ :host([data-color-scheme="dark"]) .cpk-td__try-from-here,
2215
2489
  :host([data-color-scheme="dark"]) .cpk-td__bubble-inner--assistant,
2216
2490
  :host([data-color-scheme="dark"]) .cpk-td__tool-block,
2217
2491
  :host([data-color-scheme="dark"]) .cpk-td__event,
@@ -2224,11 +2498,15 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
2224
2498
  }
2225
2499
 
2226
2500
  :host([data-color-scheme="dark"]) .cpk-td__timeline-header,
2227
- :host([data-color-scheme="dark"]) .cpk-td__tool-body,
2228
- :host([data-color-scheme="dark"]) .cpk-td__tool-pre {
2501
+ :host([data-color-scheme="dark"]) .cpk-td__tool-body {
2229
2502
  background: #171a22;
2230
2503
  }
2231
2504
 
2505
+ :host([data-color-scheme="dark"]) .cpk-td__tool-pre {
2506
+ background: #111319;
2507
+ color: #f3f4f8;
2508
+ }
2509
+
2232
2510
  :host([data-color-scheme="dark"]) .cpk-td__panel-toggle:hover,
2233
2511
  :host([data-color-scheme="dark"]) .cpk-td__tool-header:hover,
2234
2512
  :host([data-color-scheme="dark"]) .cpk-td__timeline-bulk-toggle:hover,
@@ -2238,12 +2516,115 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
2238
2516
 
2239
2517
  :host([data-color-scheme="dark"]) .cpk-td__panel-toggle--active,
2240
2518
  :host([data-color-scheme="dark"]) .cpk-td__inline-chip,
2241
- :host([data-color-scheme="dark"]) .cpk-td__timeline-kind,
2242
2519
  :host([data-color-scheme="dark"]) .cpk-td__genui-badge {
2243
2520
  background: #302b43;
2244
2521
  color: #d8d9ff;
2245
2522
  }
2246
2523
 
2524
+ :host([data-color-scheme="dark"]) .cpk-td__timeline-item--message {
2525
+ background: #191c24;
2526
+ border-color: #343742;
2527
+ box-shadow: none;
2528
+ }
2529
+
2530
+ :host([data-color-scheme="dark"])
2531
+ .cpk-td__timeline-item--user
2532
+ .cpk-td__timeline-header {
2533
+ background: #bec2ff1a;
2534
+ }
2535
+
2536
+ :host([data-color-scheme="dark"])
2537
+ .cpk-td__timeline-item--assistant
2538
+ .cpk-td__timeline-header {
2539
+ background: #85ecce1a;
2540
+ }
2541
+
2542
+ :host([data-color-scheme="dark"])
2543
+ .cpk-td__timeline-item--message
2544
+ .cpk-td__timeline-kind {
2545
+ background: #302b43;
2546
+ color: #d8d9ff;
2547
+ }
2548
+
2549
+ :host([data-color-scheme="dark"])
2550
+ .cpk-td__timeline-item--assistant
2551
+ .cpk-td__timeline-kind {
2552
+ background: #1a3a32;
2553
+ color: #85ecce;
2554
+ }
2555
+
2556
+ :host([data-color-scheme="dark"]) .cpk-td__timeline-item--run,
2557
+ :host([data-color-scheme="dark"]) .cpk-td__timeline-item--event,
2558
+ :host([data-color-scheme="dark"]) .cpk-td__timeline-item--state,
2559
+ :host([data-color-scheme="dark"]) .cpk-td__timeline-item--tool,
2560
+ :host([data-color-scheme="dark"]) .cpk-td__event--run,
2561
+ :host([data-color-scheme="dark"]) .cpk-td__event--event,
2562
+ :host([data-color-scheme="dark"]) .cpk-td__event--state,
2563
+ :host([data-color-scheme="dark"]) .cpk-td__event--message,
2564
+ :host([data-color-scheme="dark"]) .cpk-td__event--tool {
2565
+ background: #191c24;
2566
+ border-color: #343742;
2567
+ }
2568
+
2569
+ :host([data-color-scheme="dark"])
2570
+ .cpk-td__timeline-item--run
2571
+ .cpk-td__timeline-header,
2572
+ :host([data-color-scheme="dark"])
2573
+ .cpk-td__timeline-item--event
2574
+ .cpk-td__timeline-header,
2575
+ :host([data-color-scheme="dark"])
2576
+ .cpk-td__timeline-item--state
2577
+ .cpk-td__timeline-header {
2578
+ background: transparent;
2579
+ }
2580
+
2581
+ :host([data-color-scheme="dark"]) .cpk-td__timeline-kind {
2582
+ background: #20232d;
2583
+ color: #aeb1bd;
2584
+ }
2585
+
2586
+ :host([data-color-scheme="dark"])
2587
+ .cpk-td__timeline-item--run
2588
+ .cpk-td__timeline-title,
2589
+ :host([data-color-scheme="dark"])
2590
+ .cpk-td__timeline-item--event
2591
+ .cpk-td__timeline-title,
2592
+ :host([data-color-scheme="dark"])
2593
+ .cpk-td__timeline-item--state
2594
+ .cpk-td__timeline-title {
2595
+ color: #aeb1bd;
2596
+ }
2597
+
2598
+ :host([data-color-scheme="dark"]) .cpk-td__event-header {
2599
+ background: transparent;
2600
+ }
2601
+
2602
+ :host([data-color-scheme="dark"]) .cpk-td__event-type {
2603
+ background: #20232d;
2604
+ color: #f3f4f8;
2605
+ }
2606
+
2607
+ :host([data-color-scheme="dark"]) .cpk-td__event--message .cpk-td__event-type {
2608
+ background: #302b43;
2609
+ color: #d8d9ff;
2610
+ }
2611
+
2612
+ :host([data-color-scheme="dark"]) .cpk-td__event--tool .cpk-td__event-type {
2613
+ background: #1a3a32;
2614
+ color: #85ecce;
2615
+ }
2616
+
2617
+ :host([data-color-scheme="dark"]) .cpk-td__event--error .cpk-td__event-type {
2618
+ background: rgba(250, 95, 103, 0.2);
2619
+ color: #fa5f67;
2620
+ }
2621
+
2622
+ :host([data-color-scheme="dark"])
2623
+ .cpk-td__timeline-item--message
2624
+ .cpk-td__timeline-body {
2625
+ color: #f3f4f8;
2626
+ }
2627
+
2247
2628
  :host([data-color-scheme="dark"]) .cpk-td__tab,
2248
2629
  :host([data-color-scheme="dark"]) .cpk-td__panel-toggle,
2249
2630
  :host([data-color-scheme="dark"]) .cpk-td__metadata-label,
@@ -2263,6 +2644,7 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
2263
2644
  :host([data-color-scheme="dark"]) .cpk-td__timeline-title,
2264
2645
  :host([data-color-scheme="dark"]) .cpk-td__timeline-bulk-toggle,
2265
2646
  :host([data-color-scheme="dark"]) .cpk-td__timeline-details-toggle,
2647
+ :host([data-color-scheme="dark"]) .cpk-td__try-from-here,
2266
2648
  :host([data-color-scheme="dark"]) .cpk-tdp__value {
2267
2649
  color: #f3f4f8;
2268
2650
  }
@@ -2270,7 +2652,9 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
2270
2652
  :host([data-color-scheme="dark"]) .cpk-td__event-payload,
2271
2653
  :host([data-color-scheme="dark"]) .cpk-td__json-block,
2272
2654
  :host([data-color-scheme="dark"]) .cpk-json-block {
2273
- color: #c7c9d2;
2655
+ background: #111319;
2656
+ border-top-color: #343742;
2657
+ color: #f3f4f8;
2274
2658
  }
2275
2659
 
2276
2660
  :host([data-color-scheme="dark"]) .cpk-tdp__divider {
@@ -2290,7 +2674,8 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
2290
2674
  if (this.canFetchEvents()) {
2291
2675
  this._eventsFetched = true;
2292
2676
  this.fetchEvents(this.threadId);
2293
- } else this.fetchMessages(this.threadId);
2677
+ }
2678
+ if (this.canFetchMessages()) this.fetchMessages(this.threadId);
2294
2679
  } else {
2295
2680
  this._fetchedMetadata = null;
2296
2681
  this._conversation = [];
@@ -2301,7 +2686,7 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
2301
2686
  this._messagesAbort = null;
2302
2687
  this.fetchMessages(this.threadId, true);
2303
2688
  }
2304
- const focusedContentChanged = _changed.has("_fetchedEvents") || _changed.has("agentEventsInput") || _changed.has("_conversation");
2689
+ const focusedContentChanged = _changed.has("_fetchedEvents") || _changed.has("agentEventsInput") || _changed.has("agentMessagesInput") || _changed.has("_conversation");
2305
2690
  if (this.focusMessageId && (this.focusRequestId > this._scrolledFocusRequestId || focusedContentChanged)) {
2306
2691
  if (this._tab !== "timeline") {
2307
2692
  this._activatedTabs = new Set([...this._activatedTabs, "timeline"]);
@@ -2458,18 +2843,14 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
2458
2843
  if (result.status === "not-available") {
2459
2844
  this._eventsNotAvailable = true;
2460
2845
  this._fetchedEvents = [];
2461
- if (this.canFetchMessages()) this.fetchMessages(threadId);
2462
2846
  return;
2463
2847
  }
2464
- const mappedEvents = this.mapApiEvents(result.events);
2465
- this._fetchedEvents = mappedEvents;
2466
- if (mappedEvents.length === 0 && this.canFetchMessages()) this.fetchMessages(threadId);
2848
+ this._fetchedEvents = this.mapApiEvents(result.events);
2467
2849
  } catch (err) {
2468
2850
  if (err instanceof Error && err.name === "AbortError") return;
2469
2851
  if (this.threadId !== threadId) return;
2470
2852
  this._eventsError = err instanceof Error ? err.message : "Failed to load events";
2471
2853
  this._fetchedEvents = [];
2472
- if (this.canFetchMessages()) this.fetchMessages(threadId);
2473
2854
  } finally {
2474
2855
  if (!controller.signal.aborted && this.threadId === threadId) this._loadingEvents = false;
2475
2856
  }
@@ -2543,13 +2924,15 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
2543
2924
  mapMessages(messages) {
2544
2925
  const items = [];
2545
2926
  const toolCallMap = /* @__PURE__ */ new Map();
2546
- for (const msg of messages) if (msg.role === "user" && msg.content) items.push({
2547
- id: msg.id,
2548
- type: "user",
2549
- content: msg.content,
2550
- createdAt: ""
2551
- });
2552
- else if (msg.role === "assistant") {
2927
+ for (const msg of messages) if (msg.role === "user") {
2928
+ const content = textFromUnknownContent(msg.content);
2929
+ if (content) items.push({
2930
+ id: msg.id,
2931
+ type: "user",
2932
+ content,
2933
+ createdAt: ""
2934
+ });
2935
+ } else if (msg.role === "assistant") {
2553
2936
  if (msg.toolCalls?.length) for (const tc of msg.toolCalls) {
2554
2937
  let args = {};
2555
2938
  if (typeof tc.args === "string") try {
@@ -2578,10 +2961,11 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
2578
2961
  toolCallMap.set(tc.id, item);
2579
2962
  items.push(item);
2580
2963
  }
2581
- if (msg.content) items.push({
2964
+ const assistantContent = textFromUnknownContent(msg.content);
2965
+ if (assistantContent) items.push({
2582
2966
  id: msg.id,
2583
2967
  type: "assistant",
2584
- content: msg.content,
2968
+ content: assistantContent,
2585
2969
  createdAt: ""
2586
2970
  });
2587
2971
  } else if (msg.role === "activity") items.push({
@@ -2629,14 +3013,86 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
2629
3013
  return this.timelineItemsForEvents(this.activeEvents);
2630
3014
  }
2631
3015
  timelineItemsForEvents(events) {
2632
- if (this._timelineItemsCache?.events === events) return this._timelineItemsCache.items;
2633
- const items = this.timelineItemsFromEvents(events);
3016
+ const conversation = this._conversation;
3017
+ const agentMessages = this.agentMessagesInput;
3018
+ if (this._timelineItemsCache?.events === events && this._timelineItemsCache.conversation === conversation && this._timelineItemsCache.agentMessages === agentMessages) return this._timelineItemsCache.items;
3019
+ const items = this.mergeUserMessagesIntoTimeline(this.timelineItemsFromEvents(events));
2634
3020
  this._timelineItemsCache = {
2635
3021
  events,
3022
+ conversation,
3023
+ agentMessages,
2636
3024
  items
2637
3025
  };
2638
3026
  return items;
2639
3027
  }
3028
+ conversationUsers() {
3029
+ const users = [];
3030
+ const seenIds = /* @__PURE__ */ new Set();
3031
+ const seenBodies = /* @__PURE__ */ new Set();
3032
+ const push = (user) => {
3033
+ const body = user.content.trim();
3034
+ if (!body) return;
3035
+ if (seenIds.has(user.id) || seenBodies.has(body)) return;
3036
+ seenIds.add(user.id);
3037
+ seenBodies.add(body);
3038
+ users.push(user);
3039
+ };
3040
+ for (const item of this._conversation) if (item.type === "user") push(item);
3041
+ this.agentMessagesInput.forEach((message, index) => {
3042
+ if (message.role !== "user") return;
3043
+ push({
3044
+ id: message.id ?? `live-user-${index}`,
3045
+ type: "user",
3046
+ content: message.contentText,
3047
+ createdAt: ""
3048
+ });
3049
+ });
3050
+ return users;
3051
+ }
3052
+ mergeUserMessagesIntoTimeline(items) {
3053
+ if (items.length === 0) return items;
3054
+ const users = this.conversationUsers();
3055
+ if (users.length === 0) return items;
3056
+ const shownIds = /* @__PURE__ */ new Set();
3057
+ const shownBodies = /* @__PURE__ */ new Set();
3058
+ for (const item of items) {
3059
+ if (item.kind !== "message") continue;
3060
+ if (!item.title.toLowerCase().startsWith("user")) continue;
3061
+ if (item.messageId) shownIds.add(item.messageId);
3062
+ const body = item.body?.trim();
3063
+ if (body) shownBodies.add(body);
3064
+ }
3065
+ const missing = users.filter((user) => {
3066
+ if (shownIds.has(user.id)) return false;
3067
+ if (shownBodies.has(user.content.trim())) return false;
3068
+ return true;
3069
+ });
3070
+ if (missing.length === 0) return items;
3071
+ const insertAt = [];
3072
+ for (let index = 0; index < items.length; index++) {
3073
+ const item = items[index];
3074
+ if (item.kind === "run" && item.title === "Run started") insertAt.push(index);
3075
+ }
3076
+ if (insertAt.length === 0) for (let index = 0; index < items.length; index++) {
3077
+ const item = items[index];
3078
+ if (item.kind === "message" && item.title.toLowerCase().includes("assistant")) insertAt.push(index);
3079
+ }
3080
+ const merged = [...items];
3081
+ for (let index = missing.length - 1; index >= 0; index--) {
3082
+ const user = missing[index];
3083
+ const row = {
3084
+ id: `conversation-user-${user.id}`,
3085
+ messageId: user.id,
3086
+ kind: "message",
3087
+ title: "User message",
3088
+ body: user.content,
3089
+ timestamp: user.createdAt || 0,
3090
+ sourceIndex: 0
3091
+ };
3092
+ merged.splice(insertAt[index] ?? 0, 0, row);
3093
+ }
3094
+ return merged;
3095
+ }
2640
3096
  timelineItemsFromEvents(events) {
2641
3097
  if (events.length === 0) return [];
2642
3098
  const items = [];
@@ -2675,7 +3131,7 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
2675
3131
  id: `message-${key}`,
2676
3132
  messageId: key,
2677
3133
  kind: "message",
2678
- title: `${role || "message"} message`,
3134
+ title: messageTitle(role || "message"),
2679
3135
  body: "",
2680
3136
  timestamp: event.timestamp,
2681
3137
  sourceIndex
@@ -2823,7 +3279,7 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
2823
3279
  items.push({
2824
3280
  id: `${type}-${sourceIndex}`,
2825
3281
  kind: "state",
2826
- title: type === "STATE_SNAPSHOT" ? "State snapshot captured" : "State delta captured",
3282
+ title: type === "STATE_SNAPSHOT" ? "State snapshot" : "State delta",
2827
3283
  timestamp: event.timestamp,
2828
3284
  sourceIndex,
2829
3285
  details: payload
@@ -2833,7 +3289,7 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
2833
3289
  items.push({
2834
3290
  id: `event-${sourceIndex}`,
2835
3291
  kind: "event",
2836
- title: type,
3292
+ title: humanizeEventType(type),
2837
3293
  timestamp: event.timestamp,
2838
3294
  sourceIndex,
2839
3295
  details: payload
@@ -2972,6 +3428,7 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
2972
3428
  });
2973
3429
  }
2974
3430
  render() {
3431
+ const viewInApp = this.renderViewInAppAction();
2975
3432
  return html`
2976
3433
  <div class="cpk-td">
2977
3434
  <!-- ── Left area: tabs + content ─────────────────────────────────── -->
@@ -2999,6 +3456,7 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
2999
3456
  </button>
3000
3457
  `)}
3001
3458
  </div>
3459
+ ${viewInApp !== nothing ? html`<div class="cpk-td__chrome-actions">${viewInApp}</div>` : nothing}
3002
3460
  ${this.renderPanelToggle()}
3003
3461
  </div>
3004
3462
  ${this.renderMetadataStrip()}
@@ -3053,8 +3511,7 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
3053
3511
  value: metadata?.name ?? this.thread?.name ?? "Untitled"
3054
3512
  }, {
3055
3513
  label: "ID",
3056
- value: metadata?.id ?? this.threadId ?? "—",
3057
- wrap: true
3514
+ value: metadata?.id ?? this.threadId ?? "—"
3058
3515
  }];
3059
3516
  for (const fact of [
3060
3517
  {
@@ -3076,7 +3533,6 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
3076
3533
  value: fact.label === "Created" || fact.label === "Updated" ? this.fmtTime(fact.value) : fact.value
3077
3534
  });
3078
3535
  }
3079
- const bulkControls = this.renderActiveBulkControls();
3080
3536
  return html`
3081
3537
  <div
3082
3538
  class="cpk-td__metadata-strip"
@@ -3099,8 +3555,6 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
3099
3555
  </span>
3100
3556
  `)}
3101
3557
  </div>
3102
- ${this.renderViewInAppAction()}
3103
- ${bulkControls}
3104
3558
  </div>
3105
3559
  `;
3106
3560
  }
@@ -3123,17 +3577,55 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
3123
3577
  ${isStop ? "Stop viewing" : "View in your app"}
3124
3578
  </button>
3125
3579
  ${this.viewInAppError ? html`<span class="cpk-td__view-in-app-error" role="alert"
3126
- >${this.viewInAppError}</span
3127
- >` : nothing}
3580
+ >${this.viewInAppError}</span
3581
+ >` : nothing}
3582
+ `;
3583
+ }
3584
+ renderTryFromHereControl() {
3585
+ if (!this.tryFromHereAvailable) return nothing;
3586
+ return html`
3587
+ <button
3588
+ type="button"
3589
+ class="cpk-td__try-from-here"
3590
+ aria-label="Try from here"
3591
+ ?disabled=${this.tryFromHereBusy}
3592
+ @click=${this.onTryFromHere}
3593
+ >
3594
+ ${this.tryFromHereBusy ? "Loading…" : "Try from here"}
3595
+ <svg
3596
+ class="cpk-td__try-from-here-icon"
3597
+ aria-hidden="true"
3598
+ width="12"
3599
+ height="12"
3600
+ viewBox="0 0 24 24"
3601
+ fill="none"
3602
+ stroke="currentColor"
3603
+ stroke-width="2"
3604
+ stroke-linecap="round"
3605
+ stroke-linejoin="round"
3606
+ >
3607
+ <path d="M7 7h10v10" />
3608
+ <path d="M7 17 17 7" />
3609
+ </svg>
3610
+ </button>
3611
+ ${this.tryFromHereError ? html`<span class="cpk-td__try-from-here-error" role="alert"
3612
+ >${this.tryFromHereError}</span
3613
+ >` : nothing}
3128
3614
  `;
3129
3615
  }
3130
- renderActiveBulkControls() {
3616
+ renderTimelineBulkControls() {
3617
+ const bulk = this.renderTimelineBulkButtons();
3618
+ const tryFromHere = this.renderTryFromHereControl();
3619
+ if (bulk === nothing && tryFromHere === nothing) return nothing;
3620
+ return html`<div class="cpk-td__timeline-toolbar">
3621
+ ${bulk}${tryFromHere}
3622
+ </div>`;
3623
+ }
3624
+ renderTimelineBulkButtons() {
3131
3625
  if (this._eventsNotAvailable) return nothing;
3132
- if (this._tab === "raw-events") return this.renderRawEventBulkControls();
3133
- if (this._tab !== "timeline") return nothing;
3134
3626
  const detailIds = this.timelineItemsForEvents(this.activeEvents).filter((item) => item.details).map((item) => item.id);
3135
3627
  if (detailIds.length <= 1) return nothing;
3136
- return html`<div class="cpk-td__timeline-toolbar">
3628
+ return html`
3137
3629
  <button
3138
3630
  type="button"
3139
3631
  class="cpk-td__timeline-bulk-toggle"
@@ -3150,7 +3642,7 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
3150
3642
  >
3151
3643
  Collapse all
3152
3644
  </button>
3153
- </div>`;
3645
+ `;
3154
3646
  }
3155
3647
  renderRawEventBulkControls() {
3156
3648
  const eventIds = this.activeEvents.map((event) => this.rawEventId(event));
@@ -3182,6 +3674,9 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
3182
3674
  (this.shadowRoot?.querySelector(`[data-source-index="${sourceIndex}"]`))?.scrollIntoView?.({ block: "center" });
3183
3675
  });
3184
3676
  }
3677
+ withMessagesToolbar(content) {
3678
+ return html`${this.renderTimelineBulkControls()}${content}`;
3679
+ }
3185
3680
  renderTimeline() {
3186
3681
  if (this._loadingEvents) return html`
3187
3682
  <div class="cpk-td__status">Loading timeline…</div>
@@ -3203,7 +3698,12 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
3203
3698
  `;
3204
3699
  }
3205
3700
  const events = this.activeEvents;
3206
- const cachedTimeline = this.getCachedPanelTpl("timeline", [events, this._expandedTimelineDetails]);
3701
+ const cachedTimeline = this.getCachedPanelTpl("timeline", [
3702
+ events,
3703
+ this._conversation,
3704
+ this.agentMessagesInput,
3705
+ this._expandedTimelineDetails
3706
+ ]);
3207
3707
  if (cachedTimeline) return cachedTimeline;
3208
3708
  const timelineItems = this.timelineItemsForEvents(events);
3209
3709
  if (timelineItems.length === 0) {
@@ -3219,14 +3719,28 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
3219
3719
  </div>
3220
3720
  `;
3221
3721
  }
3222
- return this.cachedPanelTpl("timeline", [events, this._expandedTimelineDetails], () => html`${timelineItems.map((item) => this.renderTimelineItem(item))}`);
3722
+ return this.cachedPanelTpl("timeline", [
3723
+ events,
3724
+ this._conversation,
3725
+ this.agentMessagesInput,
3726
+ this._expandedTimelineDetails
3727
+ ], () => html`${timelineItems.map((item) => this.renderTimelineItem(item))}`);
3728
+ }
3729
+ timelineItemClass(item) {
3730
+ const classes = ["cpk-td__timeline-item", `cpk-td__timeline-item--${item.kind}`];
3731
+ if (item.kind === "warning" || item.severity === "error") classes.push("cpk-td__timeline-item--warning");
3732
+ if (item.kind === "message") {
3733
+ const title = item.title.toLowerCase();
3734
+ if (title.startsWith("user")) classes.push("cpk-td__timeline-item--user");
3735
+ else if (title.includes("assistant")) classes.push("cpk-td__timeline-item--assistant");
3736
+ }
3737
+ return classes.join(" ");
3223
3738
  }
3224
3739
  renderTimelineItem(item) {
3225
- const isWarning = item.kind === "warning";
3226
3740
  const detailsExpanded = this._expandedTimelineDetails.has(item.id);
3227
3741
  return html`
3228
3742
  <div
3229
- class="cpk-td__timeline-item ${isWarning ? "cpk-td__timeline-item--warning" : ""}"
3743
+ class=${this.timelineItemClass(item)}
3230
3744
  data-message-id=${item.messageId ?? nothing}
3231
3745
  >
3232
3746
  <div class="cpk-td__timeline-header">
@@ -3234,13 +3748,15 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
3234
3748
  >${item.severity === "error" ? "error" : item.kind}</span
3235
3749
  >
3236
3750
  <span class="cpk-td__timeline-title">${item.title}</span>
3237
- <button
3238
- type="button"
3239
- class="cpk-td__source-link"
3240
- @click=${() => this.revealSourceEvent(item.sourceIndex)}
3241
- >
3242
- Source event #${item.sourceIndex}
3243
- </button>
3751
+ ${item.sourceIndex ? html`
3752
+ <button
3753
+ type="button"
3754
+ class="cpk-td__source-link"
3755
+ @click=${() => this.revealSourceEvent(item.sourceIndex)}
3756
+ >
3757
+ Source event #${item.sourceIndex}
3758
+ </button>
3759
+ ` : nothing}
3244
3760
  <span class="cpk-td__timeline-time"
3245
3761
  >${formatTimestamp(item.timestamp)}</span
3246
3762
  >
@@ -3277,9 +3793,7 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
3277
3793
  <span>${detailsExpanded ? "Hide details" : "Show details"}</span>
3278
3794
  </button>` : nothing}
3279
3795
  ${item.body ? html`<div class="cpk-td__timeline-body">${item.body}</div>` : nothing}
3280
- ${item.details && detailsExpanded ? html`<pre class="cpk-td__timeline-body">
3281
- ${unsafeHTML(highlightedJson(item.details))}</pre
3282
- >` : nothing}
3796
+ ${item.details && detailsExpanded ? renderHighlightedJsonBlock(item.details) : nothing}
3283
3797
  </div>
3284
3798
  `;
3285
3799
  }
@@ -3409,9 +3923,7 @@ ${unsafeHTML(highlightedJson(item.details))}</pre
3409
3923
  ${expanded ? html`
3410
3924
  <div class="cpk-td__tool-body">
3411
3925
  <div class="cpk-td__tool-section-label">Arguments</div>
3412
- <pre class="cpk-td__tool-pre">
3413
- ${unsafeHTML(highlightedJson(item.arguments))}</pre
3414
- >
3926
+ ${renderHighlightedJsonBlock(item.arguments)}
3415
3927
  ${item.result ? html`
3416
3928
  <div
3417
3929
  class="cpk-td__tool-section-label"
@@ -3419,9 +3931,7 @@ ${unsafeHTML(highlightedJson(item.arguments))}</pre
3419
3931
  >
3420
3932
  Result
3421
3933
  </div>
3422
- <pre class="cpk-td__tool-pre">
3423
- ${unsafeHTML(highlightedJson(item.result))}</pre
3424
- >
3934
+ ${renderHighlightedJsonBlock(item.result)}
3425
3935
  ` : nothing}
3426
3936
  </div>
3427
3937
  ` : nothing}
@@ -3536,58 +4046,58 @@ ${unsafeHTML(highlightedJson(item.result))}</pre
3536
4046
  </div>
3537
4047
  `;
3538
4048
  return this.cachedPanelTpl("raw-events", [events, this._expandedRawEvents], () => {
3539
- return html`${events.map((event) => {
3540
- const { bg, fg } = eventColors(event.type);
4049
+ return html`${this.renderRawEventBulkControls()}${events.map((event) => {
3541
4050
  const eventId = this.rawEventId(event);
3542
4051
  const detailsExpanded = this._expandedRawEvents.has(eventId);
3543
4052
  return html`
3544
- <div class="cpk-td__event" data-source-index=${event.sourceIndex}>
3545
- <div class="cpk-td__event-header" style="background:${bg}">
3546
- <span class="cpk-td__event-type" style="color:${fg}"
3547
- >${event.type}</span
3548
- >
3549
- <span class="cpk-td__event-time"
3550
- >${formatTimestamp(event.timestamp)}</span
3551
- >
3552
- </div>
3553
- <button
3554
- type="button"
3555
- class="cpk-td__timeline-details-toggle"
3556
- aria-expanded=${detailsExpanded ? "true" : "false"}
3557
- @click=${() => this.toggleRawEventDetails(eventId)}
4053
+ <div
4054
+ class="cpk-td__event cpk-td__event--${eventCategory(event.type)}"
4055
+ data-source-index=${event.sourceIndex}
3558
4056
  >
3559
- ${detailsExpanded ? html`
3560
- <svg
3561
- aria-hidden="true"
3562
- viewBox="0 0 24 24"
3563
- fill="none"
3564
- stroke="currentColor"
3565
- stroke-linecap="round"
3566
- stroke-linejoin="round"
3567
- >
3568
- <path d="m6 9 6 6 6-6" />
3569
- </svg>
3570
- ` : html`
3571
- <svg
3572
- aria-hidden="true"
3573
- viewBox="0 0 24 24"
3574
- fill="none"
3575
- stroke="currentColor"
3576
- stroke-linecap="round"
3577
- stroke-linejoin="round"
3578
- >
3579
- <path d="m9 18 6-6-6-6" />
3580
- </svg>
3581
- `}
3582
- <span
3583
- >${detailsExpanded ? "Hide details" : "Show details"}</span
4057
+ <div class="cpk-td__event-header">
4058
+ <span class="cpk-td__event-type" title=${event.type}
4059
+ >${humanizeEventType(event.type)}</span
4060
+ >
4061
+ <span class="cpk-td__event-time"
4062
+ >${formatTimestamp(event.timestamp)}</span
4063
+ >
4064
+ </div>
4065
+ <button
4066
+ type="button"
4067
+ class="cpk-td__timeline-details-toggle"
4068
+ aria-expanded=${detailsExpanded ? "true" : "false"}
4069
+ @click=${() => this.toggleRawEventDetails(eventId)}
3584
4070
  >
3585
- </button>
3586
- ${detailsExpanded ? html`<pre class="cpk-td__event-payload">
3587
- ${unsafeHTML(highlightedJson(event.rawEvent ?? event))}</pre
3588
- >` : nothing}
3589
- </div>
3590
- `;
4071
+ ${detailsExpanded ? html`
4072
+ <svg
4073
+ aria-hidden="true"
4074
+ viewBox="0 0 24 24"
4075
+ fill="none"
4076
+ stroke="currentColor"
4077
+ stroke-linecap="round"
4078
+ stroke-linejoin="round"
4079
+ >
4080
+ <path d="m6 9 6 6 6-6" />
4081
+ </svg>
4082
+ ` : html`
4083
+ <svg
4084
+ aria-hidden="true"
4085
+ viewBox="0 0 24 24"
4086
+ fill="none"
4087
+ stroke="currentColor"
4088
+ stroke-linecap="round"
4089
+ stroke-linejoin="round"
4090
+ >
4091
+ <path d="m9 18 6-6-6-6" />
4092
+ </svg>
4093
+ `}
4094
+ <span
4095
+ >${detailsExpanded ? "Hide details" : "Show details"}</span
4096
+ >
4097
+ </button>
4098
+ ${detailsExpanded ? renderHighlightedJsonBlock(event.rawEvent ?? event) : nothing}
4099
+ </div>
4100
+ `;
3591
4101
  })}`;
3592
4102
  });
3593
4103
  }
@@ -4396,6 +4906,13 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
4396
4906
  this.systemColorSchemeMediaQuery = null;
4397
4907
  this.briefingRestoreMenu = null;
4398
4908
  this.homeViewedThisOpen = false;
4909
+ this.onboardingRunId = null;
4910
+ this.promptCopyState = "idle";
4911
+ this.promptCopyResetTimer = null;
4912
+ this.intelStoryBeat = 0;
4913
+ this.intelStoryUserPinned = false;
4914
+ this.intelStoryTimer = null;
4915
+ this.intelStoryReducedMotion = null;
4399
4916
  this.hasResolvedCore = false;
4400
4917
  this.settingsOpen = false;
4401
4918
  this.lastSelectedMenuByGroup = {
@@ -4441,9 +4958,12 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
4441
4958
  this.playgroundError = null;
4442
4959
  this.playgroundSourceThreadId = null;
4443
4960
  this.playgroundShowEphemeralNotice = false;
4961
+ this.tryFromHereBusy = false;
4962
+ this.tryFromHereError = null;
4444
4963
  this.threadCapabilityEnabled = null;
4445
4964
  this.threadCapabilityGeneration = 0;
4446
4965
  this.contextMenuOpen = false;
4966
+ this.iconRailContextCloseTimer = null;
4447
4967
  this.layoutMenuOpen = false;
4448
4968
  this.dockMode = "floating";
4449
4969
  this.popOut = null;
@@ -4505,6 +5025,9 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
4505
5025
  this.launcherHudSide = "left";
4506
5026
  this.launcherHudHelp = null;
4507
5027
  this.launcherHudCloseTimer = null;
5028
+ this.launcherHudIntro = false;
5029
+ this.launcherHudIntroStartTimer = null;
5030
+ this.launcherHudIntroEndTimer = null;
4508
5031
  this.hudLandingMenu = null;
4509
5032
  this.pillOutcome = null;
4510
5033
  this.viewedNewsSignalIds = /* @__PURE__ */ new Set();
@@ -4589,6 +5112,7 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
4589
5112
  this.openInspector("floating_button");
4590
5113
  };
4591
5114
  this.handleLauncherHudEnter = () => {
5115
+ this.cancelLauncherHudIntro();
4592
5116
  this.openLauncherHud();
4593
5117
  };
4594
5118
  this.handleLauncherHudLeave = () => {
@@ -4599,6 +5123,7 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
4599
5123
  }, 160);
4600
5124
  };
4601
5125
  this.handleLauncherHudFocusIn = () => {
5126
+ this.cancelLauncherHudIntro();
4602
5127
  this.openLauncherHud();
4603
5128
  };
4604
5129
  this.handleLauncherHudFocusOut = (event) => {
@@ -4675,6 +5200,26 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
4675
5200
  this.applyEventErrorLanding(key);
4676
5201
  this.requestUpdate();
4677
5202
  };
5203
+ this.handleIntelligencePromptCopy = async (event) => {
5204
+ this.clearIntelligencePromptReset();
5205
+ const runId = this.getOnboardingRunId();
5206
+ const clipboard = this.getClipboard(event);
5207
+ let outcome = "failed";
5208
+ if (clipboard?.writeText) try {
5209
+ await clipboard.writeText(createOnboardingPrompt(runId));
5210
+ outcome = "copied";
5211
+ } catch {
5212
+ outcome = "failed";
5213
+ }
5214
+ if (!this.isConnected) return;
5215
+ this.promptCopyState = outcome;
5216
+ this.requestUpdate();
5217
+ if (outcome === "copied") this.scheduleIntelligencePromptReset();
5218
+ if (!this.core?.telemetryDisabled) trackHomePromptCopied({
5219
+ onboarding_run_id: runId,
5220
+ outcome
5221
+ });
5222
+ };
4678
5223
  this.handleSystemColorSchemeChange = (event) => {
4679
5224
  if (this.hasExplicitColorScheme) return;
4680
5225
  this.colorScheme = event.matches ? "dark" : "light";
@@ -4919,21 +5464,14 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
4919
5464
  this.startPlaygroundSession(false);
4920
5465
  return;
4921
5466
  }
4922
- const core = this._core;
4923
5467
  const thread = this._threads.find((candidate) => candidate.id === threadId);
4924
- if (!core?.runtimeUrl || !thread) return;
5468
+ if (!thread) return;
4925
5469
  this.playgroundIsLoadingThread = true;
4926
5470
  this.playgroundError = null;
4927
5471
  this.requestUpdate();
4928
5472
  try {
4929
- const baseUrl = core.runtimeUrl.replace(/\/+$/, "");
4930
- const encodedThreadId = encodeURIComponent(threadId);
4931
- const [messagesResponse, stateResponse] = await Promise.all([fetch(`${baseUrl}/threads/${encodedThreadId}/messages`, { headers: { ...core.headers } }), fetch(`${baseUrl}/threads/${encodedThreadId}/state`, { headers: { ...core.headers } })]);
4932
- if (!messagesResponse.ok) throw new Error(`Failed to load thread (HTTP ${messagesResponse.status}).`);
4933
- const messagesBody = await messagesResponse.json();
4934
- const stateBody = stateResponse.ok ? await stateResponse.json() : { state: {} };
4935
- this.startPlaygroundSession(false, this.mapThreadMessagesToPlayground(messagesBody.messages ?? []), stateBody.state ?? {}, thread.agentId);
4936
- this.playgroundSourceThreadId = threadId;
5473
+ const snapshot = await this.loadThreadSnapshot(thread);
5474
+ this.applyThreadSnapshotToPlayground(thread, snapshot);
4937
5475
  } catch (error) {
4938
5476
  this.playgroundError = error instanceof Error ? error.message : "Failed to load thread.";
4939
5477
  } finally {
@@ -4941,6 +5479,35 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
4941
5479
  this.requestUpdate();
4942
5480
  }
4943
5481
  };
5482
+ this.handleTryFromHere = async (threadId) => {
5483
+ if (!threadId || this.tryFromHereBusy) return;
5484
+ const thread = this._threads.find((candidate) => candidate.id === threadId) ?? null;
5485
+ if (!thread) return;
5486
+ this.tryFromHereBusy = true;
5487
+ this.tryFromHereError = null;
5488
+ this.requestUpdate();
5489
+ const isCurrentTryFromHereRequest = () => this.selectedThreadId === threadId && this.selectedMenu === "threads";
5490
+ try {
5491
+ const snapshot = await this.loadThreadSnapshot(thread);
5492
+ if (isCurrentTryFromHereRequest()) {
5493
+ this.applyThreadSnapshotToPlayground(thread, snapshot);
5494
+ this.handleMenuSelect("playground");
5495
+ }
5496
+ if (!this.core?.telemetryDisabled) trackThreadsTryFromHereClicked({
5497
+ ...this.getThreadsTelemetryProps(),
5498
+ outcome: "success"
5499
+ });
5500
+ } catch (error) {
5501
+ if (isCurrentTryFromHereRequest()) this.tryFromHereError = error instanceof Error ? error.message : "Failed to load thread.";
5502
+ if (!this.core?.telemetryDisabled) trackThreadsTryFromHereClicked({
5503
+ ...this.getThreadsTelemetryProps(),
5504
+ outcome: "failure"
5505
+ });
5506
+ } finally {
5507
+ this.tryFromHereBusy = false;
5508
+ this.requestUpdate();
5509
+ }
5510
+ };
4944
5511
  this.runPlaygroundAgent = async () => {
4945
5512
  const core = this._core;
4946
5513
  const agent = this.playgroundAgent;
@@ -5145,15 +5712,21 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
5145
5712
  this.requestUpdate();
5146
5713
  };
5147
5714
  this.handleIconRailContextPointerEnter = (event) => {
5148
- if (event.pointerType === "touch" || this.contextMenuOpen) return;
5715
+ if (event.pointerType === "touch") return;
5716
+ this.clearIconRailContextCloseTimer();
5717
+ if (this.contextMenuOpen) return;
5149
5718
  this.layoutMenuOpen = false;
5150
5719
  this.contextMenuOpen = true;
5151
5720
  this.requestUpdate();
5152
5721
  };
5153
5722
  this.handleIconRailContextPointerLeave = () => {
5154
5723
  if (!this.contextMenuOpen) return;
5155
- this.contextMenuOpen = false;
5156
- this.requestUpdate();
5724
+ this.clearIconRailContextCloseTimer();
5725
+ this.iconRailContextCloseTimer = setTimeout(() => {
5726
+ this.iconRailContextCloseTimer = null;
5727
+ this.contextMenuOpen = false;
5728
+ this.requestUpdate();
5729
+ }, 180);
5157
5730
  };
5158
5731
  this.handleIconRailContextPointerDown = (event) => {
5159
5732
  if (event.pointerType === "touch") {
@@ -5164,6 +5737,7 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
5164
5737
  event.stopPropagation();
5165
5738
  };
5166
5739
  this.handleIconRailContextFocusIn = () => {
5740
+ this.clearIconRailContextCloseTimer();
5167
5741
  if (this.contextMenuOpen) return;
5168
5742
  this.layoutMenuOpen = false;
5169
5743
  this.contextMenuOpen = true;
@@ -5584,7 +6158,7 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
5584
6158
  if (this.core?.getThreadStore(agentId)) return;
5585
6159
  const core = this.core;
5586
6160
  if (!core?.runtimeUrl) return;
5587
- const store = ɵcreateThreadStore({ fetch: globalThis.fetch });
6161
+ const store = ɵcreateThreadStore({ fetch: typeof core.ɵruntimeFetch === "function" ? core.ɵruntimeFetch : globalThis.fetch });
5588
6162
  store.start();
5589
6163
  store.setContext({
5590
6164
  runtimeUrl: core.runtimeUrl,
@@ -6134,7 +6708,7 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
6134
6708
  const messages = this.normalizeAgentMessages(agent.messages);
6135
6709
  if (messages) this.agentMessages.set(agent.agentId, messages);
6136
6710
  else this.agentMessages.delete(agent.agentId);
6137
- const runThreadId = agent.threadId;
6711
+ const runThreadId = this.readAgentThreadId(agent);
6138
6712
  if (runThreadId) this.liveMessageVersion.set(runThreadId, (this.liveMessageVersion.get(runThreadId) ?? 0) + 1);
6139
6713
  this.requestUpdate();
6140
6714
  } catch (error) {
@@ -6238,6 +6812,20 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
6238
6812
  getLatestMessagesForAgent(agentId) {
6239
6813
  return this.agentMessages.get(agentId) ?? null;
6240
6814
  }
6815
+ readAgentThreadId(agent) {
6816
+ if (!("threadId" in agent)) return void 0;
6817
+ const threadId = agent.threadId;
6818
+ return typeof threadId === "string" ? threadId : void 0;
6819
+ }
6820
+ getLiveAgentMessagesForThread(thread) {
6821
+ const messages = this.agentMessages.get(thread.agentId) ?? EMPTY_INSPECTOR_MESSAGES;
6822
+ const core = this._core;
6823
+ if (!core || typeof core.getAgent !== "function") return messages;
6824
+ const agent = core.getAgent(thread.agentId);
6825
+ if (!agent) return EMPTY_INSPECTOR_MESSAGES;
6826
+ if (this.readAgentThreadId(agent) !== thread.id) return EMPTY_INSPECTOR_MESSAGES;
6827
+ return messages;
6828
+ }
6241
6829
  getAgentStatus(agentId) {
6242
6830
  const events = this.agentEvents.get(agentId) ?? [];
6243
6831
  if (events.length === 0) return "idle";
@@ -6281,14 +6869,14 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
6281
6869
  <span>${functionName}${isFailedCall ? " failed" : ""}</span>
6282
6870
  <span class="text-[10px] text-gray-600">ID: ${callId}</span>
6283
6871
  </div>
6284
- ${isFailedCall && toolError?.message ? html`<p class="mt-2 break-words leading-relaxed text-gray-800">
6872
+ ${isFailedCall && toolError?.message ? html`<p
6873
+ class="mt-2 break-words leading-relaxed text-gray-800"
6874
+ >
6285
6875
  ${toolError.message}
6286
6876
  </p>` : nothing}
6287
- ${argsString ? html`<pre
6288
- class="mt-2 overflow-auto rounded bg-white p-2 text-[11px] leading-relaxed text-gray-800"
6289
- >
6290
- ${argsString}</pre
6291
- >` : nothing}
6877
+ ${argsString ? html`<div class="mt-2">
6878
+ ${renderHighlightedJsonBlock(coerceJsonValue(call.function?.arguments))}
6879
+ </div>` : nothing}
6292
6880
  </div>
6293
6881
  `;
6294
6882
  })}
@@ -6340,15 +6928,14 @@ ${argsString}</pre
6340
6928
  return String(state);
6341
6929
  }
6342
6930
  getEventBadgeClasses(type) {
6343
- const base = "font-mono text-[10px] font-medium inline-flex items-center rounded-sm px-1.5 py-0.5 border";
6344
- if (type === "RUN_ERROR") return `${base} bg-rose-50 text-rose-700 border-rose-200`;
6345
- if (type.startsWith("RUN_")) return `${base} bg-blue-50 text-blue-700 border-blue-200`;
6346
- if (type.startsWith("TEXT_MESSAGE")) return `${base} bg-emerald-50 text-emerald-700 border-emerald-200`;
6347
- if (type.startsWith("TOOL_CALL")) return `${base} bg-amber-50 text-amber-700 border-amber-200`;
6348
- if (type.startsWith("REASONING")) return `${base} bg-fuchsia-50 text-fuchsia-700 border-fuchsia-200`;
6349
- if (type.startsWith("STATE")) return `${base} bg-violet-50 text-violet-700 border-violet-200`;
6350
- if (type.startsWith("MESSAGES")) return `${base} bg-sky-50 text-sky-700 border-sky-200`;
6351
- return `${base} bg-gray-100 text-gray-600 border-gray-200`;
6931
+ const base = "font-mono text-[10px] font-semibold inline-flex items-center rounded-sm px-1.5 py-0.5 border";
6932
+ if (type === "RUN_ERROR") return `${base} bg-rose-50 text-rose-800 border-rose-200`;
6933
+ if (type.startsWith("TEXT_MESSAGE")) return `${base} bg-violet-50 text-gray-900 border-violet-200`;
6934
+ if (type.startsWith("TOOL_CALL")) return `${base} bg-emerald-50 text-gray-900 border-emerald-200`;
6935
+ if (type.startsWith("RUN_") || type.startsWith("STEP_")) return `${base} bg-gray-100 text-gray-900 border-gray-200`;
6936
+ if (type.startsWith("REASONING")) return `${base} bg-violet-50 text-gray-900 border-violet-200`;
6937
+ if (type.startsWith("STATE") || type.startsWith("MESSAGES")) return `${base} bg-violet-50 text-gray-900 border-violet-200`;
6938
+ return `${base} bg-gray-100 text-gray-900 border-gray-200`;
6352
6939
  }
6353
6940
  stringifyPayload(payload, pretty) {
6354
6941
  try {
@@ -6395,6 +6982,13 @@ ${argsString}</pre
6395
6982
  static {
6396
6983
  this.styles = [unsafeCSS(generated_default), css`
6397
6984
  :host {
6985
+ --cpk-inspector-shell-radius: 5px;
6986
+ --cpk-inspector-surface-dark: #111319;
6987
+ --cpk-json-key: #3d408f;
6988
+ --cpk-json-str: #0b6b4c;
6989
+ --cpk-json-num: #8a5900;
6990
+ --cpk-json-bool: #c0333a;
6991
+ --cpk-json-nil: #57575b;
6398
6992
  position: fixed;
6399
6993
  top: 0;
6400
6994
  left: 0;
@@ -6404,6 +6998,194 @@ ${argsString}</pre
6404
6998
  font-family: "Plus Jakarta Sans", system-ui, sans-serif;
6405
6999
  }
6406
7000
 
7001
+ :host([data-color-scheme="dark"]),
7002
+ .inspector-window[data-color-scheme="dark"] {
7003
+ --cpk-json-key: #bec2ff;
7004
+ --cpk-json-str: #85ecce;
7005
+ --cpk-json-num: #ffac4d;
7006
+ --cpk-json-bool: #fa5f67;
7007
+ --cpk-json-nil: #afafb7;
7008
+ }
7009
+
7010
+ .cpk-json-token--key {
7011
+ color: var(--cpk-json-key);
7012
+ }
7013
+
7014
+ .cpk-json-token--str {
7015
+ color: var(--cpk-json-str);
7016
+ }
7017
+
7018
+ .cpk-json-token--num {
7019
+ color: var(--cpk-json-num);
7020
+ }
7021
+
7022
+ .cpk-json-token--bool {
7023
+ color: var(--cpk-json-bool);
7024
+ }
7025
+
7026
+ .cpk-json-token--nil {
7027
+ color: var(--cpk-json-nil);
7028
+ }
7029
+
7030
+ .cpk-json-block {
7031
+ margin: 0;
7032
+ padding: 10px 12px;
7033
+ border: 1px solid #dbdbe5;
7034
+ border-radius: 8px;
7035
+ background: #f7f7f9;
7036
+ font-family: "Spline Sans Mono", monospace;
7037
+ font-size: 12px;
7038
+ line-height: 1.65;
7039
+ white-space: pre-wrap;
7040
+ overflow-wrap: anywhere;
7041
+ word-break: normal;
7042
+ color: #010507;
7043
+ overflow: auto;
7044
+ }
7045
+
7046
+ :host([data-color-scheme="dark"]) .cpk-json-block,
7047
+ .inspector-window[data-color-scheme="dark"] .cpk-json-block {
7048
+ background: #111319;
7049
+ border-color: #343742;
7050
+ color: #f3f4f8;
7051
+ }
7052
+
7053
+ @keyframes cpk-playground-message-enter {
7054
+ from {
7055
+ opacity: 0;
7056
+ filter: blur(2px);
7057
+ transform: translateY(4px);
7058
+ }
7059
+ to {
7060
+ opacity: 1;
7061
+ filter: blur(0);
7062
+ transform: translateY(0);
7063
+ }
7064
+ }
7065
+
7066
+ @keyframes cpk-playground-thinking {
7067
+ 0%,
7068
+ 60%,
7069
+ 100% {
7070
+ opacity: 0.28;
7071
+ transform: translateY(0);
7072
+ }
7073
+ 30% {
7074
+ opacity: 1;
7075
+ transform: translateY(-2px);
7076
+ }
7077
+ }
7078
+
7079
+ .cpk-playground-root {
7080
+ container-type: inline-size;
7081
+ background: #fbfbfd !important;
7082
+ }
7083
+
7084
+ .cpk-playground-header {
7085
+ min-height: 58px;
7086
+ background: #f7f6fd !important;
7087
+ }
7088
+
7089
+ .cpk-playground-welcome {
7090
+ max-width: 560px;
7091
+ padding: 24px;
7092
+ }
7093
+
7094
+ .cpk-playground-welcome-title {
7095
+ color: #24242b;
7096
+ font-size: 15px;
7097
+ font-weight: 600;
7098
+ letter-spacing: -0.015em;
7099
+ }
7100
+
7101
+ .cpk-playground-composer {
7102
+ border: 1px solid #dcdce8;
7103
+ box-shadow:
7104
+ 0 8px 22px rgba(31, 23, 57, 0.08),
7105
+ 0 1px 2px rgba(31, 23, 57, 0.1);
7106
+ }
7107
+
7108
+ .cpk-playground-composer:focus-within {
7109
+ border-color: #aaa4d4;
7110
+ box-shadow:
7111
+ 0 10px 26px rgba(86, 53, 155, 0.13),
7112
+ 0 0 0 3px rgba(190, 194, 255, 0.3);
7113
+ }
7114
+
7115
+ .inspector-window[data-color-scheme="dark"] .cpk-playground-root,
7116
+ .inspector-window[data-color-scheme="dark"] .cpk-playground-header {
7117
+ background: #15171e !important;
7118
+ }
7119
+
7120
+ .inspector-window[data-color-scheme="dark"]
7121
+ .cpk-playground-welcome-title {
7122
+ color: #f3f4f8 !important;
7123
+ }
7124
+
7125
+ .inspector-window[data-color-scheme="dark"] .cpk-playground-composer {
7126
+ border-color: #464957;
7127
+ background: #15171e !important;
7128
+ box-shadow:
7129
+ 0 8px 22px rgba(0, 0, 0, 0.26),
7130
+ 0 1px 2px rgba(0, 0, 0, 0.36);
7131
+ }
7132
+
7133
+ .inspector-window[data-color-scheme="dark"]
7134
+ .cpk-playground-composer:focus-within {
7135
+ border-color: #777aae;
7136
+ box-shadow:
7137
+ 0 10px 26px rgba(0, 0, 0, 0.34),
7138
+ 0 0 0 3px rgba(102, 106, 158, 0.3);
7139
+ }
7140
+
7141
+ .cpk-playground-message-enter {
7142
+ animation: cpk-playground-message-enter 0.24s
7143
+ cubic-bezier(0.16, 1, 0.3, 1) both;
7144
+ }
7145
+
7146
+ .cpk-playground-thinking-dot {
7147
+ animation: cpk-playground-thinking 1.2s ease-in-out infinite;
7148
+ }
7149
+
7150
+ .cpk-playground-thinking-dot:nth-child(2) {
7151
+ animation-delay: 0.12s;
7152
+ }
7153
+
7154
+ .cpk-playground-thinking-dot:nth-child(3) {
7155
+ animation-delay: 0.24s;
7156
+ }
7157
+
7158
+ .cpk-playground-reasoning summary::-webkit-details-marker {
7159
+ display: none;
7160
+ }
7161
+
7162
+ .cpk-playground-reasoning[open] .cpk-playground-reasoning-chevron {
7163
+ transform: rotate(90deg);
7164
+ }
7165
+
7166
+ @container (max-width: 560px) {
7167
+ .cpk-playground-header {
7168
+ align-items: stretch;
7169
+ }
7170
+
7171
+ .cpk-playground-actions {
7172
+ width: 100%;
7173
+ }
7174
+
7175
+ .cpk-playground-thread-select {
7176
+ min-width: 0;
7177
+ max-width: none;
7178
+ flex: 1;
7179
+ }
7180
+ }
7181
+
7182
+ @media (prefers-reduced-motion: reduce) {
7183
+ .cpk-playground-message-enter,
7184
+ .cpk-playground-thinking-dot {
7185
+ animation: none;
7186
+ }
7187
+ }
7188
+
6407
7189
  .rounded-sm {
6408
7190
  border-radius: 3px;
6409
7191
  }
@@ -6463,6 +7245,10 @@ ${argsString}</pre
6463
7245
  box-sizing: border-box;
6464
7246
  transition:
6465
7247
  transform 300ms cubic-bezier(0.34, 1.56, 0.64, 1),
7248
+ scale 300ms cubic-bezier(0.34, 1.56, 0.64, 1),
7249
+ background-color 200ms ease,
7250
+ border-color 200ms ease,
7251
+ box-shadow 200ms ease,
6466
7252
  opacity 160ms ease;
6467
7253
  }
6468
7254
 
@@ -6490,6 +7276,7 @@ ${argsString}</pre
6490
7276
  touch-action: none;
6491
7277
  user-select: none;
6492
7278
  z-index: 60;
7279
+ background: transparent;
6493
7280
  }
6494
7281
 
6495
7282
  .edge-resize-handle {
@@ -6624,11 +7411,67 @@ ${argsString}</pre
6624
7411
  flex-shrink: 0;
6625
7412
  transition:
6626
7413
  background-color 0.15s,
6627
- border-color 0.15s;
7414
+ border-color 0.15s,
7415
+ color 0.15s;
7416
+ }
7417
+ .cpk-copy-btn:hover {
7418
+ background-color: #f0f0f4;
7419
+ border-color: #afafb7;
7420
+ }
7421
+
7422
+ .inspector-window[data-color-scheme="dark"] .cpk-copy-btn {
7423
+ background: #191c24;
7424
+ border-color: #3a3d49;
7425
+ color: #f3f4f8;
7426
+ }
7427
+
7428
+ .inspector-window[data-color-scheme="dark"] .cpk-copy-btn:hover {
7429
+ background: #20232d;
7430
+ border-color: #57575b;
7431
+ }
7432
+
7433
+ .inspector-sidebar[data-icon-rail="true"]
7434
+ .inspector-sidebar-agent-scope
7435
+ [data-context-dropdown-root="true"]
7436
+ > div {
7437
+ left: 100%;
7438
+ margin-inline-start: 8px;
7439
+ }
7440
+
7441
+ .inspector-icon-rail-menu {
7442
+ transform-origin: left center;
7443
+ opacity: 0;
7444
+ visibility: hidden;
7445
+ pointer-events: none;
7446
+ transform: translateX(-8px) scale(0.96);
7447
+ transition:
7448
+ opacity 180ms ease,
7449
+ transform 180ms ease,
7450
+ visibility 180ms ease;
7451
+ }
7452
+
7453
+ .inspector-icon-rail-menu[data-open="true"] {
7454
+ opacity: 1;
7455
+ visibility: visible;
7456
+ pointer-events: auto;
7457
+ transform: translateX(0) scale(1);
7458
+ }
7459
+
7460
+ @media (prefers-reduced-motion: reduce) {
7461
+ .inspector-icon-rail-menu {
7462
+ transition: none;
7463
+ }
6628
7464
  }
6629
- .cpk-copy-btn:hover {
6630
- background-color: #f0f0f4;
6631
- border-color: #afafb7;
7465
+
7466
+ .inspector-sidebar[data-icon-rail="true"]
7467
+ .inspector-sidebar-agent-scope
7468
+ [data-context-dropdown-root="true"]
7469
+ > div::before {
7470
+ content: "";
7471
+ position: absolute;
7472
+ inset-block: 0;
7473
+ inset-inline-end: 100%;
7474
+ width: 12px;
6632
7475
  }
6633
7476
 
6634
7477
  .cpk-section-header {
@@ -6636,6 +7479,9 @@ ${argsString}</pre
6636
7479
  border-bottom: 1px solid rgba(0, 0, 0, 0.08);
6637
7480
  padding: 10px 16px;
6638
7481
  }
7482
+ .inspector-window[data-color-scheme="dark"] .cpk-section-header {
7483
+ border-bottom-color: #3a3d49;
7484
+ }
6639
7485
  .cpk-section-header h4 {
6640
7486
  font-size: 11px;
6641
7487
  font-weight: 600;
@@ -6882,6 +7728,7 @@ ${argsString}</pre
6882
7728
  .console-button:hover {
6883
7729
  background-color: var(--cpk-launcher-face-solid) !important;
6884
7730
  border-color: rgba(190, 194, 255, 0.45) !important;
7731
+ transform: scale(1.05);
6885
7732
  }
6886
7733
  .console-button:focus-visible {
6887
7734
  outline-color: #bec2ff !important;
@@ -7230,6 +8077,12 @@ ${argsString}</pre
7230
8077
  .cpk-launcher-signal-wash {
7231
8078
  animation: none !important;
7232
8079
  }
8080
+ .console-button {
8081
+ transition: opacity 160ms ease;
8082
+ }
8083
+ .console-button:hover {
8084
+ transform: none;
8085
+ }
7233
8086
  }
7234
8087
 
7235
8088
  /* ── Launcher HUD: hover menu, quieter than the error island ── */
@@ -7241,6 +8094,9 @@ ${argsString}</pre
7241
8094
  }
7242
8095
 
7243
8096
  .cpk-launcher-hud {
8097
+ --hud-fill: var(--cpk-inspector-surface-dark);
8098
+ --hud-line: rgb(190 194 255 / 0.5);
8099
+ --hud-blur: blur(12px) saturate(1.2);
7244
8100
  position: absolute;
7245
8101
  top: 0;
7246
8102
  z-index: 4;
@@ -7274,38 +8130,47 @@ ${argsString}</pre
7274
8130
  }
7275
8131
 
7276
8132
  .cpk-launcher-hud__card {
7277
- --hud-fill: rgb(28 31 36 / 0.88);
7278
- --hud-line: rgb(190 194 255 / 0.5);
7279
8133
  position: relative;
7280
8134
  width: 228px;
7281
8135
  padding: 4px;
7282
8136
  border: 1px dotted var(--hud-line);
7283
- border-radius: 10px;
8137
+ border-radius: var(--cpk-inspector-shell-radius);
7284
8138
  background: var(--hud-fill);
7285
8139
  color: #fff;
7286
- backdrop-filter: blur(12px) saturate(1.2);
8140
+ backdrop-filter: var(--hud-blur);
8141
+ -webkit-backdrop-filter: var(--hud-blur);
7287
8142
  box-shadow: 0 8px 20px rgb(1 5 7 / 0.18);
7288
8143
  }
7289
8144
 
8145
+ .cpk-launcher-hud[data-color-scheme="light"] {
8146
+ --hud-fill: #fff;
8147
+ --hud-line: #d8d8e8;
8148
+ }
8149
+
8150
+ .cpk-launcher-hud[data-color-scheme="light"] .cpk-launcher-hud__card {
8151
+ color: #010507;
8152
+ }
8153
+
7290
8154
  .cpk-launcher-hud__arrow {
7291
8155
  position: absolute;
7292
8156
  top: calc(var(--cpk-launcher-size) / 2);
8157
+ z-index: 1;
7293
8158
  width: 10px;
7294
8159
  height: 10px;
7295
- background: var(--hud-fill);
8160
+ border: 0;
8161
+ /* The card frosts the page behind it, so it reads lighter than the
8162
+ raw fill. Mix a little white so the arrow matches the glass card
8163
+ without going lighter than the HUD. */
8164
+ background: color-mix(in srgb, var(--hud-fill) 88%, white 12%);
7296
8165
  transform: translateY(-50%) rotate(45deg);
7297
8166
  }
7298
8167
 
7299
8168
  .cpk-launcher-hud[data-cpk-hud-side="left"] .cpk-launcher-hud__arrow {
7300
- right: -5px;
7301
- border-top: 1px solid var(--hud-line);
7302
- border-right: 1px solid var(--hud-line);
8169
+ right: 9px;
7303
8170
  }
7304
8171
 
7305
8172
  .cpk-launcher-hud[data-cpk-hud-side="right"] .cpk-launcher-hud__arrow {
7306
- left: -5px;
7307
- border-bottom: 1px solid var(--hud-line);
7308
- border-left: 1px solid var(--hud-line);
8173
+ left: 9px;
7309
8174
  }
7310
8175
 
7311
8176
  .cpk-launcher-hud__list {
@@ -7339,6 +8204,14 @@ ${argsString}</pre
7339
8204
  background: rgb(255 255 255 / 0.06);
7340
8205
  }
7341
8206
 
8207
+ .cpk-launcher-hud[data-color-scheme="light"] .cpk-launcher-hud__row:hover,
8208
+ .cpk-launcher-hud[data-color-scheme="light"]
8209
+ .cpk-launcher-hud__row:focus-within,
8210
+ .cpk-launcher-hud[data-color-scheme="light"]
8211
+ .cpk-launcher-hud__row[data-cpk-hud-help="open"] {
8212
+ background: #f0f0f4;
8213
+ }
8214
+
7342
8215
  .cpk-launcher-hud__action {
7343
8216
  display: flex;
7344
8217
  gap: 8px;
@@ -7356,6 +8229,10 @@ ${argsString}</pre
7356
8229
  cursor: pointer;
7357
8230
  }
7358
8231
 
8232
+ .cpk-launcher-hud[data-color-scheme="light"] .cpk-launcher-hud__action {
8233
+ color: #010507;
8234
+ }
8235
+
7359
8236
  /* Stretch the row action over the whole tab, including the detail
7360
8237
  copy. The help mark sits above this layer. */
7361
8238
  .cpk-launcher-hud__action::after {
@@ -7399,6 +8276,10 @@ ${argsString}</pre
7399
8276
  line-height: 1;
7400
8277
  }
7401
8278
 
8279
+ .cpk-launcher-hud[data-color-scheme="light"] .cpk-launcher-hud__help {
8280
+ color: #68686e;
8281
+ }
8282
+
7402
8283
  .cpk-launcher-hud__help:focus-visible,
7403
8284
  .cpk-launcher-hud__action:focus-visible {
7404
8285
  outline: 2px solid #bec2ff;
@@ -7425,9 +8306,14 @@ ${argsString}</pre
7425
8306
  padding-bottom 200ms cubic-bezier(0.16, 1, 0.3, 1);
7426
8307
  }
7427
8308
 
8309
+ .cpk-launcher-hud[data-color-scheme="light"] .cpk-launcher-hud__detail {
8310
+ color: #68686e;
8311
+ }
8312
+
7428
8313
  .cpk-launcher-hud__row:hover .cpk-launcher-hud__detail,
7429
8314
  .cpk-launcher-hud__row:focus-within .cpk-launcher-hud__detail,
7430
- .cpk-launcher-hud__row[data-cpk-hud-help="open"] .cpk-launcher-hud__detail {
8315
+ .cpk-launcher-hud__row[data-cpk-hud-help="open"]
8316
+ .cpk-launcher-hud__detail {
7431
8317
  max-height: 72px;
7432
8318
  padding: 0 8px 7px;
7433
8319
  opacity: 1;
@@ -7441,6 +8327,98 @@ ${argsString}</pre
7441
8327
  }
7442
8328
  }
7443
8329
 
8330
+ /*
8331
+ * On mount, borrow the hover HUD for one short introduction. The card
8332
+ * establishes the destination first; its rows then resolve in order so
8333
+ * the eye can count the available features instead of receiving one
8334
+ * undifferentiated block. Only opacity and transform move.
8335
+ */
8336
+ @keyframes cpk-launcher-hud-intro {
8337
+ 0% {
8338
+ opacity: 0;
8339
+ transform: translateX(8px);
8340
+ }
8341
+ 8%,
8342
+ 88% {
8343
+ opacity: 1;
8344
+ transform: none;
8345
+ }
8346
+ 100% {
8347
+ opacity: 0;
8348
+ transform: translateX(4px);
8349
+ }
8350
+ }
8351
+
8352
+ @keyframes cpk-launcher-hud-intro-right {
8353
+ 0% {
8354
+ opacity: 0;
8355
+ transform: translateX(-8px);
8356
+ }
8357
+ 8%,
8358
+ 88% {
8359
+ opacity: 1;
8360
+ transform: none;
8361
+ }
8362
+ 100% {
8363
+ opacity: 0;
8364
+ transform: translateX(-4px);
8365
+ }
8366
+ }
8367
+
8368
+ @keyframes cpk-launcher-hud-row-online {
8369
+ from {
8370
+ opacity: 0;
8371
+ transform: translateY(4px);
8372
+ }
8373
+ to {
8374
+ opacity: 1;
8375
+ transform: none;
8376
+ }
8377
+ }
8378
+
8379
+ @keyframes cpk-launcher-hud-check-online {
8380
+ from {
8381
+ opacity: 0;
8382
+ transform: scale(0.65);
8383
+ }
8384
+ to {
8385
+ opacity: 1;
8386
+ transform: scale(1);
8387
+ }
8388
+ }
8389
+
8390
+ .cpk-launcher-hud[data-cpk-hud-intro="true"] {
8391
+ animation: cpk-launcher-hud-intro var(--cpk-launcher-hud-intro-duration)
8392
+ cubic-bezier(0.16, 1, 0.3, 1) both;
8393
+ }
8394
+
8395
+ .cpk-launcher-hud[data-cpk-hud-intro="true"][data-cpk-hud-side="right"] {
8396
+ animation-name: cpk-launcher-hud-intro-right;
8397
+ }
8398
+
8399
+ .cpk-launcher-hud[data-cpk-hud-intro="true"] .cpk-launcher-hud__row {
8400
+ animation: cpk-launcher-hud-row-online
8401
+ var(--cpk-launcher-hud-row-duration) cubic-bezier(0.16, 1, 0.3, 1)
8402
+ both;
8403
+ animation-delay: var(--cpk-hud-row-delay);
8404
+ }
8405
+
8406
+ .cpk-launcher-hud[data-cpk-hud-intro="true"] .cpk-launcher-hud__check {
8407
+ animation: cpk-launcher-hud-check-online 220ms
8408
+ cubic-bezier(0.16, 1, 0.3, 1) both;
8409
+ animation-delay: calc(var(--cpk-hud-row-delay) + 90ms);
8410
+ }
8411
+
8412
+ @media (prefers-reduced-motion: reduce) {
8413
+ .cpk-launcher-hud[data-cpk-hud-intro="true"],
8414
+ .cpk-launcher-hud[data-cpk-hud-intro="true"] .cpk-launcher-hud__row,
8415
+ .cpk-launcher-hud[data-cpk-hud-intro="true"] .cpk-launcher-hud__check {
8416
+ animation: none !important;
8417
+ opacity: 1;
8418
+ transform: none;
8419
+ }
8420
+ }
8421
+
7444
8422
  /*
7445
8423
  * Marker on the navigation entry, which is what keeps a signal alive
7446
8424
  * once the panel is open and the launcher is hidden. Static by design:
@@ -7467,7 +8445,7 @@ ${argsString}</pre
7467
8445
  /* ── Inspector window ────────────────────────────────────────── */
7468
8446
  .inspector-window {
7469
8447
  border: 1px solid #d8d8e8 !important;
7470
- border-radius: 5px !important;
8448
+ border-radius: var(--cpk-inspector-shell-radius) !important;
7471
8449
  box-shadow: none !important;
7472
8450
  }
7473
8451
 
@@ -7583,10 +8561,71 @@ ${argsString}</pre
7583
8561
  .inspector-sidebar[data-icon-rail="true"] .inspector-nav-control,
7584
8562
  .inspector-sidebar[data-icon-rail="true"] .inspector-sidebar-control,
7585
8563
  .inspector-sidebar[data-icon-rail="true"] .inspector-sidebar-toggle {
8564
+ box-sizing: border-box !important;
8565
+ width: 36px !important;
8566
+ height: 36px !important;
8567
+ min-width: 36px !important;
8568
+ min-height: 36px !important;
8569
+ justify-content: center !important;
8570
+ align-items: center !important;
8571
+ gap: 0 !important;
8572
+ padding: 0 !important;
8573
+ overflow: visible !important;
8574
+ }
8575
+ .inspector-sidebar[data-icon-rail="true"] .inspector-nav-icon,
8576
+ .inspector-sidebar[data-icon-rail="true"] .inspector-nav-icon svg,
8577
+ .inspector-sidebar[data-icon-rail="true"]
8578
+ .inspector-context-dropdown-icon,
8579
+ .inspector-sidebar[data-icon-rail="true"]
8580
+ .inspector-context-dropdown-icon
8581
+ svg,
8582
+ .inspector-sidebar[data-icon-rail="true"]
8583
+ .inspector-agent-placeholder
8584
+ svg {
8585
+ width: 18px !important;
8586
+ height: 18px !important;
8587
+ overflow: visible !important;
8588
+ }
8589
+ .inspector-sidebar[data-icon-rail="true"]
8590
+ .inspector-agent-selector
8591
+ > [data-context-dropdown-root="true"] {
8592
+ display: flex !important;
8593
+ flex: none !important;
8594
+ width: 36px !important;
8595
+ min-width: 36px !important;
8596
+ max-width: 36px !important;
7586
8597
  justify-content: center !important;
7587
8598
  align-items: center !important;
8599
+ }
8600
+ .inspector-sidebar[data-icon-rail="true"]
8601
+ .inspector-agent-selector
8602
+ > [data-context-dropdown-root="true"]
8603
+ > button,
8604
+ .inspector-sidebar[data-icon-rail="true"] .inspector-agent-placeholder {
8605
+ display: flex !important;
8606
+ width: 36px !important;
8607
+ height: 36px !important;
8608
+ min-width: 36px !important;
8609
+ min-height: 36px !important;
8610
+ max-width: 36px !important;
8611
+ align-items: center !important;
8612
+ justify-content: center !important;
7588
8613
  gap: 0 !important;
7589
- padding-inline: 0 !important;
8614
+ padding: 0 !important;
8615
+ transition:
8616
+ background-color 180ms ease,
8617
+ border-color 180ms ease,
8618
+ color 180ms ease !important;
8619
+ }
8620
+ .inspector-sidebar[data-icon-rail="true"]
8621
+ .inspector-context-dropdown-label,
8622
+ .inspector-sidebar[data-icon-rail="true"]
8623
+ .inspector-context-dropdown-chevron {
8624
+ display: none !important;
8625
+ width: 0 !important;
8626
+ min-width: 0 !important;
8627
+ flex: none !important;
8628
+ overflow: hidden !important;
7590
8629
  }
7591
8630
  .inspector-sidebar[data-icon-rail="true"] .inspector-nav-label,
7592
8631
  .inspector-sidebar[data-icon-rail="true"] .inspector-sidebar-label {
@@ -7816,7 +8855,10 @@ ${argsString}</pre
7816
8855
  clearTimeout(this.transitionTimeoutId);
7817
8856
  this.transitionTimeoutId = null;
7818
8857
  }
8858
+ this.clearIconRailContextCloseTimer();
7819
8859
  this.unsubscribeFromInspectorThreadBridge();
8860
+ this.stopIntelligenceStory();
8861
+ this.clearIntelligencePromptReset();
7820
8862
  this.threadsSetupPromptCopyGeneration += 1;
7821
8863
  if (this.threadsSetupPromptCopyResetTimeoutId !== null) {
7822
8864
  window.clearTimeout(this.threadsSetupPromptCopyResetTimeoutId);
@@ -7825,6 +8867,7 @@ ${argsString}</pre
7825
8867
  this.threadsSetupPromptCopyState = "idle";
7826
8868
  this.stopSignalPulse();
7827
8869
  this.cancelGestureTail();
8870
+ this.cancelLauncherHudIntro();
7828
8871
  this.cancelThreadRefreshDebounce();
7829
8872
  this.clearInspectorUsageRefresh();
7830
8873
  this.cleanupThreadsExampleOverviewVideo();
@@ -7861,6 +8904,7 @@ ${argsString}</pre
7861
8904
  else this.centerContext("window");
7862
8905
  this.ensureAnnouncementLoading();
7863
8906
  this.updateHostTransform(this.isOpen ? "window" : "button");
8907
+ this.scheduleLauncherHudIntro();
7864
8908
  }
7865
8909
  render() {
7866
8910
  return this.isOpen ? html`
@@ -7884,6 +8928,7 @@ ${argsString}</pre
7884
8928
  this.maybeCompleteEventErrorView();
7885
8929
  this.flushErrorLandingScroll();
7886
8930
  this.maybeTrackHomeViewed();
8931
+ this.syncIntelligenceStory();
7887
8932
  if (!this.isOpen) {
7888
8933
  this.lastScrolledAgentNavigationLayout = null;
7889
8934
  return;
@@ -7923,8 +8968,6 @@ ${argsString}</pre
7923
8968
  "text-xs",
7924
8969
  "font-medium",
7925
8970
  "text-white",
7926
- "transition",
7927
- "hover:scale-105",
7928
8971
  "focus-visible:outline",
7929
8972
  "focus-visible:outline-2",
7930
8973
  "focus-visible:outline-offset-2",
@@ -8044,6 +9087,41 @@ ${argsString}</pre
8044
9087
  isLauncherHudBlocked() {
8045
9088
  return this.gestureSignal !== null;
8046
9089
  }
9090
+ scheduleLauncherHudIntro(delay = LAUNCHER_HUD_INTRO_MS.delay) {
9091
+ if (this.launcherHudIntroStartTimer !== null) clearTimeout(this.launcherHudIntroStartTimer);
9092
+ this.launcherHudIntroStartTimer = setTimeout(() => {
9093
+ this.launcherHudIntroStartTimer = null;
9094
+ if (!this.isConnected || this.isOpen) return;
9095
+ if (this.isLauncherHudBlocked()) {
9096
+ this.scheduleLauncherHudIntro(LAUNCHER_HUD_INTRO_MS.blockedRetry);
9097
+ return;
9098
+ }
9099
+ this.resolveLauncherHudSide();
9100
+ this.launcherHudIntro = true;
9101
+ this.launcherHudOpen = true;
9102
+ this.requestUpdate();
9103
+ this.launcherHudIntroEndTimer = setTimeout(() => {
9104
+ this.launcherHudIntroEndTimer = null;
9105
+ this.launcherHudIntro = false;
9106
+ this.launcherHudOpen = false;
9107
+ this.launcherHudHelp = null;
9108
+ this.requestUpdate();
9109
+ }, LAUNCHER_HUD_INTRO_MS.duration);
9110
+ }, delay);
9111
+ }
9112
+ cancelLauncherHudIntro() {
9113
+ if (this.launcherHudIntroStartTimer !== null) {
9114
+ clearTimeout(this.launcherHudIntroStartTimer);
9115
+ this.launcherHudIntroStartTimer = null;
9116
+ }
9117
+ if (this.launcherHudIntroEndTimer !== null) {
9118
+ clearTimeout(this.launcherHudIntroEndTimer);
9119
+ this.launcherHudIntroEndTimer = null;
9120
+ }
9121
+ if (!this.launcherHudIntro) return;
9122
+ this.launcherHudIntro = false;
9123
+ if (this.isConnected) this.requestUpdate();
9124
+ }
8047
9125
  resolveLauncherHudSide() {
8048
9126
  if (typeof window === "undefined") {
8049
9127
  this.launcherHudSide = "left";
@@ -8072,6 +9150,7 @@ ${argsString}</pre
8072
9150
  this.requestUpdate();
8073
9151
  }
8074
9152
  closeLauncherHud() {
9153
+ this.cancelLauncherHudIntro();
8075
9154
  if (this.launcherHudCloseTimer !== null) {
8076
9155
  clearTimeout(this.launcherHudCloseTimer);
8077
9156
  this.launcherHudCloseTimer = null;
@@ -8109,6 +9188,10 @@ ${argsString}</pre
8109
9188
  class="cpk-launcher-hud__row"
8110
9189
  data-cpk-hud-row=${args.id}
8111
9190
  data-cpk-hud-help=${helpOpen ? "open" : nothing}
9191
+ style=${styleMap({
9192
+ "--cpk-hud-row-index": `${args.introIndex}`,
9193
+ "--cpk-hud-row-delay": `${LAUNCHER_HUD_INTRO_MS.rowStart + args.introIndex * LAUNCHER_HUD_INTRO_MS.rowStagger}ms`
9194
+ })}
8112
9195
  @click=${(event) => this.handleHudRowClick(event, args.id)}
8113
9196
  >
8114
9197
  <button
@@ -8138,23 +9221,31 @@ ${argsString}</pre
8138
9221
  }
8139
9222
  renderLauncherHud() {
8140
9223
  if (!this.launcherHudOpen) return nothing;
8141
- const threadsOn = this.areThreadEndpointsAvailable();
8142
- const intelligenceOn = Boolean(this._core?.intelligence);
8143
- const learningOn = intelligenceOn && this._memoriesAvailable;
9224
+ const homeModel = this.getHomeModel();
9225
+ const threadsOn = homeModel.services.some((service) => service.id === "threads" && service.enabled);
9226
+ const learningOn = homeModel.services.some((service) => service.id === "memory" && service.enabled);
9227
+ const intelligenceOn = homeModel.hero.connection === "connected";
8144
9228
  return html`
8145
9229
  <div
8146
9230
  class="cpk-launcher-hud"
8147
9231
  id="cpk-launcher-hud"
8148
9232
  data-cpk-launcher-hud
8149
9233
  data-cpk-hud-side=${this.launcherHudSide}
9234
+ data-cpk-hud-intro=${this.launcherHudIntro ? "true" : nothing}
9235
+ data-color-scheme=${this.colorScheme}
9236
+ style=${styleMap({
9237
+ "--cpk-launcher-hud-intro-duration": `${LAUNCHER_HUD_INTRO_MS.duration}ms`,
9238
+ "--cpk-launcher-hud-row-duration": `${LAUNCHER_HUD_INTRO_MS.rowDuration}ms`
9239
+ })}
8150
9240
  >
9241
+ <span class="cpk-launcher-hud__arrow" aria-hidden="true"></span>
8151
9242
  <div class="cpk-launcher-hud__card">
8152
- <span class="cpk-launcher-hud__arrow" aria-hidden="true"></span>
8153
9243
  <ul class="cpk-launcher-hud__list" role="list">
8154
9244
  ${this.renderHudRow({
8155
9245
  id: "inspector",
8156
9246
  label: HUD_OPEN_INSPECTOR_LABEL,
8157
- detail: HUD_OPEN_INSPECTOR_DETAIL
9247
+ detail: HUD_OPEN_INSPECTOR_DETAIL,
9248
+ introIndex: 0
8158
9249
  })}
8159
9250
  </ul>
8160
9251
  <ul class="cpk-launcher-hud__list" role="list">
@@ -8162,19 +9253,22 @@ ${argsString}</pre
8162
9253
  id: "threads",
8163
9254
  label: threadsOn ? HUD_THREADS_ON_LABEL : HUD_THREADS_OFF_LABEL,
8164
9255
  detail: threadsOn ? HUD_THREADS_ON_DETAIL : HUD_THREADS_OFF_DETAIL,
8165
- connected: threadsOn
9256
+ connected: threadsOn,
9257
+ introIndex: 1
8166
9258
  })}
8167
9259
  ${this.renderHudRow({
8168
9260
  id: "intelligence",
8169
9261
  label: intelligenceOn ? HUD_INTELLIGENCE_ON_LABEL : HUD_INTELLIGENCE_OFF_LABEL,
8170
9262
  detail: intelligenceOn ? HUD_INTELLIGENCE_ON_DETAIL : HUD_INTELLIGENCE_OFF_DETAIL,
8171
- connected: intelligenceOn
9263
+ connected: intelligenceOn,
9264
+ introIndex: 2
8172
9265
  })}
8173
9266
  ${this.renderHudRow({
8174
9267
  id: "learning",
8175
9268
  label: learningOn ? HUD_LEARNING_ON_LABEL : HUD_LEARNING_OFF_LABEL,
8176
9269
  detail: learningOn ? HUD_LEARNING_ON_DETAIL : HUD_LEARNING_OFF_DETAIL,
8177
- connected: learningOn
9270
+ connected: learningOn,
9271
+ introIndex: 3
8178
9272
  })}
8179
9273
  </ul>
8180
9274
  </div>
@@ -8263,12 +9357,12 @@ ${argsString}</pre
8263
9357
  </span>
8264
9358
  <span class="inspector-nav-label">${item.label}</span>
8265
9359
  ${marker ? html`
8266
- <span
8267
- class="inspector-nav-signal-dot"
8268
- data-cpk-signal-tone=${marker.tone}
8269
- aria-hidden="true"
8270
- ></span>
8271
- ` : nothing}
9360
+ <span
9361
+ class="inspector-nav-signal-dot"
9362
+ data-cpk-signal-tone=${marker.tone}
9363
+ aria-hidden="true"
9364
+ ></span>
9365
+ ` : nothing}
8272
9366
  </button>
8273
9367
  `;
8274
9368
  })}
@@ -8277,34 +9371,34 @@ ${argsString}</pre
8277
9371
  })}
8278
9372
  </nav>
8279
9373
  ${automaticallyCollapsed ? nothing : html`
8280
- <button
8281
- type="button"
8282
- class="inspector-sidebar-toggle"
8283
- data-inspector-sidebar-toggle
8284
- aria-label=${iconRail ? "Expand sidebar" : "Collapse sidebar"}
8285
- aria-expanded=${iconRail ? "false" : "true"}
8286
- data-inspector-tooltip=${iconRail ? "Expand sidebar" : nothing}
8287
- title=${iconRail ? nothing : "Collapse sidebar"}
8288
- style=${INTERACTIVE_FOCUS_BASE_STYLE}
8289
- @pointerenter=${iconRail ? this.handleSidebarRailTooltipShow : nothing}
8290
- @pointerleave=${iconRail ? this.handleSidebarRailTooltipHide : nothing}
8291
- @focus=${iconRail ? this.handleSidebarRailTooltipShow : nothing}
8292
- @blur=${iconRail ? this.handleSidebarRailTooltipHide : nothing}
8293
- @click=${this.handleSidebarToggle}
8294
- >
8295
- <span class="inspector-nav-icon" aria-hidden="true">
8296
- ${this.renderIcon(iconRail ? "ChevronRight" : "ChevronLeft")}
8297
- </span>
8298
- <span class="inspector-nav-label"
8299
- >${iconRail ? "Expand" : "Collapse"}</span
8300
- >
8301
- </button>
8302
- `}
8303
- ${iconRail ? nothing : html`
8304
9374
  <div class="inspector-sidebar-footer">
8305
- <div class="inspector-sidebar-status-list">
8306
- ${this.renderSidebarIntelligenceStatus(homeModel)}
8307
- </div>
9375
+ ${iconRail ? nothing : html`
9376
+ <div class="inspector-sidebar-status-list">
9377
+ ${this.renderSidebarIntelligenceStatus(homeModel)}
9378
+ </div>
9379
+ `}
9380
+ <button
9381
+ type="button"
9382
+ class="inspector-sidebar-toggle"
9383
+ data-inspector-sidebar-toggle
9384
+ aria-label=${iconRail ? "Expand sidebar" : "Collapse sidebar"}
9385
+ aria-expanded=${iconRail ? "false" : "true"}
9386
+ data-inspector-tooltip=${iconRail ? "Expand sidebar" : nothing}
9387
+ title=${iconRail ? nothing : "Collapse sidebar"}
9388
+ style=${INTERACTIVE_FOCUS_BASE_STYLE}
9389
+ @pointerenter=${iconRail ? this.handleSidebarRailTooltipShow : nothing}
9390
+ @pointerleave=${iconRail ? this.handleSidebarRailTooltipHide : nothing}
9391
+ @focus=${iconRail ? this.handleSidebarRailTooltipShow : nothing}
9392
+ @blur=${iconRail ? this.handleSidebarRailTooltipHide : nothing}
9393
+ @click=${this.handleSidebarToggle}
9394
+ >
9395
+ <span class="inspector-nav-icon" aria-hidden="true">
9396
+ ${this.renderIcon(iconRail ? "ChevronRight" : "ChevronLeft")}
9397
+ </span>
9398
+ <span class="inspector-nav-label"
9399
+ >${iconRail ? "Expand" : "Collapse"}</span
9400
+ >
9401
+ </button>
8308
9402
  </div>
8309
9403
  `}
8310
9404
  </aside>
@@ -8509,23 +9603,37 @@ ${argsString}</pre
8509
9603
  const connected = model.hero.connection === "connected";
8510
9604
  const action = model.hero.action;
8511
9605
  const renewing = action?.kind === "renew";
9606
+ const installing = !connected && !renewing;
8512
9607
  return html`
8513
9608
  <section
8514
9609
  class="inspector-home-section inspector-intelligence-hud"
8515
9610
  data-inspector-home-card="intelligence"
8516
9611
  data-state=${connected ? "connected" : "disconnected"}
9612
+ data-mode=${connected ? "connected" : renewing ? "renew" : "install"}
8517
9613
  aria-label="Intelligence ${connected ? "connected" : renewing ? "plan expired" : "not enabled"}"
8518
9614
  >
8519
9615
  <header class="inspector-intelligence-hud-header">
8520
9616
  <div class="inspector-intelligence-hud-heading">
8521
9617
  <h2 class="inspector-home-section-title">
9618
+ ${installing ? html`
9619
+ <img
9620
+ class="inspector-intelligence-mark"
9621
+ src=${inspector_logo_kite_default}
9622
+ alt=""
9623
+ aria-hidden="true"
9624
+ />
9625
+ ` : nothing}
8522
9626
  ${connected ? "Intelligence" : model.hero.title}
8523
9627
  </h2>
8524
- ${connected ? nothing : html`
8525
- <p class="inspector-intelligence-hud-description">
8526
- ${model.hero.body}
8527
- </p>
8528
- `}
9628
+ ${connected ? nothing : installing ? html`
9629
+ <p class="inspector-intelligence-sr-summary">
9630
+ ${model.hero.body}
9631
+ </p>
9632
+ ` : html`
9633
+ <p class="inspector-intelligence-hud-description">
9634
+ ${model.hero.body}
9635
+ </p>
9636
+ `}
8529
9637
  </div>
8530
9638
  <div class="inspector-intelligence-hud-header-actions">
8531
9639
  ${connected || renewing ? html`
@@ -8537,7 +9645,7 @@ ${argsString}</pre
8537
9645
  ${connected ? "Connected" : "Plan expired"}
8538
9646
  </span>
8539
9647
  ` : nothing}
8540
- ${!connected && action ? html`
9648
+ ${renewing && action ? html`
8541
9649
  <a
8542
9650
  class="inspector-intelligence-hud-action inspector-intelligence-hud-connect-action"
8543
9651
  data-inspector-home-intelligence-action=${action.kind}
@@ -8551,9 +9659,18 @@ ${argsString}</pre
8551
9659
  ${action.label} ${this.renderIcon("ArrowUpRight")}
8552
9660
  </a>
8553
9661
  ` : nothing}
9662
+ ${installing ? this.renderIntelligenceInstallActions(action) : nothing}
8554
9663
  </div>
8555
9664
  </header>
8556
9665
 
9666
+ ${installing && this.promptCopyState === "failed" ? html`
9667
+ <code
9668
+ class="inspector-intelligence-install-fallback"
9669
+ tabindex="0"
9670
+ >${createOnboardingPrompt(this.getOnboardingRunId())}</code
9671
+ >
9672
+ ` : nothing}
9673
+ ${installing ? this.renderIntelligenceStory() : nothing}
8557
9674
  ${connected ? html`
8558
9675
  <div
8559
9676
  class="inspector-intelligence-hud-details"
@@ -8836,24 +9953,394 @@ ${argsString}</pre
8836
9953
  data-feature-state-group="available"
8837
9954
  aria-label="Available features"
8838
9955
  >
8839
- <header class="inspector-home-feature-group-header">
8840
- <strong>Available</strong>
8841
- <span>${disabledServices.length}</span>
8842
- </header>
8843
- <div class="inspector-home-feature-list">
8844
- ${disabledServices.length > 0 ? disabledServices.map(renderService) : html`
8845
- <p class="inspector-home-feature-group-empty">Everything is active</p>
8846
- `}
8847
- </div>
8848
- </section>
8849
- </div>
8850
- `}
8851
- </section>
9956
+ <header class="inspector-home-feature-group-header">
9957
+ <strong>Available</strong>
9958
+ <span>${disabledServices.length}</span>
9959
+ </header>
9960
+ <div class="inspector-home-feature-list">
9961
+ ${disabledServices.length > 0 ? disabledServices.map(renderService) : html`
9962
+ <p class="inspector-home-feature-group-empty">Everything is active</p>
9963
+ `}
9964
+ </div>
9965
+ </section>
9966
+ </div>
9967
+ `}
9968
+ </section>
9969
+ `;
9970
+ }
9971
+ handleHomeHeroCta(action) {
9972
+ if (this.core?.telemetryDisabled) return;
9973
+ trackHomeCtaClicked({ action_kind: action.kind });
9974
+ }
9975
+ /**
9976
+ * The install row: copy the prompt, or fall back to the signup page.
9977
+ *
9978
+ * The prompt is primary and the link is secondary, which is the inversion
9979
+ * this card exists for. Leaving for a signup page is where developers drop
9980
+ * out; pasting into the editor they are already in is not.
9981
+ *
9982
+ * No third-party coding-agent logos here, unlike the Intelligence app. That
9983
+ * app is a private hosted surface; this one is a published npm package
9984
+ * embedded in other people's sites, and shipping Anthropic's and OpenAI's
9985
+ * marks inside it is a trademark call that is not ours to make quietly. The
9986
+ * helper line names the agents in text instead.
9987
+ */
9988
+ renderIntelligenceInstallActions(action) {
9989
+ const copied = this.promptCopyState === "copied";
9990
+ const failed = this.promptCopyState === "failed";
9991
+ return html`
9992
+ <div
9993
+ class="inspector-intelligence-install"
9994
+ data-copy-state=${this.promptCopyState}
9995
+ >
9996
+ ${this.promptCopyState === "idle" ? action ? html`
9997
+ <a
9998
+ class="inspector-intelligence-install-secondary"
9999
+ data-inspector-home-intelligence-action=${action.kind}
10000
+ href=${action.url}
10001
+ target="_blank"
10002
+ rel="noopener noreferrer"
10003
+ aria-label="Set Intelligence up yourself (opens in a new tab)"
10004
+ style=${INTERACTIVE_FOCUS_BASE_STYLE}
10005
+ @click=${() => this.handleHomeHeroCta(action)}
10006
+ >
10007
+ Set it up yourself ${this.renderIcon("ArrowUpRight")}
10008
+ </a>
10009
+ ` : nothing : html`
10010
+ <p
10011
+ class="inspector-intelligence-install-hint"
10012
+ data-tone=${failed ? "error" : "success"}
10013
+ role="status"
10014
+ >
10015
+ ${failed ? "Clipboard blocked — copy the prompt below." : "Paste it into your coding agent."}
10016
+ </p>
10017
+ `}
10018
+ <button
10019
+ type="button"
10020
+ class="inspector-intelligence-hud-action inspector-intelligence-install-copy"
10021
+ data-inspector-intelligence-copy-prompt
10022
+ aria-label=${copied ? "Install prompt copied to clipboard. Paste it into your coding agent." : "Copy the Intelligence install prompt"}
10023
+ style=${INTERACTIVE_FOCUS_BASE_STYLE}
10024
+ @click=${this.handleIntelligencePromptCopy}
10025
+ >
10026
+ ${this.renderIcon(copied ? "Check" : "ClipboardCopy")}
10027
+ ${copied ? "Prompt copied" : "Copy setup prompt"}
10028
+ </button>
10029
+ </div>
10030
+ `;
10031
+ }
10032
+ /** One run id per element lifetime; minted on first use, never rotated. */
10033
+ getOnboardingRunId() {
10034
+ this.onboardingRunId ??= createOnboardingRunId();
10035
+ return this.onboardingRunId;
10036
+ }
10037
+ /**
10038
+ * Return the button and its secondary line to the idle state.
10039
+ *
10040
+ * Long enough to read six words, short enough that a developer who went to
10041
+ * their editor and came back — because the paste went somewhere wrong, or
10042
+ * the terminal is gone — finds a button that plainly invites a second press
10043
+ * rather than a spent one wearing a checkmark.
10044
+ *
10045
+ * Only the copied state resets. A failed copy has the prompt on screen for
10046
+ * manual selection, and yanking that away mid-drag would be worse than the
10047
+ * clipboard failing in the first place.
10048
+ */
10049
+ scheduleIntelligencePromptReset() {
10050
+ this.clearIntelligencePromptReset();
10051
+ this.promptCopyResetTimer = setTimeout(() => {
10052
+ this.promptCopyResetTimer = null;
10053
+ if (!this.isConnected || this.promptCopyState !== "copied") return;
10054
+ this.promptCopyState = "idle";
10055
+ this.requestUpdate();
10056
+ }, PROMPT_COPY_RESET_MS);
10057
+ }
10058
+ clearIntelligencePromptReset() {
10059
+ if (this.promptCopyResetTimer !== null) {
10060
+ clearTimeout(this.promptCopyResetTimer);
10061
+ this.promptCopyResetTimer = null;
10062
+ }
10063
+ }
10064
+ /**
10065
+ * The three-beat Intelligence story.
10066
+ *
10067
+ * Every beat is in the DOM at all times and switched by opacity, so the
10068
+ * strip never reflows and screen readers get one stable structure. The
10069
+ * caption is the live text; the beats themselves are decorative and hidden
10070
+ * from assistive tech, because reading out a mocked code listing helps
10071
+ * nobody.
10072
+ */
10073
+ /**
10074
+ * The rotating argument, paired to whatever the picture below is showing.
10075
+ *
10076
+ * Hidden from assistive tech: a sentence that replaces itself every few
10077
+ * seconds is noise in a screen reader, so the stable summary above carries
10078
+ * the message there instead. Both sentences are always in the DOM and only
10079
+ * their opacity changes, so the block cannot reflow and the card never jumps
10080
+ * height mid-loop.
10081
+ */
10082
+ /**
10083
+ * Where a slide sits relative to the one on screen.
10084
+ *
10085
+ * This is what makes the motion agree with the rail: the rail reads left to
10086
+ * right, so a slide that has not been reached yet waits to the right, and one
10087
+ * already passed leaves to the left. Deriving it from the indices rather than
10088
+ * remembering a direction means clicking backwards through the tabs animates
10089
+ * backwards for free, with no state to keep in sync. The loop's wrap from the
10090
+ * last tab to the first therefore reads as a rewind, which is what it is.
10091
+ */
10092
+ intelligenceSlidePosition(index) {
10093
+ if (index === this.intelStoryBeat) return "active";
10094
+ return index < this.intelStoryBeat ? "before" : "after";
10095
+ }
10096
+ /** Same rule, addressed by beat id, for the picture halves. */
10097
+ intelligenceBeatPosition(beatId) {
10098
+ return this.intelligenceSlidePosition(INTELLIGENCE_STORY_BEATS.findIndex((beat) => beat.id === beatId));
10099
+ }
10100
+ renderIntelligenceStoryCopy() {
10101
+ return html`
10102
+ <div
10103
+ class="inspector-intelligence-copy"
10104
+ data-inspector-intelligence-copy
10105
+ data-beat=${INTELLIGENCE_STORY_BEATS[this.intelStoryBeat]?.id ?? "threads"}
10106
+ aria-hidden="true"
10107
+ >
10108
+ ${INTELLIGENCE_STORY_BEATS.map((beat, index) => html`
10109
+ <div
10110
+ class="inspector-intelligence-copy-slide"
10111
+ data-beat-id=${beat.id}
10112
+ data-active=${index === this.intelStoryBeat}
10113
+ data-position=${this.intelligenceSlidePosition(index)}
10114
+ >
10115
+ <strong>${beat.lead}</strong>
10116
+ <span>${beat.support}</span>
10117
+ </div>
10118
+ `)}
10119
+ </div>
10120
+ `;
10121
+ }
10122
+ renderIntelligenceStory() {
10123
+ return html`
10124
+ <section
10125
+ class="inspector-intelligence-story"
10126
+ data-inspector-intelligence-story
10127
+ data-beat=${INTELLIGENCE_STORY_BEATS[this.intelStoryBeat]?.id ?? "threads"}
10128
+ >
10129
+ ${this.renderIntelligenceStoryCopy()}
10130
+ <div class="inspector-intelligence-story-stage" aria-hidden="true">
10131
+ ${this.renderIntelligenceStoryThreads()}
10132
+ ${this.renderIntelligenceStoryLearning()}
10133
+ ${this.renderIntelligenceStorySkill()}
10134
+ ${this.renderIntelligenceStoryReuse()}
10135
+ </div>
10136
+ <div
10137
+ class="inspector-intelligence-story-rail"
10138
+ role="tablist"
10139
+ aria-label="What Intelligence adds"
10140
+ >
10141
+ ${INTELLIGENCE_STORY_BEATS.map((beat, index) => html`
10142
+ <button
10143
+ type="button"
10144
+ role="tab"
10145
+ class="inspector-intelligence-story-tab"
10146
+ aria-selected=${index === this.intelStoryBeat}
10147
+ data-active=${index === this.intelStoryBeat}
10148
+ style=${INTERACTIVE_FOCUS_BASE_STYLE}
10149
+ @click=${() => this.pinIntelligenceStoryBeat(index)}
10150
+ >
10151
+ ${beat.label}
10152
+ </button>
10153
+ `)}
10154
+ </div>
10155
+ </section>
10156
+ `;
10157
+ }
10158
+ /** Beat 1 — the developer's own users' conversations, one of them broken. */
10159
+ renderIntelligenceStoryThreads() {
10160
+ return html`
10161
+ <div
10162
+ class="inspector-intelligence-beat"
10163
+ data-beat-id="threads"
10164
+ data-position=${this.intelligenceBeatPosition("threads")}
10165
+ >
10166
+ <div class="inspector-intelligence-threads">
10167
+ ${INTELLIGENCE_STORY_THREADS.map((thread, index) => html`
10168
+ <span
10169
+ class="inspector-intelligence-thread"
10170
+ data-failed=${thread.failed}
10171
+ style="--thread-index:${index}"
10172
+ >
10173
+ <i></i>
10174
+ <strong>${thread.title}</strong>
10175
+ <small>${thread.meta}</small>
10176
+ </span>
10177
+ `)}
10178
+ </div>
10179
+ </div>
10180
+ `;
10181
+ }
10182
+ renderIntelligenceStoryLearning() {
10183
+ return html`
10184
+ <div
10185
+ class="inspector-intelligence-beat"
10186
+ data-beat-id="learning"
10187
+ data-position=${this.intelligenceBeatPosition("learning")}
10188
+ >
10189
+ <div class="inspector-intelligence-beat-col">
10190
+ <span class="inspector-intelligence-beat-label">
10191
+ Signals from ${INTELLIGENCE_STORY_SIGNALS.length} threads
10192
+ </span>
10193
+ ${INTELLIGENCE_STORY_SIGNALS.map((signal, index) => html`
10194
+ <span
10195
+ class="inspector-intelligence-signal"
10196
+ style="--signal-index:${index}"
10197
+ >${signal}</span
10198
+ >
10199
+ `)}
10200
+ </div>
10201
+ <div class="inspector-intelligence-beat-flow">
10202
+ ${this.renderIcon("ArrowRight")}
10203
+ </div>
10204
+ <div class="inspector-intelligence-beat-col">
10205
+ <span class="inspector-intelligence-beat-label">
10206
+ Reusable pattern
10207
+ </span>
10208
+ ${INTELLIGENCE_STORY_RULES.map((rule, index) => html`
10209
+ <span
10210
+ class="inspector-intelligence-rule"
10211
+ style="--rule-index:${index}"
10212
+ >
10213
+ <i>${this.renderIcon("Check")}</i>${rule}
10214
+ </span>
10215
+ `)}
10216
+ </div>
10217
+ </div>
10218
+ `;
10219
+ }
10220
+ renderIntelligenceStorySkill() {
10221
+ return html`
10222
+ <div
10223
+ class="inspector-intelligence-beat"
10224
+ data-beat-id="skill"
10225
+ data-position=${this.intelligenceBeatPosition("skill")}
10226
+ >
10227
+ <div class="inspector-intelligence-skill-file">
10228
+ <header>
10229
+ ${this.renderIcon("FileText")}
10230
+ <strong>${INTELLIGENCE_STORY_SKILL_FILE}</strong>
10231
+ <em>Pending review</em>
10232
+ </header>
10233
+ <div class="inspector-intelligence-skill-code">
10234
+ <span data-line="1"><b># Meeting scheduling</b></span>
10235
+ <span data-line="2">When planning a meeting:</span>
10236
+ ${INTELLIGENCE_STORY_RULES.map((rule, index) => html`
10237
+ <span data-line=${index + 3} style="--rule-index:${index}"
10238
+ >${index + 1}. ${rule}</span
10239
+ >
10240
+ `)}
10241
+ </div>
10242
+ </div>
10243
+ </div>
8852
10244
  `;
8853
10245
  }
8854
- handleHomeHeroCta(action) {
8855
- if (this.core?.telemetryDisabled) return;
8856
- trackHomeCtaClicked({ action_kind: action.kind });
10246
+ renderIntelligenceStoryReuse() {
10247
+ return html`
10248
+ <div
10249
+ class="inspector-intelligence-beat"
10250
+ data-beat-id="intelligence"
10251
+ data-position=${this.intelligenceBeatPosition("intelligence")}
10252
+ >
10253
+ <div class="inspector-intelligence-chain">
10254
+ ${INTELLIGENCE_STORY_CHAIN.map((step, index) => html`
10255
+ <span
10256
+ class="inspector-intelligence-chain-step"
10257
+ style="--step-index:${index}"
10258
+ >
10259
+ <i>${this.renderIcon(step.icon)}</i>
10260
+ <strong>${step.name}</strong>
10261
+ <small>${step.detail}</small>
10262
+ </span>
10263
+ ${index === INTELLIGENCE_STORY_CHAIN.length - 1 ? nothing : html`
10264
+ <span
10265
+ class="inspector-intelligence-chain-arrow"
10266
+ style="--step-index:${index}"
10267
+ >${this.renderIcon("ChevronRight")}</span
10268
+ >
10269
+ `}
10270
+ `)}
10271
+ </div>
10272
+ <span class="inspector-intelligence-chain-proof">
10273
+ ${this.renderIcon("Sparkles")} Next run starts with
10274
+ <code>${INTELLIGENCE_STORY_SKILL_FILE}</code>
10275
+ </span>
10276
+ </div>
10277
+ `;
10278
+ }
10279
+ /** A press pins that beat and stops the loop; the developer is now driving. */
10280
+ pinIntelligenceStoryBeat(index) {
10281
+ this.intelStoryUserPinned = true;
10282
+ this.intelStoryBeat = index;
10283
+ this.stopIntelligenceStory();
10284
+ this.requestUpdate();
10285
+ if (!this.core?.telemetryDisabled) {
10286
+ const beat = INTELLIGENCE_STORY_BEATS[index];
10287
+ if (beat) trackHomeStoryBeatSelected({
10288
+ beat: beat.id,
10289
+ beat_index: index
10290
+ });
10291
+ }
10292
+ }
10293
+ /**
10294
+ * Advance the story only while it is actually on screen.
10295
+ *
10296
+ * Gated on the panel being open, Home being the visible tab, settings being
10297
+ * closed and the document being visible. Anything less and a debugging tool
10298
+ * would be holding a repeating timer behind a closed panel.
10299
+ */
10300
+ syncIntelligenceStory() {
10301
+ if (!(this.isOpen && !this.settingsOpen && this.selectedMenu === "home" && !this._core?.intelligence && typeof document !== "undefined" && document.visibilityState !== "hidden")) {
10302
+ this.intelStoryUserPinned = false;
10303
+ this.stopIntelligenceStory();
10304
+ return;
10305
+ }
10306
+ if (this.intelStoryUserPinned || this.prefersReducedMotion()) {
10307
+ this.stopIntelligenceStory();
10308
+ return;
10309
+ }
10310
+ if (this.intelStoryTimer !== null) return;
10311
+ const advance = () => {
10312
+ const current = INTELLIGENCE_STORY_BEATS[this.intelStoryBeat];
10313
+ this.intelStoryTimer = setTimeout(() => {
10314
+ this.intelStoryTimer = null;
10315
+ if (!this.isConnected) return;
10316
+ this.intelStoryBeat = (this.intelStoryBeat + 1) % INTELLIGENCE_STORY_BEATS.length;
10317
+ this.requestUpdate();
10318
+ advance();
10319
+ }, current?.duration ?? 3800);
10320
+ };
10321
+ advance();
10322
+ }
10323
+ stopIntelligenceStory() {
10324
+ if (this.intelStoryTimer !== null) {
10325
+ clearTimeout(this.intelStoryTimer);
10326
+ this.intelStoryTimer = null;
10327
+ }
10328
+ }
10329
+ /**
10330
+ * Reduced motion parks the story on the closing beat.
10331
+ *
10332
+ * That beat is the whole argument in one static frame, so a developer who
10333
+ * asked their OS for less motion still gets the point rather than a
10334
+ * fragment of it.
10335
+ */
10336
+ prefersReducedMotion() {
10337
+ if (typeof window === "undefined" || !window.matchMedia) return false;
10338
+ this.intelStoryReducedMotion ??= window.matchMedia("(prefers-reduced-motion: reduce)");
10339
+ if (this.intelStoryReducedMotion.matches) {
10340
+ this.intelStoryBeat = INTELLIGENCE_STORY_BEATS.length - 1;
10341
+ return true;
10342
+ }
10343
+ return false;
8857
10344
  }
8858
10345
  maybeTrackHomeViewed() {
8859
10346
  if (this.selectedMenu !== "home" || this.settingsOpen || !this.isOpen) return;
@@ -9067,16 +10554,6 @@ ${argsString}</pre
9067
10554
  @pointerup=${this.handleResizePointerUp}
9068
10555
  @pointercancel=${this.handleResizePointerCancel}
9069
10556
  ></div>
9070
- <div
9071
- class="resize-handle pointer-events-auto absolute bottom-0 left-0 flex h-7 w-7 cursor-nesw-resize items-center justify-center text-gray-600 transition hover:text-gray-900"
9072
- data-resize-edge="sw"
9073
- role="presentation"
9074
- aria-hidden="true"
9075
- @pointerdown=${this.handleResizePointerDown}
9076
- @pointermove=${this.handleResizePointerMove}
9077
- @pointerup=${this.handleResizePointerUp}
9078
- @pointercancel=${this.handleResizePointerCancel}
9079
- ></div>
9080
10557
  `}
9081
10558
  <div
9082
10559
  class="resize-handle pointer-events-auto absolute bottom-0 right-0 flex h-7 w-7 cursor-nwse-resize items-center justify-center text-gray-600 transition hover:text-gray-900"
@@ -9668,11 +11145,8 @@ ${argsString}</pre
9668
11145
  return this.sanitizeForLogging(payload);
9669
11146
  }
9670
11147
  normalizeMessageContent(content) {
9671
- if (typeof content === "string") return content;
9672
- if (content && typeof content === "object" && "text" in content) {
9673
- const maybeText = content.text;
9674
- if (typeof maybeText === "string") return maybeText;
9675
- }
11148
+ const extracted = textFromUnknownContent(content);
11149
+ if (extracted) return extracted;
9676
11150
  if (content === null || content === void 0) return "";
9677
11151
  if (typeof content === "object") try {
9678
11152
  return JSON.stringify(this.sanitizeForLogging(content));
@@ -9873,6 +11347,24 @@ ${argsString}</pre
9873
11347
  });
9874
11348
  return mapped;
9875
11349
  }
11350
+ async loadThreadSnapshot(thread) {
11351
+ const core = this._core;
11352
+ if (!core?.runtimeUrl) throw new Error("Failed to load thread.");
11353
+ const baseUrl = core.runtimeUrl.replace(/\/+$/, "");
11354
+ const encodedThreadId = encodeURIComponent(thread.id);
11355
+ const [messagesResponse, stateResponse] = await Promise.all([fetch(`${baseUrl}/threads/${encodedThreadId}/messages`, { headers: { ...core.headers } }), fetch(`${baseUrl}/threads/${encodedThreadId}/state`, { headers: { ...core.headers } })]);
11356
+ if (!messagesResponse.ok) throw new Error(`Failed to load thread (HTTP ${messagesResponse.status}).`);
11357
+ const messagesBody = await messagesResponse.json();
11358
+ const stateBody = stateResponse.ok ? await stateResponse.json() : { state: {} };
11359
+ return {
11360
+ messages: this.mapThreadMessagesToPlayground(messagesBody.messages ?? []),
11361
+ state: stateBody.state ?? {}
11362
+ };
11363
+ }
11364
+ applyThreadSnapshotToPlayground(thread, snapshot) {
11365
+ this.startPlaygroundSession(false, snapshot.messages, snapshot.state, thread.agentId);
11366
+ this.playgroundSourceThreadId = thread.id;
11367
+ }
9876
11368
  sendPlaygroundMessage(content) {
9877
11369
  if (!content || this.playgroundIsRunning || this.playgroundIsLoadingThread) return;
9878
11370
  const selectedAgentId = this.resolvePlaygroundAgentId(this.selectedContext);
@@ -9892,39 +11384,39 @@ ${argsString}</pre
9892
11384
  const sendDisabled = !agentId || this.playgroundIsLoadingThread || !this.playgroundIsRunning && !this.playgroundInput.trim();
9893
11385
  return html`
9894
11386
  <form
9895
- class=${centered ? "mt-5 w-full" : "bg-white px-3 pb-3 pt-1.5"}
11387
+ class=${centered ? "cpk-playground-form mt-5 w-full" : "cpk-playground-form bg-white px-3 pb-3 pt-1.5"}
9896
11388
  @submit=${this.handlePlaygroundSubmit}
9897
11389
  >
9898
11390
  ${this.playgroundError ? html`<div
9899
- class="mx-auto mb-2 flex max-w-3xl items-start gap-2 rounded-lg border border-rose-200 bg-rose-50 px-2.5 py-2 text-[10px] text-rose-950"
9900
- role="alert"
9901
- data-playground-error
11391
+ class="mx-auto mb-2 flex max-w-3xl items-start gap-2 rounded-lg border border-rose-200 bg-rose-50 px-2.5 py-2 text-[10px] text-rose-950"
11392
+ role="alert"
11393
+ data-playground-error
11394
+ >
11395
+ <span class="mt-0.5 shrink-0"
11396
+ >${this.renderIcon("TriangleAlert")}</span
9902
11397
  >
9903
- <span class="mt-0.5 shrink-0"
9904
- >${this.renderIcon("TriangleAlert")}</span
9905
- >
9906
- <div class="min-w-0 flex-1">
9907
- <p class="font-semibold">Agent run failed</p>
9908
- <p class="mt-0.5 break-words leading-relaxed">
9909
- ${this.playgroundError}
9910
- </p>
9911
- </div>
9912
- ${hasRetry ? html`
9913
- <button
9914
- type="button"
9915
- class="shrink-0 rounded-md border border-rose-200 bg-white px-2 py-1 font-medium text-rose-700 transition hover:bg-rose-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-rose-300 focus-visible:ring-offset-1 disabled:opacity-50"
9916
- ?disabled=${busy}
9917
- @click=${this.handlePlaygroundRetry}
9918
- >
9919
- Retry
9920
- </button>
9921
- ` : nothing}
9922
- </div>` : nothing}
11398
+ <div class="min-w-0 flex-1">
11399
+ <p class="font-semibold">Agent run failed</p>
11400
+ <p class="mt-0.5 break-words leading-relaxed">
11401
+ ${this.playgroundError}
11402
+ </p>
11403
+ </div>
11404
+ ${hasRetry ? html`
11405
+ <button
11406
+ type="button"
11407
+ class="shrink-0 rounded-md border border-rose-200 bg-white px-2 py-1 font-medium text-rose-700 transition hover:bg-rose-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-rose-300 focus-visible:ring-offset-1 disabled:opacity-50"
11408
+ ?disabled=${busy}
11409
+ @click=${this.handlePlaygroundRetry}
11410
+ >
11411
+ Retry
11412
+ </button>
11413
+ ` : nothing}
11414
+ </div>` : nothing}
9923
11415
  <div
9924
- class="mx-auto flex max-w-3xl items-end gap-1.5 rounded-[28px] bg-white px-2.5 py-1.5 shadow-[0_4px_4px_0_#0000000a,0_0_1px_0_#0000009e] transition-shadow duration-200 focus-within:shadow-[0_6px_18px_0_#00000014,0_0_1px_0_#0000009e]"
11416
+ class="cpk-playground-composer mx-auto flex max-w-3xl items-end gap-1.5 rounded-[28px] bg-white px-2.5 py-1.5 shadow-[0_4px_4px_0_#0000000a,0_0_1px_0_#0000009e] transition-shadow duration-200 focus-within:shadow-[0_6px_18px_0_#00000014,0_0_1px_0_#0000009e]"
9925
11417
  >
9926
11418
  <textarea
9927
- class="min-h-[40px] max-h-32 flex-1 resize-none bg-transparent px-2.5 py-2.5 text-[13px] leading-5 text-gray-900 outline-none placeholder:text-gray-500 disabled:cursor-not-allowed disabled:opacity-60"
11419
+ class="cpk-playground-input min-h-[40px] max-h-32 flex-1 resize-none bg-transparent px-2.5 py-2.5 text-[13px] leading-5 text-gray-900 outline-none placeholder:text-gray-500 disabled:cursor-not-allowed disabled:opacity-60"
9928
11420
  rows="1"
9929
11421
  placeholder=${placeholder}
9930
11422
  aria-label="Playground message"
@@ -9935,7 +11427,7 @@ ${argsString}</pre
9935
11427
  ></textarea>
9936
11428
  <button
9937
11429
  type=${this.playgroundIsRunning ? "button" : "submit"}
9938
- class=${`mb-0.5 flex h-9 w-9 shrink-0 items-center justify-center rounded-full transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-violet-400 focus-visible:ring-offset-2 [&>svg]:h-[18px] [&>svg]:w-[18px] ${sendDisabled ? "cursor-not-allowed bg-[#00000014] text-[rgb(13,13,13)] opacity-50" : "cursor-pointer bg-black text-white hover:opacity-70 active:opacity-60"}`}
11430
+ class=${`cpk-playground-send mb-0.5 flex h-9 w-9 shrink-0 items-center justify-center rounded-full transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-violet-400 focus-visible:ring-offset-2 [&>svg]:h-[18px] [&>svg]:w-[18px] ${sendDisabled ? "cursor-not-allowed bg-[#00000014] text-[rgb(13,13,13)] opacity-50" : "cursor-pointer bg-black text-white hover:opacity-70 active:opacity-60"}`}
9939
11431
  aria-label=${this.playgroundIsRunning ? "Stop agent" : "Send playground message"}
9940
11432
  ?disabled=${sendDisabled}
9941
11433
  @click=${this.playgroundIsRunning ? this.handlePlaygroundStop : nothing}
@@ -10007,31 +11499,41 @@ ${argsString}</pre
10007
11499
  class="h-3 w-px shrink-0 bg-gray-200"
10008
11500
  aria-hidden="true"
10009
11501
  ></span>
10010
- <span class="truncate" title=${runtimeLabel}>${runtimeLabel}</span>
11502
+ <span class="truncate" title=${runtimeLabel}
11503
+ >${runtimeLabel}</span
11504
+ >
10011
11505
  </div>
10012
11506
  </div>
10013
11507
  <div
10014
11508
  class="cpk-playground-actions ml-auto flex min-w-0 items-center gap-2"
10015
11509
  >
10016
11510
  ${sourceThreads.length > 0 ? html`
10017
- <label class="sr-only" for="cpk-playground-thread-source"
10018
- >Start from a thread</label
10019
- >
10020
- <select
10021
- id="cpk-playground-thread-source"
10022
- class="cpk-playground-thread-select max-w-[200px] rounded-md border border-gray-200 bg-white px-2 py-1 text-[10px] text-gray-700 outline-none transition hover:border-gray-300 focus:border-violet-400 focus:ring-2 focus:ring-violet-100 disabled:cursor-not-allowed disabled:opacity-50"
10023
- .value=${this.playgroundSourceThreadId ?? ""}
10024
- ?disabled=${busy}
10025
- @change=${this.handlePlaygroundThreadSourceChange}
11511
+ <label class="sr-only" for="cpk-playground-thread-source"
11512
+ >Start from a thread</label
11513
+ >
11514
+ <select
11515
+ id="cpk-playground-thread-source"
11516
+ class="cpk-playground-thread-select max-w-[200px] rounded-md border border-gray-200 bg-white px-2 py-1 text-[10px] text-gray-700 outline-none transition hover:border-gray-300 focus:border-violet-400 focus:ring-2 focus:ring-violet-100 disabled:cursor-not-allowed disabled:opacity-50"
11517
+ .value=${this.playgroundSourceThreadId ?? ""}
11518
+ ?disabled=${busy}
11519
+ @change=${this.handlePlaygroundThreadSourceChange}
11520
+ >
11521
+ <option
11522
+ value=""
11523
+ ?selected=${!this.playgroundSourceThreadId}
10026
11524
  >
10027
- <option value="">Load a thread...</option>
10028
- ${sourceThreads.map((thread) => html`
10029
- <option value=${thread.id}>
10030
- ${thread.name?.trim() || `Thread ${thread.id.slice(0, 8)}`}
10031
- </option>
10032
- `)}
10033
- </select>
10034
- ` : nothing}
11525
+ Load a thread...
11526
+ </option>
11527
+ ${sourceThreads.map((thread) => html`
11528
+ <option
11529
+ value=${thread.id}
11530
+ ?selected=${this.playgroundSourceThreadId === thread.id}
11531
+ >
11532
+ ${thread.name?.trim() || `Thread ${thread.id.slice(0, 8)}`}
11533
+ </option>
11534
+ `)}
11535
+ </select>
11536
+ ` : nothing}
10035
11537
  <button
10036
11538
  type="button"
10037
11539
  class="inline-flex shrink-0 items-center gap-1 rounded-md border border-gray-200 bg-white px-2 py-1 text-[10px] font-medium text-gray-700 transition hover:border-gray-300 hover:bg-gray-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-violet-300 focus-visible:ring-offset-1 disabled:cursor-not-allowed disabled:opacity-50 [&>svg]:h-3.5 [&>svg]:w-3.5"
@@ -10044,67 +11546,66 @@ ${argsString}</pre
10044
11546
  </header>
10045
11547
 
10046
11548
  ${this.playgroundShowEphemeralNotice && runtimeMode !== "intelligence" ? html`
10047
- <div
10048
- role="alert"
10049
- class="mx-3 mt-2 flex items-start gap-2 rounded-lg border border-violet-200 bg-violet-50 px-2.5 py-2 text-[10px] text-violet-950"
10050
- data-playground-ephemeral-notice
11549
+ <div
11550
+ role="alert"
11551
+ class="mx-3 mt-2 flex items-start gap-2 rounded-lg border border-violet-200 bg-violet-50 px-2.5 py-2 text-[10px] text-violet-950"
11552
+ data-playground-ephemeral-notice
11553
+ >
11554
+ <span class="mt-0.5 text-violet-600 [&>svg]:h-3.5 [&>svg]:w-3.5"
11555
+ >${this.renderIcon("Clock3")}</span
10051
11556
  >
10052
- <span
10053
- class="mt-0.5 text-violet-600 [&>svg]:h-3.5 [&>svg]:w-3.5"
10054
- >${this.renderIcon("Clock3")}</span
10055
- >
10056
- <p class="min-w-0 flex-1 leading-relaxed">
10057
- Scratch threads are ephemeral and will be deleted when your
10058
- local session ends. Need durable history?
10059
- <a
10060
- class="font-semibold underline decoration-violet-300 underline-offset-2 hover:decoration-violet-700 focus-visible:rounded-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-violet-400 focus-visible:ring-offset-1"
10061
- href=${this.getThreadsIntelligenceSignupUrl()}
10062
- target="_blank"
10063
- rel="noopener noreferrer"
10064
- >Set up Intelligence</a
10065
- >.
10066
- </p>
10067
- <button
10068
- type="button"
10069
- class="rounded p-0.5 text-violet-500 transition hover:bg-violet-100 hover:text-violet-800 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-violet-400 focus-visible:ring-offset-1"
10070
- aria-label="Dismiss ephemeral thread notice"
10071
- @click=${() => {
11557
+ <p class="min-w-0 flex-1 leading-relaxed">
11558
+ Scratch threads are ephemeral and will be deleted when your
11559
+ local session ends. Need durable history?
11560
+ <a
11561
+ class="font-semibold underline decoration-violet-300 underline-offset-2 hover:decoration-violet-700 focus-visible:rounded-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-violet-400 focus-visible:ring-offset-1"
11562
+ href=${this.getThreadsIntelligenceSignupUrl()}
11563
+ target="_blank"
11564
+ rel="noopener noreferrer"
11565
+ >Set up Intelligence</a
11566
+ >.
11567
+ </p>
11568
+ <button
11569
+ type="button"
11570
+ class="rounded p-0.5 text-violet-500 transition hover:bg-violet-100 hover:text-violet-800 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-violet-400 focus-visible:ring-offset-1"
11571
+ aria-label="Dismiss ephemeral thread notice"
11572
+ @click=${() => {
10072
11573
  this.playgroundShowEphemeralNotice = false;
10073
11574
  this.requestUpdate();
10074
11575
  }}
10075
- >
10076
- ${this.renderIcon("X")}
10077
- </button>
10078
- </div>
10079
- ` : nothing}
11576
+ >
11577
+ ${this.renderIcon("X")}
11578
+ </button>
11579
+ </div>
11580
+ ` : nothing}
10080
11581
 
10081
11582
  <div
10082
11583
  class="min-h-0 flex-1 overflow-y-auto px-3 py-3"
10083
11584
  data-playground-messages
10084
11585
  >
10085
11586
  ${this.playgroundIsLoadingThread ? html`
11587
+ <div
11588
+ class="flex h-full items-center justify-center gap-1.5 text-[10px] text-gray-600"
11589
+ >
11590
+ <span
11591
+ class="text-gray-500 [&>svg]:animate-spin"
11592
+ aria-hidden="true"
11593
+ >${this.renderIcon("LoaderCircle")}</span
11594
+ >
11595
+ Loading thread into a scratch session...
11596
+ </div>
11597
+ ` : visibleMessages.length === 0 ? html`
10086
11598
  <div
10087
- class="flex h-full items-center justify-center gap-1.5 text-[10px] text-gray-600"
11599
+ class="cpk-playground-welcome mx-auto flex h-full w-full flex-col items-center justify-center text-center"
10088
11600
  >
10089
- <span
10090
- class="text-gray-500 [&>svg]:animate-spin"
10091
- aria-hidden="true"
10092
- >${this.renderIcon("LoaderCircle")}</span
10093
- >
10094
- Loading thread into a scratch session...
11601
+ <p class="cpk-playground-welcome-title">
11602
+ How can I help you today?
11603
+ </p>
11604
+ ${this.renderPlaygroundComposer(agentId, busy, hasRetry, true)}
10095
11605
  </div>
10096
- ` : visibleMessages.length === 0 ? html`
10097
- <div
10098
- class="mx-auto flex h-full w-full max-w-3xl flex-col items-center justify-center text-center"
10099
- >
10100
- <p class="text-base font-medium tracking-tight text-gray-900">
10101
- How can I help you today?
10102
- </p>
10103
- ${this.renderPlaygroundComposer(agentId, busy, hasRetry, true)}
10104
- </div>
10105
- ` : html`
10106
- <div class="mx-auto flex max-w-3xl flex-col pb-5">
10107
- ${visibleMessages.map((message, index) => {
11606
+ ` : html`
11607
+ <div class="mx-auto flex max-w-3xl flex-col pb-5">
11608
+ ${visibleMessages.map((message, index) => {
10108
11609
  const isUser = message.role === "user";
10109
11610
  const isReasoning = message.role === "reasoning";
10110
11611
  const isActivity = message.role === "activity";
@@ -10116,152 +11617,156 @@ ${argsString}</pre
10116
11617
  const durationLabel = duration === void 0 || duration < 1e3 ? "a few seconds" : `${Math.round(duration / 1e3)} seconds`;
10117
11618
  const label = isStreaming ? "Thinking…" : `Thought for ${durationLabel}`;
10118
11619
  if (isStreaming) return html`
10119
- <section
10120
- class="cpk-playground-message-enter my-1 text-[11px] text-gray-500"
11620
+ <section
11621
+ class="cpk-playground-message-enter my-1 text-[11px] text-gray-500"
11622
+ data-playground-message-role="reasoning"
11623
+ >
11624
+ <div
11625
+ class="inline-flex items-center gap-1 py-1 font-medium"
11626
+ >
11627
+ <span>${label}</span>
11628
+ ${content ? nothing : html`
11629
+ <span
11630
+ class="cpk-playground-thinking-dot ml-1 h-1.5 w-1.5 rounded-full bg-gray-500"
11631
+ aria-hidden="true"
11632
+ ></span>
11633
+ `}
11634
+ </div>
11635
+ ${content ? html`<div
11636
+ class="pb-2 pt-1 leading-5 text-gray-500"
11637
+ >
11638
+ ${content}
11639
+ </div>` : nothing}
11640
+ </section>
11641
+ `;
11642
+ return content ? html`
11643
+ <details
11644
+ class="cpk-playground-message-enter cpk-playground-reasoning my-1 text-[11px] text-gray-500"
10121
11645
  data-playground-message-role="reasoning"
10122
11646
  >
10123
- <div
10124
- class="inline-flex items-center gap-1 py-1 font-medium"
11647
+ <summary
11648
+ class="inline-flex cursor-pointer list-none items-center gap-1 py-1 font-medium transition-colors hover:text-gray-900 focus-visible:rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-violet-300 focus-visible:ring-offset-1"
10125
11649
  >
10126
11650
  <span>${label}</span>
10127
- ${content ? nothing : html`
10128
- <span
10129
- class="cpk-playground-thinking-dot ml-1 h-1.5 w-1.5 rounded-full bg-gray-500"
10130
- aria-hidden="true"
10131
- ></span>
10132
- `}
11651
+ <span
11652
+ class="cpk-playground-reasoning-chevron transition-transform duration-200 [&>svg]:h-3 [&>svg]:w-3"
11653
+ >${this.renderIcon("ChevronRight")}</span
11654
+ >
11655
+ </summary>
11656
+ <div class="pb-2 pt-1 leading-5 text-gray-500">
11657
+ ${content}
10133
11658
  </div>
10134
- ${content ? html`<div
10135
- class="pb-2 pt-1 leading-5 text-gray-500"
10136
- >
10137
- ${content}
10138
- </div>` : nothing}
10139
- </section>
11659
+ </details>
11660
+ ` : html`
11661
+ <div
11662
+ class="cpk-playground-message-enter my-1 py-1 text-[11px] font-medium text-gray-500"
11663
+ data-playground-message-role="reasoning"
11664
+ >
11665
+ ${label}
11666
+ </div>
10140
11667
  `;
10141
- return content ? html`
10142
- <details
10143
- class="cpk-playground-message-enter cpk-playground-reasoning my-1 text-[11px] text-gray-500"
10144
- data-playground-message-role="reasoning"
11668
+ }
11669
+ const isMultiline = content.includes("\n") || content.length > 72;
11670
+ const copyKey = `playground-message-${message.id ?? index}`;
11671
+ const showToolbar = !isUser && !isActivity && Boolean(content) && !(this.playgroundIsRunning && index === lastAssistantIndex);
11672
+ return html`
11673
+ <article
11674
+ class=${isActivity ? "cpk-playground-message-enter mr-auto mt-3 flex max-w-full items-center gap-1.5 rounded-lg border border-gray-200 bg-gray-50 px-2.5 py-1.5 text-[10px] text-gray-600" : isUser ? "cpk-playground-message-enter flex w-full flex-col items-end pt-8" : "cpk-playground-message-enter w-full"}
11675
+ data-playground-message-role=${message.role}
11676
+ >
11677
+ ${isActivity ? html`
11678
+ <span class="text-gray-500"
11679
+ >${this.renderIcon("Activity")}</span
11680
+ >
11681
+ <span class="font-medium text-gray-700"
11682
+ >Activity</span
10145
11683
  >
10146
- <summary
10147
- class="inline-flex cursor-pointer list-none items-center gap-1 py-1 font-medium transition-colors hover:text-gray-900 focus-visible:rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-violet-300 focus-visible:ring-offset-1"
11684
+ <span class="truncate">${content}</span>
11685
+ ` : isUser ? html`
11686
+ <div
11687
+ class=${`max-w-[80%] whitespace-pre-wrap break-words rounded-[16px] bg-gray-100 px-3 text-[13px] leading-5 text-gray-900 ${isMultiline ? "py-2.5" : "py-1"}`}
11688
+ >
11689
+ ${content}
11690
+ </div>
11691
+ ` : html`
11692
+ <div
11693
+ class="whitespace-pre-wrap break-words py-3 text-[13px] leading-[22px] text-gray-800"
10148
11694
  >
10149
- <span>${label}</span>
10150
- <span
10151
- class="cpk-playground-reasoning-chevron transition-transform duration-200 [&>svg]:h-3 [&>svg]:w-3"
10152
- >${this.renderIcon("ChevronRight")}</span
10153
- >
10154
- </summary>
10155
- <div class="pb-2 pt-1 leading-5 text-gray-500">
10156
11695
  ${content}
10157
11696
  </div>
10158
- </details>
10159
- ` : html`
11697
+ `}
11698
+ ${!isUser && message.toolCalls.length > 0 ? this.renderToolCallDetails(message.toolCalls) : nothing}
11699
+ ${showToolbar ? html`
10160
11700
  <div
10161
- class="cpk-playground-message-enter my-1 py-1 text-[11px] font-medium text-gray-500"
10162
- data-playground-message-role="reasoning"
11701
+ class="-ml-1 flex min-h-7 w-full items-center gap-1 bg-transparent"
11702
+ data-playground-assistant-toolbar
10163
11703
  >
10164
- ${label}
11704
+ <button
11705
+ type="button"
11706
+ class="flex h-7 w-7 items-center justify-center rounded-md text-gray-500 transition hover:bg-gray-100 hover:text-gray-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-violet-300 focus-visible:ring-offset-1 [&>svg]:h-3.5 [&>svg]:w-3.5"
11707
+ title="Copy message"
11708
+ aria-label="Copy message"
11709
+ @click=${(event) => this.copyToClipboard(content, copyKey, event)}
11710
+ >
11711
+ ${this.copiedEvents.has(copyKey) ? this.renderIcon("Check") : this.renderIcon("Copy")}
11712
+ </button>
11713
+ ${index === lastAssistantIndex && hasRetry && !busy && !this.playgroundError ? html`
11714
+ <button
11715
+ type="button"
11716
+ class="flex h-7 w-7 items-center justify-center rounded-md text-gray-500 transition hover:bg-gray-100 hover:text-gray-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-violet-300 focus-visible:ring-offset-1 [&>svg]:h-3.5 [&>svg]:w-3.5"
11717
+ title="Retry last prompt"
11718
+ aria-label="Retry last prompt"
11719
+ @click=${this.handlePlaygroundRetry}
11720
+ >
11721
+ ${this.renderIcon("RotateCcw")}
11722
+ </button>
11723
+ ` : nothing}
10165
11724
  </div>
10166
- `;
10167
- }
10168
- const isMultiline = content.includes("\n") || content.length > 72;
10169
- const copyKey = `playground-message-${message.id ?? index}`;
10170
- const showToolbar = !isUser && !isActivity && Boolean(content) && !(this.playgroundIsRunning && index === lastAssistantIndex);
10171
- return html`
10172
- <article
10173
- class=${isActivity ? "cpk-playground-message-enter mr-auto mt-3 flex max-w-full items-center gap-1.5 rounded-lg border border-gray-200 bg-gray-50 px-2.5 py-1.5 text-[10px] text-gray-600" : isUser ? "cpk-playground-message-enter flex w-full flex-col items-end pt-8" : "cpk-playground-message-enter w-full"}
10174
- data-playground-message-role=${message.role}
10175
- >
10176
- ${isActivity ? html`
10177
- <span class="text-gray-500"
10178
- >${this.renderIcon("Activity")}</span
10179
- >
10180
- <span class="font-medium text-gray-700"
10181
- >Activity</span
10182
- >
10183
- <span class="truncate">${content}</span>
10184
- ` : isUser ? html`
10185
- <div
10186
- class=${`max-w-[80%] whitespace-pre-wrap break-words rounded-[16px] bg-gray-100 px-3 text-[13px] leading-5 text-gray-900 ${isMultiline ? "py-2.5" : "py-1"}`}
10187
- >${content}</div>
10188
- ` : html`
10189
- <div
10190
- class="whitespace-pre-wrap break-words py-3 text-[13px] leading-[22px] text-gray-800"
10191
- >${content}</div>
10192
- `}
10193
- ${!isUser && message.toolCalls.length > 0 ? this.renderToolCallDetails(message.toolCalls) : nothing}
10194
- ${showToolbar ? html`
10195
- <div
10196
- class="-ml-1 flex min-h-7 w-full items-center gap-1 bg-transparent"
10197
- data-playground-assistant-toolbar
10198
- >
10199
- <button
10200
- type="button"
10201
- class="flex h-7 w-7 items-center justify-center rounded-md text-gray-500 transition hover:bg-gray-100 hover:text-gray-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-violet-300 focus-visible:ring-offset-1 [&>svg]:h-3.5 [&>svg]:w-3.5"
10202
- title="Copy message"
10203
- aria-label="Copy message"
10204
- @click=${(event) => this.copyToClipboard(content, copyKey, event)}
10205
- >
10206
- ${this.copiedEvents.has(copyKey) ? this.renderIcon("Check") : this.renderIcon("Copy")}
10207
- </button>
10208
- ${index === lastAssistantIndex && hasRetry && !busy && !this.playgroundError ? html`
10209
- <button
10210
- type="button"
10211
- class="flex h-7 w-7 items-center justify-center rounded-md text-gray-500 transition hover:bg-gray-100 hover:text-gray-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-violet-300 focus-visible:ring-offset-1 [&>svg]:h-3.5 [&>svg]:w-3.5"
10212
- title="Retry last prompt"
10213
- aria-label="Retry last prompt"
10214
- @click=${this.handlePlaygroundRetry}
10215
- >
10216
- ${this.renderIcon("RotateCcw")}
10217
- </button>
10218
- ` : nothing}
10219
- </div>
10220
- ` : nothing}
10221
- </article>
10222
- `;
11725
+ ` : nothing}
11726
+ </article>
11727
+ `;
10223
11728
  })}
10224
- ${this.playgroundIsRunning && lastReasoningIndex < 0 ? html`
10225
- <div
10226
- class="cpk-playground-message-enter mt-3 flex items-center gap-1 px-1 py-1"
10227
- aria-label="Agent is working"
10228
- >
10229
- <span
10230
- class="cpk-playground-thinking-dot h-1.5 w-1.5 rounded-full bg-gray-500"
10231
- ></span>
10232
- <span
10233
- class="cpk-playground-thinking-dot h-1.5 w-1.5 rounded-full bg-gray-500"
10234
- ></span>
10235
- <span
10236
- class="cpk-playground-thinking-dot h-1.5 w-1.5 rounded-full bg-gray-500"
10237
- ></span>
10238
- </div>
10239
- ` : nothing}
10240
- ${!busy && lastAssistantIndex >= 0 && suggestions.length > 0 ? html`
10241
- <div
10242
- class="mt-3 flex flex-wrap items-center gap-1.5"
10243
- data-playground-suggestions
10244
- >
10245
- ${suggestions.map((suggestion) => html`
10246
- <button
10247
- type="button"
10248
- class="inline-flex h-7 items-center gap-1 rounded-full border border-gray-200 bg-white px-2.5 text-[10px] font-medium leading-none text-gray-900 transition-colors hover:bg-gray-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-violet-300 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:text-gray-500"
10249
- ?disabled=${suggestion.isLoading}
10250
- aria-busy=${suggestion.isLoading ? "true" : "false"}
10251
- @click=${() => this.handlePlaygroundSuggestion(suggestion.message)}
10252
- >
10253
- ${suggestion.isLoading ? html`<span
10254
- class="[&>svg]:animate-spin"
10255
- aria-hidden="true"
10256
- >${this.renderIcon("LoaderCircle")}</span
10257
- >` : nothing}
10258
- <span>${suggestion.title}</span>
10259
- </button>
10260
- `)}
10261
- </div>
10262
- ` : nothing}
10263
- </div>
10264
- `}
11729
+ ${this.playgroundIsRunning && lastReasoningIndex < 0 ? html`
11730
+ <div
11731
+ class="cpk-playground-message-enter mt-3 flex items-center gap-1 px-1 py-1"
11732
+ aria-label="Agent is working"
11733
+ >
11734
+ <span
11735
+ class="cpk-playground-thinking-dot h-1.5 w-1.5 rounded-full bg-gray-500"
11736
+ ></span>
11737
+ <span
11738
+ class="cpk-playground-thinking-dot h-1.5 w-1.5 rounded-full bg-gray-500"
11739
+ ></span>
11740
+ <span
11741
+ class="cpk-playground-thinking-dot h-1.5 w-1.5 rounded-full bg-gray-500"
11742
+ ></span>
11743
+ </div>
11744
+ ` : nothing}
11745
+ ${!busy && lastAssistantIndex >= 0 && suggestions.length > 0 ? html`
11746
+ <div
11747
+ class="mt-3 flex flex-wrap items-center gap-1.5"
11748
+ data-playground-suggestions
11749
+ >
11750
+ ${suggestions.map((suggestion) => html`
11751
+ <button
11752
+ type="button"
11753
+ class="inline-flex h-7 items-center gap-1 rounded-full border border-gray-200 bg-white px-2.5 text-[10px] font-medium leading-none text-gray-900 transition-colors hover:bg-gray-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-violet-300 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:text-gray-500"
11754
+ ?disabled=${suggestion.isLoading}
11755
+ aria-busy=${suggestion.isLoading ? "true" : "false"}
11756
+ @click=${() => this.handlePlaygroundSuggestion(suggestion.message)}
11757
+ >
11758
+ ${suggestion.isLoading ? html`<span
11759
+ class="[&>svg]:animate-spin"
11760
+ aria-hidden="true"
11761
+ >${this.renderIcon("LoaderCircle")}</span
11762
+ >` : nothing}
11763
+ <span>${suggestion.title}</span>
11764
+ </button>
11765
+ `)}
11766
+ </div>
11767
+ ` : nothing}
11768
+ </div>
11769
+ `}
10265
11770
  </div>
10266
11771
 
10267
11772
  ${showWelcome ? nothing : this.renderPlaygroundComposer(agentId, busy, hasRetry)}
@@ -10648,6 +12153,7 @@ ${argsString}</pre
10648
12153
  this.requestUpdate();
10649
12154
  return;
10650
12155
  }
12156
+ this.tryFromHereError = null;
10651
12157
  this.selectedThreadId = threadId;
10652
12158
  if (showingExamples && this.isExampleThreadId(threadId)) {
10653
12159
  this.selectedRealThreadIsExplicit = false;
@@ -10911,6 +12417,7 @@ ${argsString}</pre
10911
12417
  <p class="cpk-threads-overview-copy">
10912
12418
  ${lockedCopy?.description ?? "Take a tour with the example threads in the sidebar. Then, start chatting in your app to create the first real thread."}
10913
12419
  </p>
12420
+ ${locked ? this.renderRuntimeEntitlementDiagnostic(this.getRuntimeEntitlementDiagnostic()) : nothing}
10914
12421
  <div class="cpk-threads-overview-actions">
10915
12422
  ${locked ? html`
10916
12423
  ${this.inspectorMetadataProjection.licenseState === "valid" ? html`
@@ -11089,6 +12596,74 @@ ${argsString}</pre
11089
12596
  }
11090
12597
  }
11091
12598
  /**
12599
+ * Prefer the Runtime's structured entitlement diagnostic and derive a
12600
+ * compatibility diagnostic only when an older Core exposes legacy status.
12601
+ */
12602
+ getRuntimeEntitlementDiagnostic() {
12603
+ const runtimeEntitlements = this.core?.runtimeEntitlements;
12604
+ if (runtimeEntitlements) return runtimeEntitlements.status === "ready" ? { status: runtimeEntitlements.status } : {
12605
+ status: runtimeEntitlements.status,
12606
+ error: runtimeEntitlements.error
12607
+ };
12608
+ switch (this.core?.licenseStatus) {
12609
+ case "valid": return { status: "ready" };
12610
+ case "expired": return {
12611
+ status: "degraded",
12612
+ error: {
12613
+ code: "legacy_license_expired",
12614
+ message: "Legacy Runtime license has expired.",
12615
+ retryable: false
12616
+ }
12617
+ };
12618
+ case "expiring": return {
12619
+ status: "degraded",
12620
+ error: {
12621
+ code: "legacy_license_expiring",
12622
+ message: "Legacy Runtime license is expiring.",
12623
+ retryable: false
12624
+ }
12625
+ };
12626
+ case "invalid": return {
12627
+ status: "misconfigured",
12628
+ error: {
12629
+ code: "legacy_license_invalid",
12630
+ message: "Legacy Runtime license is invalid.",
12631
+ retryable: false
12632
+ }
12633
+ };
12634
+ case "none":
12635
+ case "unknown": return { status: "unavailable" };
12636
+ default: return null;
12637
+ }
12638
+ }
12639
+ /** Render exact Runtime entitlement correlation details without gating UI. */
12640
+ renderRuntimeEntitlementDiagnostic(diagnostic) {
12641
+ if (!diagnostic) return nothing;
12642
+ return html`
12643
+ <div
12644
+ role="status"
12645
+ data-runtime-entitlement-status=${diagnostic.status}
12646
+ style="
12647
+ margin: -8px auto 18px;
12648
+ max-width: 380px;
12649
+ font-size: 11px;
12650
+ line-height: 1.5;
12651
+ color: #57575b;
12652
+ "
12653
+ >
12654
+ <div style="font-weight: 600;">
12655
+ Runtime entitlement: ${diagnostic.status}
12656
+ </div>
12657
+ ${diagnostic.error ? html`
12658
+ <div>${diagnostic.error.message}</div>
12659
+ <div>Code: ${diagnostic.error.code}</div>
12660
+ ${diagnostic.error.requestId ? html`<div>Request ID: ${diagnostic.error.requestId}</div>` : nothing}
12661
+ ${diagnostic.error.traceId ? html`<div>Trace ID: ${diagnostic.error.traceId}</div>` : nothing}
12662
+ ` : nothing}
12663
+ </div>
12664
+ `;
12665
+ }
12666
+ /**
11092
12667
  * Renders the realtime-connection indicator in the memory-store header.
11093
12668
  * Only `"connected"` shows the live (green-dot) state; `"connecting"` shows a
11094
12669
  * muted amber "reconnecting" and `"unavailable"` a muted grey "offline", so
@@ -11472,6 +13047,13 @@ ${argsString}</pre
11472
13047
  .focusRequestId=${this.threadFocusRequestId}
11473
13048
  .agentStateInput=${this.getLatestStateForAgent(selectedThread.agentId)}
11474
13049
  .agentEventsInput=${this.agentEvents.get(selectedThread.agentId) ?? []}
13050
+ .agentMessagesInput=${selectedThreadIsLocalExample ? EMPTY_INSPECTOR_MESSAGES : this.getLiveAgentMessagesForThread(selectedThread)}
13051
+ .tryFromHereAvailable=${!selectedThreadIsLocalExample && this.areThreadEndpointsAvailable() && this._core?.threadEndpoints?.inspect !== false}
13052
+ .tryFromHereBusy=${this.tryFromHereBusy}
13053
+ .tryFromHereError=${this.tryFromHereError}
13054
+ @tryFromHere=${(event) => {
13055
+ this.handleTryFromHere(event.detail);
13056
+ }}
11475
13057
  ></cpk-thread-details>
11476
13058
  ${selectedThreadIsLocalExample ? this.renderThreadsExampleTour() : nothing}` : showingExamples ? this.renderThreadsExampleOverview(locked) : html`
11477
13059
  <div
@@ -11712,11 +13294,7 @@ ${argsString}</pre
11712
13294
  >
11713
13295
  ${isExpanded ? html`
11714
13296
  <div class="group relative">
11715
- <pre
11716
- class="m-0 whitespace-pre-wrap break-words text-[10px] font-mono text-gray-600"
11717
- >
11718
- ${prettyEvent}</pre
11719
- >
13297
+ ${renderHighlightedJsonBlock(extractedEvent)}
11720
13298
  <button
11721
13299
  class="absolute right-0 top-0 cursor-pointer rounded px-2 py-1 text-[10px] opacity-0 transition group-hover:opacity-100 ${this.copiedEvents.has(event.id) ? "bg-green-100 text-green-700" : "bg-gray-100 text-gray-600 hover:bg-gray-200 hover:text-gray-900"}"
11722
13300
  @click=${(e) => {
@@ -11938,7 +13516,7 @@ ${prettyEvent}</pre
11938
13516
  <div class="overflow-auto">
11939
13517
  ${messages && messages.length > 0 ? html`
11940
13518
  <div class="w-full text-xs">
11941
- <div class="flex bg-gray-50">
13519
+ <div class="cpk-agent-messages-head flex bg-gray-50">
11942
13520
  <div
11943
13521
  class="w-40 shrink-0 px-4 py-2 font-medium text-gray-700"
11944
13522
  >
@@ -11948,7 +13526,7 @@ ${prettyEvent}</pre
11948
13526
  Content
11949
13527
  </div>
11950
13528
  </div>
11951
- <div class="divide-y divide-gray-200">
13529
+ <div class="cpk-agent-messages-rows">
11952
13530
  ${messages.map((msg) => {
11953
13531
  const role = msg.role || "unknown";
11954
13532
  const roleColors = {
@@ -11966,7 +13544,7 @@ ${prettyEvent}</pre
11966
13544
  const isFailedResult = role === "tool" && toolError?.toolCallId !== void 0 && toolError.toolCallId === msg.toolCallId;
11967
13545
  return html`
11968
13546
  <div
11969
- class=${isFailedResult ? "flex items-start bg-rose-50" : "flex items-start"}
13547
+ class=${isFailedResult ? "cpk-agent-message-row flex items-start bg-rose-50" : "cpk-agent-message-row flex items-start"}
11970
13548
  data-cpk-failed-tool-result=${isFailedResult ? msg.toolCallId : nothing}
11971
13549
  >
11972
13550
  <div class="w-40 shrink-0 px-4 py-2">
@@ -11977,9 +13555,10 @@ ${prettyEvent}</pre
11977
13555
  </span>
11978
13556
  </div>
11979
13557
  <div class="flex-1 px-4 py-2">
11980
- ${hasContent ? html`<div
11981
- class="whitespace-pre-wrap break-words text-gray-700"
11982
- >${rawContent}</div>` : html`<div class="italic text-gray-400">
13558
+ ${hasContent ? html`
13559
+ <!-- prettier-ignore -->
13560
+ <div class="whitespace-pre-wrap break-words text-gray-700">${rawContent}</div>
13561
+ ` : html`<div class="italic text-gray-400">
11983
13562
  ${contentFallback}
11984
13563
  </div>`}
11985
13564
  ${role === "assistant" && toolCalls.length > 0 ? this.renderToolCallDetails(toolCalls) : nothing}
@@ -12048,10 +13627,12 @@ ${prettyEvent}</pre
12048
13627
  >${this.renderIcon("ChevronDown")}</span
12049
13628
  >
12050
13629
  </button>
12051
- ${this.contextMenuOpen ? html`
13630
+ ${iconRail || this.contextMenuOpen ? html`
12052
13631
  <div
12053
- class="absolute left-0 z-50 mt-1.5 w-40 rounded-md border border-gray-200 bg-white py-1 shadow-md ring-1 ring-black/5"
13632
+ class="absolute left-0 z-50 mt-1.5 w-40 rounded-md border border-gray-200 bg-white py-1 shadow-md ring-1 ring-black/5${iconRail ? " inspector-icon-rail-menu" : ""}"
12054
13633
  data-context-dropdown-root="true"
13634
+ data-open=${this.contextMenuOpen ? "true" : "false"}
13635
+ aria-hidden=${this.contextMenuOpen ? "false" : "true"}
12055
13636
  >
12056
13637
  ${filteredOptions.map((option) => html`
12057
13638
  <button
@@ -12188,8 +13769,14 @@ ${prettyEvent}</pre
12188
13769
  this.contextMenuOpen = !this.contextMenuOpen;
12189
13770
  this.requestUpdate();
12190
13771
  }
13772
+ clearIconRailContextCloseTimer() {
13773
+ if (this.iconRailContextCloseTimer === null) return;
13774
+ clearTimeout(this.iconRailContextCloseTimer);
13775
+ this.iconRailContextCloseTimer = null;
13776
+ }
12191
13777
  handleContextOptionSelect(key) {
12192
13778
  if (!this.contextOptions.some((option) => option.key === key)) return;
13779
+ this.clearIconRailContextCloseTimer();
12193
13780
  if (this.selectedContext !== key) {
12194
13781
  this.selectedContext = key;
12195
13782
  this.expandedRows.clear();
@@ -12684,23 +14271,25 @@ ${prettyEvent}</pre
12684
14271
  </button>
12685
14272
 
12686
14273
  ${isExpanded ? html`
12687
- <div class="border-t border-gray-200 bg-gray-50/50 px-4 py-3">
14274
+ <div class="border-t border-gray-200 px-4 py-3">
12688
14275
  <div class="mb-3">
12689
- <h5 class="mb-1 text-xs font-semibold text-gray-700">ID</h5>
12690
- <code
12691
- class="font-mono text-xs font-medium text-gray-800 flex-1 truncate min-w-0"
12692
- >${id}</code
12693
- >
12694
- <button
12695
- type="button"
12696
- class="cpk-copy-btn"
12697
- @click=${(e) => {
14276
+ <div class="mb-1 flex items-center justify-between gap-2">
14277
+ <h5 class="text-xs font-semibold text-gray-700">ID</h5>
14278
+ <button
14279
+ type="button"
14280
+ class="cpk-copy-btn"
14281
+ @click=${(e) => {
12698
14282
  e.stopPropagation();
12699
14283
  this.copyContextValue(id, `${id}:id`, e);
12700
14284
  }}
14285
+ >
14286
+ ${this.copiedContextItems.has(`${id}:id`) ? "Copied" : "Copy"}
14287
+ </button>
14288
+ </div>
14289
+ <code
14290
+ class="block min-w-0 truncate font-mono text-xs font-medium text-gray-800"
14291
+ >${id}</code
12701
14292
  >
12702
- ${this.copiedContextItems.has(`${id}:id`) ? "✓" : "Copy"}
12703
- </button>
12704
14293
  </div>
12705
14294
  ${hasValue ? html`
12706
14295
  <div class="mb-2 flex items-center justify-between gap-2">
@@ -13427,8 +15016,18 @@ function defineWebInspector(registry = globalThis.customElements) {
13427
15016
  defineElementOnce(registry, "cpk-memory-list", CpkMemoryList);
13428
15017
  defineElementOnce(registry, WEB_INSPECTOR_TAG, WebInspectorElement);
13429
15018
  }
15019
+ /**
15020
+ * Bind a host-owned core before an Inspector is connected to the DOM. Disabling
15021
+ * auto-attachment first prevents `connectedCallback` from briefly selecting a
15022
+ * different global core.
15023
+ */
15024
+ function configureWebInspectorElement(inspector, core) {
15025
+ inspector.autoAttachCore = false;
15026
+ inspector.core = core;
15027
+ return inspector;
15028
+ }
13430
15029
  defineWebInspector();
13431
15030
 
13432
15031
  //#endregion
13433
- export { CpkThreadInspector, THREAD_INSPECTOR_TAG, WEB_INSPECTOR_TAG, WebInspectorElement, defineWebInspector, ɵCpkThreadDetails, buildCapabilityRows as ɵbuildCapabilityRows, maxRecallScore as ɵmaxRecallScore, normalizeRelevance as ɵnormalizeRelevance, relevanceBarWidth as ɵrelevanceBarWidth };
15032
+ export { CpkThreadInspector, THREAD_INSPECTOR_TAG, WEB_INSPECTOR_TAG, WebInspectorElement, configureWebInspectorElement, defineWebInspector, ɵCpkThreadDetails, buildCapabilityRows as ɵbuildCapabilityRows, maxRecallScore as ɵmaxRecallScore, normalizeRelevance as ɵnormalizeRelevance, relevanceBarWidth as ɵrelevanceBarWidth };
13434
15033
  //# sourceMappingURL=index.mjs.map