@tooluminati/diagnostics 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/action-availability.d.ts +24 -0
- package/dist/action-availability.d.ts.map +1 -0
- package/dist/action-availability.js +44 -0
- package/dist/app-info.d.ts +16 -0
- package/dist/app-info.d.ts.map +1 -0
- package/dist/app-info.js +28 -0
- package/dist/errors.d.ts +35 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +91 -0
- package/dist/feature-flags.d.ts +10 -0
- package/dist/feature-flags.d.ts.map +1 -0
- package/dist/feature-flags.js +13 -0
- package/dist/hydration.d.ts +11 -0
- package/dist/hydration.d.ts.map +1 -0
- package/dist/hydration.js +26 -0
- package/dist/index.cjs +1199 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1141 -0
- package/dist/mounted-forms.d.ts +26 -0
- package/dist/mounted-forms.d.ts.map +1 -0
- package/dist/mounted-forms.js +32 -0
- package/dist/timeline.d.ts +99 -0
- package/dist/timeline.d.ts.map +1 -0
- package/dist/timeline.js +302 -0
- package/dist/timeline.test.d.ts +2 -0
- package/dist/timeline.test.d.ts.map +1 -0
- package/dist/timeline.test.js +94 -0
- package/dist/troubleshooting-guidance.d.ts +15 -0
- package/dist/troubleshooting-guidance.d.ts.map +1 -0
- package/dist/troubleshooting-guidance.js +130 -0
- package/dist/troubleshooting-guidance.test.d.ts +2 -0
- package/dist/troubleshooting-guidance.test.d.ts.map +1 -0
- package/dist/troubleshooting-guidance.test.js +27 -0
- package/dist/troubleshooting-panel.d.ts +77 -0
- package/dist/troubleshooting-panel.d.ts.map +1 -0
- package/dist/troubleshooting-panel.js +243 -0
- package/dist/troubleshooting-panel.test.d.ts +2 -0
- package/dist/troubleshooting-panel.test.d.ts.map +1 -0
- package/dist/troubleshooting-panel.test.js +105 -0
- package/dist/webmcp-environment.d.ts +23 -0
- package/dist/webmcp-environment.d.ts.map +1 -0
- package/dist/webmcp-environment.js +156 -0
- package/dist/webmcp-environment.test.d.ts +2 -0
- package/dist/webmcp-environment.test.d.ts.map +1 -0
- package/dist/webmcp-environment.test.js +49 -0
- package/dist/workflow-blockers.d.ts +53 -0
- package/dist/workflow-blockers.d.ts.map +1 -0
- package/dist/workflow-blockers.js +62 -0
- package/dist/workflow-blockers.test.d.ts +2 -0
- package/dist/workflow-blockers.test.d.ts.map +1 -0
- package/dist/workflow-blockers.test.js +41 -0
- package/package.json +50 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { getModelContext, isWebMcpSupported, } from '@tooluminati/core';
|
|
2
|
+
export function createWebMcpEnvironmentSummary(options = {}) {
|
|
3
|
+
const globalObject = options.globalObject ?? globalThis;
|
|
4
|
+
let usingNavigatorFallback = false;
|
|
5
|
+
const documentContext = typeof globalObject.document !== 'undefined'
|
|
6
|
+
? globalObject.document
|
|
7
|
+
.modelContext
|
|
8
|
+
: undefined;
|
|
9
|
+
getModelContext({
|
|
10
|
+
globalObject,
|
|
11
|
+
onNavigatorFallback: () => {
|
|
12
|
+
usingNavigatorFallback = true;
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
const supported = isWebMcpSupported({ globalObject });
|
|
16
|
+
const origin = typeof globalObject.location !== 'undefined'
|
|
17
|
+
? globalObject.location.origin
|
|
18
|
+
: 'unknown';
|
|
19
|
+
const toolCount = options.registry?.getRegisteredToolNames().length ?? 0;
|
|
20
|
+
const checks = [];
|
|
21
|
+
const warnings = [];
|
|
22
|
+
checks.push({
|
|
23
|
+
id: 'document.modelContext',
|
|
24
|
+
label: 'document.modelContext',
|
|
25
|
+
value: documentContext ? 'available' : 'missing',
|
|
26
|
+
status: documentContext ? 'ok' : 'fail',
|
|
27
|
+
...(documentContext
|
|
28
|
+
? {}
|
|
29
|
+
: {
|
|
30
|
+
hint: 'No document.modelContext on this page. Enable WebMCP in Chrome ' +
|
|
31
|
+
'or attach the Model Context Inspector Extension.',
|
|
32
|
+
}),
|
|
33
|
+
});
|
|
34
|
+
checks.push({
|
|
35
|
+
id: 'navigator.modelContext',
|
|
36
|
+
label: 'navigator.modelContext fallback',
|
|
37
|
+
value: usingNavigatorFallback ? 'in use' : 'not used',
|
|
38
|
+
status: usingNavigatorFallback ? 'warn' : 'ok',
|
|
39
|
+
...(usingNavigatorFallback
|
|
40
|
+
? {
|
|
41
|
+
hint: 'Deprecated navigator.modelContext path detected. Migrate to ' +
|
|
42
|
+
'document.modelContext.',
|
|
43
|
+
}
|
|
44
|
+
: {}),
|
|
45
|
+
});
|
|
46
|
+
const originIsolation = detectOriginIsolationIssue(globalObject);
|
|
47
|
+
checks.push({
|
|
48
|
+
id: 'origin-isolation',
|
|
49
|
+
label: 'Origin isolation',
|
|
50
|
+
value: originIsolation.value,
|
|
51
|
+
status: originIsolation.status,
|
|
52
|
+
...(originIsolation.hint ? { hint: originIsolation.hint } : {}),
|
|
53
|
+
});
|
|
54
|
+
if (originIsolation.warning) {
|
|
55
|
+
warnings.push(originIsolation.warning);
|
|
56
|
+
}
|
|
57
|
+
const permissionsPolicy = detectPermissionsPolicy(globalObject);
|
|
58
|
+
checks.push({
|
|
59
|
+
id: 'permissions-policy',
|
|
60
|
+
label: 'tools Permissions-Policy',
|
|
61
|
+
value: permissionsPolicy.value,
|
|
62
|
+
status: permissionsPolicy.status,
|
|
63
|
+
...(permissionsPolicy.hint ? { hint: permissionsPolicy.hint } : {}),
|
|
64
|
+
});
|
|
65
|
+
if (permissionsPolicy.warning) {
|
|
66
|
+
warnings.push(permissionsPolicy.warning);
|
|
67
|
+
}
|
|
68
|
+
if (toolCount === 0 && supported) {
|
|
69
|
+
warnings.push('No tools registered yet.');
|
|
70
|
+
checks.push({
|
|
71
|
+
id: 'tool-count',
|
|
72
|
+
label: 'Registered tools',
|
|
73
|
+
value: '0',
|
|
74
|
+
status: 'warn',
|
|
75
|
+
hint: 'WebMCP is supported but no tools are registered. Verify the ' +
|
|
76
|
+
'Tooluminati provider is mounted.',
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
if (!supported) {
|
|
80
|
+
warnings.push('WebMCP is unsupported in this browser context.');
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
supported,
|
|
84
|
+
toolCount,
|
|
85
|
+
origin,
|
|
86
|
+
usingNavigatorFallback,
|
|
87
|
+
checks,
|
|
88
|
+
warnings,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function detectOriginIsolationIssue(globalObject) {
|
|
92
|
+
if (typeof globalObject.document === 'undefined') {
|
|
93
|
+
return { value: 'n/a', status: 'muted' };
|
|
94
|
+
}
|
|
95
|
+
const doc = globalObject.document;
|
|
96
|
+
if (doc.domain && doc.domain.length > 0) {
|
|
97
|
+
const hint = 'document.domain is set. Origin-Agent-Cluster may be ?0. Remove ' +
|
|
98
|
+
'document.domain writes or set Origin-Agent-Cluster: ?1.';
|
|
99
|
+
return {
|
|
100
|
+
value: 'review',
|
|
101
|
+
status: 'warn',
|
|
102
|
+
hint,
|
|
103
|
+
warning: hint,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
return { value: 'ok', status: 'ok' };
|
|
107
|
+
}
|
|
108
|
+
function detectPermissionsPolicy(globalObject) {
|
|
109
|
+
if (typeof globalObject.document === 'undefined') {
|
|
110
|
+
return { value: 'n/a', status: 'muted' };
|
|
111
|
+
}
|
|
112
|
+
const doc = globalObject.document;
|
|
113
|
+
if (doc.permissionsPolicy?.allowsFeature) {
|
|
114
|
+
const allowed = doc.permissionsPolicy.allowsFeature('tools');
|
|
115
|
+
if (!allowed) {
|
|
116
|
+
const hint = 'tools is blocked by Permissions-Policy. Allow tools for this ' +
|
|
117
|
+
'origin or review iframe allow attributes.';
|
|
118
|
+
return {
|
|
119
|
+
value: 'blocked',
|
|
120
|
+
status: 'fail',
|
|
121
|
+
hint,
|
|
122
|
+
warning: hint,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (typeof globalObject.document.querySelector !== 'function') {
|
|
127
|
+
return { value: 'self', status: 'ok' };
|
|
128
|
+
}
|
|
129
|
+
const iframe = globalObject.document.querySelector('iframe');
|
|
130
|
+
if (iframe &&
|
|
131
|
+
iframe.src &&
|
|
132
|
+
!iframe.src.startsWith(globalObject.location.origin)) {
|
|
133
|
+
const hint = 'Cross-origin iframe detected. Verify Permissions-Policy allows ' +
|
|
134
|
+
'tools for embedded origins.';
|
|
135
|
+
return {
|
|
136
|
+
value: 'review cross-origin iframe',
|
|
137
|
+
status: 'warn',
|
|
138
|
+
hint,
|
|
139
|
+
warning: hint,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
return { value: 'self', status: 'ok' };
|
|
143
|
+
}
|
|
144
|
+
export function createWebMcpEnvironmentTool(getSummary, name = 'get_webmcp_environment') {
|
|
145
|
+
return {
|
|
146
|
+
name,
|
|
147
|
+
description: 'Reports WebMCP browser support, registered tool count, and setup warnings.',
|
|
148
|
+
inputSchema: {
|
|
149
|
+
type: 'object',
|
|
150
|
+
properties: {},
|
|
151
|
+
additionalProperties: false,
|
|
152
|
+
},
|
|
153
|
+
annotations: { readOnlyHint: true },
|
|
154
|
+
execute: () => getSummary(),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webmcp-environment.test.d.ts","sourceRoot":"","sources":["../src/webmcp-environment.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { createWebMcpEnvironmentSummary, createWebMcpEnvironmentTool, } from './webmcp-environment';
|
|
3
|
+
describe('createWebMcpEnvironmentSummary', () => {
|
|
4
|
+
it('reports unsupported when modelContext is missing', () => {
|
|
5
|
+
const summary = createWebMcpEnvironmentSummary({
|
|
6
|
+
globalObject: {
|
|
7
|
+
window: {},
|
|
8
|
+
document: {},
|
|
9
|
+
location: { origin: 'https://app.test' },
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
expect(summary.supported).toBe(false);
|
|
13
|
+
expect(summary.checks[0]?.status).toBe('fail');
|
|
14
|
+
expect(summary.warnings.length).toBeGreaterThan(0);
|
|
15
|
+
});
|
|
16
|
+
it('includes registered tool count from registry', () => {
|
|
17
|
+
const registry = {
|
|
18
|
+
getRegisteredToolNames: () => ['demo_tool'],
|
|
19
|
+
};
|
|
20
|
+
const summary = createWebMcpEnvironmentSummary({
|
|
21
|
+
registry,
|
|
22
|
+
globalObject: {
|
|
23
|
+
window: {},
|
|
24
|
+
document: { modelContext: {} },
|
|
25
|
+
location: { origin: 'https://app.test' },
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
expect(summary.toolCount).toBe(1);
|
|
29
|
+
expect(summary.supported).toBe(true);
|
|
30
|
+
});
|
|
31
|
+
it('warns when document.domain is set', () => {
|
|
32
|
+
const summary = createWebMcpEnvironmentSummary({
|
|
33
|
+
globalObject: {
|
|
34
|
+
window: {},
|
|
35
|
+
document: { modelContext: {}, domain: 'example.com' },
|
|
36
|
+
location: { origin: 'https://app.test' },
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
const originCheck = summary.checks.find((c) => c.id === 'origin-isolation');
|
|
40
|
+
expect(originCheck?.status).toBe('warn');
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
describe('createWebMcpEnvironmentTool', () => {
|
|
44
|
+
it('returns summary from getter', async () => {
|
|
45
|
+
const tool = createWebMcpEnvironmentTool(() => createWebMcpEnvironmentSummary());
|
|
46
|
+
const result = await tool.execute({}, {});
|
|
47
|
+
expect(result).toHaveProperty('checks');
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { WebMcpToolDescriptor } from '@tooluminati/core';
|
|
2
|
+
import type { ActionAvailabilityProvider } from './action-availability';
|
|
3
|
+
import type { ClientErrorSummary } from './errors';
|
|
4
|
+
import type { MountedFormSummary } from './mounted-forms';
|
|
5
|
+
export interface FormDiagnosticSummary {
|
|
6
|
+
name: string;
|
|
7
|
+
valid: boolean;
|
|
8
|
+
submitting?: boolean | undefined;
|
|
9
|
+
blockers: string[];
|
|
10
|
+
}
|
|
11
|
+
export interface DeclarativeFormSummary {
|
|
12
|
+
toolName: string;
|
|
13
|
+
formId?: string | undefined;
|
|
14
|
+
autoSubmit?: boolean | undefined;
|
|
15
|
+
}
|
|
16
|
+
export interface QuerySummary {
|
|
17
|
+
queryKey: string;
|
|
18
|
+
status: string;
|
|
19
|
+
error?: string | undefined;
|
|
20
|
+
isFetching?: boolean | undefined;
|
|
21
|
+
}
|
|
22
|
+
export interface WorkflowBlockersSources {
|
|
23
|
+
actionProvider?: ActionAvailabilityProvider | undefined;
|
|
24
|
+
formSummaries?: () => FormDiagnosticSummary[];
|
|
25
|
+
declarativeFormSummaries?: () => DeclarativeFormSummary[];
|
|
26
|
+
querySummaries?: () => QuerySummary[];
|
|
27
|
+
recentErrors?: () => ClientErrorSummary[];
|
|
28
|
+
hydrationHealth?: () => {
|
|
29
|
+
healthy: boolean;
|
|
30
|
+
issues: string[];
|
|
31
|
+
};
|
|
32
|
+
featureFlags?: () => Record<string, boolean>;
|
|
33
|
+
}
|
|
34
|
+
export interface WorkflowBlockersResult {
|
|
35
|
+
actions: Array<{
|
|
36
|
+
actionId: string;
|
|
37
|
+
available: boolean;
|
|
38
|
+
reasons: string[];
|
|
39
|
+
}>;
|
|
40
|
+
forms: FormDiagnosticSummary[];
|
|
41
|
+
declarativeForms: DeclarativeFormSummary[];
|
|
42
|
+
queries: QuerySummary[];
|
|
43
|
+
errors: ClientErrorSummary[];
|
|
44
|
+
hydration?: {
|
|
45
|
+
healthy: boolean;
|
|
46
|
+
issues: string[];
|
|
47
|
+
};
|
|
48
|
+
featureFlags?: Record<string, boolean>;
|
|
49
|
+
}
|
|
50
|
+
export declare function createWorkflowBlockersTool(sources: WorkflowBlockersSources, name?: string): WebMcpToolDescriptor<Record<string, never>, WorkflowBlockersResult>;
|
|
51
|
+
export declare function formSummaryFromMounted(form: MountedFormSummary): FormDiagnosticSummary;
|
|
52
|
+
export declare function discoverDeclarativeForms(root?: ParentNode): DeclarativeFormSummary[];
|
|
53
|
+
//# sourceMappingURL=workflow-blockers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-blockers.d.ts","sourceRoot":"","sources":["../src/workflow-blockers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AACnD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAE1D,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACjC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAClC;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAClC;AAED,MAAM,WAAW,uBAAuB;IACtC,cAAc,CAAC,EAAE,0BAA0B,GAAG,SAAS,CAAC;IACxD,aAAa,CAAC,EAAE,MAAM,qBAAqB,EAAE,CAAC;IAC9C,wBAAwB,CAAC,EAAE,MAAM,sBAAsB,EAAE,CAAC;IAC1D,cAAc,CAAC,EAAE,MAAM,YAAY,EAAE,CAAC;IACtC,YAAY,CAAC,EAAE,MAAM,kBAAkB,EAAE,CAAC;IAC1C,eAAe,CAAC,EAAE,MAAM;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAC/D,YAAY,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,KAAK,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,OAAO,CAAC;QACnB,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC,CAAC;IACH,KAAK,EAAE,qBAAqB,EAAE,CAAC;IAC/B,gBAAgB,EAAE,sBAAsB,EAAE,CAAC;IAC3C,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,MAAM,EAAE,kBAAkB,EAAE,CAAC;IAC7B,SAAS,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IACnD,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC;AAED,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,uBAAuB,EAChC,IAAI,SAA0B,GAC7B,oBAAoB,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,sBAAsB,CAAC,CAwCrE;AAED,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,kBAAkB,GACvB,qBAAqB,CAWvB;AAED,wBAAgB,wBAAwB,CACtC,IAAI,GAAE,UAAyE,GAC9E,sBAAsB,EAAE,CAgB1B"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export function createWorkflowBlockersTool(sources, name = 'get_workflow_blockers') {
|
|
2
|
+
return {
|
|
3
|
+
name,
|
|
4
|
+
description: 'Aggregates action, form, query, and error blockers for the current workflow.',
|
|
5
|
+
inputSchema: {
|
|
6
|
+
type: 'object',
|
|
7
|
+
properties: {},
|
|
8
|
+
additionalProperties: false,
|
|
9
|
+
},
|
|
10
|
+
annotations: { readOnlyHint: true, untrustedContentHint: true },
|
|
11
|
+
execute: () => {
|
|
12
|
+
const actions = sources.actionProvider?.listActions?.().map((action) => ({
|
|
13
|
+
actionId: action.actionId,
|
|
14
|
+
available: action.available,
|
|
15
|
+
reasons: action.available ? [] : action.reasons,
|
|
16
|
+
})) ?? [];
|
|
17
|
+
const result = {
|
|
18
|
+
actions,
|
|
19
|
+
forms: sources.formSummaries?.() ?? [],
|
|
20
|
+
declarativeForms: sources.declarativeFormSummaries?.() ?? [],
|
|
21
|
+
queries: sources.querySummaries?.() ?? [],
|
|
22
|
+
errors: sources.recentErrors?.() ?? [],
|
|
23
|
+
};
|
|
24
|
+
const hydration = sources.hydrationHealth?.();
|
|
25
|
+
if (hydration) {
|
|
26
|
+
result.hydration = hydration;
|
|
27
|
+
}
|
|
28
|
+
const flags = sources.featureFlags?.();
|
|
29
|
+
if (flags) {
|
|
30
|
+
result.featureFlags = flags;
|
|
31
|
+
}
|
|
32
|
+
return result;
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export function formSummaryFromMounted(form) {
|
|
37
|
+
const blockers = form.errors.map((e) => `${e.path}: ${e.message}`);
|
|
38
|
+
if (form.submitting) {
|
|
39
|
+
blockers.push('Form is submitting.');
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
name: form.name,
|
|
43
|
+
valid: blockers.length === 0,
|
|
44
|
+
submitting: form.submitting,
|
|
45
|
+
blockers,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export function discoverDeclarativeForms(root = typeof document !== 'undefined' ? document : null) {
|
|
49
|
+
if (!root) {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
const summaries = new Map();
|
|
53
|
+
for (const form of root.querySelectorAll('form[toolname]')) {
|
|
54
|
+
const el = form;
|
|
55
|
+
summaries.set(el.getAttribute('toolname') ?? 'unknown', {
|
|
56
|
+
toolName: el.getAttribute('toolname') ?? 'unknown',
|
|
57
|
+
...(el.id ? { formId: el.id } : {}),
|
|
58
|
+
autoSubmit: el.hasAttribute('toolautosubmit'),
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return [...summaries.values()];
|
|
62
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-blockers.test.d.ts","sourceRoot":"","sources":["../src/workflow-blockers.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { createListActionsTool } from './action-availability';
|
|
3
|
+
import { createWorkflowBlockersTool } from './workflow-blockers';
|
|
4
|
+
describe('createWorkflowBlockersTool', () => {
|
|
5
|
+
it('aggregates action and error sources', async () => {
|
|
6
|
+
const provider = {
|
|
7
|
+
getActionAvailability: (id) => ({
|
|
8
|
+
actionId: id,
|
|
9
|
+
label: id,
|
|
10
|
+
available: false,
|
|
11
|
+
reasons: ['blocked'],
|
|
12
|
+
}),
|
|
13
|
+
listActions: () => [
|
|
14
|
+
{
|
|
15
|
+
actionId: 'submit',
|
|
16
|
+
label: 'Submit',
|
|
17
|
+
available: false,
|
|
18
|
+
reasons: ['invalid form'],
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
};
|
|
22
|
+
const tool = createWorkflowBlockersTool({
|
|
23
|
+
actionProvider: provider,
|
|
24
|
+
recentErrors: () => [
|
|
25
|
+
{
|
|
26
|
+
message: 'err',
|
|
27
|
+
source: 'app',
|
|
28
|
+
timestamp: new Date().toISOString(),
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
});
|
|
32
|
+
const result = await tool.execute({}, {});
|
|
33
|
+
expect(result.actions[0]?.reasons).toContain('invalid form');
|
|
34
|
+
expect(result.errors).toHaveLength(1);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
describe('createListActionsTool export', () => {
|
|
38
|
+
it('is re-exported from action-availability', () => {
|
|
39
|
+
expect(createListActionsTool).toBeDefined();
|
|
40
|
+
});
|
|
41
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tooluminati/diagnostics",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Runtime diagnostic tool factories for Tooluminati.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"main": "./dist/index.cjs",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"require": "./dist/index.cjs"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@tooluminati/core": "0.1.0"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist"
|
|
22
|
+
],
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/jitterbox/Tooluminati.git",
|
|
30
|
+
"directory": "packages/diagnostics"
|
|
31
|
+
},
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": "https://github.com/jitterbox/Tooluminati/issues"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://github.com/jitterbox/Tooluminati#readme",
|
|
36
|
+
"keywords": [
|
|
37
|
+
"tooluminati",
|
|
38
|
+
"webmcp",
|
|
39
|
+
"react",
|
|
40
|
+
"diagnostics",
|
|
41
|
+
"observability"
|
|
42
|
+
],
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=18"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"build": "tsup src/index.ts --format esm,cjs && tsc -p tsconfig.json --emitDeclarationOnly",
|
|
48
|
+
"typecheck": "tsc --noEmit"
|
|
49
|
+
}
|
|
50
|
+
}
|