@tylertech/forge-ai 0.10.0 → 0.11.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.
@@ -0,0 +1,400 @@
1
+ import { SubscriptionManager } from "../ai-chatbot/event-emitter.mjs";
2
+ import { FileUploadManager } from "../ai-chatbot/file-upload-manager.mjs";
3
+ import { MessageStateController } from "../ai-chatbot/message-state-controller.mjs";
4
+ import { generateId } from "../ai-chatbot/utils.mjs";
5
+ class ChatbotCoreController {
6
+ #host;
7
+ #callbacks;
8
+ #messageStateController;
9
+ #fileUploadManager;
10
+ #adapterSubscriptions;
11
+ #adapter;
12
+ #toolsMap;
13
+ #executingToolHandlers = 0;
14
+ constructor(host, config) {
15
+ this.#host = host;
16
+ this.#callbacks = config.callbacks;
17
+ host.addController(this);
18
+ }
19
+ hostConnected() {
20
+ this.#messageStateController = new MessageStateController(this.#host, {
21
+ tools: this.tools,
22
+ onThreadSettled: () => this.#emitThreadStateChange()
23
+ });
24
+ this.#fileUploadManager = new FileUploadManager({
25
+ onError: (error) => {
26
+ this.#callbacks.onDispatchEvent("forge-ai-chatbot-error", { error });
27
+ },
28
+ onStateChange: () => {
29
+ this.#callbacks.onRequestUpdate();
30
+ }
31
+ });
32
+ if (this.#adapter) {
33
+ void this.#setupAdapter();
34
+ }
35
+ }
36
+ hostDisconnected() {
37
+ this.#adapterSubscriptions?.unsubscribe();
38
+ this.#adapter?.disconnect();
39
+ this.#callbacks.onDispatchEvent("forge-ai-chatbot-disconnected");
40
+ }
41
+ get adapter() {
42
+ return this.#adapter;
43
+ }
44
+ set adapter(value) {
45
+ this.#adapter = value;
46
+ this.#toolsMap = void 0;
47
+ if (value) {
48
+ this.#setupAdapter();
49
+ }
50
+ }
51
+ get messageItems() {
52
+ return this.#messageStateController?.messageItems ?? [];
53
+ }
54
+ get isStreaming() {
55
+ return (this.#adapter?.isRunning ?? false) || this.#executingToolHandlers > 0;
56
+ }
57
+ get isUploading() {
58
+ return this.#fileUploadManager?.isUploading ?? false;
59
+ }
60
+ get hasMessages() {
61
+ return this.messageItems.length > 0;
62
+ }
63
+ get tools() {
64
+ if (!this.#toolsMap) {
65
+ this.#toolsMap = new Map(this.#adapter?.getTools().map((t) => [t.name, t]) ?? []);
66
+ }
67
+ return this.#toolsMap;
68
+ }
69
+ get pendingAttachments() {
70
+ return this.#fileUploadManager?.pendingAttachments ?? [];
71
+ }
72
+ get completedAttachments() {
73
+ return this.#fileUploadManager?.completedAttachments ?? [];
74
+ }
75
+ async #setupAdapter() {
76
+ if (!this.#adapter || this.#adapter.isConnecting) {
77
+ return;
78
+ }
79
+ await this.#adapter.connect();
80
+ this.#adapterSubscriptions?.unsubscribe();
81
+ this.#adapterSubscriptions = new SubscriptionManager();
82
+ this.#adapterSubscriptions.add(
83
+ this.#adapter.onMessageStart(this.#handleMessageStart.bind(this)),
84
+ this.#adapter.onMessageDelta(this.#handleMessageDelta.bind(this)),
85
+ this.#adapter.onMessageEnd(this.#handleMessageEnd.bind(this)),
86
+ this.#adapter.onToolCallStart(this.#handleToolCallStart.bind(this)),
87
+ this.#adapter.onToolCallArgs(this.#handleToolCallArgs.bind(this)),
88
+ this.#adapter.onToolCallEnd(this.#handleToolCallEnd.bind(this)),
89
+ this.#adapter.onToolCall(this.#handleToolCall.bind(this)),
90
+ this.#adapter.onToolCallResult(this.#handleToolCallResult.bind(this)),
91
+ this.#adapter.onRunFinished(this.#handleRunFinished.bind(this)),
92
+ this.#adapter.onRunAborted(this.#handleRunAborted.bind(this)),
93
+ this.#adapter.onError(this.#handleError.bind(this)),
94
+ this.#adapter.onStateChange(this.#handleStateChange.bind(this))
95
+ );
96
+ this.#toolsMap = void 0;
97
+ this.#messageStateController?.updateConfig({ tools: this.tools });
98
+ this.#callbacks.onDispatchEvent("forge-ai-chatbot-connected");
99
+ }
100
+ #handleMessageStart(event) {
101
+ this.#messageStateController.addTextToResponse(event.messageId, "", event);
102
+ }
103
+ #handleMessageDelta(event) {
104
+ this.#messageStateController.appendTextDelta(event.messageId, event.delta, event);
105
+ this.#callbacks.onScrollToBottom();
106
+ }
107
+ #handleMessageEnd(event) {
108
+ this.#messageStateController.markTextComplete(event.messageId, event);
109
+ }
110
+ #handleRunFinished() {
111
+ this.#tryCompleteResponse();
112
+ }
113
+ #tryCompleteResponse() {
114
+ if (this.#executingToolHandlers > 0 || this.#adapter?.isRunning) {
115
+ return;
116
+ }
117
+ this.#messageStateController.tryFinalizeResponse();
118
+ const messages = this.getMessages();
119
+ const lastMessage = messages[messages.length - 1];
120
+ if (lastMessage?.role === "assistant" && lastMessage.status === "complete") {
121
+ this.#callbacks.onDispatchEvent("forge-ai-chatbot-message-received", { message: lastMessage });
122
+ }
123
+ }
124
+ #handleToolCallStart(event) {
125
+ const toolCall = {
126
+ id: event.id,
127
+ messageId: event.messageId,
128
+ name: event.name,
129
+ args: {},
130
+ argsBuffer: "",
131
+ status: "parsing",
132
+ type: this.tools.has(event.name) ? "client" : "agent"
133
+ };
134
+ this.#messageStateController.addToolCallToResponse(toolCall, event);
135
+ }
136
+ #handleToolCallArgs(event) {
137
+ const updates = {
138
+ argsBuffer: event.argsBuffer,
139
+ args: event.partialArgs ?? {}
140
+ };
141
+ const rawEvent = { eventType: "tool-call-args", event };
142
+ this.#messageStateController.updateToolCallInResponse(event.id, updates, rawEvent);
143
+ this.#callbacks.onScrollToBottom();
144
+ }
145
+ #handleToolCallEnd(event) {
146
+ const updates = {
147
+ args: event.args,
148
+ argsBuffer: void 0,
149
+ status: "executing"
150
+ };
151
+ const rawEvent = { eventType: "tool-call-end", event };
152
+ this.#messageStateController.updateToolCallInResponse(event.id, updates, rawEvent);
153
+ }
154
+ #createToolResponse(toolName, handlerReturn) {
155
+ if (typeof handlerReturn === "string") {
156
+ return handlerReturn;
157
+ }
158
+ if (handlerReturn && typeof handlerReturn === "object") {
159
+ return handlerReturn;
160
+ }
161
+ return `Tool '${toolName}' executed successfully`;
162
+ }
163
+ async #handleToolCall(event) {
164
+ let toolCall = this.#messageStateController.getToolCall(event.id);
165
+ if (toolCall) {
166
+ this.#messageStateController.updateToolCallInResponse(event.id, {
167
+ args: event.args,
168
+ status: "executing"
169
+ });
170
+ } else {
171
+ toolCall = {
172
+ id: event.id,
173
+ messageId: event.messageId,
174
+ name: event.name,
175
+ args: event.args,
176
+ status: "executing",
177
+ type: this.tools.has(event.name) ? "client" : "agent"
178
+ };
179
+ this.#messageStateController.addToolCallToResponse(toolCall);
180
+ }
181
+ if (toolCall?.type === "client") {
182
+ this.#callbacks.onDispatchEvent("forge-ai-chatbot-tool-call", {
183
+ toolCallId: event.id,
184
+ toolName: event.name,
185
+ arguments: event.args
186
+ });
187
+ const toolDef = this.tools.get(event.name);
188
+ if (toolDef?.handler) {
189
+ await Promise.resolve(this.#executeToolHandler(event.id, event.name, toolDef.handler, event.args));
190
+ } else {
191
+ this.#sendToolResult(event.id, this.#createToolResponse(event.name));
192
+ }
193
+ } else {
194
+ this.#messageStateController.updateToolCallInResponse(event.id, { status: "complete" });
195
+ }
196
+ }
197
+ async #executeToolHandler(toolCallId, toolName, handler, args) {
198
+ this.#executingToolHandlers++;
199
+ this.#callbacks.onRequestUpdate();
200
+ try {
201
+ const context = {
202
+ args,
203
+ toolCallId,
204
+ toolName,
205
+ signal: void 0
206
+ };
207
+ const handlerReturn = await handler(context);
208
+ await this.#sendToolResult(toolCallId, this.#createToolResponse(toolName, handlerReturn));
209
+ } catch (error) {
210
+ console.error(`Tool handler error [${toolName}]:`, error);
211
+ this.#messageStateController.updateToolCallInResponse(toolCallId, {
212
+ status: "error",
213
+ result: { error: error.message }
214
+ });
215
+ const errorMessage = {
216
+ id: generateId(),
217
+ role: "assistant",
218
+ content: "An unexpected error occurred.",
219
+ timestamp: Date.now(),
220
+ status: "error"
221
+ };
222
+ this.#messageStateController.addMessage(errorMessage);
223
+ this.#callbacks.onDispatchEvent("forge-ai-chatbot-error", { error: error.message });
224
+ } finally {
225
+ this.#executingToolHandlers--;
226
+ this.#tryCompleteResponse();
227
+ this.#callbacks.onRequestUpdate();
228
+ }
229
+ }
230
+ #handleError(event) {
231
+ const errorMessage = {
232
+ id: generateId(),
233
+ role: "assistant",
234
+ content: event.message,
235
+ timestamp: Date.now(),
236
+ status: "error"
237
+ };
238
+ this.#messageStateController.addMessage(errorMessage);
239
+ this.#callbacks.onDispatchEvent("forge-ai-chatbot-message-received", { message: errorMessage });
240
+ this.#callbacks.onDispatchEvent("forge-ai-chatbot-error", { error: event.message });
241
+ }
242
+ #handleRunAborted() {
243
+ const abortMessage = {
244
+ id: generateId(),
245
+ role: "system",
246
+ content: "Run cancelled",
247
+ timestamp: Date.now(),
248
+ status: "complete",
249
+ clientOnly: true
250
+ };
251
+ this.#messageStateController.addMessage(abortMessage);
252
+ this.#callbacks.onDispatchEvent("forge-ai-chatbot-message-received", { message: abortMessage });
253
+ }
254
+ #handleStateChange(_state) {
255
+ this.#callbacks.onRequestUpdate();
256
+ }
257
+ #handleToolCallResult(event) {
258
+ this.#messageStateController.completeToolCallInResponse(event.toolCallId, event.result, event);
259
+ }
260
+ async #sendToolResult(toolCallId, result) {
261
+ const toolCall = this.#messageStateController.getToolCall(toolCallId);
262
+ if (!toolCall || !this.#adapter) {
263
+ return;
264
+ }
265
+ this.#messageStateController.completeToolCallInResponse(toolCallId, result);
266
+ this.#adapter.sendToolResult(toolCallId, result, this.getMessages());
267
+ }
268
+ async sendMessage(config) {
269
+ if (!config.content.trim() || !this.#adapter || this.isStreaming) {
270
+ if (!this.#adapter) {
271
+ console.warn("No adapter configured.");
272
+ }
273
+ return;
274
+ }
275
+ if (!this.#fileUploadManager.canSend()) {
276
+ return;
277
+ }
278
+ const userMessage = {
279
+ id: generateId(),
280
+ role: "user",
281
+ content: config.content,
282
+ timestamp: config.timestamp ?? Date.now(),
283
+ status: "pending"
284
+ };
285
+ this.#messageStateController.addMessage(userMessage);
286
+ try {
287
+ this.#adapter.sendMessage(this.getMessages());
288
+ this.#messageStateController.updateMessageStatus(userMessage.id, "complete");
289
+ } catch (error) {
290
+ this.#messageStateController.updateMessageStatus(userMessage.id, "error");
291
+ const errorMessage = error instanceof Error ? error.message : "Failed to send message";
292
+ this.#callbacks.onDispatchEvent("forge-ai-chatbot-error", { error: errorMessage });
293
+ } finally {
294
+ this.#callbacks.onDispatchEvent("forge-ai-chatbot-message-sent", { message: userMessage });
295
+ }
296
+ }
297
+ processFileUpload(file, timestamp) {
298
+ const fileId = generateId();
299
+ this.#fileUploadManager.addAttachment(fileId, {
300
+ filename: file.name,
301
+ size: file.size,
302
+ mimeType: file.type,
303
+ timestamp
304
+ });
305
+ const callbacks = this.createFileUploadCallbacks(fileId);
306
+ this.#adapter?.emitFileUpload(file, callbacks);
307
+ return fileId;
308
+ }
309
+ createFileUploadCallbacks(fileId) {
310
+ return {
311
+ updateProgress: (progress) => {
312
+ this.#fileUploadManager.updateProgress(fileId, progress);
313
+ },
314
+ markComplete: (uploadedFile) => {
315
+ this.#fileUploadManager.markComplete(fileId, uploadedFile);
316
+ },
317
+ markError: (error) => {
318
+ this.#fileUploadManager.markError(fileId, error);
319
+ },
320
+ onAbort: (callback) => {
321
+ this.#fileUploadManager.registerOnAbort(fileId, callback);
322
+ }
323
+ };
324
+ }
325
+ abortFileUpload(fileId) {
326
+ this.#fileUploadManager.abort(fileId);
327
+ }
328
+ removeCompletedAttachment(attachmentId) {
329
+ const attachment = this.completedAttachments.find((a) => a.id === attachmentId);
330
+ if (attachment) {
331
+ this.#fileUploadManager.removeCompletedAttachment(attachmentId);
332
+ this.#callbacks.onRequestUpdate();
333
+ if (attachment.fileId) {
334
+ this.#adapter?.emitFileRemove(attachment.fileId, {
335
+ onSuccess: () => {
336
+ },
337
+ onError: (error) => {
338
+ console.error(`Failed to remove file ${attachment.filename}:`, error);
339
+ }
340
+ });
341
+ }
342
+ }
343
+ }
344
+ getMessage(id) {
345
+ return this.#messageStateController.getMessage(id);
346
+ }
347
+ getToolCall(id) {
348
+ return this.#messageStateController.getToolCall(id);
349
+ }
350
+ clearMessages() {
351
+ this.#messageStateController.clearMessages();
352
+ this.#fileUploadManager.clear();
353
+ }
354
+ getMessages() {
355
+ return this.#messageStateController.getMessages();
356
+ }
357
+ setMessages(messages) {
358
+ this.#messageStateController.setMessages(messages);
359
+ }
360
+ updateMessageContent(id, content) {
361
+ this.#messageStateController.updateMessageContent(id, content);
362
+ }
363
+ removeMessageItemsFrom(index) {
364
+ this.#messageStateController.removeMessageItemsFrom(index);
365
+ }
366
+ setResponseFeedback(responseId, feedback) {
367
+ this.#messageStateController.setResponseFeedback(responseId, feedback);
368
+ }
369
+ addMessage(message) {
370
+ this.#messageStateController.addMessage(message);
371
+ }
372
+ getThreadState() {
373
+ return {
374
+ threadId: this.#adapter?.threadId,
375
+ messages: this.getMessages(),
376
+ timestamp: Date.now()
377
+ };
378
+ }
379
+ setThreadState(state) {
380
+ this.setMessages(state.messages);
381
+ if (state.threadId && this.#adapter) {
382
+ this.#adapter.threadId = state.threadId;
383
+ }
384
+ }
385
+ abort() {
386
+ if (this.#adapter?.isRunning) {
387
+ this.#adapter.abort();
388
+ }
389
+ this.#callbacks.onRequestUpdate();
390
+ }
391
+ canSendMessage() {
392
+ return this.#fileUploadManager?.canSend() ?? true;
393
+ }
394
+ #emitThreadStateChange() {
395
+ this.#callbacks.onDispatchEvent("forge-ai-chatbot-thread-state-change");
396
+ }
397
+ }
398
+ export {
399
+ ChatbotCoreController
400
+ };
@@ -1 +1,2 @@
1
1
  export { DragController, type DragControllerOptions } from './drag-controller.js';
2
+ export { ChatbotCoreController, type ChatbotCoreCallbacks, type ChatbotCoreControllerConfig } from './chatbot-core-controller.js';
@@ -1,4 +1,6 @@
1
1
  import { DragController } from "./drag-controller.mjs";
2
+ import { ChatbotCoreController } from "./chatbot-core-controller.mjs";
2
3
  export {
4
+ ChatbotCoreController,
3
5
  DragController
4
6
  };
package/dist/index.d.ts CHANGED
@@ -11,6 +11,7 @@ export * from './ai-chain-of-thought';
11
11
  export * from './ai-chat-header';
12
12
  export * from './ai-chat-interface';
13
13
  export * from './ai-chatbot';
14
+ export * from './ai-chatbot-launcher';
14
15
  export * from './ai-confirmation-prompt';
15
16
  export * from './ai-dialog';
16
17
  export * from './ai-dropdown-menu';
@@ -33,7 +34,6 @@ export * from './ai-sidebar';
33
34
  export * from './ai-sidebar-chat';
34
35
  export * from './ai-slash-command-menu';
35
36
  export * from './ai-suggestions';
36
- export * from './ai-suggestions';
37
37
  export * from './ai-thinking-indicator';
38
38
  export * from './ai-threads';
39
39
  export * from './ai-user-message';
package/dist/index.mjs CHANGED
@@ -14,6 +14,7 @@ import { ThoughtImageComponent, ThoughtImageComponentTagName } from "./ai-chain-
14
14
  import { ThoughtDetailComponent, ThoughtDetailComponentTagName } from "./ai-chain-of-thought/thought-detail/thought-detail.mjs";
15
15
  import { AiChatHeaderComponent, AiChatHeaderComponentTagName } from "./ai-chat-header/ai-chat-header.mjs";
16
16
  import { AiChatInterfaceComponent, AiChatInterfaceComponentTagName } from "./ai-chat-interface/ai-chat-interface.mjs";
17
+ import { AiChatbotBase } from "./ai-chatbot/ai-chatbot-base.mjs";
17
18
  import { AiChatbotComponent, AiChatbotComponentTagName } from "./ai-chatbot/ai-chatbot.mjs";
18
19
  import { AiChatbotToolCallComponent, AiChatbotToolCallComponentTagName } from "./ai-chatbot/ai-chatbot-tool-call.mjs";
19
20
  import { AgentAdapter } from "./ai-chatbot/agent-adapter.mjs";
@@ -26,6 +27,7 @@ import { MessageStateController } from "./ai-chatbot/message-state-controller.mj
26
27
  import { FileUploadManager } from "./ai-chatbot/file-upload-manager.mjs";
27
28
  import { MarkdownStreamController } from "./ai-chatbot/markdown-stream-controller.mjs";
28
29
  import { generateId, renderMarkdown } from "./ai-chatbot/utils.mjs";
30
+ import { AiChatbotLauncherComponent, AiChatbotLauncherComponentTagName } from "./ai-chatbot-launcher/ai-chatbot-launcher.mjs";
29
31
  import { AiConfirmationPromptComponent, AiConfirmationPromptComponentTagName } from "./ai-confirmation-prompt/ai-confirmation-prompt.mjs";
30
32
  import { AiDialogComponent, AiDialogComponentTagName } from "./ai-dialog/ai-dialog.mjs";
31
33
  import { ForgeAiDropdownMenuComponent } from "./ai-dropdown-menu/ai-dropdown-menu.mjs";
@@ -78,8 +80,11 @@ export {
78
80
  AiChatHeaderComponentTagName,
79
81
  AiChatInterfaceComponent,
80
82
  AiChatInterfaceComponentTagName,
83
+ AiChatbotBase,
81
84
  AiChatbotComponent,
82
85
  AiChatbotComponentTagName,
86
+ AiChatbotLauncherComponent,
87
+ AiChatbotLauncherComponentTagName,
83
88
  AiChatbotToolCallComponent,
84
89
  AiChatbotToolCallComponentTagName,
85
90
  AiConfirmationPromptComponent,
@@ -1,3 +1,4 @@
1
+ import "../../ai-chatbot/ai-chatbot-base.mjs";
1
2
  import "../../ai-chatbot/ai-chatbot.mjs";
2
3
  import "../../ai-chatbot/ai-chatbot-tool-call.mjs";
3
4
  import "@ag-ui/client";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tylertech/forge-ai",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "A library of Tyler Forge™ AI chat interface web components.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Tyler Technologies, Inc.",
@@ -39,14 +39,14 @@
39
39
  "url": "git+https://github.com/tyler-technologies-oss/forge-ai.git"
40
40
  },
41
41
  "dependencies": {
42
- "@ag-ui/client": "^0.0.42",
43
- "@ag-ui/core": "^0.0.42",
44
- "@floating-ui/dom": "^1.7.4",
42
+ "@ag-ui/client": "^0.0.47",
43
+ "@ag-ui/core": "^0.0.47",
44
+ "@floating-ui/dom": "^1.7.6",
45
45
  "@lit/context": "^1.1.6",
46
- "dompurify": "^3.3.1",
46
+ "dompurify": "^3.3.3",
47
47
  "lit": "3.3.2",
48
- "marked": "^17.0.1",
49
- "remend": "^1.0.1",
48
+ "marked": "^17.0.4",
49
+ "remend": "^1.3.0",
50
50
  "uuid": "^13.0.0"
51
51
  },
52
52
  "devDependencies": {
@@ -54,19 +54,19 @@
54
54
  "@esm-bundle/chai": "4.3.4-fix.0",
55
55
  "@open-wc/testing": "4.0.0",
56
56
  "@repo/prettier-config": "",
57
- "@storybook/addon-a11y": "9.1.17",
58
- "@storybook/addon-docs": "9.1.17",
59
- "@storybook/addon-links": "9.1.17",
60
- "@storybook/addon-themes": "9.1.17",
61
- "@storybook/web-components-vite": "9.1.17",
57
+ "@storybook/addon-a11y": "9.1.20",
58
+ "@storybook/addon-docs": "9.1.20",
59
+ "@storybook/addon-links": "9.1.20",
60
+ "@storybook/addon-themes": "9.1.20",
61
+ "@storybook/web-components-vite": "9.1.20",
62
62
  "@tylertech/forge": "3.13.1",
63
63
  "@tylertech/stylelint-rules": "5.1.2",
64
- "@tylertech/tyler-icons": "2.0.4",
64
+ "@tylertech/tyler-icons": "2.1.0",
65
65
  "@types/cssbeautify": "^0.3.5",
66
66
  "@types/dompurify": "^3.2.0",
67
67
  "@types/mocha": "10.0.10",
68
- "@types/node": "25.0.3",
69
- "@types/react": "^18.3.27",
68
+ "@types/node": "25.5.0",
69
+ "@types/react": "^18.3.28",
70
70
  "@types/sinon": "21.0.0",
71
71
  "@ungap/structured-clone": "^1.3.0",
72
72
  "@vueless/storybook-dark-mode": "9.0.10",
@@ -80,25 +80,25 @@
80
80
  "cssbeautify": "^0.3.1",
81
81
  "custom-element-svelte-integration": "^1.2.0",
82
82
  "custom-element-vuejs-integration": "^1.4.0",
83
- "eslint": "9.39.2",
84
- "glob": "13.0.0",
83
+ "eslint": "9.39.4",
84
+ "glob": "13.0.6",
85
85
  "lit-analyzer": "2.0.3",
86
- "plop": "4.0.4",
87
- "postcss-lit": "1.3.1",
86
+ "plop": "4.0.5",
87
+ "postcss-lit": "1.4.1",
88
88
  "react": "^18.3.1",
89
89
  "react-dom": "^18.3.1",
90
90
  "react-ga4": "^2.1.0",
91
91
  "remark-gfm": "4.0.1",
92
- "rimraf": "6.1.2",
92
+ "rimraf": "6.1.3",
93
93
  "sass": "1.93.3",
94
- "sinon": "21.0.1",
95
- "storybook": "9.1.17",
94
+ "sinon": "21.0.3",
95
+ "storybook": "9.1.20",
96
96
  "stylelint": "16.26.1",
97
97
  "stylelint-config-standard": "39.0.1",
98
98
  "typescript": "~5.9.3",
99
- "vite": "7.3.0",
99
+ "vite": "7.3.1",
100
100
  "vite-plugin-dts": "4.5.4",
101
- "vite-tsconfig-paths": "6.0.3"
101
+ "vite-tsconfig-paths": "6.0.5"
102
102
  },
103
103
  "scripts": {
104
104
  "dev": "vite src/dev",