@tooluminati/react-troubleshooting 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/WebMcpErrorBoundary.d.ts +8 -0
- package/dist/WebMcpErrorBoundary.d.ts.map +1 -0
- package/dist/WebMcpErrorBoundary.js +29 -0
- package/dist/WebMcpTroubleshootingContext.d.ts +12 -0
- package/dist/WebMcpTroubleshootingContext.d.ts.map +1 -0
- package/dist/WebMcpTroubleshootingContext.js +9 -0
- package/dist/WebMcpTroubleshootingPanel.d.ts +9 -0
- package/dist/WebMcpTroubleshootingPanel.d.ts.map +1 -0
- package/dist/WebMcpTroubleshootingPanel.js +170 -0
- package/dist/WebMcpTroubleshootingProvider.d.ts +23 -0
- package/dist/WebMcpTroubleshootingProvider.d.ts.map +1 -0
- package/dist/WebMcpTroubleshootingProvider.js +106 -0
- package/dist/declarative-form.d.ts +23 -0
- package/dist/declarative-form.d.ts.map +1 -0
- package/dist/declarative-form.js +33 -0
- package/dist/index.cjs +833 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +822 -0
- package/dist/panel-visibility.d.ts +8 -0
- package/dist/panel-visibility.d.ts.map +1 -0
- package/dist/panel-visibility.js +23 -0
- package/dist/useFormSubmitBlockers.d.ts +11 -0
- package/dist/useFormSubmitBlockers.d.ts.map +1 -0
- package/dist/useFormSubmitBlockers.js +35 -0
- package/dist/useTanStackQueryWebMcpTools.d.ts +9 -0
- package/dist/useTanStackQueryWebMcpTools.d.ts.map +1 -0
- package/dist/useTanStackQueryWebMcpTools.js +16 -0
- package/dist/useTroubleshootingPanel.d.ts +14 -0
- package/dist/useTroubleshootingPanel.d.ts.map +1 -0
- package/dist/useTroubleshootingPanel.js +29 -0
- package/dist/webmcp-declarative-attributes.d.ts +20 -0
- package/dist/webmcp-declarative-attributes.d.ts.map +1 -0
- package/dist/webmcp-declarative-attributes.js +2 -0
- package/package.json +67 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 jitterbox
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
export interface WebMcpErrorBoundaryProps {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
fallback?: ReactNode;
|
|
5
|
+
source?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function WebMcpErrorBoundary({ children, fallback, source, }: WebMcpErrorBoundaryProps): import("react").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=WebMcpErrorBoundary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebMcpErrorBoundary.d.ts","sourceRoot":"","sources":["../src/WebMcpErrorBoundary.tsx"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAOlE,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAsCD,wBAAgB,mBAAmB,CAAC,EAClC,QAAQ,EACR,QAAQ,EACR,MAAM,GACP,EAAE,wBAAwB,+BAY1B"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Component } from 'react';
|
|
3
|
+
import { useWebMcpTroubleshootingContext } from './WebMcpTroubleshootingContext';
|
|
4
|
+
class Boundary extends Component {
|
|
5
|
+
state = { hasError: false };
|
|
6
|
+
static getDerivedStateFromError() {
|
|
7
|
+
return { hasError: true };
|
|
8
|
+
}
|
|
9
|
+
componentDidCatch(error, info) {
|
|
10
|
+
this.props.errors.push({
|
|
11
|
+
message: error.message,
|
|
12
|
+
source: this.props.source ??
|
|
13
|
+
info.componentStack?.split('\n')[1]?.trim() ??
|
|
14
|
+
'react',
|
|
15
|
+
timestamp: new Date().toISOString(),
|
|
16
|
+
...(error.stack ? { stack: error.stack } : {}),
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
render() {
|
|
20
|
+
if (this.state.hasError) {
|
|
21
|
+
return this.props.fallback ?? null;
|
|
22
|
+
}
|
|
23
|
+
return this.props.children;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export function WebMcpErrorBoundary({ children, fallback, source, }) {
|
|
27
|
+
const { errors, timeline } = useWebMcpTroubleshootingContext();
|
|
28
|
+
return (_jsx(Boundary, { errors: errors, timeline: timeline, fallback: fallback, ...(source ? { source } : {}), children: children }));
|
|
29
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ClientErrorBuffer, MountedFormsRegistry, TroubleshootingPanelViewModel, TroubleshootingPanelVisibilityController, TroubleshootingTimelineBuffer } from '@tooluminati/diagnostics';
|
|
2
|
+
export interface WebMcpTroubleshootingContextValue {
|
|
3
|
+
timeline: TroubleshootingTimelineBuffer;
|
|
4
|
+
errors: ClientErrorBuffer;
|
|
5
|
+
mountedForms: MountedFormsRegistry;
|
|
6
|
+
viewModel: TroubleshootingPanelViewModel;
|
|
7
|
+
visibility: TroubleshootingPanelVisibilityController;
|
|
8
|
+
isPanelEnabled: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare const WebMcpTroubleshootingContext: import("react").Context<WebMcpTroubleshootingContextValue | null>;
|
|
11
|
+
export declare function useWebMcpTroubleshootingContext(): WebMcpTroubleshootingContextValue;
|
|
12
|
+
//# sourceMappingURL=WebMcpTroubleshootingContext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebMcpTroubleshootingContext.d.ts","sourceRoot":"","sources":["../src/WebMcpTroubleshootingContext.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,iBAAiB,EACjB,oBAAoB,EACpB,6BAA6B,EAC7B,wCAAwC,EACxC,6BAA6B,EAC9B,MAAM,0BAA0B,CAAC;AAElC,MAAM,WAAW,iCAAiC;IAChD,QAAQ,EAAE,6BAA6B,CAAC;IACxC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,YAAY,EAAE,oBAAoB,CAAC;IACnC,SAAS,EAAE,6BAA6B,CAAC;IACzC,UAAU,EAAE,wCAAwC,CAAC;IACrD,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,eAAO,MAAM,4BAA4B,mEACsB,CAAC;AAEhE,wBAAgB,+BAA+B,IAAI,iCAAiC,CAQnF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { createContext, useContext } from 'react';
|
|
2
|
+
export const WebMcpTroubleshootingContext = createContext(null);
|
|
3
|
+
export function useWebMcpTroubleshootingContext() {
|
|
4
|
+
const value = useContext(WebMcpTroubleshootingContext);
|
|
5
|
+
if (!value) {
|
|
6
|
+
throw new Error('useWebMcpTroubleshootingContext requires WebMcpTroubleshootingProvider.');
|
|
7
|
+
}
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface WebMcpTroubleshootingPanelProps {
|
|
2
|
+
position?: 'br' | 'bl' | 'tr' | 'tl';
|
|
3
|
+
startCollapsed?: boolean;
|
|
4
|
+
eventLimit?: number;
|
|
5
|
+
pollMs?: number | null;
|
|
6
|
+
onCopyDiagnostics?: (json: string) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function WebMcpTroubleshootingPanel({ position, startCollapsed, onCopyDiagnostics, }: WebMcpTroubleshootingPanelProps): import("react").JSX.Element | null;
|
|
9
|
+
//# sourceMappingURL=WebMcpTroubleshootingPanel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebMcpTroubleshootingPanel.d.ts","sourceRoot":"","sources":["../src/WebMcpTroubleshootingPanel.tsx"],"names":[],"mappings":"AAiBA,MAAM,WAAW,+BAA+B;IAC9C,QAAQ,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IACrC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5C;AAYD,wBAAgB,0BAA0B,CAAC,EACzC,QAAe,EACf,cAAc,EACd,iBAAiB,GAClB,EAAE,+BAA+B,sCAkTjC"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
3
|
+
import { filterPanelEvents, serializeTroubleshootingDiagnostics, } from '@tooluminati/diagnostics';
|
|
4
|
+
import { useWebMcpTroubleshootingContext } from './WebMcpTroubleshootingContext';
|
|
5
|
+
const PALETTE = {
|
|
6
|
+
surface: '#0a0e1a',
|
|
7
|
+
navy: '#17316A',
|
|
8
|
+
amber: '#FECD10',
|
|
9
|
+
cyan: '#0AADF2',
|
|
10
|
+
red: '#FF5C6C',
|
|
11
|
+
};
|
|
12
|
+
const positionStyle = {
|
|
13
|
+
br: { right: '26px', bottom: '26px' },
|
|
14
|
+
bl: { left: '26px', bottom: '26px' },
|
|
15
|
+
tr: { right: '26px', top: '26px' },
|
|
16
|
+
tl: { left: '26px', top: '26px' },
|
|
17
|
+
};
|
|
18
|
+
export function WebMcpTroubleshootingPanel({ position = 'br', startCollapsed, onCopyDiagnostics, }) {
|
|
19
|
+
const { viewModel, visibility, isPanelEnabled } = useWebMcpTroubleshootingContext();
|
|
20
|
+
const [snapshot, setSnapshot] = useState(() => viewModel.refresh());
|
|
21
|
+
const [filter, setFilter] = useState('all');
|
|
22
|
+
const [openChecks, setOpenChecks] = useState({});
|
|
23
|
+
const [openEvents, setOpenEvents] = useState({});
|
|
24
|
+
const [openErrors, setOpenErrors] = useState({});
|
|
25
|
+
const [copied, setCopied] = useState(false);
|
|
26
|
+
const [spinning, setSpinning] = useState(false);
|
|
27
|
+
useEffect(() => {
|
|
28
|
+
if (startCollapsed) {
|
|
29
|
+
visibility.setCollapsed(true);
|
|
30
|
+
}
|
|
31
|
+
}, [startCollapsed, visibility]);
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
const refresh = () => setSnapshot(viewModel.refresh());
|
|
34
|
+
refresh();
|
|
35
|
+
const unsubVm = viewModel.subscribe(refresh);
|
|
36
|
+
const unsubVis = visibility.subscribe(refresh);
|
|
37
|
+
return () => {
|
|
38
|
+
unsubVm();
|
|
39
|
+
unsubVis();
|
|
40
|
+
};
|
|
41
|
+
}, [viewModel, visibility]);
|
|
42
|
+
const filteredEvents = useMemo(() => filterPanelEvents(snapshot.events, filter), [snapshot.events, filter]);
|
|
43
|
+
if (!isPanelEnabled || !visibility.visible) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
const pos = positionStyle[position];
|
|
47
|
+
const supportColor = snapshot.supported ? PALETTE.cyan : PALETTE.red;
|
|
48
|
+
const collapsed = visibility.collapsed;
|
|
49
|
+
const refresh = () => {
|
|
50
|
+
setSpinning(true);
|
|
51
|
+
setSnapshot(viewModel.refresh());
|
|
52
|
+
window.setTimeout(() => setSpinning(false), 650);
|
|
53
|
+
};
|
|
54
|
+
const copyDiagnostics = async () => {
|
|
55
|
+
const json = serializeTroubleshootingDiagnostics(snapshot);
|
|
56
|
+
if (onCopyDiagnostics) {
|
|
57
|
+
onCopyDiagnostics(json);
|
|
58
|
+
}
|
|
59
|
+
else if (navigator.clipboard) {
|
|
60
|
+
await navigator.clipboard.writeText(json);
|
|
61
|
+
}
|
|
62
|
+
setCopied(true);
|
|
63
|
+
window.setTimeout(() => setCopied(false), 1500);
|
|
64
|
+
};
|
|
65
|
+
if (collapsed) {
|
|
66
|
+
return (_jsxs("button", { type: "button", "aria-label": "Expand WebMCP troubleshooting panel", "data-testid": "webmcp-troubleshooting-badge", onClick: () => visibility.setCollapsed(false), style: {
|
|
67
|
+
position: 'fixed',
|
|
68
|
+
...pos,
|
|
69
|
+
zIndex: 99990,
|
|
70
|
+
display: 'flex',
|
|
71
|
+
alignItems: 'center',
|
|
72
|
+
gap: 11,
|
|
73
|
+
padding: '11px 15px 11px 13px',
|
|
74
|
+
background: '#0d1322',
|
|
75
|
+
border: '1px solid #1f2940',
|
|
76
|
+
borderRadius: 13,
|
|
77
|
+
cursor: 'pointer',
|
|
78
|
+
boxShadow: '0 14px 40px rgba(0,0,0,.5)',
|
|
79
|
+
fontFamily: "'IBM Plex Sans', system-ui, sans-serif",
|
|
80
|
+
}, children: [_jsx(BrandMark, {}), _jsxs("span", { style: { display: 'flex', flexDirection: 'column', lineHeight: 1.15 }, children: [_jsx("span", { style: { fontSize: 12, fontWeight: 600, color: '#e7ecf6' }, children: "WebMCP" }), _jsx("span", { style: {
|
|
81
|
+
fontFamily: "'IBM Plex Mono', monospace",
|
|
82
|
+
fontSize: 10,
|
|
83
|
+
color: supportColor,
|
|
84
|
+
}, children: snapshot.supported ? 'supported' : 'unsupported' })] }), _jsxs("span", { style: {
|
|
85
|
+
display: 'flex',
|
|
86
|
+
alignItems: 'center',
|
|
87
|
+
gap: 6,
|
|
88
|
+
paddingLeft: 11,
|
|
89
|
+
marginLeft: 3,
|
|
90
|
+
borderLeft: '1px solid #20293f',
|
|
91
|
+
}, children: [_jsx("span", { style: {
|
|
92
|
+
fontFamily: "'IBM Plex Mono', monospace",
|
|
93
|
+
fontSize: 12,
|
|
94
|
+
color: '#aeb7cb',
|
|
95
|
+
}, children: snapshot.toolCount }), snapshot.issueCount > 0 ? (_jsx("span", { style: {
|
|
96
|
+
width: 8,
|
|
97
|
+
height: 8,
|
|
98
|
+
borderRadius: '50%',
|
|
99
|
+
background: snapshot.errors.length > 0 ? PALETTE.red : PALETTE.amber,
|
|
100
|
+
} })) : null] })] }));
|
|
101
|
+
}
|
|
102
|
+
return (_jsxs("div", { "aria-label": "WebMCP troubleshooting panel", "data-testid": "webmcp-troubleshooting-panel", style: {
|
|
103
|
+
position: 'fixed',
|
|
104
|
+
...pos,
|
|
105
|
+
zIndex: 99990,
|
|
106
|
+
width: 412,
|
|
107
|
+
maxHeight: 'calc(100vh - 52px)',
|
|
108
|
+
display: 'flex',
|
|
109
|
+
flexDirection: 'column',
|
|
110
|
+
background: PALETTE.surface,
|
|
111
|
+
border: '1px solid #1c2438',
|
|
112
|
+
borderRadius: 15,
|
|
113
|
+
boxShadow: '0 26px 70px rgba(0,0,0,.62)',
|
|
114
|
+
overflow: 'hidden',
|
|
115
|
+
fontFamily: "'IBM Plex Sans', system-ui, sans-serif",
|
|
116
|
+
color: '#eef2fa',
|
|
117
|
+
}, children: [_jsxs("header", { style: {
|
|
118
|
+
display: 'flex',
|
|
119
|
+
alignItems: 'center',
|
|
120
|
+
gap: 11,
|
|
121
|
+
padding: '13px 14px',
|
|
122
|
+
borderBottom: '1px solid #161d2e',
|
|
123
|
+
}, children: [_jsx(BrandMark, {}), _jsxs("div", { style: { marginRight: 'auto', lineHeight: 1.2 }, children: [_jsx("div", { style: { fontSize: 13.5, fontWeight: 600 }, children: "WebMCP Troubleshooting" }), _jsx("div", { style: {
|
|
124
|
+
fontFamily: "'IBM Plex Mono', monospace",
|
|
125
|
+
fontSize: 9.5,
|
|
126
|
+
letterSpacing: 1.6,
|
|
127
|
+
color: '#5f6a82',
|
|
128
|
+
textTransform: 'uppercase',
|
|
129
|
+
}, children: "Tooluminati \u00B7 dev panel" })] }), _jsx(PanelButton, { title: "Re-run checks", onClick: refresh, children: _jsx("span", { style: { display: 'inline-block', animation: spinning ? 'tlmSpin .65s linear' : 'none' }, children: "\u27F3" }) }), _jsx(PanelButton, { onClick: () => void copyDiagnostics(), children: _jsx("span", { style: { fontFamily: "'IBM Plex Mono', monospace", fontSize: 11, color: copied ? PALETTE.cyan : '#9aa5bd' }, children: copied ? 'Copied ✓' : 'Copy JSON' }) }), _jsx(PanelButton, { title: "Minimize", onClick: () => visibility.setCollapsed(true), children: "\u2013" })] }), _jsxs("div", { style: {
|
|
130
|
+
display: 'grid',
|
|
131
|
+
gridTemplateColumns: '1fr 1fr 1fr',
|
|
132
|
+
gap: 1,
|
|
133
|
+
background: '#161d2e',
|
|
134
|
+
}, children: [_jsx(StatTile, { label: "WebMCP", value: snapshot.supported ? 'Supported' : 'Unsupported', color: supportColor }), _jsx(StatTile, { label: "Tools", value: String(snapshot.toolCount), color: snapshot.toolCount > 0 ? '#eef2fa' : PALETTE.amber }), _jsx(StatTile, { label: "Issues", value: String(snapshot.issueCount), color: snapshot.errors.length ? PALETTE.red : snapshot.issueCount ? PALETTE.amber : PALETTE.cyan })] }), _jsxs("div", { style: { overflow: 'auto', flex: 1, minHeight: 0 }, children: [_jsx(Section, { title: "Environment", children: snapshot.checks.map((check) => (_jsx(Row, { open: openChecks[check.id] ?? false, onToggle: () => setOpenChecks((s) => ({ ...s, [check.id]: !s[check.id] })), hint: check.guidance, label: check.label, value: check.value, status: check.status }, check.id))) }), _jsxs(Section, { title: "Timeline", meta: `${snapshot.events.length} captured`, children: [_jsx("div", { style: { display: 'flex', flexWrap: 'wrap', gap: 6, padding: '0 12px 8px' }, children: ['all', 'failures', 'blocked', 'tools', 'nav'].map((chip) => (_jsx("button", { type: "button", onClick: () => setFilter(chip), style: {
|
|
135
|
+
fontFamily: "'IBM Plex Mono', monospace",
|
|
136
|
+
fontSize: 10.5,
|
|
137
|
+
padding: '4px 9px',
|
|
138
|
+
borderRadius: 20,
|
|
139
|
+
cursor: 'pointer',
|
|
140
|
+
border: `1px solid ${filter === chip ? PALETTE.cyan : '#1f2840'}`,
|
|
141
|
+
background: filter === chip ? 'rgba(10,173,242,.13)' : '#0d1322',
|
|
142
|
+
color: filter === chip ? '#5EC8F7' : '#8893a8',
|
|
143
|
+
}, children: chip }, chip))) }), filteredEvents.length === 0 ? (_jsx(EmptyRow, { label: snapshot.events.length === 0 ? 'No timeline activity yet' : 'No events in this filter' })) : (filteredEvents.map((event) => (_jsx(Row, { open: openEvents[event.id] ?? false, onToggle: () => setOpenEvents((s) => ({ ...s, [event.id]: !s[event.id] })), hint: event.detail ?? event.guidance, meta: event.metadata ? JSON.stringify(event.metadata, null, 2) : undefined, label: event.title, value: event.time, tag: event.category.slice(0, 4).toUpperCase() }, event.id))))] }), _jsx(Section, { title: "Client Errors", meta: snapshot.errors.length ? `${snapshot.errors.length} captured` : 'clean', children: snapshot.errors.length === 0 ? (_jsx(EmptyRow, { label: "No errors captured this session", ok: true })) : (snapshot.errors.map((error) => (_jsx(Row, { open: openErrors[error.id] ?? false, onToggle: () => setOpenErrors((s) => ({ ...s, [error.id]: !s[error.id] })), hint: error.guidance, meta: error.stack, label: error.message, value: error.time, tag: "ERR", error: true }, error.id)))) })] }), _jsxs("footer", { style: {
|
|
144
|
+
display: 'flex',
|
|
145
|
+
alignItems: 'center',
|
|
146
|
+
gap: 8,
|
|
147
|
+
padding: '9px 14px',
|
|
148
|
+
borderTop: '1px solid #161d2e',
|
|
149
|
+
background: '#0c1120',
|
|
150
|
+
}, children: [_jsx("span", { style: { width: 6, height: 6, borderRadius: '50%', background: PALETTE.cyan } }), _jsxs("span", { style: { fontFamily: "'IBM Plex Mono', monospace", fontSize: 10.5, color: '#6b768c' }, children: ["Live \u00B7 ", snapshot.panelState] })] }), _jsx("style", { children: `@keyframes tlmSpin { to { transform: rotate(360deg); } }` })] }));
|
|
151
|
+
}
|
|
152
|
+
function BrandMark() {
|
|
153
|
+
return (_jsxs("span", { style: { position: 'relative', width: 26, height: 26, display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }, children: [_jsx("span", { style: { width: 0, height: 0, borderLeft: '13px solid transparent', borderRight: '13px solid transparent', borderBottom: '22px solid #17316A', position: 'absolute', top: 1 } }), _jsx("span", { style: { position: 'relative', width: 7, height: 7, borderRadius: '50%', background: '#FECD10', marginTop: 6, boxShadow: '0 0 8px #FECD10' } })] }));
|
|
154
|
+
}
|
|
155
|
+
function PanelButton({ children, onClick, title }) {
|
|
156
|
+
return (_jsx("button", { type: "button", title: title, onClick: onClick, style: { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', minWidth: 30, height: 30, borderRadius: 8, background: '#121a2b', border: '1px solid #1f2840', color: '#9aa5bd', cursor: 'pointer' }, children: children }));
|
|
157
|
+
}
|
|
158
|
+
function StatTile({ label, value, color }) {
|
|
159
|
+
return (_jsxs("div", { style: { background: '#0a0e1a', padding: '12px 13px' }, children: [_jsx("div", { style: { fontFamily: "'IBM Plex Mono', monospace", fontSize: 9.5, letterSpacing: 1, color: '#5f6a82', textTransform: 'uppercase' }, children: label }), _jsx("div", { style: { fontSize: 14, fontWeight: 600, color }, children: value })] }));
|
|
160
|
+
}
|
|
161
|
+
function Section({ title, meta, children }) {
|
|
162
|
+
return (_jsxs("div", { style: { paddingBottom: 8 }, children: [_jsxs("div", { style: { padding: '13px 14px 6px', display: 'flex', alignItems: 'center', gap: 8 }, children: [_jsx("span", { style: { fontFamily: "'IBM Plex Mono', monospace", fontSize: 10, letterSpacing: 1.5, color: '#7b8aa6', textTransform: 'uppercase', fontWeight: 600 }, children: title }), meta ? _jsx("span", { style: { fontFamily: "'IBM Plex Mono', monospace", fontSize: 10, color: '#4f5870' }, children: meta }) : null] }), _jsx("div", { style: { padding: '0 12px' }, children: children })] }));
|
|
163
|
+
}
|
|
164
|
+
function Row({ label, value, hint, meta, tag, status, open, onToggle, error, }) {
|
|
165
|
+
const expandable = Boolean(hint || meta);
|
|
166
|
+
return (_jsxs("div", { style: { borderRadius: 8, overflow: 'hidden', marginBottom: 3, background: open ? '#0e1424' : error ? 'rgba(255,92,108,.05)' : '#0b0f1c', borderLeft: error ? `2px solid #FF5C6C` : undefined }, children: [_jsxs("button", { type: "button", onClick: expandable ? onToggle : undefined, style: { width: '100%', display: 'flex', alignItems: 'center', gap: 9, padding: '7px 10px', background: 'transparent', border: 0, cursor: expandable ? 'pointer' : 'default', color: 'inherit', textAlign: 'left' }, children: [tag ? _jsx("span", { style: { fontFamily: "'IBM Plex Mono', monospace", fontSize: 8.5, fontWeight: 600, padding: '2px 5px', borderRadius: 4, color: error ? '#FF8088' : '#5EC8F7', background: error ? 'rgba(255,92,108,.12)' : 'rgba(10,173,242,.13)' }, children: tag }) : null, _jsx("span", { style: { fontSize: 12, flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: label }), value ? _jsx("span", { style: { fontFamily: "'IBM Plex Mono', monospace", fontSize: 10, color: status === 'warn' ? '#FFD86B' : status === 'fail' ? '#FF8088' : '#58627a' }, children: value }) : null, expandable ? _jsx("span", { style: { fontFamily: "'IBM Plex Mono', monospace", fontSize: 11, color: '#586279' }, children: open ? '▾' : '▸' }) : null] }), open && hint ? _jsx("div", { style: { padding: '0 12px 11px 36px', fontSize: 11.5, lineHeight: 1.55, color: '#9aa5bd' }, children: hint }) : null, open && meta ? _jsx("pre", { style: { margin: '0 12px 11px', fontFamily: "'IBM Plex Mono', monospace", fontSize: 10.5, color: '#6b768c', background: '#070b14', border: '1px solid #161d2e', borderRadius: 6, padding: '7px 9px', whiteSpace: 'pre-wrap' }, children: meta }) : null] }));
|
|
167
|
+
}
|
|
168
|
+
function EmptyRow({ label, ok }) {
|
|
169
|
+
return (_jsxs("div", { style: { padding: '12px 10px', fontSize: 12, color: '#586279', fontFamily: "'IBM Plex Mono', monospace" }, children: [ok ? '✓ ' : '', label] }));
|
|
170
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import { type ActionAvailabilityProvider, type QuerySummary } from '@tooluminati/diagnostics';
|
|
3
|
+
import { type WebMcpProviderProps } from '@tooluminati/react';
|
|
4
|
+
export interface WebMcpTroubleshootingPanelOptions {
|
|
5
|
+
enabled?: boolean | 'auto';
|
|
6
|
+
render?: boolean | 'auto';
|
|
7
|
+
position?: 'br' | 'bl' | 'tr' | 'tl';
|
|
8
|
+
startCollapsed?: boolean;
|
|
9
|
+
pollMs?: number | null;
|
|
10
|
+
allowUrlOverride?: boolean;
|
|
11
|
+
eventLimit?: number;
|
|
12
|
+
}
|
|
13
|
+
export interface WebMcpTroubleshootingProviderProps extends Omit<WebMcpProviderProps, 'tools'> {
|
|
14
|
+
children: ReactNode;
|
|
15
|
+
actionProvider?: ActionAvailabilityProvider;
|
|
16
|
+
querySummaries?: () => QuerySummary[];
|
|
17
|
+
trackFetchFailures?: boolean;
|
|
18
|
+
panel?: WebMcpTroubleshootingPanelOptions;
|
|
19
|
+
tools?: WebMcpProviderProps['tools'];
|
|
20
|
+
extraTools?: WebMcpProviderProps['tools'];
|
|
21
|
+
}
|
|
22
|
+
export declare function WebMcpTroubleshootingProvider({ children, actionProvider, querySummaries, trackFetchFailures, panel, tools, extraTools, ...providerProps }: WebMcpTroubleshootingProviderProps): import("react").JSX.Element;
|
|
23
|
+
//# sourceMappingURL=WebMcpTroubleshootingProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebMcpTroubleshootingProvider.d.ts","sourceRoot":"","sources":["../src/WebMcpTroubleshootingProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAO,EAqBL,KAAK,0BAA0B,EAC/B,KAAK,YAAY,EAClB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,oBAAoB,CAAC;AAS5B,MAAM,WAAW,iCAAiC;IAChD,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IACrC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kCACf,SAAQ,IAAI,CAAC,mBAAmB,EAAE,OAAO,CAAC;IAC1C,QAAQ,EAAE,SAAS,CAAC;IACpB,cAAc,CAAC,EAAE,0BAA0B,CAAC;IAC5C,cAAc,CAAC,EAAE,MAAM,YAAY,EAAE,CAAC;IACtC,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,KAAK,CAAC,EAAE,iCAAiC,CAAC;IAC1C,KAAK,CAAC,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC;IACrC,UAAU,CAAC,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC;CAC3C;AAgHD,wBAAgB,6BAA6B,CAAC,EAC5C,QAAQ,EACR,cAAc,EACd,cAAc,EACd,kBAAyB,EACzB,KAAK,EACL,KAAU,EACV,UAAe,EACf,GAAG,aAAa,EACjB,EAAE,kCAAkC,+BAyEpC"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useMemo, useRef, } from 'react';
|
|
3
|
+
import { ClientErrorBuffer, TroubleshootingTimelineBuffer, createErrorCollector, createFetchFailureTracker, createActionAvailabilityTool, createListActionsTool, createMountedFormsRegistry, createMountedFormsSummaryTool, createRecentClientErrorsTool, createTimelineFromErrorBuffer, createTroubleshootingPanelViewModel, createTroubleshootingTimelineTool, createWebMcpEnvironmentSummary, createWebMcpEnvironmentTool, createWebMcpLifecycleCollector, createWorkflowBlockersTool, discoverDeclarativeForms, formSummaryFromMounted, isPanelEnabledByDefault, isPanelUrlOverrideEnabled, } from '@tooluminati/diagnostics';
|
|
4
|
+
import { WebMcpProvider, useWebMcpRegistry, } from '@tooluminati/react';
|
|
5
|
+
import { WebMcpTroubleshootingContext } from './WebMcpTroubleshootingContext';
|
|
6
|
+
import { WebMcpTroubleshootingPanel } from './WebMcpTroubleshootingPanel';
|
|
7
|
+
import { getPanelVisibilityController, resetPanelVisibilityController, wirePanelVisibilityController, } from './panel-visibility';
|
|
8
|
+
function WebMcpTroubleshootingInner({ children, timeline, errors, mountedForms, trackFetchFailures, panel, panelEnabled, registryRef, }) {
|
|
9
|
+
const registry = useWebMcpRegistry();
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
registryRef.current = registry;
|
|
12
|
+
}, [registry, registryRef]);
|
|
13
|
+
const visibility = useMemo(() => {
|
|
14
|
+
const controller = getPanelVisibilityController();
|
|
15
|
+
wirePanelVisibilityController(controller);
|
|
16
|
+
if (panel?.startCollapsed) {
|
|
17
|
+
controller.setCollapsed(true);
|
|
18
|
+
}
|
|
19
|
+
return controller;
|
|
20
|
+
}, [panel?.startCollapsed]);
|
|
21
|
+
const viewModel = useMemo(() => createTroubleshootingPanelViewModel({
|
|
22
|
+
timeline,
|
|
23
|
+
errors,
|
|
24
|
+
environment: () => createWebMcpEnvironmentSummary({ registry }),
|
|
25
|
+
registry,
|
|
26
|
+
}, {
|
|
27
|
+
pollMs: panel?.pollMs ?? 2000,
|
|
28
|
+
registry,
|
|
29
|
+
...(panel?.eventLimit !== undefined
|
|
30
|
+
? { eventLimit: panel.eventLimit }
|
|
31
|
+
: {}),
|
|
32
|
+
}), [timeline, errors, registry, panel?.eventLimit, panel?.pollMs]);
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
const cleanups = [
|
|
35
|
+
createErrorCollector({ buffer: errors }),
|
|
36
|
+
createTimelineFromErrorBuffer(errors, timeline),
|
|
37
|
+
createWebMcpLifecycleCollector({ buffer: timeline }),
|
|
38
|
+
];
|
|
39
|
+
if (trackFetchFailures) {
|
|
40
|
+
cleanups.push(createFetchFailureTracker({ buffer: timeline }));
|
|
41
|
+
}
|
|
42
|
+
return () => {
|
|
43
|
+
for (const cleanup of cleanups) {
|
|
44
|
+
cleanup();
|
|
45
|
+
}
|
|
46
|
+
viewModel.dispose();
|
|
47
|
+
};
|
|
48
|
+
}, [errors, timeline, trackFetchFailures, viewModel]);
|
|
49
|
+
const shouldRenderPanel = panelEnabled &&
|
|
50
|
+
panel?.render !== false &&
|
|
51
|
+
(panel?.render === true ||
|
|
52
|
+
panel?.render === 'auto' ||
|
|
53
|
+
panel?.render === undefined);
|
|
54
|
+
const contextValue = useMemo(() => ({
|
|
55
|
+
timeline,
|
|
56
|
+
errors,
|
|
57
|
+
mountedForms,
|
|
58
|
+
viewModel,
|
|
59
|
+
visibility,
|
|
60
|
+
isPanelEnabled: panelEnabled,
|
|
61
|
+
}), [timeline, errors, mountedForms, viewModel, visibility, panelEnabled]);
|
|
62
|
+
return (_jsxs(WebMcpTroubleshootingContext.Provider, { value: contextValue, children: [children, shouldRenderPanel ? (_jsx(WebMcpTroubleshootingPanel, { position: panel?.position ?? 'br', ...(panel?.startCollapsed !== undefined
|
|
63
|
+
? { startCollapsed: panel.startCollapsed }
|
|
64
|
+
: {}), ...(panel?.eventLimit !== undefined
|
|
65
|
+
? { eventLimit: panel.eventLimit }
|
|
66
|
+
: {}), pollMs: panel?.pollMs ?? 2000 })) : null] }));
|
|
67
|
+
}
|
|
68
|
+
export function WebMcpTroubleshootingProvider({ children, actionProvider, querySummaries, trackFetchFailures = true, panel, tools = [], extraTools = [], ...providerProps }) {
|
|
69
|
+
const timeline = useMemo(() => new TroubleshootingTimelineBuffer(), []);
|
|
70
|
+
const errors = useMemo(() => new ClientErrorBuffer({ includeStacks: true }), []);
|
|
71
|
+
const mountedForms = useMemo(() => createMountedFormsRegistry(), []);
|
|
72
|
+
const registryRef = useRef(undefined);
|
|
73
|
+
const actionProviderRef = useRef(actionProvider);
|
|
74
|
+
const querySummariesRef = useRef(querySummaries);
|
|
75
|
+
actionProviderRef.current = actionProvider;
|
|
76
|
+
querySummariesRef.current = querySummaries;
|
|
77
|
+
useEffect(() => () => resetPanelVisibilityController(), []);
|
|
78
|
+
const panelEnabled = isPanelEnabledByDefault(panel?.enabled) ||
|
|
79
|
+
isPanelUrlOverrideEnabled(panel?.allowUrlOverride);
|
|
80
|
+
const liveActionProvider = useMemo(() => ({
|
|
81
|
+
getActionAvailability: (actionId) => actionProviderRef.current?.getActionAvailability(actionId),
|
|
82
|
+
listActions: () => actionProviderRef.current?.listActions?.() ?? [],
|
|
83
|
+
}), []);
|
|
84
|
+
const diagnosticTools = useMemo(() => [
|
|
85
|
+
createTroubleshootingTimelineTool(timeline),
|
|
86
|
+
createWebMcpEnvironmentTool(() => createWebMcpEnvironmentSummary({ registry: registryRef.current })),
|
|
87
|
+
createRecentClientErrorsTool(errors),
|
|
88
|
+
createMountedFormsSummaryTool(mountedForms),
|
|
89
|
+
createWorkflowBlockersTool({
|
|
90
|
+
...(actionProvider ? { actionProvider: liveActionProvider } : {}),
|
|
91
|
+
formSummaries: () => mountedForms.list().map(formSummaryFromMounted),
|
|
92
|
+
declarativeFormSummaries: () => discoverDeclarativeForms(),
|
|
93
|
+
recentErrors: () => errors.list(),
|
|
94
|
+
querySummaries: () => querySummariesRef.current?.() ?? [],
|
|
95
|
+
}),
|
|
96
|
+
...(actionProvider
|
|
97
|
+
? [
|
|
98
|
+
createActionAvailabilityTool(liveActionProvider),
|
|
99
|
+
createListActionsTool(liveActionProvider),
|
|
100
|
+
]
|
|
101
|
+
: []),
|
|
102
|
+
...tools,
|
|
103
|
+
...extraTools,
|
|
104
|
+
], [timeline, errors, mountedForms, actionProvider, liveActionProvider, tools, extraTools]);
|
|
105
|
+
return (_jsx(WebMcpProvider, { ...providerProps, tools: diagnosticTools, children: _jsx(WebMcpTroubleshootingInner, { timeline: timeline, errors: errors, mountedForms: mountedForms, trackFetchFailures: trackFetchFailures, panelEnabled: panelEnabled, registryRef: registryRef, ...(actionProvider ? { actionProvider } : {}), ...(querySummaries ? { querySummaries } : {}), ...(panel ? { panel } : {}), children: children }) }));
|
|
106
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type FormEventHandler, type InputHTMLAttributes, type ReactNode, type SelectHTMLAttributes, type TextareaHTMLAttributes, type FormHTMLAttributes } from 'react';
|
|
2
|
+
export interface WebMcpFormProps extends FormHTMLAttributes<HTMLFormElement> {
|
|
3
|
+
toolName: string;
|
|
4
|
+
toolDescription: string;
|
|
5
|
+
toolAutoSubmit?: boolean;
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
export declare function WebMcpForm({ toolName, toolDescription, toolAutoSubmit, children, ...props }: WebMcpFormProps): import("react").JSX.Element;
|
|
9
|
+
export declare function WebMcpInput(props: InputHTMLAttributes<HTMLInputElement> & {
|
|
10
|
+
toolParamDescription?: string;
|
|
11
|
+
}): import("react").JSX.Element;
|
|
12
|
+
export declare function WebMcpSelect(props: SelectHTMLAttributes<HTMLSelectElement> & {
|
|
13
|
+
toolParamDescription?: string;
|
|
14
|
+
}): import("react").JSX.Element;
|
|
15
|
+
export declare function WebMcpTextarea(props: TextareaHTMLAttributes<HTMLTextAreaElement> & {
|
|
16
|
+
toolParamDescription?: string;
|
|
17
|
+
}): import("react").JSX.Element;
|
|
18
|
+
export declare function useAgentInvokedSubmit(handler: FormEventHandler<HTMLFormElement>): FormEventHandler<HTMLFormElement>;
|
|
19
|
+
export interface DeclarativeFormToolEventsOptions {
|
|
20
|
+
formSelector?: string;
|
|
21
|
+
}
|
|
22
|
+
export declare function useDeclarativeFormToolEvents(_options?: DeclarativeFormToolEventsOptions): void;
|
|
23
|
+
//# sourceMappingURL=declarative-form.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"declarative-form.d.ts","sourceRoot":"","sources":["../src/declarative-form.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,SAAS,EACd,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,kBAAkB,EACxB,MAAM,OAAO,CAAC;AAIf,MAAM,WAAW,eAAgB,SAAQ,kBAAkB,CAAC,eAAe,CAAC;IAC1E,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,UAAU,CAAC,EACzB,QAAQ,EACR,eAAe,EACf,cAAc,EACd,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,eAAe,+BAWjB;AAED,wBAAgB,WAAW,CACzB,KAAK,EAAE,mBAAmB,CAAC,gBAAgB,CAAC,GAAG;IAC7C,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B,+BAWF;AAED,wBAAgB,YAAY,CAC1B,KAAK,EAAE,oBAAoB,CAAC,iBAAiB,CAAC,GAAG;IAC/C,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B,+BAWF;AAED,wBAAgB,cAAc,CAC5B,KAAK,EAAE,sBAAsB,CAAC,mBAAmB,CAAC,GAAG;IACnD,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B,+BAWF;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,gBAAgB,CAAC,eAAe,CAAC,GACzC,gBAAgB,CAAC,eAAe,CAAC,CAOnC;AAED,MAAM,WAAW,gCAAgC;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,4BAA4B,CAC1C,QAAQ,GAAE,gCAAqC,GAC9C,IAAI,CAEN"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
export function WebMcpForm({ toolName, toolDescription, toolAutoSubmit, children, ...props }) {
|
|
3
|
+
return (_jsx("form", { ...props, toolname: toolName, tooldescription: toolDescription, ...(toolAutoSubmit ? { toolautosubmit: '' } : {}), children: children }));
|
|
4
|
+
}
|
|
5
|
+
export function WebMcpInput(props) {
|
|
6
|
+
const { toolParamDescription, ...rest } = props;
|
|
7
|
+
return (_jsx("input", { ...rest, ...(toolParamDescription
|
|
8
|
+
? { toolparamdescription: toolParamDescription }
|
|
9
|
+
: {}) }));
|
|
10
|
+
}
|
|
11
|
+
export function WebMcpSelect(props) {
|
|
12
|
+
const { toolParamDescription, ...rest } = props;
|
|
13
|
+
return (_jsx("select", { ...rest, ...(toolParamDescription
|
|
14
|
+
? { toolparamdescription: toolParamDescription }
|
|
15
|
+
: {}) }));
|
|
16
|
+
}
|
|
17
|
+
export function WebMcpTextarea(props) {
|
|
18
|
+
const { toolParamDescription, ...rest } = props;
|
|
19
|
+
return (_jsx("textarea", { ...rest, ...(toolParamDescription
|
|
20
|
+
? { toolparamdescription: toolParamDescription }
|
|
21
|
+
: {}) }));
|
|
22
|
+
}
|
|
23
|
+
export function useAgentInvokedSubmit(handler) {
|
|
24
|
+
return (event) => {
|
|
25
|
+
const submitEvent = event.nativeEvent;
|
|
26
|
+
if (submitEvent.agentInvoked) {
|
|
27
|
+
handler(event);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export function useDeclarativeFormToolEvents(_options = {}) {
|
|
32
|
+
// Agent form submits are captured by createWebMcpLifecycleCollector().
|
|
33
|
+
}
|