@liminalcash/nim-chat 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 (45) hide show
  1. package/README.md +160 -0
  2. package/dist/NimChat.d.ts +4 -0
  3. package/dist/NimChat.d.ts.map +1 -0
  4. package/dist/components/ChatInput.d.ts +8 -0
  5. package/dist/components/ChatInput.d.ts.map +1 -0
  6. package/dist/components/ChatMessage.d.ts +8 -0
  7. package/dist/components/ChatMessage.d.ts.map +1 -0
  8. package/dist/components/ChatPanel.d.ts +17 -0
  9. package/dist/components/ChatPanel.d.ts.map +1 -0
  10. package/dist/components/ConfirmationCard.d.ts +10 -0
  11. package/dist/components/ConfirmationCard.d.ts.map +1 -0
  12. package/dist/components/LoginPanel.d.ts +7 -0
  13. package/dist/components/LoginPanel.d.ts.map +1 -0
  14. package/dist/components/ThinkingIndicator.d.ts +2 -0
  15. package/dist/components/ThinkingIndicator.d.ts.map +1 -0
  16. package/dist/fonts/abc-marist/ABCMarist-Black.otf +0 -0
  17. package/dist/fonts/abc-marist/ABCMarist-BlackItalic.otf +0 -0
  18. package/dist/fonts/abc-marist/ABCMarist-Bold.otf +0 -0
  19. package/dist/fonts/abc-marist/ABCMarist-BoldItalic.otf +0 -0
  20. package/dist/fonts/abc-marist/ABCMarist-Book.otf +0 -0
  21. package/dist/fonts/abc-marist/ABCMarist-BookItalic.otf +0 -0
  22. package/dist/fonts/abc-marist/ABCMarist-Medium.otf +0 -0
  23. package/dist/fonts/abc-marist/ABCMarist-MediumItalic.otf +0 -0
  24. package/dist/fonts/abc-marist/ABCMarist-Regular.otf +0 -0
  25. package/dist/fonts/abc-marist/ABCMarist-RegularItalic.otf +0 -0
  26. package/dist/fonts/abc-marist/ABCMarist-SemiBold.otf +0 -0
  27. package/dist/fonts/abc-marist/ABCMarist-SemiBoldItalic.otf +0 -0
  28. package/dist/fonts/helvetica-monospaced-pro/HelveticaMonospacedPro-Bd.otf +0 -0
  29. package/dist/fonts/helvetica-monospaced-pro/HelveticaMonospacedPro-BdIt.otf +0 -0
  30. package/dist/fonts/helvetica-monospaced-pro/HelveticaMonospacedPro-It.otf +0 -0
  31. package/dist/fonts/helvetica-monospaced-pro/HelveticaMonospacedPro-Rg.otf +0 -0
  32. package/dist/hooks/useNimWebSocket.d.ts +20 -0
  33. package/dist/hooks/useNimWebSocket.d.ts.map +1 -0
  34. package/dist/index.cjs +53 -0
  35. package/dist/index.d.ts +10 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +7515 -0
  38. package/dist/styles/theme.d.ts +90 -0
  39. package/dist/styles/theme.d.ts.map +1 -0
  40. package/dist/styles.css +1 -0
  41. package/dist/types.d.ts +67 -0
  42. package/dist/types.d.ts.map +1 -0
  43. package/dist/utils/auth.d.ts +12 -0
  44. package/dist/utils/auth.d.ts.map +1 -0
  45. package/package.json +60 -0
package/README.md ADDED
@@ -0,0 +1,160 @@
1
+ # @becomeliminal/nim-chat
2
+
3
+ A React chat widget that connects to any nim SDK backend (Go, Python, etc).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @becomeliminal/nim-chat
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```tsx
14
+ import { NimChat } from '@becomeliminal/nim-chat';
15
+ import '@becomeliminal/nim-chat/styles.css';
16
+
17
+ function App() {
18
+ return (
19
+ <NimChat
20
+ wsUrl="ws://localhost:8080/ws"
21
+ title="Nim"
22
+ position="bottom-right"
23
+ />
24
+ );
25
+ }
26
+ ```
27
+
28
+ ## Props
29
+
30
+ | Prop | Type | Default | Description |
31
+ |------|------|---------|-------------|
32
+ | `wsUrl` | `string` | **required** | WebSocket URL to connect to |
33
+ | `title` | `string` | `"Nim"` | Header title in the chat panel |
34
+ | `position` | `"bottom-right" \| "bottom-left"` | `"bottom-right"` | Widget position |
35
+ | `defaultOpen` | `boolean` | `false` | Whether the panel starts open |
36
+
37
+ ## WebSocket Protocol
38
+
39
+ The widget implements the nim SDK WebSocket protocol:
40
+
41
+ ### Client → Server
42
+
43
+ | Type | Fields | Description |
44
+ |------|--------|-------------|
45
+ | `new_conversation` | - | Start a new conversation |
46
+ | `resume_conversation` | `conversationId` | Resume existing conversation |
47
+ | `message` | `content` | Send a user message |
48
+ | `confirm` | `actionId` | Approve a pending action |
49
+ | `cancel` | `actionId` | Cancel a pending action |
50
+
51
+ ### Server → Client
52
+
53
+ | Type | Fields | Description |
54
+ |------|--------|-------------|
55
+ | `conversation_started` | `conversationId` | New conversation created |
56
+ | `conversation_resumed` | `conversationId`, `messages[]` | Conversation restored |
57
+ | `text_chunk` | `content` | Streaming text chunk |
58
+ | `text` | `content` | Complete message |
59
+ | `confirm_request` | `actionId`, `tool`, `summary`, `expiresAt` | Action requires approval |
60
+ | `complete` | `tokenUsage?` | Turn completed |
61
+ | `error` | `content` | Error occurred |
62
+
63
+ ## Advanced Usage
64
+
65
+ ### Custom Implementation
66
+
67
+ You can use individual components and the hook for custom implementations:
68
+
69
+ ```tsx
70
+ import {
71
+ ChatPanel,
72
+ ChatMessage,
73
+ ChatInput,
74
+ ConfirmationCard,
75
+ ThinkingIndicator,
76
+ useNimWebSocket,
77
+ } from '@becomeliminal/nim-chat';
78
+ import '@becomeliminal/nim-chat/styles.css';
79
+
80
+ function CustomChat() {
81
+ const {
82
+ messages,
83
+ isStreaming,
84
+ connectionState,
85
+ confirmationRequest,
86
+ sendMessage,
87
+ confirmAction,
88
+ cancelAction,
89
+ } = useNimWebSocket({
90
+ wsUrl: 'ws://localhost:8080/ws',
91
+ onError: (error) => console.error(error),
92
+ });
93
+
94
+ // Build your own UI...
95
+ }
96
+ ```
97
+
98
+ ### Theme Tokens
99
+
100
+ Access design tokens for consistent styling:
101
+
102
+ ```tsx
103
+ import { theme, colors, typography, spacing } from '@becomeliminal/nim-chat';
104
+
105
+ // colors.orange = '#FF6D00'
106
+ // colors.cream = '#F1EDE7'
107
+ // etc.
108
+ ```
109
+
110
+ ## Development
111
+
112
+ ```bash
113
+ # Install dependencies
114
+ npm install
115
+
116
+ # Start dev server with example
117
+ npm run dev
118
+
119
+ # Build for production
120
+ npm run build
121
+
122
+ # Type check
123
+ npm run typecheck
124
+ ```
125
+
126
+ ## Testing with nim-go-sdk
127
+
128
+ 1. Start the nim-go-sdk example server:
129
+ ```bash
130
+ cd /path/to/nim-go-sdk/examples/basic
131
+ ANTHROPIC_API_KEY=your-key go run main.go
132
+ ```
133
+
134
+ 2. Run the nim-chat example:
135
+ ```bash
136
+ cd nim-chat
137
+ npm run dev
138
+ ```
139
+
140
+ 3. Open http://localhost:5173 and test:
141
+ - Click bubble → panel opens
142
+ - Send message → streaming response
143
+ - Trigger tool → confirmation card appears
144
+ - Approve/cancel → action executes or cancels
145
+ - Refresh → conversation resumes from localStorage
146
+
147
+ ## Design System
148
+
149
+ Based on the Liminal mobile app design:
150
+
151
+ - **Orange** `#FF6D00` - Primary, user bubbles, CTAs
152
+ - **Cream** `#F1EDE7` - Background, assistant bubbles
153
+ - **Blue** `#9BC1F3` - Focus states, interactive elements
154
+ - **Black** `#231F18` - Primary text
155
+ - **Brown** `#492610` - Secondary text
156
+ - **Green** `#188A31` - Success, approval
157
+
158
+ ## License
159
+
160
+ MIT
@@ -0,0 +1,4 @@
1
+ import { NimChatProps } from './types';
2
+
3
+ export declare function NimChat({ wsUrl, apiUrl, title, position, defaultOpen, }: NimChatProps): import("react/jsx-runtime").JSX.Element;
4
+ //# sourceMappingURL=NimChat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NimChat.d.ts","sourceRoot":"","sources":["../src/NimChat.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,wBAAgB,OAAO,CAAC,EACtB,KAAK,EACL,MAAmC,EACnC,KAAa,EACb,QAAyB,EACzB,WAAmB,GACpB,EAAE,YAAY,2CAqId"}
@@ -0,0 +1,8 @@
1
+ interface ChatInputProps {
2
+ onSend: (message: string) => void;
3
+ disabled?: boolean;
4
+ placeholder?: string;
5
+ }
6
+ export declare function ChatInput({ onSend, disabled, placeholder, }: ChatInputProps): import("react/jsx-runtime").JSX.Element;
7
+ export {};
8
+ //# sourceMappingURL=ChatInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatInput.d.ts","sourceRoot":"","sources":["../../src/components/ChatInput.tsx"],"names":[],"mappings":"AAEA,UAAU,cAAc;IACtB,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,SAAS,CAAC,EACxB,MAAM,EACN,QAAgB,EAChB,WAAiC,GAClC,EAAE,cAAc,2CA6EhB"}
@@ -0,0 +1,8 @@
1
+ import { Message } from '../types';
2
+
3
+ interface ChatMessageProps {
4
+ message: Message;
5
+ }
6
+ export declare function ChatMessage({ message }: ChatMessageProps): import("react/jsx-runtime").JSX.Element;
7
+ export {};
8
+ //# sourceMappingURL=ChatMessage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatMessage.d.ts","sourceRoot":"","sources":["../../src/components/ChatMessage.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAExC,UAAU,gBAAgB;IACxB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,WAAW,CAAC,EAAE,OAAO,EAAE,EAAE,gBAAgB,2CAmCxD"}
@@ -0,0 +1,17 @@
1
+ import { Message, ConfirmationRequest, ConnectionState } from '../types';
2
+
3
+ interface ChatPanelProps {
4
+ title: string;
5
+ messages: Message[];
6
+ isStreaming: boolean;
7
+ connectionState: ConnectionState;
8
+ confirmationRequest: ConfirmationRequest | null;
9
+ onSendMessage: (content: string) => void;
10
+ onConfirm: (actionId: string) => void;
11
+ onCancel: (actionId: string) => void;
12
+ onClose: () => void;
13
+ onLogout?: () => void;
14
+ }
15
+ export declare function ChatPanel({ title, messages, isStreaming, connectionState, confirmationRequest, onSendMessage, onConfirm, onCancel, onClose, onLogout, }: ChatPanelProps): import("react/jsx-runtime").JSX.Element;
16
+ export {};
17
+ //# sourceMappingURL=ChatPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatPanel.d.ts","sourceRoot":"","sources":["../../src/components/ChatPanel.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAE9E,UAAU,cAAc;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,EAAE,eAAe,CAAC;IACjC,mBAAmB,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAChD,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,wBAAgB,SAAS,CAAC,EACxB,KAAK,EACL,QAAQ,EACR,WAAW,EACX,eAAe,EACf,mBAAmB,EACnB,aAAa,EACb,SAAS,EACT,QAAQ,EACR,OAAO,EACP,QAAQ,GACT,EAAE,cAAc,2CAkIhB"}
@@ -0,0 +1,10 @@
1
+ import { ConfirmationRequest } from '../types';
2
+
3
+ interface ConfirmationCardProps {
4
+ request: ConfirmationRequest;
5
+ onConfirm: (actionId: string) => void;
6
+ onCancel: (actionId: string) => void;
7
+ }
8
+ export declare function ConfirmationCard({ request, onConfirm, onCancel }: ConfirmationCardProps): import("react/jsx-runtime").JSX.Element;
9
+ export {};
10
+ //# sourceMappingURL=ConfirmationCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfirmationCard.d.ts","sourceRoot":"","sources":["../../src/components/ConfirmationCard.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAEpD,UAAU,qBAAqB;IAC7B,OAAO,EAAE,mBAAmB,CAAC;IAC7B,SAAS,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,QAAQ,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED,wBAAgB,gBAAgB,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,qBAAqB,2CAsGvF"}
@@ -0,0 +1,7 @@
1
+ interface LoginPanelProps {
2
+ onLoginSuccess: (jwt: string, userId: string) => void;
3
+ apiUrl?: string;
4
+ }
5
+ export declare function LoginPanel({ onLoginSuccess, apiUrl }: LoginPanelProps): import("react/jsx-runtime").JSX.Element;
6
+ export {};
7
+ //# sourceMappingURL=LoginPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LoginPanel.d.ts","sourceRoot":"","sources":["../../src/components/LoginPanel.tsx"],"names":[],"mappings":"AAEA,UAAU,eAAe;IACvB,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,UAAU,CAAC,EAAE,cAAc,EAAE,MAAmC,EAAE,EAAE,eAAe,2CA8JlG"}
@@ -0,0 +1,2 @@
1
+ export declare function ThinkingIndicator(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=ThinkingIndicator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ThinkingIndicator.d.ts","sourceRoot":"","sources":["../../src/components/ThinkingIndicator.tsx"],"names":[],"mappings":"AAAA,wBAAgB,iBAAiB,4CAQhC"}
@@ -0,0 +1,20 @@
1
+ import { Message, ConfirmationRequest, ConnectionState } from '../types';
2
+
3
+ interface UseNimWebSocketOptions {
4
+ wsUrl: string;
5
+ jwt: string | null;
6
+ onError?: (error: string) => void;
7
+ }
8
+ interface UseNimWebSocketReturn {
9
+ messages: Message[];
10
+ isStreaming: boolean;
11
+ connectionState: ConnectionState;
12
+ confirmationRequest: ConfirmationRequest | null;
13
+ sendMessage: (content: string) => void;
14
+ confirmAction: (actionId: string) => void;
15
+ cancelAction: (actionId: string) => void;
16
+ reconnect: () => void;
17
+ }
18
+ export declare function useNimWebSocket({ wsUrl, jwt, onError, }: UseNimWebSocketOptions): UseNimWebSocketReturn;
19
+ export {};
20
+ //# sourceMappingURL=useNimWebSocket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useNimWebSocket.d.ts","sourceRoot":"","sources":["../../src/hooks/useNimWebSocket.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,OAAO,EAGP,mBAAmB,EACnB,eAAe,EAChB,MAAM,UAAU,CAAC;AAIlB,UAAU,sBAAsB;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,UAAU,qBAAqB;IAC7B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,EAAE,eAAe,CAAC;IACjC,mBAAmB,EAAE,mBAAmB,GAAG,IAAI,CAAC;IAChD,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,YAAY,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,GAAG,EACH,OAAO,GACR,EAAE,sBAAsB,GAAG,qBAAqB,CAyUhD"}