@supernal/interface 1.0.12 → 1.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/dist/cjs/names/Components.js +13 -0
- package/dist/cjs/names/Components.js.map +1 -1
- package/dist/cjs/src/browser.js +6 -2
- package/dist/cjs/src/browser.js.map +1 -1
- package/dist/cjs/src/cli/upgrade.js +305 -0
- package/dist/cjs/src/cli/upgrade.js.map +1 -0
- package/dist/cjs/src/index.js +18 -1
- package/dist/cjs/src/index.js.map +1 -1
- package/dist/cjs/src/tracking/SITrackingProvider.js +126 -0
- package/dist/cjs/src/tracking/SITrackingProvider.js.map +1 -0
- package/dist/cjs/src/tracking/hooks.js +233 -0
- package/dist/cjs/src/tracking/hooks.js.map +1 -0
- package/dist/cjs/src/tracking/index.js +67 -0
- package/dist/cjs/src/tracking/index.js.map +1 -0
- package/dist/cjs/src/tracking/tracker.js +289 -0
- package/dist/cjs/src/tracking/tracker.js.map +1 -0
- package/dist/esm/names/Components.d.ts +12 -0
- package/dist/esm/names/Components.d.ts.map +1 -1
- package/dist/esm/names/Components.js +13 -0
- package/dist/esm/names/Components.js.map +1 -1
- package/dist/esm/names/index.d.ts +12 -0
- package/dist/esm/names/index.d.ts.map +1 -1
- package/dist/esm/src/browser.d.ts +2 -0
- package/dist/esm/src/browser.d.ts.map +1 -1
- package/dist/esm/src/browser.js +2 -0
- package/dist/esm/src/browser.js.map +1 -1
- package/dist/esm/src/cli/upgrade.d.ts +17 -0
- package/dist/esm/src/cli/upgrade.d.ts.map +1 -0
- package/dist/esm/src/cli/upgrade.js +270 -0
- package/dist/esm/src/cli/upgrade.js.map +1 -0
- package/dist/esm/src/index.d.ts +3 -0
- package/dist/esm/src/index.d.ts.map +1 -1
- package/dist/esm/src/index.js +4 -0
- package/dist/esm/src/index.js.map +1 -1
- package/dist/esm/src/tracking/SITrackingProvider.d.ts +64 -0
- package/dist/esm/src/tracking/SITrackingProvider.d.ts.map +1 -0
- package/dist/esm/src/tracking/SITrackingProvider.js +82 -0
- package/dist/esm/src/tracking/SITrackingProvider.js.map +1 -0
- package/dist/esm/src/tracking/hooks.d.ts +112 -0
- package/dist/esm/src/tracking/hooks.d.ts.map +1 -0
- package/dist/esm/src/tracking/hooks.js +215 -0
- package/dist/esm/src/tracking/hooks.js.map +1 -0
- package/dist/esm/src/tracking/index.d.ts +48 -0
- package/dist/esm/src/tracking/index.d.ts.map +1 -0
- package/dist/esm/src/tracking/index.js +51 -0
- package/dist/esm/src/tracking/index.js.map +1 -0
- package/dist/esm/src/tracking/tracker.d.ts +121 -0
- package/dist/esm/src/tracking/tracker.d.ts.map +1 -0
- package/dist/esm/src/tracking/tracker.js +284 -0
- package/dist/esm/src/tracking/tracker.js.map +1 -0
- package/package.json +14 -4
- package/src/claude/agents/si-mcp.md +136 -0
- package/src/claude/agents/si-react.md +136 -0
- package/src/claude/agents/si-tools.md +109 -0
- package/src/claude/skills/si-add-provider/SKILL.md +88 -0
- package/src/claude/skills/si-add-tool/SKILL.md +66 -0
- package/src/claude/skills/si-setup-mcp-oss/SKILL.md +115 -0
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supernal Interface Interaction Tracking
|
|
3
|
+
*
|
|
4
|
+
* Tracks user interactions with SI components for analytics and AI analysis.
|
|
5
|
+
* Batches events to minimize network requests and handles offline gracefully.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* SI Tracker - Core tracking class
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const tracker = new SITracker({ endpoint: '/api/analytics' });
|
|
15
|
+
* tracker.track('PostCard', 'view', 'post-123');
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export class SITracker {
|
|
19
|
+
constructor(config = {}) {
|
|
20
|
+
this.queue = [];
|
|
21
|
+
this.flushInterval = null;
|
|
22
|
+
this.engagementSessions = new Map();
|
|
23
|
+
this.scrollState = {
|
|
24
|
+
maxDepth: 0,
|
|
25
|
+
lastReportedDepth: 0,
|
|
26
|
+
lastUpdateTime: Date.now(),
|
|
27
|
+
};
|
|
28
|
+
this.userId = null;
|
|
29
|
+
this.config = {
|
|
30
|
+
endpoint: config.endpoint ?? '/api/v1/analytics',
|
|
31
|
+
batchSize: config.batchSize ?? 10,
|
|
32
|
+
flushIntervalMs: config.flushIntervalMs ?? 5000,
|
|
33
|
+
minEngagementMs: config.minEngagementMs ?? 3000,
|
|
34
|
+
scrollDebounceMs: config.scrollDebounceMs ?? 500,
|
|
35
|
+
debug: config.debug ?? false,
|
|
36
|
+
customFetch: config.customFetch ?? fetch,
|
|
37
|
+
};
|
|
38
|
+
this.isClient = typeof window !== 'undefined';
|
|
39
|
+
this.sessionId = this.generateSessionId();
|
|
40
|
+
if (this.isClient) {
|
|
41
|
+
this.startFlushInterval();
|
|
42
|
+
this.setupBeforeUnload();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/** Generate a unique session ID */
|
|
46
|
+
generateSessionId() {
|
|
47
|
+
if (!this.isClient)
|
|
48
|
+
return 'server-session';
|
|
49
|
+
// Try to reuse session ID from sessionStorage
|
|
50
|
+
const stored = sessionStorage.getItem('si_session_id');
|
|
51
|
+
if (stored)
|
|
52
|
+
return stored;
|
|
53
|
+
const id = `si_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 9)}`;
|
|
54
|
+
sessionStorage.setItem('si_session_id', id);
|
|
55
|
+
return id;
|
|
56
|
+
}
|
|
57
|
+
/** Log debug message */
|
|
58
|
+
log(...args) {
|
|
59
|
+
if (this.config.debug) {
|
|
60
|
+
console.log('[SI Tracking]', ...args);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/** Set the current user ID for tracking */
|
|
64
|
+
setUserId(userId) {
|
|
65
|
+
this.userId = userId;
|
|
66
|
+
}
|
|
67
|
+
/** Get current session ID */
|
|
68
|
+
getSessionId() {
|
|
69
|
+
return this.sessionId;
|
|
70
|
+
}
|
|
71
|
+
/** Get queue length (for testing) */
|
|
72
|
+
getQueueLength() {
|
|
73
|
+
return this.queue.length;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Track an interaction
|
|
77
|
+
*/
|
|
78
|
+
track(componentId, action, targetId, metadata) {
|
|
79
|
+
if (!this.isClient)
|
|
80
|
+
return;
|
|
81
|
+
const interaction = {
|
|
82
|
+
componentId,
|
|
83
|
+
action,
|
|
84
|
+
targetId,
|
|
85
|
+
metadata,
|
|
86
|
+
timestamp: Date.now(),
|
|
87
|
+
sessionId: this.sessionId,
|
|
88
|
+
};
|
|
89
|
+
this.queue.push(interaction);
|
|
90
|
+
this.log('Queued:', action, targetId);
|
|
91
|
+
// Flush if queue is full
|
|
92
|
+
if (this.queue.length >= this.config.batchSize) {
|
|
93
|
+
this.flush();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/** Alias for track - for click events */
|
|
97
|
+
trackClick(componentId, action, targetId, metadata) {
|
|
98
|
+
this.track(componentId, action, targetId, metadata);
|
|
99
|
+
}
|
|
100
|
+
/** Track view (impression) of a component */
|
|
101
|
+
trackView(componentId, targetId) {
|
|
102
|
+
this.track(componentId, 'view', targetId);
|
|
103
|
+
}
|
|
104
|
+
/** Start engagement tracking for a target */
|
|
105
|
+
startEngagement(targetId) {
|
|
106
|
+
if (!this.isClient)
|
|
107
|
+
return;
|
|
108
|
+
this.engagementSessions.set(targetId, {
|
|
109
|
+
targetId,
|
|
110
|
+
startTime: Date.now(),
|
|
111
|
+
scrollDepth: 0,
|
|
112
|
+
interactions: 0,
|
|
113
|
+
});
|
|
114
|
+
this.log('Engagement started:', targetId);
|
|
115
|
+
}
|
|
116
|
+
/** Record an interaction during engagement */
|
|
117
|
+
recordEngagementInteraction(targetId) {
|
|
118
|
+
const session = this.engagementSessions.get(targetId);
|
|
119
|
+
if (session) {
|
|
120
|
+
session.interactions++;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/** Update scroll depth for engagement session */
|
|
124
|
+
updateEngagementScrollDepth(targetId, depth) {
|
|
125
|
+
const session = this.engagementSessions.get(targetId);
|
|
126
|
+
if (session && depth > session.scrollDepth) {
|
|
127
|
+
session.scrollDepth = depth;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/** End engagement tracking and log the session */
|
|
131
|
+
endEngagement(targetId, componentId = 'Content') {
|
|
132
|
+
if (!this.isClient)
|
|
133
|
+
return;
|
|
134
|
+
const session = this.engagementSessions.get(targetId);
|
|
135
|
+
if (!session)
|
|
136
|
+
return;
|
|
137
|
+
const duration = Date.now() - session.startTime;
|
|
138
|
+
// Only track if engagement was meaningful
|
|
139
|
+
if (duration >= this.config.minEngagementMs) {
|
|
140
|
+
this.track(componentId, 'view', targetId, {
|
|
141
|
+
engagementDuration: duration,
|
|
142
|
+
scrollDepth: session.scrollDepth,
|
|
143
|
+
interactions: session.interactions,
|
|
144
|
+
});
|
|
145
|
+
this.log('Engagement ended:', targetId, { duration, ...session });
|
|
146
|
+
}
|
|
147
|
+
this.engagementSessions.delete(targetId);
|
|
148
|
+
}
|
|
149
|
+
/** Track scroll depth in feed */
|
|
150
|
+
trackScrollDepth(depth, componentId = 'Feed') {
|
|
151
|
+
if (!this.isClient)
|
|
152
|
+
return;
|
|
153
|
+
const now = Date.now();
|
|
154
|
+
// Only update if depth increased
|
|
155
|
+
if (depth > this.scrollState.maxDepth) {
|
|
156
|
+
this.scrollState.maxDepth = depth;
|
|
157
|
+
}
|
|
158
|
+
// Debounce reporting
|
|
159
|
+
if (now - this.scrollState.lastUpdateTime < this.config.scrollDebounceMs) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
// Report at 25%, 50%, 75%, 100% milestones
|
|
163
|
+
const milestones = [25, 50, 75, 100];
|
|
164
|
+
const currentMilestone = milestones.find((m) => this.scrollState.maxDepth >= m && this.scrollState.lastReportedDepth < m);
|
|
165
|
+
if (currentMilestone) {
|
|
166
|
+
this.track(componentId, 'scroll', undefined, {
|
|
167
|
+
depth: currentMilestone,
|
|
168
|
+
maxDepth: this.scrollState.maxDepth,
|
|
169
|
+
});
|
|
170
|
+
this.scrollState.lastReportedDepth = currentMilestone;
|
|
171
|
+
this.log('Scroll milestone:', currentMilestone);
|
|
172
|
+
}
|
|
173
|
+
this.scrollState.lastUpdateTime = now;
|
|
174
|
+
}
|
|
175
|
+
/** Reset scroll tracking (e.g., on page navigation) */
|
|
176
|
+
resetScrollTracking() {
|
|
177
|
+
this.scrollState = {
|
|
178
|
+
maxDepth: 0,
|
|
179
|
+
lastReportedDepth: 0,
|
|
180
|
+
lastUpdateTime: Date.now(),
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
/** Start periodic flush interval */
|
|
184
|
+
startFlushInterval() {
|
|
185
|
+
if (this.flushInterval)
|
|
186
|
+
return;
|
|
187
|
+
this.flushInterval = setInterval(() => {
|
|
188
|
+
this.flush();
|
|
189
|
+
}, this.config.flushIntervalMs);
|
|
190
|
+
}
|
|
191
|
+
/** Stop flush interval */
|
|
192
|
+
stopFlushInterval() {
|
|
193
|
+
if (this.flushInterval) {
|
|
194
|
+
clearInterval(this.flushInterval);
|
|
195
|
+
this.flushInterval = null;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/** Setup beforeunload handler to flush remaining events */
|
|
199
|
+
setupBeforeUnload() {
|
|
200
|
+
window.addEventListener('beforeunload', () => {
|
|
201
|
+
// End all engagement sessions
|
|
202
|
+
for (const targetId of this.engagementSessions.keys()) {
|
|
203
|
+
this.endEngagement(targetId);
|
|
204
|
+
}
|
|
205
|
+
// Use sendBeacon for reliable delivery
|
|
206
|
+
this.flushWithBeacon();
|
|
207
|
+
});
|
|
208
|
+
// Also handle visibility change for mobile
|
|
209
|
+
document.addEventListener('visibilitychange', () => {
|
|
210
|
+
if (document.visibilityState === 'hidden') {
|
|
211
|
+
this.flushWithBeacon();
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
/** Flush queued events to the API */
|
|
216
|
+
async flush() {
|
|
217
|
+
if (!this.isClient || this.queue.length === 0)
|
|
218
|
+
return;
|
|
219
|
+
const events = [...this.queue];
|
|
220
|
+
this.queue = [];
|
|
221
|
+
this.log('Flushing', events.length, 'events');
|
|
222
|
+
try {
|
|
223
|
+
const response = await this.config.customFetch(this.config.endpoint, {
|
|
224
|
+
method: 'POST',
|
|
225
|
+
headers: {
|
|
226
|
+
'Content-Type': 'application/json',
|
|
227
|
+
},
|
|
228
|
+
body: JSON.stringify({
|
|
229
|
+
events,
|
|
230
|
+
userId: this.userId,
|
|
231
|
+
}),
|
|
232
|
+
});
|
|
233
|
+
if (!response.ok) {
|
|
234
|
+
// Re-queue events on failure (with limit to prevent infinite growth)
|
|
235
|
+
if (this.queue.length < this.config.batchSize * 3) {
|
|
236
|
+
this.queue.unshift(...events);
|
|
237
|
+
}
|
|
238
|
+
this.log('Flush failed, re-queued');
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
catch (error) {
|
|
242
|
+
// Re-queue events on network error
|
|
243
|
+
if (this.queue.length < this.config.batchSize * 3) {
|
|
244
|
+
this.queue.unshift(...events);
|
|
245
|
+
}
|
|
246
|
+
console.warn('[SI Tracking] Failed to flush events:', error);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/** Flush using sendBeacon (for unload events) */
|
|
250
|
+
flushWithBeacon() {
|
|
251
|
+
if (!this.isClient || this.queue.length === 0)
|
|
252
|
+
return;
|
|
253
|
+
const events = [...this.queue];
|
|
254
|
+
this.queue = [];
|
|
255
|
+
try {
|
|
256
|
+
const blob = new Blob([JSON.stringify({ events, userId: this.userId })], {
|
|
257
|
+
type: 'application/json',
|
|
258
|
+
});
|
|
259
|
+
navigator.sendBeacon(this.config.endpoint, blob);
|
|
260
|
+
this.log('Beacon sent', events.length, 'events');
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
console.warn('[SI Tracking] Beacon failed:', error);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/** Cleanup (for testing or unmounting) */
|
|
267
|
+
destroy() {
|
|
268
|
+
this.stopFlushInterval();
|
|
269
|
+
this.flush();
|
|
270
|
+
this.engagementSessions.clear();
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Create a singleton tracker instance
|
|
275
|
+
*
|
|
276
|
+
* @example
|
|
277
|
+
* ```typescript
|
|
278
|
+
* export const tracker = createTracker({ endpoint: '/api/analytics' });
|
|
279
|
+
* ```
|
|
280
|
+
*/
|
|
281
|
+
export function createTracker(config) {
|
|
282
|
+
return new SITracker(config);
|
|
283
|
+
}
|
|
284
|
+
//# sourceMappingURL=tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tracker.js","sourceRoot":"","sources":["../../../../src/tracking/tracker.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAiFH;;;;;;;;GAQG;AACH,MAAM,OAAO,SAAS;IAcpB,YAAY,SAA0B,EAAE;QAbhC,UAAK,GAA6B,EAAE,CAAC;QAErC,kBAAa,GAA0C,IAAI,CAAC;QAC5D,uBAAkB,GAAmC,IAAI,GAAG,EAAE,CAAC;QAC/D,gBAAW,GAAgB;YACjC,QAAQ,EAAE,CAAC;YACX,iBAAiB,EAAE,CAAC;YACpB,cAAc,EAAE,IAAI,CAAC,GAAG,EAAE;SAC3B,CAAC;QAEM,WAAM,GAAkB,IAAI,CAAC;QAInC,IAAI,CAAC,MAAM,GAAG;YACZ,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,mBAAmB;YAChD,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,EAAE;YACjC,eAAe,EAAE,MAAM,CAAC,eAAe,IAAI,IAAI;YAC/C,eAAe,EAAE,MAAM,CAAC,eAAe,IAAI,IAAI;YAC/C,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,IAAI,GAAG;YAChD,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,KAAK;YAC5B,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,KAAK;SACzC,CAAC;QAEF,IAAI,CAAC,QAAQ,GAAG,OAAO,MAAM,KAAK,WAAW,CAAC;QAC9C,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAE1C,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC1B,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,mCAAmC;IAC3B,iBAAiB;QACvB,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAO,gBAAgB,CAAC;QAE5C,8CAA8C;QAC9C,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QACvD,IAAI,MAAM;YAAE,OAAO,MAAM,CAAC;QAE1B,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;QACrF,cAAc,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC,CAAC;QAC5C,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,wBAAwB;IAChB,GAAG,CAAC,GAAG,IAAe;QAC5B,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YACtB,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,GAAG,IAAI,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IAED,2CAA2C;IAC3C,SAAS,CAAC,MAAqB;QAC7B,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,6BAA6B;IAC7B,YAAY;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,qCAAqC;IACrC,cAAc;QACZ,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,KAAK,CACH,WAAmB,EACnB,MAAe,EACf,QAAiB,EACjB,QAAkC;QAElC,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAO;QAE3B,MAAM,WAAW,GAA2B;YAC1C,WAAW;YACX,MAAM;YACN,QAAQ;YACR,QAAQ;YACR,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B,CAAC;QAEF,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QAC7B,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;QAEtC,yBAAyB;QACzB,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;YAC/C,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,CAAC;IACH,CAAC;IAED,yCAAyC;IACzC,UAAU,CACR,WAAmB,EACnB,MAAe,EACf,QAAiB,EACjB,QAAkC;QAElC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACtD,CAAC;IAED,6CAA6C;IAC7C,SAAS,CAAC,WAAmB,EAAE,QAAiB;QAC9C,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,MAAiB,EAAE,QAAQ,CAAC,CAAC;IACvD,CAAC;IAED,6CAA6C;IAC7C,eAAe,CAAC,QAAgB;QAC9B,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAO;QAE3B,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,QAAQ,EAAE;YACpC,QAAQ;YACR,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,WAAW,EAAE,CAAC;YACd,YAAY,EAAE,CAAC;SAChB,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,qBAAqB,EAAE,QAAQ,CAAC,CAAC;IAC5C,CAAC;IAED,8CAA8C;IAC9C,2BAA2B,CAAC,QAAgB;QAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACtD,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,CAAC,YAAY,EAAE,CAAC;QACzB,CAAC;IACH,CAAC;IAED,iDAAiD;IACjD,2BAA2B,CAAC,QAAgB,EAAE,KAAa;QACzD,MAAM,OAAO,GAAG,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACtD,IAAI,OAAO,IAAI,KAAK,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;YAC3C,OAAO,CAAC,WAAW,GAAG,KAAK,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,kDAAkD;IAClD,aAAa,CAAC,QAAgB,EAAE,WAAW,GAAG,SAAS;QACrD,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAO;QAE3B,MAAM,OAAO,GAAG,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACtD,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,SAAS,CAAC;QAEhD,0CAA0C;QAC1C,IAAI,QAAQ,IAAI,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC;YAC5C,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,MAAiB,EAAE,QAAQ,EAAE;gBACnD,kBAAkB,EAAE,QAAQ;gBAC5B,WAAW,EAAE,OAAO,CAAC,WAAW;gBAChC,YAAY,EAAE,OAAO,CAAC,YAAY;aACnC,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,mBAAmB,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;QACpE,CAAC;QAED,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC3C,CAAC;IAED,iCAAiC;IACjC,gBAAgB,CAAC,KAAa,EAAE,WAAW,GAAG,MAAM;QAClD,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAO;QAE3B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEvB,iCAAiC;QACjC,IAAI,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;YACtC,IAAI,CAAC,WAAW,CAAC,QAAQ,GAAG,KAAK,CAAC;QACpC,CAAC;QAED,qBAAqB;QACrB,IAAI,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC;YACzE,OAAO;QACT,CAAC;QAED,2CAA2C;QAC3C,MAAM,UAAU,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;QACrC,MAAM,gBAAgB,GAAG,UAAU,CAAC,IAAI,CACtC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,QAAQ,IAAI,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,iBAAiB,GAAG,CAAC,CAChF,CAAC;QAEF,IAAI,gBAAgB,EAAE,CAAC;YACrB,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,QAAmB,EAAE,SAAS,EAAE;gBACtD,KAAK,EAAE,gBAAgB;gBACvB,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ;aACpC,CAAC,CAAC;YACH,IAAI,CAAC,WAAW,CAAC,iBAAiB,GAAG,gBAAgB,CAAC;YACtD,IAAI,CAAC,GAAG,CAAC,mBAAmB,EAAE,gBAAgB,CAAC,CAAC;QAClD,CAAC;QAED,IAAI,CAAC,WAAW,CAAC,cAAc,GAAG,GAAG,CAAC;IACxC,CAAC;IAED,uDAAuD;IACvD,mBAAmB;QACjB,IAAI,CAAC,WAAW,GAAG;YACjB,QAAQ,EAAE,CAAC;YACX,iBAAiB,EAAE,CAAC;YACpB,cAAc,EAAE,IAAI,CAAC,GAAG,EAAE;SAC3B,CAAC;IACJ,CAAC;IAED,oCAAoC;IAC5B,kBAAkB;QACxB,IAAI,IAAI,CAAC,aAAa;YAAE,OAAO;QAE/B,IAAI,CAAC,aAAa,GAAG,WAAW,CAAC,GAAG,EAAE;YACpC,IAAI,CAAC,KAAK,EAAE,CAAC;QACf,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC;IAClC,CAAC;IAED,0BAA0B;IAClB,iBAAiB;QACvB,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,aAAa,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YAClC,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,2DAA2D;IACnD,iBAAiB;QACvB,MAAM,CAAC,gBAAgB,CAAC,cAAc,EAAE,GAAG,EAAE;YAC3C,8BAA8B;YAC9B,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,kBAAkB,CAAC,IAAI,EAAE,EAAE,CAAC;gBACtD,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;YAC/B,CAAC;YAED,uCAAuC;YACvC,IAAI,CAAC,eAAe,EAAE,CAAC;QACzB,CAAC,CAAC,CAAC;QAEH,2CAA2C;QAC3C,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,GAAG,EAAE;YACjD,IAAI,QAAQ,CAAC,eAAe,KAAK,QAAQ,EAAE,CAAC;gBAC1C,IAAI,CAAC,eAAe,EAAE,CAAC;YACzB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAED,qCAAqC;IACrC,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAEtD,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/B,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;QAEhB,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAE9C,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE;gBACnE,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;iBACnC;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,MAAM;oBACN,MAAM,EAAE,IAAI,CAAC,MAAM;iBACpB,CAAC;aACH,CAAC,CAAC;YAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,qEAAqE;gBACrE,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,CAAC,EAAE,CAAC;oBAClD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC;gBAChC,CAAC;gBACD,IAAI,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;YACtC,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,mCAAmC;YACnC,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,CAAC,EAAE,CAAC;gBAClD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC,CAAC;YAChC,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,uCAAuC,EAAE,KAAK,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;IAED,iDAAiD;IACzC,eAAe;QACrB,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAEtD,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/B,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;QAEhB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE;gBACvE,IAAI,EAAE,kBAAkB;aACzB,CAAC,CAAC;YACH,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YACjD,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACnD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;IAED,0CAA0C;IAC1C,OAAO;QACL,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACzB,IAAI,CAAC,KAAK,EAAE,CAAC;QACb,IAAI,CAAC,kBAAkB,CAAC,KAAK,EAAE,CAAC;IAClC,CAAC;CACF;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAC3B,MAAwB;IAExB,OAAO,IAAI,SAAS,CAAU,MAAM,CAAC,CAAC;AACxC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@supernal/interface",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Universal AI Interface - Make any application AI-controllable with decorators (Open Source Edition)",
|
|
5
5
|
"main": "./dist/cjs/src/index.js",
|
|
6
6
|
"module": "./dist/esm/src/index.js",
|
|
@@ -61,6 +61,11 @@
|
|
|
61
61
|
"types": "./dist/esm/src/storage/index.d.ts",
|
|
62
62
|
"import": "./dist/esm/src/storage/index.js",
|
|
63
63
|
"require": "./dist/cjs/src/storage/index.js"
|
|
64
|
+
},
|
|
65
|
+
"./tracking": {
|
|
66
|
+
"types": "./dist/esm/src/tracking/index.d.ts",
|
|
67
|
+
"import": "./dist/esm/src/tracking/index.js",
|
|
68
|
+
"require": "./dist/cjs/src/tracking/index.js"
|
|
64
69
|
}
|
|
65
70
|
},
|
|
66
71
|
"scripts": {
|
|
@@ -123,9 +128,9 @@
|
|
|
123
128
|
"@types/node": "^25.0.2",
|
|
124
129
|
"@types/react": "^19.2.7",
|
|
125
130
|
"@types/react-dom": "^19.2.3",
|
|
126
|
-
"@typescript-eslint/eslint-plugin": "^
|
|
127
|
-
"@typescript-eslint/parser": "^
|
|
128
|
-
"eslint": "^
|
|
131
|
+
"@typescript-eslint/eslint-plugin": "^8.32.0",
|
|
132
|
+
"@typescript-eslint/parser": "^8.32.0",
|
|
133
|
+
"eslint": "^9.26.0",
|
|
129
134
|
"eslint-plugin-react": "^7.37.5",
|
|
130
135
|
"jest": "^29.7.0",
|
|
131
136
|
"jest-environment-jsdom": "^29.7.0",
|
|
@@ -135,8 +140,13 @@
|
|
|
135
140
|
"ts-jest": "^29.4.6",
|
|
136
141
|
"typescript": "^5.3.2"
|
|
137
142
|
},
|
|
143
|
+
"bin": {
|
|
144
|
+
"si-oss": "./dist/cjs/src/cli/upgrade.js",
|
|
145
|
+
"supernal-upgrade": "./dist/cjs/src/cli/upgrade.js"
|
|
146
|
+
},
|
|
138
147
|
"files": [
|
|
139
148
|
"dist",
|
|
149
|
+
"src/claude",
|
|
140
150
|
"README.md",
|
|
141
151
|
"LICENSE"
|
|
142
152
|
],
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: si-mcp
|
|
3
|
+
description: Help setting up MCP (Model Context Protocol) server for AI assistant integration. Free and open source.
|
|
4
|
+
tools: Read, Write, Edit, Bash(npm *), Bash(node *)
|
|
5
|
+
model: sonnet
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Supernal Interface MCP Agent
|
|
9
|
+
|
|
10
|
+
You are a specialist in setting up MCP (Model Context Protocol) servers with `@supernal/interface`.
|
|
11
|
+
|
|
12
|
+
## Your Role
|
|
13
|
+
|
|
14
|
+
Help users expose their @Tool decorated functions to AI assistants via MCP:
|
|
15
|
+
1. Create an MCP server configuration
|
|
16
|
+
2. Register with Claude Desktop or Cursor
|
|
17
|
+
3. Test the connection
|
|
18
|
+
4. Debug common issues
|
|
19
|
+
|
|
20
|
+
## What is MCP?
|
|
21
|
+
|
|
22
|
+
MCP allows AI assistants to call functions in your application. When you set up an MCP server, Claude Desktop (or other MCP clients) can execute your @Tool functions.
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install @supernal/interface
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## MCP Server Setup
|
|
31
|
+
|
|
32
|
+
### 1. Create Server File
|
|
33
|
+
|
|
34
|
+
```javascript
|
|
35
|
+
// mcp-server.js
|
|
36
|
+
const { createMCPServer } = require('@supernal/interface/mcp-server');
|
|
37
|
+
|
|
38
|
+
// Import your tools
|
|
39
|
+
const { MyTools } = require('./dist/tools');
|
|
40
|
+
|
|
41
|
+
const server = createMCPServer({
|
|
42
|
+
name: 'my-app-tools',
|
|
43
|
+
version: '1.0.0',
|
|
44
|
+
tools: [MyTools]
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
server.start();
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 2. Add npm Script
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"scripts": {
|
|
55
|
+
"mcp": "node mcp-server.js",
|
|
56
|
+
"mcp:debug": "DEBUG=mcp:* node mcp-server.js"
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 3. Configure Claude Desktop
|
|
62
|
+
|
|
63
|
+
**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
64
|
+
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
{
|
|
68
|
+
"mcpServers": {
|
|
69
|
+
"my-app": {
|
|
70
|
+
"command": "node",
|
|
71
|
+
"args": ["/path/to/your/project/mcp-server.js"],
|
|
72
|
+
"env": {}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 4. Configure Cursor IDE
|
|
79
|
+
|
|
80
|
+
**macOS**: `~/.cursor/mcp.json`
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"mcpServers": {
|
|
85
|
+
"my-app": {
|
|
86
|
+
"command": "node",
|
|
87
|
+
"args": ["/path/to/your/project/mcp-server.js"]
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## Testing
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
# Run server manually to test
|
|
97
|
+
npm run mcp:debug
|
|
98
|
+
|
|
99
|
+
# You should see:
|
|
100
|
+
# mcp:server Starting MCP server...
|
|
101
|
+
# mcp:server Registered 5 tools
|
|
102
|
+
# mcp:server Server ready
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Troubleshooting
|
|
106
|
+
|
|
107
|
+
### "Server not found"
|
|
108
|
+
- Check the path in config is absolute
|
|
109
|
+
- Ensure mcp-server.js exists and is executable
|
|
110
|
+
- Restart Claude Desktop after config changes
|
|
111
|
+
|
|
112
|
+
### "No tools registered"
|
|
113
|
+
- Verify @Tool decorators are on exported functions
|
|
114
|
+
- Check imports in mcp-server.js
|
|
115
|
+
- Add DEBUG=mcp:* to see registration logs
|
|
116
|
+
|
|
117
|
+
### "Permission denied"
|
|
118
|
+
- Ensure node has permission to run
|
|
119
|
+
- Check file permissions on mcp-server.js
|
|
120
|
+
|
|
121
|
+
## Enterprise Features
|
|
122
|
+
|
|
123
|
+
For users who need more:
|
|
124
|
+
|
|
125
|
+
> **Want automated MCP setup?** Enterprise `si setup-mcp` command auto-configures Claude Desktop and Cursor with zero manual editing.
|
|
126
|
+
>
|
|
127
|
+
> **Want AI-assisted tool development?** Enterprise includes 12 Claude Code skills for creating and managing tools.
|
|
128
|
+
>
|
|
129
|
+
> **Want comprehensive testing?** Enterprise generates tests from your MCP tools automatically.
|
|
130
|
+
>
|
|
131
|
+
> Install enterprise: `npm install @supernalintelligence/interface-enterprise`
|
|
132
|
+
> Then run: `npx si setup-mcp`
|
|
133
|
+
|
|
134
|
+
## Task
|
|
135
|
+
|
|
136
|
+
Help the user set up an MCP server to expose their tools to AI assistants. Create the server file, configure the IDE, and verify the connection works.
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: si-react
|
|
3
|
+
description: Help integrating Supernal Interface with React/Next.js applications. Free and open source.
|
|
4
|
+
tools: Read, Write, Edit, Glob, Grep
|
|
5
|
+
model: sonnet
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Supernal Interface React Agent
|
|
9
|
+
|
|
10
|
+
You are a specialist in integrating `@supernal/interface` with React and Next.js applications.
|
|
11
|
+
|
|
12
|
+
## Your Role
|
|
13
|
+
|
|
14
|
+
Help users set up the React integration by:
|
|
15
|
+
1. Configuring InterfaceProvider
|
|
16
|
+
2. Using React hooks (useToolBinding, etc.)
|
|
17
|
+
3. Setting up CopilotKit adapter for chat UI
|
|
18
|
+
4. Adding data-testid attributes to components
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install @supernal/interface
|
|
24
|
+
# For chat UI:
|
|
25
|
+
npm install @copilotkit/react-core @copilotkit/react-ui
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Integration Patterns
|
|
29
|
+
|
|
30
|
+
### Basic Provider Setup
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
// src/app/layout.tsx (Next.js App Router)
|
|
34
|
+
'use client';
|
|
35
|
+
|
|
36
|
+
import { InterfaceProvider } from '@supernal/interface/react';
|
|
37
|
+
import { MyTools } from './tools';
|
|
38
|
+
|
|
39
|
+
export default function RootLayout({ children }) {
|
|
40
|
+
return (
|
|
41
|
+
<html>
|
|
42
|
+
<body>
|
|
43
|
+
<InterfaceProvider
|
|
44
|
+
tools={[MyTools]}
|
|
45
|
+
config={{ enabled: true }}
|
|
46
|
+
>
|
|
47
|
+
{children}
|
|
48
|
+
</InterfaceProvider>
|
|
49
|
+
</body>
|
|
50
|
+
</html>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### With CopilotKit Chat UI
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
'use client';
|
|
59
|
+
|
|
60
|
+
import { InterfaceProvider } from '@supernal/interface/react';
|
|
61
|
+
import { CopilotKit } from '@copilotkit/react-core';
|
|
62
|
+
import { CopilotSidebar } from '@copilotkit/react-ui';
|
|
63
|
+
import { useCopilotKitAdapter } from '@supernal/interface/adapters/copilotkit';
|
|
64
|
+
|
|
65
|
+
function AppWithChat({ children }) {
|
|
66
|
+
const { actions } = useCopilotKitAdapter();
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<CopilotKit actions={actions}>
|
|
70
|
+
<CopilotSidebar>
|
|
71
|
+
{children}
|
|
72
|
+
</CopilotSidebar>
|
|
73
|
+
</CopilotKit>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Hook: useToolBinding
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import { useToolBinding } from '@supernal/interface/react';
|
|
82
|
+
|
|
83
|
+
function Counter() {
|
|
84
|
+
const [count, setCount] = useState(0);
|
|
85
|
+
|
|
86
|
+
// Bind tools to this component
|
|
87
|
+
useToolBinding({
|
|
88
|
+
tools: [
|
|
89
|
+
{
|
|
90
|
+
id: 'increment',
|
|
91
|
+
description: 'Add one to counter',
|
|
92
|
+
execute: () => setCount(c => c + 1)
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
return <div>{count}</div>;
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Data-TestID Best Practices
|
|
102
|
+
|
|
103
|
+
Always add data-testid to interactive elements:
|
|
104
|
+
|
|
105
|
+
```tsx
|
|
106
|
+
// Good
|
|
107
|
+
<button data-testid="submit-form">Submit</button>
|
|
108
|
+
<input data-testid="email-input" />
|
|
109
|
+
|
|
110
|
+
// For namespaced components
|
|
111
|
+
<button data-testid="counter-increment">+</button>
|
|
112
|
+
<button data-testid="counter-decrement">-</button>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## When Helping Users
|
|
116
|
+
|
|
117
|
+
1. **Check framework** - Next.js App Router, Pages Router, or plain React
|
|
118
|
+
2. **Set up provider** - At the root layout level
|
|
119
|
+
3. **Add tools** - Either inline or via ToolProvider classes
|
|
120
|
+
4. **Configure chat UI** - If they want CopilotKit integration
|
|
121
|
+
|
|
122
|
+
## Enterprise Features
|
|
123
|
+
|
|
124
|
+
For users who need more:
|
|
125
|
+
|
|
126
|
+
> **Want a built-in chat UI?** Enterprise includes `SupernalProvider` for Next.js with glass-mode overlay chat - no CopilotKit setup required.
|
|
127
|
+
>
|
|
128
|
+
> **Want type-safe contracts?** Enterprise `si` CLI generates Routes.ts and ComponentNames.ts from your codebase.
|
|
129
|
+
>
|
|
130
|
+
> **Want auto-generated tests?** Enterprise generates Playwright tests from your tools and Gherkin features.
|
|
131
|
+
>
|
|
132
|
+
> Install enterprise: `npm install @supernalintelligence/interface-enterprise`
|
|
133
|
+
|
|
134
|
+
## Task
|
|
135
|
+
|
|
136
|
+
Help the user integrate Supernal Interface with their React application. Understand their setup, configure providers, and add tools.
|