handhold-sdk 1.0.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/README.md +427 -0
- package/dist/d44f1fe8001e32f8e74d.svg +3056 -0
- package/dist/fonts/Phosphor.ttf +0 -0
- package/dist/fonts/Phosphor.woff +0 -0
- package/dist/fonts/Phosphor.woff2 +0 -0
- package/dist/handhold.min.js +1 -0
- package/package.json +114 -0
- package/src/HandHold.js +1599 -0
- package/src/agent/VENDOR.md +203 -0
- package/src/agent/agent/AgentLoop.js +366 -0
- package/src/agent/agent/prompts.js +163 -0
- package/src/agent/agent/tools.js +148 -0
- package/src/agent/controller.js +235 -0
- package/src/agent/dom/actions.js +456 -0
- package/src/agent/dom/domTree.js +1761 -0
- package/src/agent/dom/redact.js +98 -0
- package/src/agent/dom/serializer.js +332 -0
- package/src/agent/dom/utils.js +99 -0
- package/src/agent/index.js +169 -0
- package/src/agent/llm/connector.js +143 -0
- package/src/agent/package.json +3 -0
- package/src/agent/policy/PolicyGuard.js +172 -0
- package/src/agent/site/manifest.js +145 -0
- package/src/agent/ui/ChatWidget.js +219 -0
- package/src/agent-mode/AgentMode.js +429 -0
- package/src/api/APIClient.js +258 -0
- package/src/core/Config.js +207 -0
- package/src/core/UiState.js +83 -0
- package/src/core/defaults.js +20 -0
- package/src/events.js +59 -0
- package/src/index.js +77 -0
- package/src/intent/ActionVerbMap.js +324 -0
- package/src/intent/IntentExtractor.js +317 -0
- package/src/observers/ElementScanner.js +284 -0
- package/src/observers/NavigationObserver.js +182 -0
- package/src/observers/PageObserver.js +293 -0
- package/src/session/SessionManager.js +402 -0
- package/src/session/SessionStorage.js +148 -0
- package/src/ui/HelpWidget.js +1189 -0
- package/src/ui/UICoach.js +1725 -0
- package/src/ui/components/Button.css +137 -0
- package/src/ui/components/Button.js +102 -0
- package/src/ui/widget.css +599 -0
- package/src/utils/Logger.js +132 -0
- package/src/utils/MarkdownRenderer.js +39 -0
- package/src/utils/domUtils.js +350 -0
- package/src/utils/eventBus.js +102 -0
- package/src/utils/index.js +8 -0
- package/src/utils/stringUtils.js +202 -0
- package/types/index.d.ts +538 -0
package/README.md
ADDED
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
# Hand Hold SDK
|
|
2
|
+
|
|
3
|
+
**Context-aware, in-app help system with visual UI guidance.**
|
|
4
|
+
|
|
5
|
+
The Hand Hold SDK provides intelligent, contextual help for web applications by:
|
|
6
|
+
- Automatically inferring user intents from page UI elements
|
|
7
|
+
- Searching a knowledge base for relevant guidance
|
|
8
|
+
- Highlighting specific UI elements users should interact with
|
|
9
|
+
- Tracking multi-page workflows with persistent session state
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- 🎯 **Intent Detection** - Rule-based intent extraction from buttons, links, and interactive elements
|
|
14
|
+
- 📚 **Knowledge Base Integration** - RAG-powered search for relevant help articles
|
|
15
|
+
- 🎨 **Visual Guidance** - Element highlighting with arrows, tooltips, and overlay dimming
|
|
16
|
+
- 🔄 **Multi-Page Tracking** - Session persistence across page navigations
|
|
17
|
+
- 💬 **Conversational Fallback** - LLM-powered intent extraction for free-text queries
|
|
18
|
+
- 🌙 **Theme Support** - Light and dark modes
|
|
19
|
+
- âš¡ **Zero Configuration** - Works across any frontend framework
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
### NPM
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm install handhold-sdk
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### CDN
|
|
30
|
+
|
|
31
|
+
```html
|
|
32
|
+
<!-- Production (minified) -->
|
|
33
|
+
<script src="https://cdn.handhold.com/v1/handhold.min.js"></script>
|
|
34
|
+
|
|
35
|
+
<!-- Development (unminified with source maps) -->
|
|
36
|
+
<script src="https://cdn.handhold.com/v1/handhold.js"></script>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Auto-Initialization (CDN)
|
|
40
|
+
|
|
41
|
+
```html
|
|
42
|
+
<script
|
|
43
|
+
src="https://cdn.handhold.com/v1/handhold.min.js"
|
|
44
|
+
data-handhold-api-key="your-api-key"
|
|
45
|
+
data-handhold-base-url="https://api.yourserver.com"
|
|
46
|
+
data-handhold-theme="light"
|
|
47
|
+
data-handhold-position="bottom-right"
|
|
48
|
+
data-handhold-debug="false">
|
|
49
|
+
</script>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Quick Start
|
|
53
|
+
|
|
54
|
+
### ES Module
|
|
55
|
+
|
|
56
|
+
```javascript
|
|
57
|
+
import HandHold from 'handhold-sdk';
|
|
58
|
+
|
|
59
|
+
await HandHold.init({
|
|
60
|
+
apiKey: 'your-api-key',
|
|
61
|
+
baseUrl: 'https://api.yourserver.com',
|
|
62
|
+
theme: 'light',
|
|
63
|
+
position: 'bottom-right'
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Script Tag
|
|
68
|
+
|
|
69
|
+
```html
|
|
70
|
+
<script src="handhold.min.js"></script>
|
|
71
|
+
<script>
|
|
72
|
+
HandHold.init({
|
|
73
|
+
apiKey: 'your-api-key',
|
|
74
|
+
baseUrl: 'https://api.yourserver.com'
|
|
75
|
+
}).then(() => {
|
|
76
|
+
console.log('Hand Hold ready!');
|
|
77
|
+
});
|
|
78
|
+
</script>
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Configuration
|
|
82
|
+
|
|
83
|
+
| Option | Type | Default | Description |
|
|
84
|
+
|--------|------|---------|-------------|
|
|
85
|
+
| `apiKey` | string | **required** | API key for authentication |
|
|
86
|
+
| `baseUrl` | string | **required** | Backend API base URL |
|
|
87
|
+
| `theme` | string | `'light'` | UI theme: `'light'` or `'dark'` |
|
|
88
|
+
| `position` | string | `'bottom-right'` | Widget position: `'bottom-right'`, `'bottom-left'`, `'top-right'`, `'top-left'` |
|
|
89
|
+
| `primaryColor` | string | `'#2196F3'` | Primary accent color (hex) |
|
|
90
|
+
| `zIndex` | number | `999999` | Z-index for overlays |
|
|
91
|
+
| `minHighlightConfidence` | number | `0.85` | Minimum confidence to highlight elements (0-1) |
|
|
92
|
+
| `sessionInactivityTimeout` | number | `600000` | Session timeout in ms (default: 10 min) |
|
|
93
|
+
| `enableMultiPageTracking` | boolean | `true` | Enable cross-page session tracking |
|
|
94
|
+
| `showHelpButton` | boolean | `true` | Show floating help button |
|
|
95
|
+
| `maxIntents` | number | `6` | Maximum intents to display |
|
|
96
|
+
| `apiTimeout` | number | `30000` | API request timeout in ms |
|
|
97
|
+
| `retryAttempts` | number | `3` | Number of retry attempts for API calls |
|
|
98
|
+
| `debug` | boolean | `false` | Enable debug logging |
|
|
99
|
+
| `logLevel` | string | `'warn'` | Log level: `'error'`, `'warn'`, `'info'`, `'debug'` |
|
|
100
|
+
|
|
101
|
+
## API Reference
|
|
102
|
+
|
|
103
|
+
### Initialization
|
|
104
|
+
|
|
105
|
+
```javascript
|
|
106
|
+
await HandHold.init(options);
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Initialize the SDK with configuration options. Must be called before using any other methods.
|
|
110
|
+
|
|
111
|
+
### Widget Control
|
|
112
|
+
|
|
113
|
+
```javascript
|
|
114
|
+
// Open the help widget
|
|
115
|
+
HandHold.open();
|
|
116
|
+
|
|
117
|
+
// Close the help widget
|
|
118
|
+
HandHold.close();
|
|
119
|
+
|
|
120
|
+
// Toggle the help widget
|
|
121
|
+
HandHold.toggle();
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Programmatic Guidance
|
|
125
|
+
|
|
126
|
+
```javascript
|
|
127
|
+
// Start guidance for a specific intent
|
|
128
|
+
await HandHold.startGuidance('approve_payroll');
|
|
129
|
+
|
|
130
|
+
// Get available intents for current page
|
|
131
|
+
const intents = HandHold.getIntents();
|
|
132
|
+
// Returns: [{ key: 'approve_payroll', label: 'Approve Payroll', confidence: 0.95 }, ...]
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Session Management
|
|
136
|
+
|
|
137
|
+
```javascript
|
|
138
|
+
// Check if there's an active session
|
|
139
|
+
const hasSession = HandHold.hasActiveSession();
|
|
140
|
+
|
|
141
|
+
// Get the active session
|
|
142
|
+
const session = HandHold.getActiveSession();
|
|
143
|
+
|
|
144
|
+
// Get session progress (0-100)
|
|
145
|
+
const progress = HandHold.getProgress();
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Events
|
|
149
|
+
|
|
150
|
+
```javascript
|
|
151
|
+
// Subscribe to events
|
|
152
|
+
const unsubscribe = HandHold.on('handhold:completed', (data) => {
|
|
153
|
+
console.log('User completed guidance for:', data.intent);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// Unsubscribe
|
|
157
|
+
unsubscribe();
|
|
158
|
+
// or
|
|
159
|
+
HandHold.off('handhold:completed', handler);
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
#### Available Events
|
|
163
|
+
|
|
164
|
+
| Event | Data | Description |
|
|
165
|
+
|-------|------|-------------|
|
|
166
|
+
| `handhold:ready` | - | SDK initialized |
|
|
167
|
+
| `handhold:completed` | `{ intent }` | User completed all steps |
|
|
168
|
+
| `handhold:closed` | `{ intent }` | User closed guidance |
|
|
169
|
+
| `help:open` | - | Help widget opened |
|
|
170
|
+
| `intent:selected` | `intent` | User selected an intent |
|
|
171
|
+
| `step:done` | - | User marked step as done |
|
|
172
|
+
| `navigation:changed` | `{ route, previousRoute }` | Page navigation detected |
|
|
173
|
+
|
|
174
|
+
### Cleanup
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
// Destroy the SDK instance
|
|
178
|
+
HandHold.destroy();
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Utility Methods
|
|
182
|
+
|
|
183
|
+
```javascript
|
|
184
|
+
// Get SDK version
|
|
185
|
+
HandHold.getVersion(); // '1.0.0'
|
|
186
|
+
|
|
187
|
+
// Check if initialized
|
|
188
|
+
HandHold.isInitialized(); // true/false
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## UI Element Detection
|
|
192
|
+
|
|
193
|
+
The SDK automatically detects interactive UI elements using:
|
|
194
|
+
|
|
195
|
+
1. **Stable Selectors** (preferred): `data-testid` attributes
|
|
196
|
+
2. **ARIA Labels**: `aria-label` attributes
|
|
197
|
+
3. **Element IDs**: Unique `id` attributes
|
|
198
|
+
4. **Text Content**: Button/link text
|
|
199
|
+
|
|
200
|
+
### Best Practices for UI Elements
|
|
201
|
+
|
|
202
|
+
```html
|
|
203
|
+
<!-- Recommended: Use data-testid for stable selectors -->
|
|
204
|
+
<button data-testid="approve-payroll">Approve Payroll</button>
|
|
205
|
+
|
|
206
|
+
<!-- Also works: ARIA labels -->
|
|
207
|
+
<button aria-label="Approve payroll for current period">Approve</button>
|
|
208
|
+
|
|
209
|
+
<!-- Falls back to: Text content -->
|
|
210
|
+
<button>Approve Payroll</button>
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Intent Extraction
|
|
214
|
+
|
|
215
|
+
Intents are automatically extracted from UI elements using action verbs:
|
|
216
|
+
|
|
217
|
+
| Verb | Canonical | Example UI Text |
|
|
218
|
+
|------|-----------|-----------------|
|
|
219
|
+
| approve, confirm, accept | `approve` | "Approve Payroll" → `approve_payroll` |
|
|
220
|
+
| create, add, new | `create` | "Add Employee" → `create_employee` |
|
|
221
|
+
| download, export | `download` | "Download Report" → `download_report` |
|
|
222
|
+
| run, execute, process | `run` | "Run Payroll" → `run_payroll` |
|
|
223
|
+
| view, see, show | `view` | "View Details" → `view_details` |
|
|
224
|
+
|
|
225
|
+
## Multi-Page Tracking
|
|
226
|
+
|
|
227
|
+
The SDK tracks user progress across page navigations:
|
|
228
|
+
|
|
229
|
+
1. **Session Persistence**: Sessions are stored in `sessionStorage`
|
|
230
|
+
2. **Element Re-matching**: UI elements are re-matched on new pages
|
|
231
|
+
3. **Flow Detection**: SDK detects if navigation is within the same workflow
|
|
232
|
+
|
|
233
|
+
```javascript
|
|
234
|
+
// Enable multi-page tracking (default: true)
|
|
235
|
+
HandHold.init({
|
|
236
|
+
enableMultiPageTracking: true,
|
|
237
|
+
sessionInactivityTimeout: 600000 // 10 minutes
|
|
238
|
+
});
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Styling & Theming
|
|
242
|
+
|
|
243
|
+
### CSS Variables
|
|
244
|
+
|
|
245
|
+
The SDK injects CSS variables for customization:
|
|
246
|
+
|
|
247
|
+
```css
|
|
248
|
+
:root {
|
|
249
|
+
--handhold-primary: #2196F3;
|
|
250
|
+
--handhold-background: #ffffff;
|
|
251
|
+
--handhold-text: #212121;
|
|
252
|
+
--handhold-text-secondary: #666666;
|
|
253
|
+
--handhold-border: #e0e0e0;
|
|
254
|
+
--handhold-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
|
|
255
|
+
--handhold-z-index: 999999;
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Dark Theme
|
|
260
|
+
|
|
261
|
+
```javascript
|
|
262
|
+
HandHold.init({
|
|
263
|
+
theme: 'dark'
|
|
264
|
+
});
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Custom Colors
|
|
268
|
+
|
|
269
|
+
```javascript
|
|
270
|
+
HandHold.init({
|
|
271
|
+
primaryColor: '#4CAF50' // Green
|
|
272
|
+
});
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Backend Integration
|
|
276
|
+
|
|
277
|
+
The SDK communicates with a backend server via REST API:
|
|
278
|
+
|
|
279
|
+
### Required Endpoints
|
|
280
|
+
|
|
281
|
+
| Endpoint | Method | Description |
|
|
282
|
+
|----------|--------|-------------|
|
|
283
|
+
| `/api/v1/intents/infer` | POST | Validate/cache intents |
|
|
284
|
+
| `/api/v1/intents/extract` | POST | LLM intent extraction |
|
|
285
|
+
| `/api/v1/guidance` | POST | Get step-by-step guidance |
|
|
286
|
+
| `/api/v1/guidance/match-element` | POST | Re-match elements |
|
|
287
|
+
| `/api/v1/guidance/sessions/update` | POST | Update session status |
|
|
288
|
+
| `/api/v1/kb/search` | GET | Search knowledge base |
|
|
289
|
+
|
|
290
|
+
### Authentication
|
|
291
|
+
|
|
292
|
+
All requests include the API key:
|
|
293
|
+
|
|
294
|
+
```
|
|
295
|
+
Authorization: Bearer <api_key>
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
## Error Handling
|
|
299
|
+
|
|
300
|
+
The SDK handles errors gracefully:
|
|
301
|
+
|
|
302
|
+
- **Network Errors**: Retry with exponential backoff
|
|
303
|
+
- **API Errors**: Display user-friendly messages
|
|
304
|
+
- **Element Not Found**: Fall back to text-only guidance
|
|
305
|
+
- **Session Expired**: Prompt user to start new session
|
|
306
|
+
|
|
307
|
+
## Browser Support
|
|
308
|
+
|
|
309
|
+
- Chrome 80+
|
|
310
|
+
- Firefox 75+
|
|
311
|
+
- Safari 13+
|
|
312
|
+
- Edge 80+
|
|
313
|
+
|
|
314
|
+
## Advanced Usage
|
|
315
|
+
|
|
316
|
+
### Custom Integration
|
|
317
|
+
|
|
318
|
+
```javascript
|
|
319
|
+
import {
|
|
320
|
+
Config,
|
|
321
|
+
PageObserver,
|
|
322
|
+
IntentExtractor,
|
|
323
|
+
UICoach,
|
|
324
|
+
EventBus
|
|
325
|
+
} from 'handhold-sdk';
|
|
326
|
+
|
|
327
|
+
// Use individual components
|
|
328
|
+
const observer = new PageObserver(config);
|
|
329
|
+
observer.observe();
|
|
330
|
+
|
|
331
|
+
const pageContext = observer.scanPage();
|
|
332
|
+
const intents = IntentExtractor.extract(pageContext.ui_elements, pageContext.route);
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### Event-Driven Architecture
|
|
336
|
+
|
|
337
|
+
```javascript
|
|
338
|
+
import { EventBus } from 'handhold-sdk';
|
|
339
|
+
|
|
340
|
+
// Subscribe to internal events
|
|
341
|
+
EventBus.on('page:changed', (data) => {
|
|
342
|
+
console.log('Page changed:', data.route);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
EventBus.on('intent:selected', (intent) => {
|
|
346
|
+
analytics.track('help_intent_selected', { intent: intent.key });
|
|
347
|
+
});
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
## File Structure
|
|
351
|
+
|
|
352
|
+
```
|
|
353
|
+
sdk/
|
|
354
|
+
├── src/
|
|
355
|
+
│ ├── api/
|
|
356
|
+
│ │ └── APIClient.js # Backend communication
|
|
357
|
+
│ ├── core/
|
|
358
|
+
│ │ └── Config.js # Configuration management
|
|
359
|
+
│ ├── intent/
|
|
360
|
+
│ │ ├── ActionVerbMap.js # Action verb taxonomy
|
|
361
|
+
│ │ └── IntentExtractor.js # Rule-based intent extraction
|
|
362
|
+
│ ├── observers/
|
|
363
|
+
│ │ ├── ElementScanner.js # UI element scanning
|
|
364
|
+
│ │ ├── NavigationObserver.js # Route change detection
|
|
365
|
+
│ │ └── PageObserver.js # Main page observer
|
|
366
|
+
│ ├── session/
|
|
367
|
+
│ │ ├── SessionManager.js # Session lifecycle
|
|
368
|
+
│ │ └── SessionStorage.js # Storage wrapper
|
|
369
|
+
│ ├── ui/
|
|
370
|
+
│ │ ├── HelpWidget.js # Main widget UI
|
|
371
|
+
│ │ └── UICoach.js # Element highlighting
|
|
372
|
+
│ ├── utils/
|
|
373
|
+
│ │ ├── domUtils.js # DOM utilities
|
|
374
|
+
│ │ ├── eventBus.js # Event system
|
|
375
|
+
│ │ ├── Logger.js # Logging
|
|
376
|
+
│ │ └── stringUtils.js # String processing
|
|
377
|
+
│ ├── HandHold.js # Main orchestrator
|
|
378
|
+
│ └── index.js # Entry point
|
|
379
|
+
├── dist/
|
|
380
|
+
│ ├── handhold.js # Development build
|
|
381
|
+
│ └── handhold.min.js # Production build
|
|
382
|
+
├── examples/
|
|
383
|
+
│ └── basic.html # Demo page
|
|
384
|
+
├── package.json
|
|
385
|
+
├── webpack.config.js
|
|
386
|
+
└── README.md
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
## Development
|
|
390
|
+
|
|
391
|
+
### Building
|
|
392
|
+
|
|
393
|
+
```bash
|
|
394
|
+
# Install dependencies
|
|
395
|
+
npm install
|
|
396
|
+
|
|
397
|
+
# Development build
|
|
398
|
+
npm run build:dev
|
|
399
|
+
|
|
400
|
+
# Production build
|
|
401
|
+
npm run build
|
|
402
|
+
|
|
403
|
+
# Watch mode
|
|
404
|
+
npm run watch
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
### Testing
|
|
408
|
+
|
|
409
|
+
```bash
|
|
410
|
+
npm test
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### Linting
|
|
414
|
+
|
|
415
|
+
```bash
|
|
416
|
+
npm run lint
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
## License
|
|
420
|
+
|
|
421
|
+
MIT © Hand Hold Team
|
|
422
|
+
|
|
423
|
+
## Support
|
|
424
|
+
|
|
425
|
+
- Documentation: https://docs.handhold.com
|
|
426
|
+
- Issues: https://github.com/handhold/sdk/issues
|
|
427
|
+
- Email: support@handhold.com
|