@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.
- package/README.md +28 -12
- package/dist/assets/inspector-logo-kite.cjs +12 -0
- package/dist/assets/inspector-logo-kite.cjs.map +1 -0
- package/dist/assets/inspector-logo-kite.mjs +6 -0
- package/dist/assets/inspector-logo-kite.mjs.map +1 -0
- package/dist/index.cjs +5574 -1584
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +490 -32
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +490 -32
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +5574 -1587
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +7014 -1917
- package/dist/index.umd.js.map +1 -1
- package/dist/lib/event-snippets.cjs +559 -0
- package/dist/lib/event-snippets.cjs.map +1 -0
- package/dist/lib/event-snippets.d.cts +61 -0
- package/dist/lib/event-snippets.d.cts.map +1 -0
- package/dist/lib/event-snippets.d.mts +61 -0
- package/dist/lib/event-snippets.d.mts.map +1 -0
- package/dist/lib/event-snippets.mjs +537 -0
- package/dist/lib/event-snippets.mjs.map +1 -0
- package/dist/lib/home-briefing.cjs +290 -0
- package/dist/lib/home-briefing.cjs.map +1 -0
- package/dist/lib/home-briefing.mjs +288 -0
- package/dist/lib/home-briefing.mjs.map +1 -0
- package/dist/lib/inspector-nav.cjs +59 -0
- package/dist/lib/inspector-nav.cjs.map +1 -0
- package/dist/lib/inspector-nav.d.cts +11 -0
- package/dist/lib/inspector-nav.d.cts.map +1 -0
- package/dist/lib/inspector-nav.d.mts +11 -0
- package/dist/lib/inspector-nav.d.mts.map +1 -0
- package/dist/lib/inspector-nav.mjs +54 -0
- package/dist/lib/inspector-nav.mjs.map +1 -0
- package/dist/lib/persistence.cjs +102 -0
- package/dist/lib/persistence.cjs.map +1 -1
- package/dist/lib/persistence.mjs +98 -1
- package/dist/lib/persistence.mjs.map +1 -1
- package/dist/lib/telemetry.cjs +93 -34
- package/dist/lib/telemetry.cjs.map +1 -1
- package/dist/lib/telemetry.d.cts +1 -1
- package/dist/lib/telemetry.d.cts.map +1 -1
- package/dist/lib/telemetry.d.mts +1 -1
- package/dist/lib/telemetry.d.mts.map +1 -1
- package/dist/lib/telemetry.mjs +86 -32
- package/dist/lib/telemetry.mjs.map +1 -1
- package/dist/package.cjs +1 -1
- package/dist/package.mjs +1 -1
- package/dist/styles/generated.cjs +1 -1
- package/dist/styles/generated.cjs.map +1 -1
- package/dist/styles/generated.mjs +1 -1
- package/dist/styles/generated.mjs.map +1 -1
- package/package.json +3 -3
- package/dist/assets/inspector-logo-icon.cjs +0 -12
- package/dist/assets/inspector-logo-icon.cjs.map +0 -1
- package/dist/assets/inspector-logo-icon.mjs +0 -6
- 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"}
|
package/dist/lib/persistence.cjs
CHANGED
|
@@ -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
|