@copilotkit/web-inspector 1.68.3 → 1.69.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +28 -12
  2. package/dist/assets/inspector-logo-kite.cjs +12 -0
  3. package/dist/assets/inspector-logo-kite.cjs.map +1 -0
  4. package/dist/assets/inspector-logo-kite.mjs +6 -0
  5. package/dist/assets/inspector-logo-kite.mjs.map +1 -0
  6. package/dist/index.cjs +5574 -1584
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.d.cts +490 -32
  9. package/dist/index.d.cts.map +1 -1
  10. package/dist/index.d.mts +490 -32
  11. package/dist/index.d.mts.map +1 -1
  12. package/dist/index.mjs +5574 -1587
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/index.umd.js +7014 -1917
  15. package/dist/index.umd.js.map +1 -1
  16. package/dist/lib/event-snippets.cjs +559 -0
  17. package/dist/lib/event-snippets.cjs.map +1 -0
  18. package/dist/lib/event-snippets.d.cts +61 -0
  19. package/dist/lib/event-snippets.d.cts.map +1 -0
  20. package/dist/lib/event-snippets.d.mts +61 -0
  21. package/dist/lib/event-snippets.d.mts.map +1 -0
  22. package/dist/lib/event-snippets.mjs +537 -0
  23. package/dist/lib/event-snippets.mjs.map +1 -0
  24. package/dist/lib/home-briefing.cjs +290 -0
  25. package/dist/lib/home-briefing.cjs.map +1 -0
  26. package/dist/lib/home-briefing.mjs +288 -0
  27. package/dist/lib/home-briefing.mjs.map +1 -0
  28. package/dist/lib/inspector-nav.cjs +59 -0
  29. package/dist/lib/inspector-nav.cjs.map +1 -0
  30. package/dist/lib/inspector-nav.d.cts +11 -0
  31. package/dist/lib/inspector-nav.d.cts.map +1 -0
  32. package/dist/lib/inspector-nav.d.mts +11 -0
  33. package/dist/lib/inspector-nav.d.mts.map +1 -0
  34. package/dist/lib/inspector-nav.mjs +54 -0
  35. package/dist/lib/inspector-nav.mjs.map +1 -0
  36. package/dist/lib/persistence.cjs +102 -0
  37. package/dist/lib/persistence.cjs.map +1 -1
  38. package/dist/lib/persistence.mjs +98 -1
  39. package/dist/lib/persistence.mjs.map +1 -1
  40. package/dist/lib/telemetry.cjs +93 -34
  41. package/dist/lib/telemetry.cjs.map +1 -1
  42. package/dist/lib/telemetry.d.cts +1 -1
  43. package/dist/lib/telemetry.d.cts.map +1 -1
  44. package/dist/lib/telemetry.d.mts +1 -1
  45. package/dist/lib/telemetry.d.mts.map +1 -1
  46. package/dist/lib/telemetry.mjs +86 -32
  47. package/dist/lib/telemetry.mjs.map +1 -1
  48. package/dist/package.cjs +1 -1
  49. package/dist/package.mjs +1 -1
  50. package/dist/styles/generated.cjs +1 -1
  51. package/dist/styles/generated.cjs.map +1 -1
  52. package/dist/styles/generated.mjs +1 -1
  53. package/dist/styles/generated.mjs.map +1 -1
  54. package/package.json +3 -3
  55. package/dist/assets/inspector-logo-icon.cjs +0 -12
  56. package/dist/assets/inspector-logo-icon.cjs.map +0 -1
  57. package/dist/assets/inspector-logo-icon.mjs +0 -6
  58. package/dist/assets/inspector-logo-icon.mjs.map +0 -1
@@ -0,0 +1,288 @@
1
+ //#region src/lib/home-briefing.ts
2
+ const SERVICE_DOCS_URL = {
3
+ threads: "https://docs.copilotkit.ai/threads",
4
+ memory: "https://docs.copilotkit.ai/premium/intelligence-platform",
5
+ a2ui: "https://docs.copilotkit.ai/generative-ui/a2ui",
6
+ "open-gen-ui": "https://docs.copilotkit.ai/generative-ui/open-generative-ui",
7
+ suggestions: "https://docs.copilotkit.ai/agentic-chat-ui",
8
+ audio: "https://docs.copilotkit.ai/voice",
9
+ websocket: "https://docs.copilotkit.ai/premium/intelligence-platform"
10
+ };
11
+ /** Return the Home hero button for a trusted metadata action. */
12
+ function homeHeroActionFromMetadata(action) {
13
+ if (action.kind === "manage_plan") return {
14
+ kind: action.kind,
15
+ url: action.url,
16
+ label: "Manage plan"
17
+ };
18
+ if (action.kind === "renew") return {
19
+ kind: action.kind,
20
+ url: action.url,
21
+ label: "Renew plan"
22
+ };
23
+ return {
24
+ kind: action.kind,
25
+ url: action.url,
26
+ label: "Setup Intelligence"
27
+ };
28
+ }
29
+ /** Return a short preview from markdown, without links or headings. */
30
+ function announcementPreview(markdown, maxLength = 140) {
31
+ const plain = markdown.replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/[#*_`]/g, "").replace(/\s+/g, " ").trim();
32
+ if (plain.length <= maxLength) return plain;
33
+ return `${plain.slice(0, maxLength).trimEnd()}…`;
34
+ }
35
+ function connectIntelligenceAction(action, connectUrl, licenseState) {
36
+ if (action) return action;
37
+ if (connectUrl && (licenseState === "none" || licenseState === "unknown")) return homeHeroActionFromMetadata({
38
+ kind: "enable_intelligence",
39
+ url: connectUrl
40
+ });
41
+ }
42
+ function heroForState(args) {
43
+ if (!args.connected) {
44
+ const renewing = args.action?.kind === "renew";
45
+ return {
46
+ connection: "disconnected",
47
+ title: renewing ? "Renew Intelligence" : "Intelligence is not setup",
48
+ body: renewing ? "Renew Intelligence to restore persistent Threads and Memory." : "Connect CopilotKit Intelligence to add persistent Threads, Learning and Analytics to your application. Inspect conversations and allow your agents to learn from real use.",
49
+ action: connectIntelligenceAction(args.action, args.connectUrl, args.licenseState)
50
+ };
51
+ }
52
+ return {
53
+ connection: "connected",
54
+ title: "Connected to Intelligence",
55
+ body: "Use Workbench to inspect threads and memory.",
56
+ action: args.action?.kind === "enable_intelligence" ? void 0 : args.action
57
+ };
58
+ }
59
+ function usageFromMetadata(metadata) {
60
+ const usage = metadata.usage;
61
+ if (!usage) return;
62
+ if (usage.limit.kind === "finite") return {
63
+ used: usage.used,
64
+ limitLabel: `${usage.used} / ${usage.limit.value}`,
65
+ ratio: usage.limit.value === 0 ? 1 : usage.used / usage.limit.value
66
+ };
67
+ if (usage.limit.kind === "unlimited") return {
68
+ used: usage.used,
69
+ limitLabel: `${usage.used} / unlimited`
70
+ };
71
+ return {
72
+ used: usage.used,
73
+ limitLabel: `${usage.used} used`
74
+ };
75
+ }
76
+ function newsFromAnnouncement(args) {
77
+ const markdown = args.markdown?.trim();
78
+ if (markdown && args.html) return {
79
+ title: markdown.match(/^#{1,3}\s+(.+)$/m)?.[1]?.trim() || "The latest from CopilotKit",
80
+ previewText: args.previewText?.trim() || announcementPreview(markdown, 160),
81
+ documentHtml: args.html,
82
+ empty: false
83
+ };
84
+ return {
85
+ title: "You're all caught up",
86
+ previewText: "Latest CopilotKit updates will appear here.",
87
+ empty: true
88
+ };
89
+ }
90
+ function runtimeEventSignal(event) {
91
+ if (!event) return {
92
+ label: "No events yet",
93
+ tone: "muted"
94
+ };
95
+ const eventDetails = {
96
+ id: event.id,
97
+ agentId: event.agentId,
98
+ type: event.type,
99
+ timestamp: event.timestamp
100
+ };
101
+ if (event.type === "RUN_ERROR" || event.type === "ERROR") return {
102
+ label: event.type === "RUN_ERROR" ? "Run error" : "Error",
103
+ tone: "error",
104
+ ...eventDetails
105
+ };
106
+ if (event.type === "RUN_FINISHED") return {
107
+ label: "Run completed",
108
+ tone: "success",
109
+ ...eventDetails
110
+ };
111
+ if (event.type.endsWith("_START") || event.type.endsWith("_STARTED") || event.type.endsWith("_CONTENT") || event.type.endsWith("_ARGS") || event.type.endsWith("_DELTA")) return {
112
+ label: "Last event is in progress",
113
+ tone: "active",
114
+ ...eventDetails
115
+ };
116
+ return {
117
+ label: "Last event received",
118
+ tone: "success",
119
+ ...eventDetails
120
+ };
121
+ }
122
+ /**
123
+ * Whether the runtime *connection* needs attention — the single condition
124
+ * shared by System Health and the launcher's error signal, so the two can
125
+ * never disagree about whether the wiring is broken.
126
+ *
127
+ * Exactly one state counts. `disconnected` is also the initial value, so
128
+ * counting it would raise the signal on every page load; `connecting` is a
129
+ * normal startup step; `unavailable` means no Core is attached, which is not
130
+ * a defect of the developer's wiring.
131
+ *
132
+ * Note the deliberate asymmetry with `health.state`: a failed *run* also
133
+ * drives System Health to "Needs attention" while the connection is fine.
134
+ * That is an event rather than a state, and it is excluded from the launcher
135
+ * on purpose — see the launcher-signal comments in index.ts.
136
+ */
137
+ function runtimeConnectionNeedsAttention(state) {
138
+ return state === "error";
139
+ }
140
+ function runtimeHealthFromInput(input) {
141
+ const lastEvent = runtimeEventSignal(input.lastRuntimeEvent);
142
+ if (input.runtimeConnectionState === "connected") return {
143
+ state: lastEvent.tone === "error" ? "error" : "healthy",
144
+ label: lastEvent.tone === "error" ? "Needs attention" : "Healthy",
145
+ runtime: {
146
+ label: "Available",
147
+ tone: "success"
148
+ },
149
+ liveUpdates: {
150
+ label: "Ready",
151
+ tone: "success"
152
+ },
153
+ lastEvent
154
+ };
155
+ if (input.runtimeConnectionState === "connecting") return {
156
+ state: "checking",
157
+ label: "Checking",
158
+ runtime: {
159
+ label: "Checking",
160
+ tone: "active"
161
+ },
162
+ liveUpdates: {
163
+ label: "Connecting",
164
+ tone: "active"
165
+ },
166
+ lastEvent
167
+ };
168
+ if (input.runtimeConnectionState === "unavailable") return {
169
+ state: "unavailable",
170
+ label: "Unavailable",
171
+ runtime: {
172
+ label: "Unavailable",
173
+ tone: "muted"
174
+ },
175
+ liveUpdates: {
176
+ label: "Not attached",
177
+ tone: "muted"
178
+ },
179
+ lastEvent
180
+ };
181
+ const needsAttention = runtimeConnectionNeedsAttention(input.runtimeConnectionState);
182
+ return {
183
+ state: needsAttention ? "error" : "offline",
184
+ label: needsAttention ? "Runtime error" : "Offline",
185
+ runtime: {
186
+ label: "Offline",
187
+ tone: "error"
188
+ },
189
+ liveUpdates: {
190
+ label: needsAttention ? "Error" : "Disconnected",
191
+ tone: "error"
192
+ },
193
+ lastEvent
194
+ };
195
+ }
196
+ /** Build the Home briefing from data the Inspector already has. */
197
+ function buildHomeModel(input) {
198
+ const metadataAction = input.metadata.threadsFooterAction ?? input.metadata.lockedAction;
199
+ const action = metadataAction ? homeHeroActionFromMetadata({
200
+ kind: metadataAction.kind,
201
+ url: metadataAction.url
202
+ }) : void 0;
203
+ const identity = input.metadata.identity;
204
+ const projectLinked = Boolean(identity);
205
+ const intelligenceConnected = input.metadata.licenseState === "valid" || input.metadata.licenseState === "unknown" && input.intelligenceConnected;
206
+ const usage = usageFromMetadata(input.metadata);
207
+ return {
208
+ hero: heroForState({
209
+ connected: intelligenceConnected,
210
+ action,
211
+ connectUrl: input.intelligenceSignupUrl,
212
+ licenseState: input.metadata.licenseState
213
+ }),
214
+ projectLinked,
215
+ project: identity ? {
216
+ organizationName: identity.organizationName,
217
+ projectName: identity.projectName,
218
+ planLabel: input.metadata.plan?.label,
219
+ license: input.metadata.licenseState,
220
+ usage
221
+ } : input.metadata.plan || usage ? {
222
+ organizationName: "Not linked",
223
+ projectName: "This runtime is not linked to a project",
224
+ planLabel: input.metadata.plan?.label,
225
+ license: input.metadata.licenseState,
226
+ usage
227
+ } : void 0,
228
+ runtime: {
229
+ url: input.runtimeUrl,
230
+ health: runtimeHealthFromInput(input)
231
+ },
232
+ services: [
233
+ {
234
+ id: "threads",
235
+ label: "Threads",
236
+ enabled: intelligenceConnected && input.threadsAvailable,
237
+ url: input.runtimeUrl,
238
+ docsUrl: SERVICE_DOCS_URL.threads
239
+ },
240
+ {
241
+ id: "memory",
242
+ label: "Memory",
243
+ enabled: intelligenceConnected && input.memoriesOn,
244
+ docsUrl: SERVICE_DOCS_URL.memory
245
+ },
246
+ {
247
+ id: "a2ui",
248
+ label: "A2UI",
249
+ enabled: input.a2uiOn,
250
+ docsUrl: SERVICE_DOCS_URL.a2ui
251
+ },
252
+ {
253
+ id: "open-gen-ui",
254
+ label: "Open Gen UI",
255
+ enabled: input.openGenUiOn,
256
+ docsUrl: SERVICE_DOCS_URL["open-gen-ui"]
257
+ },
258
+ {
259
+ id: "suggestions",
260
+ label: "Suggestions",
261
+ enabled: input.suggestionsOn,
262
+ docsUrl: SERVICE_DOCS_URL.suggestions
263
+ },
264
+ {
265
+ id: "audio",
266
+ label: "Audio",
267
+ enabled: input.audioOn,
268
+ docsUrl: SERVICE_DOCS_URL.audio
269
+ },
270
+ {
271
+ id: "websocket",
272
+ label: "Websocket",
273
+ enabled: intelligenceConnected && Boolean(input.websocketUrl),
274
+ url: input.websocketUrl,
275
+ docsUrl: SERVICE_DOCS_URL.websocket
276
+ }
277
+ ],
278
+ news: newsFromAnnouncement({
279
+ previewText: input.announcementPreviewText,
280
+ markdown: input.announcementMarkdown,
281
+ html: input.announcementHtml ?? void 0
282
+ })
283
+ };
284
+ }
285
+
286
+ //#endregion
287
+ export { buildHomeModel, runtimeConnectionNeedsAttention };
288
+ //# sourceMappingURL=home-briefing.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"home-briefing.mjs","names":[],"sources":["../../src/lib/home-briefing.ts"],"sourcesContent":["import type { InspectorMetadataProjection } from \"./inspector-metadata.js\";\n\nexport type HomeHeroActionKind =\n | \"enable_intelligence\"\n | \"manage_plan\"\n | \"renew\";\n\nexport type HomeHeroAction = {\n kind: HomeHeroActionKind;\n url: string;\n label: string;\n};\n\nexport type HomeConnection = \"connected\" | \"disconnected\";\n\nexport type HomeRuntimeConnectionState =\n | \"connected\"\n | \"connecting\"\n | \"disconnected\"\n | \"error\"\n | \"unavailable\";\n\nexport type HomeRuntimeHealthTone = \"success\" | \"active\" | \"error\" | \"muted\";\n\nexport type HomeServiceId =\n | \"threads\"\n | \"memory\"\n | \"a2ui\"\n | \"open-gen-ui\"\n | \"suggestions\"\n | \"audio\"\n | \"websocket\";\n\nexport type HomeServiceTile = {\n id: HomeServiceId;\n label: string;\n enabled: boolean;\n url?: string;\n docsUrl: string;\n};\n\nexport type HomeModel = {\n hero: {\n connection: HomeConnection;\n title: string;\n body: string;\n action?: HomeHeroAction;\n };\n project?: {\n organizationName: string;\n projectName: string;\n planLabel?: string;\n license: string;\n usage?: {\n used: number;\n limitLabel: string;\n ratio?: number;\n };\n };\n projectLinked: boolean;\n runtime: {\n url?: string;\n health: {\n state: \"healthy\" | \"checking\" | \"offline\" | \"error\" | \"unavailable\";\n label: string;\n runtime: {\n label: string;\n tone: HomeRuntimeHealthTone;\n };\n liveUpdates: {\n label: string;\n tone: HomeRuntimeHealthTone;\n };\n lastEvent: {\n label: string;\n tone: HomeRuntimeHealthTone;\n id?: string;\n agentId?: string;\n type?: string;\n timestamp?: number;\n };\n };\n };\n services: HomeServiceTile[];\n news: {\n title: string;\n previewText: string;\n documentHtml?: string;\n empty: boolean;\n };\n};\n\nexport type HomeBriefingInput = {\n intelligenceConnected: boolean;\n threadsAvailable: boolean;\n metadata: InspectorMetadataProjection;\n runtimeUrl?: string;\n runtimeConnectionState: HomeRuntimeConnectionState;\n lastRuntimeEvent?: {\n id: string;\n agentId: string;\n type: string;\n timestamp: number;\n };\n memoriesOn: boolean;\n a2uiOn: boolean;\n openGenUiOn: boolean;\n suggestionsOn: boolean;\n audioOn: boolean;\n websocketUrl?: string;\n announcementPreviewText?: string;\n announcementMarkdown?: string;\n announcementHtml?: string;\n intelligenceSignupUrl?: string;\n};\n\nconst SERVICE_DOCS_URL: Record<HomeServiceId, string> = {\n threads: \"https://docs.copilotkit.ai/threads\",\n memory: \"https://docs.copilotkit.ai/premium/intelligence-platform\",\n a2ui: \"https://docs.copilotkit.ai/generative-ui/a2ui\",\n \"open-gen-ui\": \"https://docs.copilotkit.ai/generative-ui/open-generative-ui\",\n suggestions: \"https://docs.copilotkit.ai/agentic-chat-ui\",\n audio: \"https://docs.copilotkit.ai/voice\",\n websocket: \"https://docs.copilotkit.ai/premium/intelligence-platform\",\n};\n\n/** Return the Home hero button for a trusted metadata action. */\nexport function homeHeroActionFromMetadata(action: {\n kind: HomeHeroActionKind;\n url: string;\n}): HomeHeroAction {\n if (action.kind === \"manage_plan\") {\n return { kind: action.kind, url: action.url, label: \"Manage plan\" };\n }\n\n if (action.kind === \"renew\") {\n return { kind: action.kind, url: action.url, label: \"Renew plan\" };\n }\n\n return {\n kind: action.kind,\n url: action.url,\n label: \"Setup Intelligence\",\n };\n}\n\n/** Return a short preview from markdown, without links or headings. */\nexport function announcementPreview(markdown: string, maxLength = 140): string {\n const plain = markdown\n .replace(/\\[([^\\]]+)\\]\\([^)]+\\)/g, \"$1\")\n .replace(/[#*_`]/g, \"\")\n .replace(/\\s+/g, \" \")\n .trim();\n if (plain.length <= maxLength) {\n return plain;\n }\n\n return `${plain.slice(0, maxLength).trimEnd()}…`;\n}\n\nfunction connectIntelligenceAction(\n action: HomeHeroAction | undefined,\n connectUrl?: string,\n licenseState?: InspectorMetadataProjection[\"licenseState\"],\n): HomeHeroAction | undefined {\n if (action) {\n return action;\n }\n\n if (connectUrl && (licenseState === \"none\" || licenseState === \"unknown\")) {\n return homeHeroActionFromMetadata({\n kind: \"enable_intelligence\",\n url: connectUrl,\n });\n }\n\n return undefined;\n}\n\nfunction heroForState(args: {\n connected: boolean;\n action?: HomeHeroAction;\n connectUrl?: string;\n licenseState: InspectorMetadataProjection[\"licenseState\"];\n}): HomeModel[\"hero\"] {\n if (!args.connected) {\n const renewing = args.action?.kind === \"renew\";\n return {\n connection: \"disconnected\",\n title: renewing ? \"Renew Intelligence\" : \"Intelligence is not setup\",\n body: renewing\n ? \"Renew Intelligence to restore persistent Threads and Memory.\"\n : \"Connect CopilotKit Intelligence to add persistent Threads, Learning and Analytics to your application. Inspect conversations and allow your agents to learn from real use.\",\n action: connectIntelligenceAction(\n args.action,\n args.connectUrl,\n args.licenseState,\n ),\n };\n }\n\n return {\n connection: \"connected\",\n title: \"Connected to Intelligence\",\n body: \"Use Workbench to inspect threads and memory.\",\n action:\n args.action?.kind === \"enable_intelligence\" ? undefined : args.action,\n };\n}\n\nfunction usageFromMetadata(metadata: InspectorMetadataProjection):\n | {\n used: number;\n limitLabel: string;\n ratio?: number;\n }\n | undefined {\n const usage = metadata.usage;\n if (!usage) {\n return undefined;\n }\n\n if (usage.limit.kind === \"finite\") {\n return {\n used: usage.used,\n limitLabel: `${usage.used} / ${usage.limit.value}`,\n ratio: usage.limit.value === 0 ? 1 : usage.used / usage.limit.value,\n };\n }\n\n if (usage.limit.kind === \"unlimited\") {\n return {\n used: usage.used,\n limitLabel: `${usage.used} / unlimited`,\n };\n }\n\n return {\n used: usage.used,\n limitLabel: `${usage.used} used`,\n };\n}\n\nfunction newsFromAnnouncement(args: {\n previewText?: string;\n markdown?: string;\n html?: string;\n}): HomeModel[\"news\"] {\n const markdown = args.markdown?.trim();\n if (markdown && args.html) {\n const heading = markdown.match(/^#{1,3}\\s+(.+)$/m)?.[1]?.trim();\n return {\n title: heading || \"The latest from CopilotKit\",\n previewText:\n args.previewText?.trim() || announcementPreview(markdown, 160),\n documentHtml: args.html,\n empty: false,\n };\n }\n\n return {\n title: \"You're all caught up\",\n previewText: \"Latest CopilotKit updates will appear here.\",\n empty: true,\n };\n}\n\nfunction runtimeEventSignal(\n event: HomeBriefingInput[\"lastRuntimeEvent\"],\n): HomeModel[\"runtime\"][\"health\"][\"lastEvent\"] {\n if (!event) {\n return { label: \"No events yet\", tone: \"muted\" };\n }\n\n const eventDetails = {\n id: event.id,\n agentId: event.agentId,\n type: event.type,\n timestamp: event.timestamp,\n };\n\n if (event.type === \"RUN_ERROR\" || event.type === \"ERROR\") {\n return {\n label: event.type === \"RUN_ERROR\" ? \"Run error\" : \"Error\",\n tone: \"error\",\n ...eventDetails,\n };\n }\n\n if (event.type === \"RUN_FINISHED\") {\n return {\n label: \"Run completed\",\n tone: \"success\",\n ...eventDetails,\n };\n }\n\n if (\n event.type.endsWith(\"_START\") ||\n event.type.endsWith(\"_STARTED\") ||\n event.type.endsWith(\"_CONTENT\") ||\n event.type.endsWith(\"_ARGS\") ||\n event.type.endsWith(\"_DELTA\")\n ) {\n return {\n label: \"Last event is in progress\",\n tone: \"active\",\n ...eventDetails,\n };\n }\n\n return {\n label: \"Last event received\",\n tone: \"success\",\n ...eventDetails,\n };\n}\n\n/**\n * Whether the runtime *connection* needs attention — the single condition\n * shared by System Health and the launcher's error signal, so the two can\n * never disagree about whether the wiring is broken.\n *\n * Exactly one state counts. `disconnected` is also the initial value, so\n * counting it would raise the signal on every page load; `connecting` is a\n * normal startup step; `unavailable` means no Core is attached, which is not\n * a defect of the developer's wiring.\n *\n * Note the deliberate asymmetry with `health.state`: a failed *run* also\n * drives System Health to \"Needs attention\" while the connection is fine.\n * That is an event rather than a state, and it is excluded from the launcher\n * on purpose — see the launcher-signal comments in index.ts.\n */\nexport function runtimeConnectionNeedsAttention(\n state: HomeRuntimeConnectionState,\n): boolean {\n return state === \"error\";\n}\n\nfunction runtimeHealthFromInput(\n input: HomeBriefingInput,\n): HomeModel[\"runtime\"][\"health\"] {\n const lastEvent = runtimeEventSignal(input.lastRuntimeEvent);\n\n if (input.runtimeConnectionState === \"connected\") {\n return {\n state: lastEvent.tone === \"error\" ? \"error\" : \"healthy\",\n label: lastEvent.tone === \"error\" ? \"Needs attention\" : \"Healthy\",\n runtime: { label: \"Available\", tone: \"success\" },\n liveUpdates: { label: \"Ready\", tone: \"success\" },\n lastEvent,\n };\n }\n\n if (input.runtimeConnectionState === \"connecting\") {\n return {\n state: \"checking\",\n label: \"Checking\",\n runtime: { label: \"Checking\", tone: \"active\" },\n liveUpdates: { label: \"Connecting\", tone: \"active\" },\n lastEvent,\n };\n }\n\n if (input.runtimeConnectionState === \"unavailable\") {\n return {\n state: \"unavailable\",\n label: \"Unavailable\",\n runtime: { label: \"Unavailable\", tone: \"muted\" },\n liveUpdates: { label: \"Not attached\", tone: \"muted\" },\n lastEvent,\n };\n }\n\n const needsAttention = runtimeConnectionNeedsAttention(\n input.runtimeConnectionState,\n );\n return {\n state: needsAttention ? \"error\" : \"offline\",\n label: needsAttention ? \"Runtime error\" : \"Offline\",\n runtime: { label: \"Offline\", tone: \"error\" },\n liveUpdates: {\n label: needsAttention ? \"Error\" : \"Disconnected\",\n tone: \"error\",\n },\n lastEvent,\n };\n}\n\n/** Build the Home briefing from data the Inspector already has. */\nexport function buildHomeModel(input: HomeBriefingInput): HomeModel {\n const metadataAction =\n input.metadata.threadsFooterAction ?? input.metadata.lockedAction;\n const action = metadataAction\n ? homeHeroActionFromMetadata({\n kind: metadataAction.kind,\n url: metadataAction.url,\n })\n : undefined;\n\n const identity = input.metadata.identity;\n const projectLinked = Boolean(identity);\n const intelligenceConnected =\n input.metadata.licenseState === \"valid\" ||\n (input.metadata.licenseState === \"unknown\" && input.intelligenceConnected);\n const usage = usageFromMetadata(input.metadata);\n\n return {\n hero: heroForState({\n connected: intelligenceConnected,\n action,\n connectUrl: input.intelligenceSignupUrl,\n licenseState: input.metadata.licenseState,\n }),\n projectLinked,\n project: identity\n ? {\n organizationName: identity.organizationName,\n projectName: identity.projectName,\n planLabel: input.metadata.plan?.label,\n license: input.metadata.licenseState,\n usage,\n }\n : input.metadata.plan || usage\n ? {\n organizationName: \"Not linked\",\n projectName: \"This runtime is not linked to a project\",\n planLabel: input.metadata.plan?.label,\n license: input.metadata.licenseState,\n usage,\n }\n : undefined,\n runtime: {\n url: input.runtimeUrl,\n health: runtimeHealthFromInput(input),\n },\n services: [\n {\n id: \"threads\",\n label: \"Threads\",\n enabled: intelligenceConnected && input.threadsAvailable,\n url: input.runtimeUrl,\n docsUrl: SERVICE_DOCS_URL.threads,\n },\n {\n id: \"memory\",\n label: \"Memory\",\n enabled: intelligenceConnected && input.memoriesOn,\n docsUrl: SERVICE_DOCS_URL.memory,\n },\n {\n id: \"a2ui\",\n label: \"A2UI\",\n enabled: input.a2uiOn,\n docsUrl: SERVICE_DOCS_URL.a2ui,\n },\n {\n id: \"open-gen-ui\",\n label: \"Open Gen UI\",\n enabled: input.openGenUiOn,\n docsUrl: SERVICE_DOCS_URL[\"open-gen-ui\"],\n },\n {\n id: \"suggestions\",\n label: \"Suggestions\",\n enabled: input.suggestionsOn,\n docsUrl: SERVICE_DOCS_URL.suggestions,\n },\n {\n id: \"audio\",\n label: \"Audio\",\n enabled: input.audioOn,\n docsUrl: SERVICE_DOCS_URL.audio,\n },\n {\n id: \"websocket\",\n label: \"Websocket\",\n enabled: intelligenceConnected && Boolean(input.websocketUrl),\n url: input.websocketUrl,\n docsUrl: SERVICE_DOCS_URL.websocket,\n },\n ],\n news: newsFromAnnouncement({\n previewText: input.announcementPreviewText,\n markdown: input.announcementMarkdown,\n html: input.announcementHtml ?? undefined,\n }),\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+
2
+ //#region src/lib/inspector-nav.ts
3
+ const INSPECTOR_GROUPS = {
4
+ home: ["home", "whats-new"],
5
+ workbench: [
6
+ "playground",
7
+ "threads",
8
+ "memories"
9
+ ],
10
+ inspect: [
11
+ "agents",
12
+ "ag-ui-events",
13
+ "event-snippets",
14
+ "frontend-tools",
15
+ "capabilities",
16
+ "agent-context"
17
+ ]
18
+ };
19
+ const INSPECTOR_MENU_KEYS = [
20
+ ...INSPECTOR_GROUPS.home,
21
+ ...INSPECTOR_GROUPS.workbench,
22
+ ...INSPECTOR_GROUPS.inspect
23
+ ];
24
+ const INSPECTOR_NAV_SECTIONS = [
25
+ {
26
+ group: "home",
27
+ label: null
28
+ },
29
+ {
30
+ group: "workbench",
31
+ label: "Workbench"
32
+ },
33
+ {
34
+ group: "inspect",
35
+ label: "Inspect"
36
+ }
37
+ ];
38
+ const ICON_RAIL_MAX_WIDTH_PX = 720;
39
+ /** Return whether persisted state names a known Inspector leaf. */
40
+ function isInspectorMenuKey(value) {
41
+ return typeof value === "string" && INSPECTOR_MENU_KEYS.some((menuKey) => menuKey === value);
42
+ }
43
+ /** Return the sidebar group that owns a leaf. */
44
+ function getGroupForMenu(key) {
45
+ for (const group of Object.keys(INSPECTOR_GROUPS)) if (INSPECTOR_GROUPS[group].some((menuKey) => menuKey === key)) return group;
46
+ return "workbench";
47
+ }
48
+ /** Return whether the sidebar should collapse to an icon rail. */
49
+ function shouldUseIconRail(args) {
50
+ return args.dockedLeft || args.width < ICON_RAIL_MAX_WIDTH_PX;
51
+ }
52
+
53
+ //#endregion
54
+ exports.INSPECTOR_GROUPS = INSPECTOR_GROUPS;
55
+ exports.INSPECTOR_NAV_SECTIONS = INSPECTOR_NAV_SECTIONS;
56
+ exports.getGroupForMenu = getGroupForMenu;
57
+ exports.isInspectorMenuKey = isInspectorMenuKey;
58
+ exports.shouldUseIconRail = shouldUseIconRail;
59
+ //# sourceMappingURL=inspector-nav.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspector-nav.cjs","names":[],"sources":["../../src/lib/inspector-nav.ts"],"sourcesContent":["import type { InspectorLeafKey } from \"./telemetry.js\";\n\nexport type ShellGroupKey = \"home\" | \"workbench\" | \"inspect\";\n\nexport const INSPECTOR_GROUPS = {\n home: [\"home\", \"whats-new\"],\n workbench: [\"playground\", \"threads\", \"memories\"],\n inspect: [\n \"agents\",\n \"ag-ui-events\",\n \"event-snippets\",\n \"frontend-tools\",\n \"capabilities\",\n \"agent-context\",\n ],\n} as const satisfies Record<ShellGroupKey, readonly InspectorLeafKey[]>;\n\nexport type InspectorNavGroupKey = keyof typeof INSPECTOR_GROUPS;\nexport type MenuKey = (typeof INSPECTOR_GROUPS)[InspectorNavGroupKey][number];\n\nexport const INSPECTOR_MENU_KEYS: ReadonlyArray<MenuKey> = [\n ...INSPECTOR_GROUPS.home,\n ...INSPECTOR_GROUPS.workbench,\n ...INSPECTOR_GROUPS.inspect,\n];\n\nexport const INSPECTOR_NAV_SECTIONS: ReadonlyArray<{\n group: InspectorNavGroupKey;\n label: string | null;\n}> = [\n { group: \"home\", label: null },\n { group: \"workbench\", label: \"Workbench\" },\n { group: \"inspect\", label: \"Inspect\" },\n];\n\nexport const ICON_RAIL_MAX_WIDTH_PX = 720;\n\n/** Return whether persisted state names a known Inspector leaf. */\nexport function isInspectorMenuKey(value: unknown): value is MenuKey {\n return (\n typeof value === \"string\" &&\n INSPECTOR_MENU_KEYS.some((menuKey) => menuKey === value)\n );\n}\n\n/** Return the sidebar group that owns a leaf. */\nexport function getGroupForMenu(key: MenuKey): InspectorNavGroupKey {\n for (const group of Object.keys(INSPECTOR_GROUPS) as InspectorNavGroupKey[]) {\n if (INSPECTOR_GROUPS[group].some((menuKey) => menuKey === key)) {\n return group;\n }\n }\n\n return \"workbench\";\n}\n\n/** Return whether the sidebar should collapse to an icon rail. */\nexport function shouldUseIconRail(args: {\n dockedLeft: boolean;\n width: number;\n}): boolean {\n return args.dockedLeft || args.width < ICON_RAIL_MAX_WIDTH_PX;\n}\n"],"mappings":";;AAIA,MAAa,mBAAmB;CAC9B,MAAM,CAAC,QAAQ,YAAY;CAC3B,WAAW;EAAC;EAAc;EAAW;EAAW;CAChD,SAAS;EACP;EACA;EACA;EACA;EACA;EACA;EACD;CACF;AAKD,MAAa,sBAA8C;CACzD,GAAG,iBAAiB;CACpB,GAAG,iBAAiB;CACpB,GAAG,iBAAiB;CACrB;AAED,MAAa,yBAGR;CACH;EAAE,OAAO;EAAQ,OAAO;EAAM;CAC9B;EAAE,OAAO;EAAa,OAAO;EAAa;CAC1C;EAAE,OAAO;EAAW,OAAO;EAAW;CACvC;AAED,MAAa,yBAAyB;;AAGtC,SAAgB,mBAAmB,OAAkC;AACnE,QACE,OAAO,UAAU,YACjB,oBAAoB,MAAM,YAAY,YAAY,MAAM;;;AAK5D,SAAgB,gBAAgB,KAAoC;AAClE,MAAK,MAAM,SAAS,OAAO,KAAK,iBAAiB,CAC/C,KAAI,iBAAiB,OAAO,MAAM,YAAY,YAAY,IAAI,CAC5D,QAAO;AAIX,QAAO;;;AAIT,SAAgB,kBAAkB,MAGtB;AACV,QAAO,KAAK,cAAc,KAAK,QAAQ"}
@@ -0,0 +1,11 @@
1
+ //#region src/lib/inspector-nav.d.ts
2
+ declare const INSPECTOR_GROUPS: {
3
+ readonly home: readonly ["home", "whats-new"];
4
+ readonly workbench: readonly ["playground", "threads", "memories"];
5
+ readonly inspect: readonly ["agents", "ag-ui-events", "event-snippets", "frontend-tools", "capabilities", "agent-context"];
6
+ };
7
+ type InspectorNavGroupKey = keyof typeof INSPECTOR_GROUPS;
8
+ type MenuKey = (typeof INSPECTOR_GROUPS)[InspectorNavGroupKey][number];
9
+ //#endregion
10
+ export { MenuKey };
11
+ //# sourceMappingURL=inspector-nav.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspector-nav.d.cts","names":[],"sources":["../../src/lib/inspector-nav.ts"],"mappings":";cAIa,gBAAA;EAAA;;;;KAaD,oBAAA,gBAAoC,gBAAA;AAAA,KACpC,OAAA,WAAkB,gBAAA,EAAkB,oBAAA"}
@@ -0,0 +1,11 @@
1
+ //#region src/lib/inspector-nav.d.ts
2
+ declare const INSPECTOR_GROUPS: {
3
+ readonly home: readonly ["home", "whats-new"];
4
+ readonly workbench: readonly ["playground", "threads", "memories"];
5
+ readonly inspect: readonly ["agents", "ag-ui-events", "event-snippets", "frontend-tools", "capabilities", "agent-context"];
6
+ };
7
+ type InspectorNavGroupKey = keyof typeof INSPECTOR_GROUPS;
8
+ type MenuKey = (typeof INSPECTOR_GROUPS)[InspectorNavGroupKey][number];
9
+ //#endregion
10
+ export { MenuKey };
11
+ //# sourceMappingURL=inspector-nav.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspector-nav.d.mts","names":[],"sources":["../../src/lib/inspector-nav.ts"],"mappings":";cAIa,gBAAA;EAAA;;;;KAaD,oBAAA,gBAAoC,gBAAA;AAAA,KACpC,OAAA,WAAkB,gBAAA,EAAkB,oBAAA"}
@@ -0,0 +1,54 @@
1
+ //#region src/lib/inspector-nav.ts
2
+ const INSPECTOR_GROUPS = {
3
+ home: ["home", "whats-new"],
4
+ workbench: [
5
+ "playground",
6
+ "threads",
7
+ "memories"
8
+ ],
9
+ inspect: [
10
+ "agents",
11
+ "ag-ui-events",
12
+ "event-snippets",
13
+ "frontend-tools",
14
+ "capabilities",
15
+ "agent-context"
16
+ ]
17
+ };
18
+ const INSPECTOR_MENU_KEYS = [
19
+ ...INSPECTOR_GROUPS.home,
20
+ ...INSPECTOR_GROUPS.workbench,
21
+ ...INSPECTOR_GROUPS.inspect
22
+ ];
23
+ const INSPECTOR_NAV_SECTIONS = [
24
+ {
25
+ group: "home",
26
+ label: null
27
+ },
28
+ {
29
+ group: "workbench",
30
+ label: "Workbench"
31
+ },
32
+ {
33
+ group: "inspect",
34
+ label: "Inspect"
35
+ }
36
+ ];
37
+ const ICON_RAIL_MAX_WIDTH_PX = 720;
38
+ /** Return whether persisted state names a known Inspector leaf. */
39
+ function isInspectorMenuKey(value) {
40
+ return typeof value === "string" && INSPECTOR_MENU_KEYS.some((menuKey) => menuKey === value);
41
+ }
42
+ /** Return the sidebar group that owns a leaf. */
43
+ function getGroupForMenu(key) {
44
+ for (const group of Object.keys(INSPECTOR_GROUPS)) if (INSPECTOR_GROUPS[group].some((menuKey) => menuKey === key)) return group;
45
+ return "workbench";
46
+ }
47
+ /** Return whether the sidebar should collapse to an icon rail. */
48
+ function shouldUseIconRail(args) {
49
+ return args.dockedLeft || args.width < ICON_RAIL_MAX_WIDTH_PX;
50
+ }
51
+
52
+ //#endregion
53
+ export { INSPECTOR_GROUPS, INSPECTOR_NAV_SECTIONS, getGroupForMenu, isInspectorMenuKey, shouldUseIconRail };
54
+ //# sourceMappingURL=inspector-nav.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inspector-nav.mjs","names":[],"sources":["../../src/lib/inspector-nav.ts"],"sourcesContent":["import type { InspectorLeafKey } from \"./telemetry.js\";\n\nexport type ShellGroupKey = \"home\" | \"workbench\" | \"inspect\";\n\nexport const INSPECTOR_GROUPS = {\n home: [\"home\", \"whats-new\"],\n workbench: [\"playground\", \"threads\", \"memories\"],\n inspect: [\n \"agents\",\n \"ag-ui-events\",\n \"event-snippets\",\n \"frontend-tools\",\n \"capabilities\",\n \"agent-context\",\n ],\n} as const satisfies Record<ShellGroupKey, readonly InspectorLeafKey[]>;\n\nexport type InspectorNavGroupKey = keyof typeof INSPECTOR_GROUPS;\nexport type MenuKey = (typeof INSPECTOR_GROUPS)[InspectorNavGroupKey][number];\n\nexport const INSPECTOR_MENU_KEYS: ReadonlyArray<MenuKey> = [\n ...INSPECTOR_GROUPS.home,\n ...INSPECTOR_GROUPS.workbench,\n ...INSPECTOR_GROUPS.inspect,\n];\n\nexport const INSPECTOR_NAV_SECTIONS: ReadonlyArray<{\n group: InspectorNavGroupKey;\n label: string | null;\n}> = [\n { group: \"home\", label: null },\n { group: \"workbench\", label: \"Workbench\" },\n { group: \"inspect\", label: \"Inspect\" },\n];\n\nexport const ICON_RAIL_MAX_WIDTH_PX = 720;\n\n/** Return whether persisted state names a known Inspector leaf. */\nexport function isInspectorMenuKey(value: unknown): value is MenuKey {\n return (\n typeof value === \"string\" &&\n INSPECTOR_MENU_KEYS.some((menuKey) => menuKey === value)\n );\n}\n\n/** Return the sidebar group that owns a leaf. */\nexport function getGroupForMenu(key: MenuKey): InspectorNavGroupKey {\n for (const group of Object.keys(INSPECTOR_GROUPS) as InspectorNavGroupKey[]) {\n if (INSPECTOR_GROUPS[group].some((menuKey) => menuKey === key)) {\n return group;\n }\n }\n\n return \"workbench\";\n}\n\n/** Return whether the sidebar should collapse to an icon rail. */\nexport function shouldUseIconRail(args: {\n dockedLeft: boolean;\n width: number;\n}): boolean {\n return args.dockedLeft || args.width < ICON_RAIL_MAX_WIDTH_PX;\n}\n"],"mappings":";AAIA,MAAa,mBAAmB;CAC9B,MAAM,CAAC,QAAQ,YAAY;CAC3B,WAAW;EAAC;EAAc;EAAW;EAAW;CAChD,SAAS;EACP;EACA;EACA;EACA;EACA;EACA;EACD;CACF;AAKD,MAAa,sBAA8C;CACzD,GAAG,iBAAiB;CACpB,GAAG,iBAAiB;CACpB,GAAG,iBAAiB;CACrB;AAED,MAAa,yBAGR;CACH;EAAE,OAAO;EAAQ,OAAO;EAAM;CAC9B;EAAE,OAAO;EAAa,OAAO;EAAa;CAC1C;EAAE,OAAO;EAAW,OAAO;EAAW;CACvC;AAED,MAAa,yBAAyB;;AAGtC,SAAgB,mBAAmB,OAAkC;AACnE,QACE,OAAO,UAAU,YACjB,oBAAoB,MAAM,YAAY,YAAY,MAAM;;;AAK5D,SAAgB,gBAAgB,KAAoC;AAClE,MAAK,MAAM,SAAS,OAAO,KAAK,iBAAiB,CAC/C,KAAI,iBAAiB,OAAO,MAAM,YAAY,YAAY,IAAI,CAC5D,QAAO;AAIX,QAAO;;;AAIT,SAAgB,kBAAkB,MAGtB;AACV,QAAO,KAAK,cAAc,KAAK,QAAQ"}
@@ -51,6 +51,103 @@ function isFiniteNumber(value) {
51
51
  function isValidDockMode(value) {
52
52
  return value === "floating" || value === "docked-left";
53
53
  }
54
+ const ANNOUNCEMENT_READ_COOKIE_NAME = "cpk_inspector_announcements";
55
+ const ANNOUNCEMENT_READ_MIRROR_KEY = "cpk:inspector:announcement_read";
56
+ const LEGACY_ANNOUNCEMENT_READ_KEY = "cpk:inspector:announcements";
57
+ const ANNOUNCEMENT_PULSED_SESSION_KEY = "cpk:inspector:pulsed";
58
+ const ANNOUNCEMENT_READ_COOKIE_MAX_AGE_SECONDS = 3600 * 24 * 365;
59
+ /**
60
+ * The announcement timestamp the user has already read, or `null` when
61
+ * nothing has been read yet. Prefers the host-scoped cookie and falls back to
62
+ * the origin-scoped mirror, so cookie-blocking browsers still remember the
63
+ * read within the port they are on.
64
+ */
65
+ function loadAnnouncementReadTimestamp() {
66
+ return parseTimestampPayload(readAnnouncementCookie()) ?? parseTimestampPayload(readLocalStorageItem(ANNOUNCEMENT_READ_MIRROR_KEY));
67
+ }
68
+ /**
69
+ * Records an announcement as read in both the host-scoped cookie and the
70
+ * origin-scoped mirror. The stored value is `{"timestamp":"…"}` — the same
71
+ * shape the announcement state has always used.
72
+ */
73
+ function saveAnnouncementReadTimestamp(timestamp) {
74
+ const payload = JSON.stringify({ timestamp });
75
+ writeAnnouncementCookie(payload);
76
+ writeLocalStorageItem(ANNOUNCEMENT_READ_MIRROR_KEY, payload);
77
+ }
78
+ /**
79
+ * Deletes the superseded origin-scoped read state. Safe to call on every
80
+ * startup: nothing writes that key any more, so the value cannot come back.
81
+ */
82
+ function clearLegacyAnnouncementReadState() {
83
+ removeLocalStorageItem(LEGACY_ANNOUNCEMENT_READ_KEY);
84
+ }
85
+ /**
86
+ * The announcement timestamp this browser tab has already pulsed for, or
87
+ * `null` when it hasn't pulsed yet.
88
+ */
89
+ function loadAnnouncementPulsedTimestamp() {
90
+ if (typeof window === "undefined") return null;
91
+ try {
92
+ return window.sessionStorage.getItem(ANNOUNCEMENT_PULSED_SESSION_KEY);
93
+ } catch {
94
+ return null;
95
+ }
96
+ }
97
+ /** Suppresses further pulses for this announcement in this browser tab. */
98
+ function saveAnnouncementPulsedTimestamp(timestamp) {
99
+ if (typeof window === "undefined") return;
100
+ try {
101
+ window.sessionStorage.setItem(ANNOUNCEMENT_PULSED_SESSION_KEY, timestamp);
102
+ } catch {}
103
+ }
104
+ function parseTimestampPayload(raw) {
105
+ if (!raw) return null;
106
+ try {
107
+ const parsed = JSON.parse(raw);
108
+ return typeof parsed?.timestamp === "string" ? parsed.timestamp : null;
109
+ } catch {
110
+ return null;
111
+ }
112
+ }
113
+ function readAnnouncementCookie() {
114
+ if (typeof document === "undefined") return null;
115
+ try {
116
+ for (const entry of document.cookie.split(";")) {
117
+ const separator = entry.indexOf("=");
118
+ if (separator === -1) continue;
119
+ if (entry.slice(0, separator).trim() !== ANNOUNCEMENT_READ_COOKIE_NAME) continue;
120
+ return decodeURIComponent(entry.slice(separator + 1).trim());
121
+ }
122
+ } catch {}
123
+ return null;
124
+ }
125
+ function writeAnnouncementCookie(value) {
126
+ if (typeof document === "undefined") return;
127
+ try {
128
+ document.cookie = `${ANNOUNCEMENT_READ_COOKIE_NAME}=${encodeURIComponent(value)}; Path=/; Max-Age=${ANNOUNCEMENT_READ_COOKIE_MAX_AGE_SECONDS}; SameSite=Lax`;
129
+ } catch {}
130
+ }
131
+ function readLocalStorageItem(key) {
132
+ if (typeof window === "undefined") return null;
133
+ try {
134
+ return window.localStorage.getItem(key);
135
+ } catch {
136
+ return null;
137
+ }
138
+ }
139
+ function writeLocalStorageItem(key, value) {
140
+ if (typeof window === "undefined") return;
141
+ try {
142
+ window.localStorage.setItem(key, value);
143
+ } catch {}
144
+ }
145
+ function removeLocalStorageItem(key) {
146
+ if (typeof window === "undefined") return;
147
+ try {
148
+ window.localStorage.removeItem(key);
149
+ } catch {}
150
+ }
54
151
  const TELEMETRY_DISTINCT_ID_KEY = "cpk:inspector:telemetry:distinct_id";
55
152
  const TELEMETRY_OPT_OUT_KEY = "cpk:inspector:telemetry:opt_out";
56
153
  const TELEMETRY_DISCLOSURE_SHOWN_KEY = "cpk:inspector:telemetry:disclosure_shown";
@@ -98,6 +195,7 @@ function generateUuidV4() {
98
195
  }
99
196
 
100
197
  //#endregion
198
+ exports.clearLegacyAnnouncementReadState = clearLegacyAnnouncementReadState;
101
199
  exports.getOrCreateTelemetryDistinctId = getOrCreateTelemetryDistinctId;
102
200
  exports.hasTelemetryDisclosureBeenShown = hasTelemetryDisclosureBeenShown;
103
201
  exports.isTelemetryOptedOut = isTelemetryOptedOut;
@@ -105,7 +203,11 @@ exports.isValidAnchor = isValidAnchor;
105
203
  exports.isValidDockMode = isValidDockMode;
106
204
  exports.isValidPosition = isValidPosition;
107
205
  exports.isValidSize = isValidSize;
206
+ exports.loadAnnouncementPulsedTimestamp = loadAnnouncementPulsedTimestamp;
207
+ exports.loadAnnouncementReadTimestamp = loadAnnouncementReadTimestamp;
108
208
  exports.loadInspectorState = loadInspectorState;
109
209
  exports.markTelemetryDisclosureShown = markTelemetryDisclosureShown;
210
+ exports.saveAnnouncementPulsedTimestamp = saveAnnouncementPulsedTimestamp;
211
+ exports.saveAnnouncementReadTimestamp = saveAnnouncementReadTimestamp;
110
212
  exports.saveInspectorState = saveInspectorState;
111
213
  //# sourceMappingURL=persistence.cjs.map