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.
Files changed (50) hide show
  1. package/README.md +427 -0
  2. package/dist/d44f1fe8001e32f8e74d.svg +3056 -0
  3. package/dist/fonts/Phosphor.ttf +0 -0
  4. package/dist/fonts/Phosphor.woff +0 -0
  5. package/dist/fonts/Phosphor.woff2 +0 -0
  6. package/dist/handhold.min.js +1 -0
  7. package/package.json +114 -0
  8. package/src/HandHold.js +1599 -0
  9. package/src/agent/VENDOR.md +203 -0
  10. package/src/agent/agent/AgentLoop.js +366 -0
  11. package/src/agent/agent/prompts.js +163 -0
  12. package/src/agent/agent/tools.js +148 -0
  13. package/src/agent/controller.js +235 -0
  14. package/src/agent/dom/actions.js +456 -0
  15. package/src/agent/dom/domTree.js +1761 -0
  16. package/src/agent/dom/redact.js +98 -0
  17. package/src/agent/dom/serializer.js +332 -0
  18. package/src/agent/dom/utils.js +99 -0
  19. package/src/agent/index.js +169 -0
  20. package/src/agent/llm/connector.js +143 -0
  21. package/src/agent/package.json +3 -0
  22. package/src/agent/policy/PolicyGuard.js +172 -0
  23. package/src/agent/site/manifest.js +145 -0
  24. package/src/agent/ui/ChatWidget.js +219 -0
  25. package/src/agent-mode/AgentMode.js +429 -0
  26. package/src/api/APIClient.js +258 -0
  27. package/src/core/Config.js +207 -0
  28. package/src/core/UiState.js +83 -0
  29. package/src/core/defaults.js +20 -0
  30. package/src/events.js +59 -0
  31. package/src/index.js +77 -0
  32. package/src/intent/ActionVerbMap.js +324 -0
  33. package/src/intent/IntentExtractor.js +317 -0
  34. package/src/observers/ElementScanner.js +284 -0
  35. package/src/observers/NavigationObserver.js +182 -0
  36. package/src/observers/PageObserver.js +293 -0
  37. package/src/session/SessionManager.js +402 -0
  38. package/src/session/SessionStorage.js +148 -0
  39. package/src/ui/HelpWidget.js +1189 -0
  40. package/src/ui/UICoach.js +1725 -0
  41. package/src/ui/components/Button.css +137 -0
  42. package/src/ui/components/Button.js +102 -0
  43. package/src/ui/widget.css +599 -0
  44. package/src/utils/Logger.js +132 -0
  45. package/src/utils/MarkdownRenderer.js +39 -0
  46. package/src/utils/domUtils.js +350 -0
  47. package/src/utils/eventBus.js +102 -0
  48. package/src/utils/index.js +8 -0
  49. package/src/utils/stringUtils.js +202 -0
  50. package/types/index.d.ts +538 -0
@@ -0,0 +1,538 @@
1
+ /**
2
+ * Hand Hold SDK - TypeScript Definitions
3
+ * @version 1.0.0
4
+ */
5
+
6
+ declare module 'handhold-sdk' {
7
+ // ==================== Configuration ====================
8
+
9
+ export interface HandHoldConfig {
10
+ /** API key for authentication (required) */
11
+ apiKey: string;
12
+ /** Backend API base URL (required) */
13
+ baseUrl: string;
14
+ /** UI theme */
15
+ theme?: 'light' | 'dark';
16
+ /** Widget position */
17
+ position?: 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left';
18
+ /** Primary accent color (hex) */
19
+ primaryColor?: string;
20
+ /** Z-index for overlays */
21
+ zIndex?: number;
22
+ /** Minimum confidence to highlight elements (0-1) */
23
+ minHighlightConfidence?: number;
24
+ /** Session timeout in milliseconds */
25
+ sessionInactivityTimeout?: number;
26
+ /** Enable cross-page session tracking */
27
+ enableMultiPageTracking?: boolean;
28
+ /** Show floating help button */
29
+ showHelpButton?: boolean;
30
+ /** Maximum intents to display */
31
+ maxIntents?: number;
32
+ /** API request timeout in milliseconds */
33
+ apiTimeout?: number;
34
+ /** Number of retry attempts for API calls */
35
+ retryAttempts?: number;
36
+ /** Base retry delay in milliseconds */
37
+ retryDelay?: number;
38
+ /** Enable debug logging */
39
+ debug?: boolean;
40
+ /** Log level */
41
+ logLevel?: 'error' | 'warn' | 'info' | 'debug';
42
+ /** Widget title */
43
+ widgetTitle?: string;
44
+ /** Search placeholder text */
45
+ widgetPlaceholder?: string;
46
+ /** Help button text */
47
+ helpButtonText?: string;
48
+ /** Enable client-side caching */
49
+ enableCache?: boolean;
50
+ /** Cache TTL in milliseconds */
51
+ cacheTTL?: number;
52
+ }
53
+
54
+ // ==================== Intent ====================
55
+
56
+ export interface Intent {
57
+ /** Intent key (e.g., 'approve_payroll') */
58
+ key: string;
59
+ /** Human-readable label */
60
+ label: string;
61
+ /** Canonical verb */
62
+ verb?: string;
63
+ /** Object/target of the action */
64
+ object?: string;
65
+ /** Confidence score (0-1) */
66
+ confidence: number;
67
+ /** Original text from UI element */
68
+ original_text?: string;
69
+ /** CSS selector of source element */
70
+ source_element?: string;
71
+ /** Element position on page */
72
+ element_position?: ElementPosition;
73
+ /** Element type (button, link, etc.) */
74
+ element_type?: string;
75
+ }
76
+
77
+ export interface ElementPosition {
78
+ x: number;
79
+ y: number;
80
+ width?: number;
81
+ height?: number;
82
+ }
83
+
84
+ // ==================== Guidance ====================
85
+
86
+ export interface GuidanceStep {
87
+ /** Step order (1-based) */
88
+ order: number;
89
+ /** Step instruction text */
90
+ text: string;
91
+ /** CSS selector for target element */
92
+ selector?: string;
93
+ /** Match confidence (0-1) */
94
+ confidence: number;
95
+ /** How the element was matched */
96
+ match_type?: 'exact' | 'fuzzy' | 'semantic';
97
+ /** Route where this step applies */
98
+ page_route?: string;
99
+ /** Additional UI hint */
100
+ ui_hint?: string;
101
+ }
102
+
103
+ export interface Guidance {
104
+ /** Intent key */
105
+ intent: string;
106
+ /** Brief summary */
107
+ summary: string;
108
+ /** Array of steps */
109
+ steps: GuidanceStep[];
110
+ /** Current step index (0-based) */
111
+ current_step: number;
112
+ /** Total number of steps */
113
+ total_steps: number;
114
+ /** Related KB articles */
115
+ related_articles?: RelatedArticle[];
116
+ /** Whether result was cached */
117
+ cached?: boolean;
118
+ /** Session ID */
119
+ session_id?: string;
120
+ }
121
+
122
+ export interface RelatedArticle {
123
+ title: string;
124
+ url: string;
125
+ }
126
+
127
+ // ==================== Session ====================
128
+
129
+ export interface Session {
130
+ /** Unique session ID */
131
+ session_id: string;
132
+ /** Intent key */
133
+ intent: string;
134
+ /** Intent label */
135
+ intent_label?: string;
136
+ /** Summary of the guidance */
137
+ summary?: string;
138
+ /** Array of steps */
139
+ steps: GuidanceStep[];
140
+ /** Current step index (0-based) */
141
+ current_step: number;
142
+ /** Number of steps completed */
143
+ steps_completed: number;
144
+ /** Total number of steps */
145
+ total_steps: number;
146
+ /** Route where session started */
147
+ original_route: string;
148
+ /** Current route */
149
+ current_route: string;
150
+ /** Timestamp when session started */
151
+ started_at: number;
152
+ /** Timestamp of last activity */
153
+ last_activity: number;
154
+ /** Session status */
155
+ status: 'active' | 'completed' | 'abandoned' | 'expired';
156
+ /** Navigation history */
157
+ navigation_history: string[];
158
+ }
159
+
160
+ // ==================== UI Elements ====================
161
+
162
+ export interface UIElement {
163
+ /** Element text content */
164
+ text: string;
165
+ /** ARIA label */
166
+ aria_label?: string;
167
+ /** Title attribute */
168
+ title?: string;
169
+ /** ARIA role or inferred role */
170
+ role: string;
171
+ /** CSS selector */
172
+ selector: string;
173
+ /** HTML tag name */
174
+ tag: string;
175
+ /** Input type (for inputs) */
176
+ type?: string;
177
+ /** Whether element is disabled */
178
+ disabled?: boolean;
179
+ /** Element position */
180
+ position: ElementPosition;
181
+ /** data-testid attribute */
182
+ data_testid?: string;
183
+ }
184
+
185
+ export interface PageContext {
186
+ /** Current route/URL */
187
+ route: string;
188
+ /** Page title */
189
+ title: string;
190
+ /** Page headings */
191
+ headings: string[];
192
+ /** Forms on page */
193
+ forms: FormInfo[];
194
+ /** All interactive UI elements */
195
+ ui_elements: UIElement[];
196
+ /** Primary action buttons */
197
+ primaryActions: string[];
198
+ }
199
+
200
+ export interface FormInfo {
201
+ id?: string;
202
+ name?: string;
203
+ inputs: string[];
204
+ }
205
+
206
+ // ==================== Events ====================
207
+
208
+ export type EventCallback<T = any> = (data: T) => void;
209
+
210
+ export interface NavigationEventData {
211
+ route: string;
212
+ previousRoute: string;
213
+ pathname: string;
214
+ search: string;
215
+ hash: string;
216
+ }
217
+
218
+ export interface CompletedEventData {
219
+ intent: string;
220
+ }
221
+
222
+ export interface ClosedEventData {
223
+ intent?: string;
224
+ }
225
+
226
+ // ==================== API Responses ====================
227
+
228
+ export interface IntentExtractionResult {
229
+ intent: string | null;
230
+ confidence: number;
231
+ reasoning?: string;
232
+ clarifying_question?: string;
233
+ suggested_intents?: string[];
234
+ }
235
+
236
+ export interface ElementMatchResult {
237
+ selector: string | null;
238
+ confidence: number;
239
+ match_type: 'exact' | 'fuzzy' | 'semantic' | null;
240
+ found: boolean;
241
+ fallback_message?: string;
242
+ }
243
+
244
+ export interface KBSearchResult {
245
+ query: string;
246
+ results: KBArticle[];
247
+ total: number;
248
+ }
249
+
250
+ export interface KBArticle {
251
+ id: string;
252
+ title: string;
253
+ excerpt?: string;
254
+ content?: string;
255
+ score: number;
256
+ intent_tags?: string[];
257
+ route_pattern?: string;
258
+ }
259
+
260
+ // ==================== Main SDK Class ====================
261
+
262
+ export interface HandHoldInstance {
263
+ /**
264
+ * Initialize the SDK
265
+ */
266
+ init(options: HandHoldConfig): Promise<void>;
267
+
268
+ /**
269
+ * Open the help widget
270
+ */
271
+ open(): void;
272
+
273
+ /**
274
+ * Close the help widget
275
+ */
276
+ close(): void;
277
+
278
+ /**
279
+ * Toggle the help widget
280
+ */
281
+ toggle(): void;
282
+
283
+ /**
284
+ * Start guidance for a specific intent
285
+ */
286
+ startGuidance(intentKey: string): Promise<void>;
287
+
288
+ /**
289
+ * Get available intents for current page
290
+ */
291
+ getIntents(): Intent[];
292
+
293
+ /**
294
+ * Check if there's an active session
295
+ */
296
+ hasActiveSession(): boolean;
297
+
298
+ /**
299
+ * Get the active session
300
+ */
301
+ getActiveSession(): Session | null;
302
+
303
+ /**
304
+ * Get session progress (0-100)
305
+ */
306
+ getProgress(): number;
307
+
308
+ /**
309
+ * Subscribe to events
310
+ */
311
+ on<T = any>(event: string, callback: EventCallback<T>): () => void;
312
+
313
+ /**
314
+ * Unsubscribe from events
315
+ */
316
+ off(event: string, callback: EventCallback): void;
317
+
318
+ /**
319
+ * Destroy the SDK instance
320
+ */
321
+ destroy(): void;
322
+
323
+ /**
324
+ * Get SDK version
325
+ */
326
+ getVersion(): string;
327
+
328
+ /**
329
+ * Check if SDK is initialized
330
+ */
331
+ isInitialized(): boolean;
332
+ }
333
+
334
+ // ==================== Component Classes ====================
335
+
336
+ export class Config {
337
+ constructor(options: HandHoldConfig);
338
+ get<K extends keyof HandHoldConfig>(key: K): HandHoldConfig[K];
339
+ getAll(): Readonly<HandHoldConfig>;
340
+ getCSSVariables(): Record<string, string>;
341
+ }
342
+
343
+ export class Logger {
344
+ constructor(options?: { prefix?: string; level?: string; enabled?: boolean });
345
+ error(...args: any[]): void;
346
+ warn(...args: any[]): void;
347
+ info(...args: any[]): void;
348
+ debug(...args: any[]): void;
349
+ group(label: string): void;
350
+ groupEnd(): void;
351
+ time(label: string): void;
352
+ timeEnd(label: string): void;
353
+ }
354
+
355
+ export class EventBus {
356
+ static on<T = any>(event: string, callback: EventCallback<T>): () => void;
357
+ static once<T = any>(event: string, callback: EventCallback<T>): () => void;
358
+ static off(event: string, callback: EventCallback): void;
359
+ static emit<T = any>(event: string, data?: T): void;
360
+ static clear(): void;
361
+ static listenerCount(event: string): number;
362
+ }
363
+
364
+ export class APIClient {
365
+ constructor(config: Config);
366
+ inferIntents(data: { route: string; page_title?: string; ui_elements: UIElement[] }): Promise<{ intents: Intent[]; cached: boolean }>;
367
+ extractIntent(data: { user_query: string; route: string; available_intents: string[] }): Promise<IntentExtractionResult>;
368
+ getGuidance(data: { intent: string; route: string; page_context?: any; ui_elements: UIElement[]; session_id?: string }): Promise<Guidance>;
369
+ matchElement(data: { step_description: string; original_selector?: string; route: string; ui_elements: UIElement[]; session_id?: string }): Promise<ElementMatchResult>;
370
+ updateSession(data: { session_id: string; status: string; current_step: number; total_steps: number }): Promise<any>;
371
+ searchKB(query: string, options?: { limit?: number; intent?: string; route?: string }): Promise<KBSearchResult>;
372
+ healthCheck(): Promise<{ status: string; timestamp: string }>;
373
+ }
374
+
375
+ export class PageObserver {
376
+ constructor(config: Config);
377
+ observe(): void;
378
+ disconnect(): void;
379
+ scanPage(): PageContext;
380
+ getRoute(): string;
381
+ elementExists(selector: string): boolean;
382
+ findElement(selector: string): Element | null;
383
+ waitForElement(selector: string, timeout?: number): Promise<Element>;
384
+ }
385
+
386
+ export class NavigationObserver {
387
+ constructor(config: Config);
388
+ observe(): void;
389
+ disconnect(): void;
390
+ getRoute(): string;
391
+ getPathname(): string;
392
+ forceCheck(): void;
393
+ }
394
+
395
+ export class ElementScanner {
396
+ constructor(config: Config);
397
+ scan(): UIElement[];
398
+ getPageContext(): PageContext;
399
+ findElement(selector: string): Element | null;
400
+ elementExists(selector: string): boolean;
401
+ }
402
+
403
+ export class IntentExtractor {
404
+ static extract(uiElements: UIElement[], route: string, options?: { maxIntents?: number }): Intent[];
405
+ static matchQueryToIntent(query: string, intents: Intent[]): Intent | null;
406
+ static getClarification(query: string, candidates: Intent[]): { question: string; options: Intent[] };
407
+ }
408
+
409
+ export class ActionVerbMap {
410
+ static get(word: string): string | undefined;
411
+ static getLabel(verb: string): string;
412
+ static isActionVerb(word: string): boolean;
413
+ static findInText(text: string): { verb: string; position: number } | null;
414
+ }
415
+
416
+ export class SessionManager {
417
+ constructor(config: Config);
418
+ getSessionId(): string;
419
+ startSession(data: { intent: string; intent_label?: string; steps: GuidanceStep[]; original_route: string; summary?: string }): Session;
420
+ getActiveSession(): Session | null;
421
+ hasActiveSession(): boolean;
422
+ updateSession(session: Session): void;
423
+ endSession(): void;
424
+ advanceStep(): boolean;
425
+ getCurrentStep(): GuidanceStep | null;
426
+ getStep(index: number): GuidanceStep | null;
427
+ updateStep(index: number, updates: Partial<GuidanceStep>): void;
428
+ getProgress(): number;
429
+ recordNavigation(route: string): void;
430
+ isInSameFlow(newRoute: string): boolean;
431
+ }
432
+
433
+ export class SessionStorage {
434
+ constructor(prefix?: string);
435
+ set<T>(key: string, value: T): boolean;
436
+ get<T>(key: string): T | null;
437
+ remove(key: string): boolean;
438
+ has(key: string): boolean;
439
+ clear(): void;
440
+ keys(): string[];
441
+ }
442
+
443
+ export class HelpWidget {
444
+ constructor(config: Config);
445
+ render(): void;
446
+ show(): void;
447
+ hide(): void;
448
+ toggle(): void;
449
+ destroy(): void;
450
+ showIntentMenu(intents: Intent[]): void;
451
+ showLoading(): void;
452
+ showGuidanceTooltip(guidance: Guidance): void;
453
+ updateTooltip(session: Session): void;
454
+ showError(message: string): void;
455
+ showClarification(question: string, options: Intent[]): void;
456
+ showSuccess(message: string): void;
457
+ showTextOnlyGuidance(text: string, fallback?: string): void;
458
+ showNavigationSuggestion(article: { title: string; route?: string; excerpt?: string }): void;
459
+ confirmContinueSession(message: string): Promise<boolean>;
460
+ }
461
+
462
+ export class UICoach {
463
+ constructor(config: Config);
464
+ highlightElement(selector: string, options?: HighlightOptions): boolean;
465
+ clearHighlight(): void;
466
+ updateTooltipMessage(message: string): void;
467
+ isActive(): boolean;
468
+ destroy(): void;
469
+ }
470
+
471
+ export interface HighlightOptions {
472
+ message?: string;
473
+ showArrow?: boolean;
474
+ showTooltip?: boolean;
475
+ arrowPosition?: 'top' | 'bottom' | 'left' | 'right' | 'auto';
476
+ showDoneButton?: boolean;
477
+ showSkipButton?: boolean;
478
+ }
479
+
480
+ // ==================== Utility Functions ====================
481
+
482
+ export namespace domUtils {
483
+ export function generateSelector(element: Element): string;
484
+ export function getElementText(element: Element): string;
485
+ export function getElementRole(element: Element): string;
486
+ export function getElementPosition(element: Element): ElementPosition;
487
+ export function isElementVisible(element: Element): boolean;
488
+ export function isInteractiveElement(element: Element): boolean;
489
+ export function getInteractiveElements(root?: Element): Element[];
490
+ export function createElement(html: string): Element;
491
+ export function waitForElement(selector: string, timeout?: number): Promise<Element>;
492
+ }
493
+
494
+ export namespace stringUtils {
495
+ export function toSnakeCase(str: string): string;
496
+ export function toTitleCase(str: string): string;
497
+ export function toCamelCase(str: string): string;
498
+ export function truncate(str: string, maxLength: number): string;
499
+ export function capitalize(str: string): string;
500
+ export function hashString(str: string): string;
501
+ export function extractKeywords(text: string): string[];
502
+ export function similarity(str1: string, str2: string): number;
503
+ export function containsAllKeywords(str: string, keywords: string[]): boolean;
504
+ export function pluralize(word: string, count: number): string;
505
+ export function generateId(prefix?: string): string;
506
+ }
507
+
508
+ // ==================== Default Export ====================
509
+
510
+ const HandHold: HandHoldInstance;
511
+ export default HandHold;
512
+
513
+ // Also export the class for custom instantiation
514
+ export class HandHold implements HandHoldInstance {
515
+ constructor();
516
+ init(options: HandHoldConfig): Promise<void>;
517
+ open(): void;
518
+ close(): void;
519
+ toggle(): void;
520
+ startGuidance(intentKey: string): Promise<void>;
521
+ getIntents(): Intent[];
522
+ hasActiveSession(): boolean;
523
+ getActiveSession(): Session | null;
524
+ getProgress(): number;
525
+ on<T = any>(event: string, callback: EventCallback<T>): () => void;
526
+ off(event: string, callback: EventCallback): void;
527
+ destroy(): void;
528
+ getVersion(): string;
529
+ isInitialized(): boolean;
530
+ }
531
+ }
532
+
533
+ // Global declaration for script tag usage
534
+ declare global {
535
+ interface Window {
536
+ HandHold: import('handhold-sdk').HandHoldInstance;
537
+ }
538
+ }