@cairnvibe/sdk 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.
Files changed (44) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cairn-widget.js +228 -0
  3. package/dist/context-collector.d.ts +1 -0
  4. package/dist/context-collector.js +23 -0
  5. package/dist/dashboard-sqlite.d.ts +8 -0
  6. package/dist/dashboard-sqlite.js +50 -0
  7. package/dist/dashboard.d.ts +39 -0
  8. package/dist/dashboard.js +60 -0
  9. package/dist/element-ladder.d.ts +7 -0
  10. package/dist/element-ladder.js +60 -0
  11. package/dist/index.d.ts +31 -0
  12. package/dist/index.js +1069 -0
  13. package/dist/key-rotator.d.ts +7 -0
  14. package/dist/key-rotator.js +31 -0
  15. package/dist/package.json +1 -0
  16. package/dist/realtime-cli.d.ts +2 -0
  17. package/dist/realtime-cli.js +59 -0
  18. package/dist/realtime-server.d.ts +10 -0
  19. package/dist/realtime-server.js +291 -0
  20. package/dist/server.d.ts +95 -0
  21. package/dist/server.js +298 -0
  22. package/dist/speak-server.d.ts +16 -0
  23. package/dist/speak-server.js +41 -0
  24. package/dist/transcribe-server.d.ts +14 -0
  25. package/dist/transcribe-server.js +47 -0
  26. package/dist/tts-stream.d.ts +33 -0
  27. package/dist/tts-stream.js +124 -0
  28. package/dist/verb-executor.d.ts +17 -0
  29. package/dist/verb-executor.js +67 -0
  30. package/package.json +56 -0
  31. package/src/context-collector.ts +21 -0
  32. package/src/dashboard-sqlite.ts +52 -0
  33. package/src/dashboard.ts +82 -0
  34. package/src/element-ladder.ts +67 -0
  35. package/src/index.tsx +1250 -0
  36. package/src/key-rotator.ts +29 -0
  37. package/src/realtime-cli.ts +62 -0
  38. package/src/realtime-server.ts +342 -0
  39. package/src/server.ts +386 -0
  40. package/src/speak-server.ts +56 -0
  41. package/src/transcribe-server.ts +68 -0
  42. package/src/tts-stream.ts +140 -0
  43. package/src/verb-executor.ts +84 -0
  44. package/src/web-component.ts +1252 -0
@@ -0,0 +1,84 @@
1
+ // Turns a raw server response into a UI action — or, on anything that fails
2
+ // validation, into a plain explain. This is the client-side half of
3
+ // BUILD_PLAN.md invariant #1 ("the LLM never emits code or selectors, only a
4
+ // verb from a fixed list") and invariant #3 ("any lookup failure degrades to
5
+ // explain — never guess, never wrong-click"). The server (`server.ts`)
6
+ // enforces the same schema independently — never trust the client alone.
7
+
8
+ import { VerbResponseSchema, type TourStep, type VerbResponse } from "@cairnvibe/core";
9
+ import { findElement, highlightElement, logMiss, type MissContext } from "./element-ladder";
10
+
11
+ export interface VerbExecutorOptions {
12
+ onExplain: (text: string) => void;
13
+ onNavigate?: (route: string) => void;
14
+ onDo?: (action: string, target?: string) => void;
15
+ onMiss?: (context: MissContext) => void;
16
+ /**
17
+ * A multi-step guided walkthrough (2-6 steps). Highlighting/timing/speech
18
+ * is NOT done here — this just hands the raw steps to the caller, which
19
+ * owns the UI (progress display) and, for voice, the TTS sequencing.
20
+ */
21
+ onTour?: (steps: TourStep[]) => void;
22
+ /** Action ids the customer has actually wired up. "do" is rejected for anything else. */
23
+ registeredActions?: string[];
24
+ }
25
+
26
+ const FALLBACK_TEXT = "I'm not sure — I couldn't understand that response. Try rephrasing your question.";
27
+
28
+ export function executeVerbResponse(raw: unknown, route: string, options: VerbExecutorOptions): void {
29
+ const parsed = VerbResponseSchema.safeParse(raw);
30
+ if (!parsed.success) {
31
+ options.onExplain(FALLBACK_TEXT);
32
+ return;
33
+ }
34
+
35
+ dispatchVerb(parsed.data, route, options);
36
+ }
37
+
38
+ function dispatchVerb(verb: VerbResponse, route: string, options: VerbExecutorOptions): void {
39
+ switch (verb.verb) {
40
+ case "explain":
41
+ options.onExplain(verb.text);
42
+ return;
43
+
44
+ case "highlight":
45
+ case "open": {
46
+ const el = findElement(verb.target);
47
+ if (!el) {
48
+ (options.onMiss ?? logMiss)({ attempted: verb.target, route });
49
+ options.onExplain(verb.text ?? "I know what you need, but I can't find it on this page right now.");
50
+ return;
51
+ }
52
+ highlightElement(el);
53
+ if (verb.text) options.onExplain(verb.text);
54
+ return;
55
+ }
56
+
57
+ case "navigate":
58
+ options.onNavigate?.(verb.route);
59
+ if (verb.text) options.onExplain(verb.text);
60
+ return;
61
+
62
+ case "do": {
63
+ const allowed = options.registeredActions ?? [];
64
+ if (!allowed.includes(verb.action)) {
65
+ options.onExplain("That action isn't available here.");
66
+ return;
67
+ }
68
+ options.onDo?.(verb.action, verb.target);
69
+ if (verb.text) options.onExplain(verb.text);
70
+ return;
71
+ }
72
+
73
+ case "tour":
74
+ if (options.onTour) {
75
+ options.onTour(verb.steps);
76
+ } else {
77
+ // Caller doesn't support tours (e.g. an older host app) — degrade
78
+ // to reading the steps out as one explanation rather than dropping
79
+ // the reply silently.
80
+ options.onExplain(verb.steps.map((s) => s.text).join(" "));
81
+ }
82
+ return;
83
+ }
84
+ }