@rubytech/create-maxy 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/dist/index.js +428 -0
- package/package.json +31 -0
- package/payload/maxy/.env.example +12 -0
- package/payload/maxy/app/admin/components/ActivityTimeline.tsx +348 -0
- package/payload/maxy/app/admin/components/MarkdownMessage.tsx +40 -0
- package/payload/maxy/app/api/admin/chat/route.ts +72 -0
- package/payload/maxy/app/api/admin/logs/route.ts +40 -0
- package/payload/maxy/app/api/admin/session/route.ts +74 -0
- package/payload/maxy/app/api/chat/route.ts +72 -0
- package/payload/maxy/app/api/health/route.ts +26 -0
- package/payload/maxy/app/api/onboarding/claude-auth/route.ts +216 -0
- package/payload/maxy/app/api/onboarding/set-pin/route.ts +44 -0
- package/payload/maxy/app/api/session/route.ts +51 -0
- package/payload/maxy/app/api/telegram/webhook/route.ts +107 -0
- package/payload/maxy/app/apple-icon.png +0 -0
- package/payload/maxy/app/bot/page.tsx +373 -0
- package/payload/maxy/app/favicon.ico +0 -0
- package/payload/maxy/app/globals.css +1681 -0
- package/payload/maxy/app/layout.tsx +58 -0
- package/payload/maxy/app/lib/claude-agent.ts +503 -0
- package/payload/maxy/app/og/layout.tsx +15 -0
- package/payload/maxy/app/og/page.tsx +252 -0
- package/payload/maxy/app/page.tsx +594 -0
- package/payload/maxy/app/privacy/page.tsx +72 -0
- package/payload/maxy/app/public/page.tsx +266 -0
- package/payload/maxy/next.config.mjs +26 -0
- package/payload/maxy/package-lock.json +2198 -0
- package/payload/maxy/package.json +25 -0
- package/payload/maxy/proxy.ts +41 -0
- package/payload/maxy/public/brand/claude.png +0 -0
- package/payload/maxy/public/brand/maxy-black.png +0 -0
- package/payload/maxy/public/brand/maxy.png +0 -0
- package/payload/maxy/public/favicon.ico +0 -0
- package/payload/maxy/public/og-landscape.png +0 -0
- package/payload/maxy/public/og-portrait.png +0 -0
- package/payload/maxy/public/og-square.png +0 -0
- package/payload/maxy/public/pi-5.jpg +0 -0
- package/payload/maxy/public/robots.txt +5 -0
- package/payload/maxy/tsconfig.json +41 -0
- package/payload/maxy/tsconfig.tsbuildinfo +1 -0
- package/payload/maxy/ui.md +28 -0
- package/payload/platform/config/cloudflared.yml +17 -0
- package/payload/platform/knowledge/maxy.md +161 -0
- package/payload/platform/neo4j/schema.cypher +108 -0
- package/payload/platform/package-lock.json +1835 -0
- package/payload/platform/package.json +17 -0
- package/payload/platform/plugins/admin/PLUGIN.md +24 -0
- package/payload/platform/plugins/admin/hooks/pre-tool-use.sh +56 -0
- package/payload/platform/plugins/admin/hooks/session-start.sh +20 -0
- package/payload/platform/plugins/admin/mcp/dist/index.d.ts +2 -0
- package/payload/platform/plugins/admin/mcp/dist/index.d.ts.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js +149 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -0
- package/payload/platform/plugins/admin/mcp/package.json +18 -0
- package/payload/platform/plugins/anthropic/PLUGIN.md +30 -0
- package/payload/platform/plugins/anthropic/references/setup-guide.md +146 -0
- package/payload/platform/plugins/business-assistant/PLUGIN.md +46 -0
- package/payload/platform/plugins/business-assistant/references/crm.md +112 -0
- package/payload/platform/plugins/business-assistant/references/document-management.md +96 -0
- package/payload/platform/plugins/business-assistant/references/escalation.md +126 -0
- package/payload/platform/plugins/business-assistant/references/invoicing.md +163 -0
- package/payload/platform/plugins/business-assistant/references/quoting.md +56 -0
- package/payload/platform/plugins/business-assistant/references/scheduling.md +127 -0
- package/payload/platform/plugins/cloudflare/PLUGIN.md +31 -0
- package/payload/platform/plugins/cloudflare/mcp/dist/index.d.ts +2 -0
- package/payload/platform/plugins/cloudflare/mcp/dist/index.d.ts.map +1 -0
- package/payload/platform/plugins/cloudflare/mcp/dist/index.js +174 -0
- package/payload/platform/plugins/cloudflare/mcp/dist/index.js.map +1 -0
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.d.ts +45 -0
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.d.ts.map +1 -0
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.js +256 -0
- package/payload/platform/plugins/cloudflare/mcp/dist/lib/cloudflared.js.map +1 -0
- package/payload/platform/plugins/cloudflare/mcp/package.json +18 -0
- package/payload/platform/plugins/cloudflare/references/setup-guide.md +110 -0
- package/payload/platform/plugins/contacts/PLUGIN.md +18 -0
- package/payload/platform/plugins/contacts/mcp/dist/index.d.ts +2 -0
- package/payload/platform/plugins/contacts/mcp/dist/index.d.ts.map +1 -0
- package/payload/platform/plugins/contacts/mcp/dist/index.js +182 -0
- package/payload/platform/plugins/contacts/mcp/dist/index.js.map +1 -0
- package/payload/platform/plugins/contacts/mcp/dist/lib/neo4j.d.ts +5 -0
- package/payload/platform/plugins/contacts/mcp/dist/lib/neo4j.d.ts.map +1 -0
- package/payload/platform/plugins/contacts/mcp/dist/lib/neo4j.js +34 -0
- package/payload/platform/plugins/contacts/mcp/dist/lib/neo4j.js.map +1 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.d.ts +19 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.d.ts.map +1 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js +68 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-create.js.map +1 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-list.d.ts +22 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-list.d.ts.map +1 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-list.js +46 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-list.js.map +1 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.d.ts +20 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.d.ts.map +1 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.js +56 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.js.map +1 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-update.d.ts +13 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-update.d.ts.map +1 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-update.js +54 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-update.js.map +1 -0
- package/payload/platform/plugins/contacts/mcp/package.json +19 -0
- package/payload/platform/plugins/documents/PLUGIN.md +12 -0
- package/payload/platform/plugins/documents/mcp/dist/index.d.ts +2 -0
- package/payload/platform/plugins/documents/mcp/dist/index.d.ts.map +1 -0
- package/payload/platform/plugins/documents/mcp/dist/index.js +82 -0
- package/payload/platform/plugins/documents/mcp/dist/index.js.map +1 -0
- package/payload/platform/plugins/documents/mcp/package.json +20 -0
- package/payload/platform/plugins/memory/PLUGIN.md +17 -0
- package/payload/platform/plugins/memory/mcp/dist/index.d.ts +2 -0
- package/payload/platform/plugins/memory/mcp/dist/index.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/index.js +164 -0
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.d.ts +3 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.js +29 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/embeddings.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.d.ts +5 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.js +34 -0
- package/payload/platform/plugins/memory/mcp/dist/lib/neo4j.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.d.ts +8 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.js +71 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-reindex.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.d.ts +24 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js +125 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-search.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts +18 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts.map +1 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js +56 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js.map +1 -0
- package/payload/platform/plugins/memory/mcp/package.json +19 -0
- package/payload/platform/plugins/sales/PLUGIN.md +65 -0
- package/payload/platform/plugins/sales/references/close-tracking.md +76 -0
- package/payload/platform/plugins/sales/references/closing-framework.md +108 -0
- package/payload/platform/plugins/sales/references/comparisons.md +99 -0
- package/payload/platform/plugins/sales/references/competitive-positioning.md +51 -0
- package/payload/platform/plugins/sales/references/faq.md +62 -0
- package/payload/platform/plugins/sales/references/objection-handling.md +157 -0
- package/payload/platform/plugins/sales/references/pricing.md +71 -0
- package/payload/platform/plugins/sales/references/waitlist.md +23 -0
- package/payload/platform/plugins/scheduling/PLUGIN.md +12 -0
- package/payload/platform/plugins/scheduling/mcp/dist/index.d.ts +2 -0
- package/payload/platform/plugins/scheduling/mcp/dist/index.d.ts.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/index.js +13 -0
- package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -0
- package/payload/platform/plugins/scheduling/mcp/package.json +18 -0
- package/payload/platform/plugins/telegram/PLUGIN.md +31 -0
- package/payload/platform/plugins/telegram/mcp/dist/index.d.ts +2 -0
- package/payload/platform/plugins/telegram/mcp/dist/index.d.ts.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/index.js +101 -0
- package/payload/platform/plugins/telegram/mcp/dist/index.js.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/telegram.d.ts +27 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/telegram.d.ts.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/telegram.js +41 -0
- package/payload/platform/plugins/telegram/mcp/dist/lib/telegram.js.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.d.ts +16 -0
- package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.d.ts.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.js +62 -0
- package/payload/platform/plugins/telegram/mcp/dist/tools/message-history.js.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/tools/message.d.ts +20 -0
- package/payload/platform/plugins/telegram/mcp/dist/tools/message.d.ts.map +1 -0
- package/payload/platform/plugins/telegram/mcp/dist/tools/message.js +34 -0
- package/payload/platform/plugins/telegram/mcp/dist/tools/message.js.map +1 -0
- package/payload/platform/plugins/telegram/mcp/package.json +19 -0
- package/payload/platform/plugins/telegram/references/setup-guide.md +50 -0
- package/payload/platform/plugins/web/PLUGIN.md +12 -0
- package/payload/platform/plugins/web/mcp/dist/index.d.ts +2 -0
- package/payload/platform/plugins/web/mcp/dist/index.d.ts.map +1 -0
- package/payload/platform/plugins/web/mcp/dist/index.js +12 -0
- package/payload/platform/plugins/web/mcp/dist/index.js.map +1 -0
- package/payload/platform/plugins/web/mcp/package.json +18 -0
- package/payload/platform/scripts/seed-neo4j.sh +73 -0
- package/payload/platform/scripts/setup.sh +177 -0
- package/payload/platform/scripts/start.sh +62 -0
- package/payload/platform/templates/account.json +4 -0
- package/payload/platform/templates/agents/admin/IDENTITY.md +28 -0
- package/payload/platform/templates/agents/admin/SOUL.md +1 -0
- package/payload/platform/templates/agents/public/IDENTITY.md +21 -0
- package/payload/platform/templates/agents/public/SOUL.md +1 -0
- package/payload/platform/tsconfig.base.json +18 -0
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useState, useRef, useEffect, useCallback, FormEvent } from 'react'
|
|
4
|
+
|
|
5
|
+
interface Message {
|
|
6
|
+
role: 'maxy' | 'visitor'
|
|
7
|
+
content: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const suggestions: string[] = []
|
|
11
|
+
|
|
12
|
+
/** Generate a random session ID (Taskmaster prepends its own anon- prefix). */
|
|
13
|
+
function generateSessionId(): string {
|
|
14
|
+
return crypto.randomUUID()
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export default function ChatPage() {
|
|
18
|
+
const [messages, setMessages] = useState<Message[]>([])
|
|
19
|
+
const [remainingSuggestions, setRemainingSuggestions] = useState(suggestions)
|
|
20
|
+
const [input, setInput] = useState('')
|
|
21
|
+
const [isStreaming, setIsStreaming] = useState(false)
|
|
22
|
+
const messagesEndRef = useRef<HTMLDivElement>(null)
|
|
23
|
+
const inputRef = useRef<HTMLInputElement>(null)
|
|
24
|
+
const nudgeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
|
25
|
+
const sessionKeyRef = useRef<string | null>(null)
|
|
26
|
+
const sessionPendingRef = useRef<Promise<string | null> | null>(null)
|
|
27
|
+
|
|
28
|
+
// Scroll to bottom when messages change
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })
|
|
31
|
+
}, [messages])
|
|
32
|
+
|
|
33
|
+
// Nudge timer — if no input after 15s, show gentle prompt
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
nudgeTimerRef.current = setTimeout(() => {
|
|
36
|
+
setMessages(prev => {
|
|
37
|
+
if (prev.length > 0) return prev // user already started chatting
|
|
38
|
+
return [{ role: 'maxy', content: 'No wrong answers. Just tell me what\'s on your mind.' }]
|
|
39
|
+
})
|
|
40
|
+
}, 15000)
|
|
41
|
+
return () => {
|
|
42
|
+
if (nudgeTimerRef.current) clearTimeout(nudgeTimerRef.current)
|
|
43
|
+
}
|
|
44
|
+
}, []) // eslint-disable-line react-hooks/exhaustive-deps
|
|
45
|
+
|
|
46
|
+
// Focus input on mount
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
inputRef.current?.focus()
|
|
49
|
+
}, [])
|
|
50
|
+
|
|
51
|
+
/** Ensure we have a Taskmaster session, creating one if needed. */
|
|
52
|
+
const ensureSession = useCallback(async (): Promise<string | null> => {
|
|
53
|
+
if (sessionKeyRef.current) return sessionKeyRef.current
|
|
54
|
+
|
|
55
|
+
// Deduplicate concurrent calls
|
|
56
|
+
if (sessionPendingRef.current) return sessionPendingRef.current
|
|
57
|
+
|
|
58
|
+
const promise = (async () => {
|
|
59
|
+
try {
|
|
60
|
+
const res = await fetch('/api/session', {
|
|
61
|
+
method: 'POST',
|
|
62
|
+
headers: { 'Content-Type': 'application/json' },
|
|
63
|
+
body: JSON.stringify({ session_id: generateSessionId() }),
|
|
64
|
+
})
|
|
65
|
+
if (!res.ok) return null
|
|
66
|
+
const data = await res.json()
|
|
67
|
+
sessionKeyRef.current = data.session_key
|
|
68
|
+
return data.session_key as string
|
|
69
|
+
} catch {
|
|
70
|
+
return null
|
|
71
|
+
} finally {
|
|
72
|
+
sessionPendingRef.current = null
|
|
73
|
+
}
|
|
74
|
+
})()
|
|
75
|
+
|
|
76
|
+
sessionPendingRef.current = promise
|
|
77
|
+
return promise
|
|
78
|
+
}, [])
|
|
79
|
+
|
|
80
|
+
async function sendMessage(text: string) {
|
|
81
|
+
if (!text || isStreaming) return
|
|
82
|
+
|
|
83
|
+
// Clear nudge timer
|
|
84
|
+
if (nudgeTimerRef.current) {
|
|
85
|
+
clearTimeout(nudgeTimerRef.current)
|
|
86
|
+
nudgeTimerRef.current = null
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Remove this suggestion if it was from the list
|
|
90
|
+
setRemainingSuggestions(prev => prev.filter(s => s !== text))
|
|
91
|
+
|
|
92
|
+
// Add visitor message
|
|
93
|
+
const visitorMessage: Message = { role: 'visitor', content: text }
|
|
94
|
+
const updatedMessages = [...messages, visitorMessage]
|
|
95
|
+
setMessages(updatedMessages)
|
|
96
|
+
setInput('')
|
|
97
|
+
setIsStreaming(true)
|
|
98
|
+
|
|
99
|
+
// Add placeholder for Maxy's response
|
|
100
|
+
const placeholderIndex = updatedMessages.length
|
|
101
|
+
setMessages(prev => [...prev, { role: 'maxy', content: '' }])
|
|
102
|
+
|
|
103
|
+
try {
|
|
104
|
+
// Ensure we have a session before sending
|
|
105
|
+
const sessionKey = await ensureSession()
|
|
106
|
+
if (!sessionKey) {
|
|
107
|
+
throw new Error('session')
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const res = await fetch('/api/chat', {
|
|
111
|
+
method: 'POST',
|
|
112
|
+
headers: { 'Content-Type': 'application/json' },
|
|
113
|
+
body: JSON.stringify({ message: text, session_key: sessionKey }),
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
if (!res.ok) {
|
|
117
|
+
const errorData = await res.json().catch(() => ({}))
|
|
118
|
+
throw new Error(errorData.error || 'Something went wrong')
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const reader = res.body?.getReader()
|
|
122
|
+
const decoder = new TextDecoder()
|
|
123
|
+
|
|
124
|
+
if (!reader) throw new Error('No response stream')
|
|
125
|
+
|
|
126
|
+
let accumulated = ''
|
|
127
|
+
let sseBuffer = ''
|
|
128
|
+
|
|
129
|
+
while (true) {
|
|
130
|
+
const { done, value } = await reader.read()
|
|
131
|
+
if (done) break
|
|
132
|
+
|
|
133
|
+
sseBuffer += decoder.decode(value, { stream: true })
|
|
134
|
+
const parts = sseBuffer.split('\n')
|
|
135
|
+
sseBuffer = parts.pop()! // keep incomplete trailing segment
|
|
136
|
+
|
|
137
|
+
for (const line of parts) {
|
|
138
|
+
if (!line.startsWith('data: ')) continue
|
|
139
|
+
const data = line.slice(6)
|
|
140
|
+
if (data === '[DONE]') continue
|
|
141
|
+
|
|
142
|
+
let parsed
|
|
143
|
+
try { parsed = JSON.parse(data) } catch { continue }
|
|
144
|
+
|
|
145
|
+
if (parsed.error) throw new Error(parsed.error)
|
|
146
|
+
if (parsed.text) {
|
|
147
|
+
accumulated += parsed.text
|
|
148
|
+
setMessages(prev => {
|
|
149
|
+
const updated = [...prev]
|
|
150
|
+
updated[placeholderIndex] = {
|
|
151
|
+
role: 'maxy',
|
|
152
|
+
content: accumulated,
|
|
153
|
+
}
|
|
154
|
+
return updated
|
|
155
|
+
})
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
} catch (err) {
|
|
160
|
+
const errorMessage = err instanceof Error ? err.message : 'Something went wrong'
|
|
161
|
+
setMessages(prev => {
|
|
162
|
+
const updated = [...prev]
|
|
163
|
+
updated[placeholderIndex] = {
|
|
164
|
+
role: 'maxy',
|
|
165
|
+
content: errorMessage === 'session'
|
|
166
|
+
? "I'm having trouble connecting right now. Try refreshing the page."
|
|
167
|
+
: "Sorry, I hit a snag. Try again in a moment.",
|
|
168
|
+
}
|
|
169
|
+
return updated
|
|
170
|
+
})
|
|
171
|
+
} finally {
|
|
172
|
+
setIsStreaming(false)
|
|
173
|
+
inputRef.current?.focus()
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function handleSubmit(e: FormEvent) {
|
|
178
|
+
e.preventDefault()
|
|
179
|
+
sendMessage(input.trim())
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return (
|
|
183
|
+
<div className="chat-page">
|
|
184
|
+
<header className="chat-header">
|
|
185
|
+
<img src="/brand/maxy-black.png" alt="Maxy" className="chat-logo" />
|
|
186
|
+
<h1 className="chat-tagline">No Stress. Quiet Life.</h1>
|
|
187
|
+
<p className="chat-intro">
|
|
188
|
+
Hey, I{'\u2019'}m Maxy. I{'\u2019'}m a personal AI that handles the
|
|
189
|
+
stuff you don{'\u2019'}t want to think about. I{'\u2019'}m not a product
|
|
190
|
+
yet{'\u2009'}{'\u2014'}{'\u2009'}I{'\u2019'}m learning what stresses people
|
|
191
|
+
most so I can be built right. Tell me what{'\u2019'}s on your mind.
|
|
192
|
+
No advice, no judgment, just a conversation.
|
|
193
|
+
</p>
|
|
194
|
+
<div className="chat-trust">
|
|
195
|
+
<span className="chat-trust-item">Anonymous</span>
|
|
196
|
+
<span className="chat-trust-sep">{'\u00B7'}</span>
|
|
197
|
+
<span className="chat-trust-item">Private</span>
|
|
198
|
+
<span className="chat-trust-sep">{'\u00B7'}</span>
|
|
199
|
+
<span className="chat-trust-item">No sign-up</span>
|
|
200
|
+
<span className="chat-trust-sep">{'\u00B7'}</span>
|
|
201
|
+
<span className="chat-trust-item">Free</span>
|
|
202
|
+
</div>
|
|
203
|
+
</header>
|
|
204
|
+
|
|
205
|
+
<div className="chat-messages">
|
|
206
|
+
{messages.map((msg, i) => (
|
|
207
|
+
<div key={i} className={`message ${msg.role}`}>
|
|
208
|
+
<div className="bubble">
|
|
209
|
+
{msg.content || (
|
|
210
|
+
<span className="typing-indicator">
|
|
211
|
+
<span className="typing-dot" />
|
|
212
|
+
<span className="typing-dot" />
|
|
213
|
+
<span className="typing-dot" />
|
|
214
|
+
</span>
|
|
215
|
+
)}
|
|
216
|
+
</div>
|
|
217
|
+
</div>
|
|
218
|
+
))}
|
|
219
|
+
{!isStreaming && remainingSuggestions.length > 0 && (
|
|
220
|
+
<div className="chat-suggestions">
|
|
221
|
+
{remainingSuggestions.map(s => (
|
|
222
|
+
<button
|
|
223
|
+
key={s}
|
|
224
|
+
className="chat-suggestion"
|
|
225
|
+
onClick={() => sendMessage(s)}
|
|
226
|
+
>
|
|
227
|
+
{s}
|
|
228
|
+
</button>
|
|
229
|
+
))}
|
|
230
|
+
</div>
|
|
231
|
+
)}
|
|
232
|
+
<div ref={messagesEndRef} />
|
|
233
|
+
</div>
|
|
234
|
+
|
|
235
|
+
<div className="chat-input-area">
|
|
236
|
+
<form className="chat-form" onSubmit={handleSubmit}>
|
|
237
|
+
<input
|
|
238
|
+
ref={inputRef}
|
|
239
|
+
className="chat-input"
|
|
240
|
+
type="text"
|
|
241
|
+
value={input}
|
|
242
|
+
onChange={e => setInput(e.target.value)}
|
|
243
|
+
placeholder="Tell me what you need taking care of in your life!"
|
|
244
|
+
disabled={isStreaming}
|
|
245
|
+
aria-label="Type your message"
|
|
246
|
+
/>
|
|
247
|
+
<button
|
|
248
|
+
className="chat-send"
|
|
249
|
+
type="submit"
|
|
250
|
+
disabled={isStreaming || !input.trim()}
|
|
251
|
+
aria-label="Send message"
|
|
252
|
+
>
|
|
253
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
|
254
|
+
<line x1="5" y1="12" x2="19" y2="12" />
|
|
255
|
+
<polyline points="12 5 19 12 12 19" />
|
|
256
|
+
</svg>
|
|
257
|
+
</button>
|
|
258
|
+
</form>
|
|
259
|
+
</div>
|
|
260
|
+
|
|
261
|
+
<footer className="chat-footer">
|
|
262
|
+
<a href="https://maxy.bot">maxy.bot {'\u2197'}</a>
|
|
263
|
+
</footer>
|
|
264
|
+
</div>
|
|
265
|
+
)
|
|
266
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** @type {import('next').NextConfig} */
|
|
2
|
+
const nextConfig = {
|
|
3
|
+
poweredByHeader: false,
|
|
4
|
+
devIndicators: { appIsrStatus: false },
|
|
5
|
+
async headers() {
|
|
6
|
+
return [
|
|
7
|
+
{
|
|
8
|
+
source: '/(.*)',
|
|
9
|
+
headers: [
|
|
10
|
+
{ key: 'X-Content-Type-Options', value: 'nosniff' },
|
|
11
|
+
{ key: 'X-Frame-Options', value: 'DENY' },
|
|
12
|
+
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
|
|
13
|
+
],
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
// VNC viewer is loaded in an iframe on the same origin — allow same-origin framing
|
|
17
|
+
source: '/vnc-viewer.html',
|
|
18
|
+
headers: [
|
|
19
|
+
{ key: 'X-Frame-Options', value: 'SAMEORIGIN' },
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default nextConfig
|