@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,157 @@
|
|
|
1
|
+
# Objection Handling
|
|
2
|
+
|
|
3
|
+
## Pivots vs Objections
|
|
4
|
+
|
|
5
|
+
The most important distinction in closing: is the prospect **pivoting** (changing topic to avoid commitment) or **objecting** (raising a genuine concern that needs resolving)?
|
|
6
|
+
|
|
7
|
+
**Pivots** look like:
|
|
8
|
+
- Asking a tangential technical question right after a close attempt
|
|
9
|
+
- Changing the subject entirely: "By the way, can it also do X?"
|
|
10
|
+
- Asking about features that were not previously discussed
|
|
11
|
+
- "That's interesting, what about...?"
|
|
12
|
+
|
|
13
|
+
**Objections** look like:
|
|
14
|
+
- Expressing a specific concern: "I'm worried about the cost"
|
|
15
|
+
- Raising a blocker: "I need to check with my partner first"
|
|
16
|
+
- Questioning capability directly: "Can it actually handle that?"
|
|
17
|
+
- Asking for evidence: "Do you have any case studies?"
|
|
18
|
+
|
|
19
|
+
**The rule:** Handle pivots with acknowledge-then-anchor. Handle objections with empathy, resolution, then close.
|
|
20
|
+
|
|
21
|
+
## Acknowledge-Then-Anchor (for Pivots)
|
|
22
|
+
|
|
23
|
+
The pattern:
|
|
24
|
+
|
|
25
|
+
1. **Acknowledge** — Show you heard the question. Do not dismiss it.
|
|
26
|
+
2. **Brief answer** — 1-2 sentences maximum. Enough to satisfy curiosity, not enough to derail.
|
|
27
|
+
3. **Re-anchor** — Return to the commitment ask.
|
|
28
|
+
|
|
29
|
+
The brief answer is genuine — you are not dodging the question, you are prioritising the close while still being helpful.
|
|
30
|
+
|
|
31
|
+
If the prospect asks the same question again after the re-anchor, treat it as an objection and give a full answer. A repeated question is no longer a pivot.
|
|
32
|
+
|
|
33
|
+
## Feel / Felt / Found
|
|
34
|
+
|
|
35
|
+
The universal objection-handling pattern. Works for price and almost any other concern:
|
|
36
|
+
|
|
37
|
+
> "I understand how you **feel** — [validate their concern]. Many of our users **felt** exactly the same way. However, most **found** that [positive outcome], which made the investment worthwhile."
|
|
38
|
+
|
|
39
|
+
**Examples:**
|
|
40
|
+
|
|
41
|
+
*Price too high:*
|
|
42
|
+
> "I understand how you feel — it's a significant investment. Many people felt the same way initially. However, most found that within the first month, the time saved more than covered the cost."
|
|
43
|
+
|
|
44
|
+
*Unsure about value:*
|
|
45
|
+
> "I get how you feel — it's hard to know if it's worth it before you've tried it. Others felt the same. What they found was that once Maxy started managing their calendar and messages proactively, they couldn't go back."
|
|
46
|
+
|
|
47
|
+
*Comparing to cheaper option:*
|
|
48
|
+
> "I understand how you feel — the price difference is noticeable. Others have felt the same and tried the cheaper option first. What they found was it couldn't act proactively or connect their services together, and they ended up coming back."
|
|
49
|
+
|
|
50
|
+
The key: the "found" part must be **specific and credible**. Vague claims are worthless. Concrete outcomes are persuasive.
|
|
51
|
+
|
|
52
|
+
## Common Objection Patterns
|
|
53
|
+
|
|
54
|
+
### Price: "I need to think about it" / "That's more than I expected"
|
|
55
|
+
|
|
56
|
+
This is usually about value, not money. The prospect is not sure the product is worth the price.
|
|
57
|
+
|
|
58
|
+
1. Acknowledge the concern without defensiveness
|
|
59
|
+
2. Restate the specific value that matches their stated needs
|
|
60
|
+
3. If alternatives exist, offer them (different tier, payment plan)
|
|
61
|
+
4. Surface the real objection: "Of course — what specifically would you like to think over? I want to make sure I've given you everything you need to decide."
|
|
62
|
+
|
|
63
|
+
Never discount without authorisation. Never make the prospect feel bad for asking about price.
|
|
64
|
+
|
|
65
|
+
### "That's more than I expected"
|
|
66
|
+
|
|
67
|
+
Response: "What were you expecting?" — then bridge the gap with value, not discount.
|
|
68
|
+
|
|
69
|
+
### "Your competitor is cheaper"
|
|
70
|
+
|
|
71
|
+
Response: "They may well be — and that's a valid consideration. Can I ask what's most important to you: the lowest price, or the best outcome?" Then demonstrate why the higher price delivers a better net result.
|
|
72
|
+
|
|
73
|
+
### "Can you do it for less?"
|
|
74
|
+
|
|
75
|
+
Never say no outright. Instead:
|
|
76
|
+
> "The price reflects what's included. I could adjust it if we reduce scope. Would that work, or is the full package what you actually need?"
|
|
77
|
+
|
|
78
|
+
This teaches them that price is linked to value.
|
|
79
|
+
|
|
80
|
+
### Timing: "Not right now" / "Maybe next month"
|
|
81
|
+
|
|
82
|
+
Respect the timing. Do not push against an explicit deferral.
|
|
83
|
+
|
|
84
|
+
1. Acknowledge: "No problem at all"
|
|
85
|
+
2. Set a concrete follow-up: "Shall I check back in with you on [specific date]?"
|
|
86
|
+
3. Save the deferral to memory with the agreed follow-up date
|
|
87
|
+
4. When the follow-up date arrives, use the Return Close
|
|
88
|
+
|
|
89
|
+
### Capability: "Can it do X?" / "What about Y integration?"
|
|
90
|
+
|
|
91
|
+
If this comes mid-close, it is likely a pivot. If it comes before any close attempt, it is genuine discovery.
|
|
92
|
+
|
|
93
|
+
**Mid-close (pivot):**
|
|
94
|
+
> "Good question — [brief honest answer]. We can go deeper on that once you're set up. Shall we get you started?"
|
|
95
|
+
|
|
96
|
+
**Pre-close (genuine):**
|
|
97
|
+
Answer fully. This is discovery, not closing. Do not try to close during discovery.
|
|
98
|
+
|
|
99
|
+
### Authority: "I need to check with my partner/family"
|
|
100
|
+
|
|
101
|
+
This is a legitimate blocker.
|
|
102
|
+
|
|
103
|
+
1. Respect it: "Of course — makes sense to discuss together"
|
|
104
|
+
2. Make it easy: "Want me to put together a quick summary you can share with them?"
|
|
105
|
+
3. Set a follow-up: "When do you think you'll have had a chance to chat? I can check back in"
|
|
106
|
+
4. Save to memory: who the decision-maker is, when the follow-up should happen
|
|
107
|
+
|
|
108
|
+
### Competition: "I'm also looking at [competitor]"
|
|
109
|
+
|
|
110
|
+
1. Never disparage the competitor
|
|
111
|
+
2. Ask what matters most to them — let them tell you what to sell
|
|
112
|
+
3. Position on genuine differentiators, not feature lists
|
|
113
|
+
4. Load `references/comparisons.md` for specific positioning
|
|
114
|
+
|
|
115
|
+
### Trust: "How do I know it actually works?"
|
|
116
|
+
|
|
117
|
+
1. Offer to walk them through specifics relevant to their use case
|
|
118
|
+
2. Reference the waitlist and early access — being honest about where Maxy is builds trust
|
|
119
|
+
3. Emphasise the local-first privacy model — data stays in their home
|
|
120
|
+
4. Be honest: "We're early — the best way to see is to try it. That's why we're building a waitlist of people who want to shape what Maxy becomes."
|
|
121
|
+
|
|
122
|
+
## Concession Strategy
|
|
123
|
+
|
|
124
|
+
If you must concede (with authorisation only):
|
|
125
|
+
|
|
126
|
+
1. **Never concede first.** Let them state what they want.
|
|
127
|
+
2. **Never concede for free.** Always ask for something in return:
|
|
128
|
+
- Faster commitment: "I can do that if you confirm today"
|
|
129
|
+
- Longer term: "I can reduce the monthly if you commit for 12 months"
|
|
130
|
+
- Referral: "I can offer a discount if you're happy to refer us to two others"
|
|
131
|
+
- Case study: "I can adjust the price if we can use this as a case study"
|
|
132
|
+
3. **Concede slowly.** Small steps, not big jumps. Each concession should feel hard-won.
|
|
133
|
+
4. **Name what you're giving up.** Don't just lower the number — show what the concession costs.
|
|
134
|
+
|
|
135
|
+
## When to Hold Firm
|
|
136
|
+
|
|
137
|
+
- The prospect hasn't completed discovery (they don't understand the value yet)
|
|
138
|
+
- You've already reframed and the value is clear
|
|
139
|
+
- A minimum price has been set
|
|
140
|
+
- The prospect is negotiating for sport, not from genuine budget constraints
|
|
141
|
+
|
|
142
|
+
## When to Flex
|
|
143
|
+
|
|
144
|
+
- The prospect has genuine budget constraints but is otherwise a great fit
|
|
145
|
+
- A smaller deal now could lead to a larger one later
|
|
146
|
+
- Flexibility has been authorised
|
|
147
|
+
- You can reduce scope rather than reduce price
|
|
148
|
+
|
|
149
|
+
## Escalation
|
|
150
|
+
|
|
151
|
+
Some objections require a human. Escalate when:
|
|
152
|
+
|
|
153
|
+
- The prospect wants to negotiate pricing or custom terms
|
|
154
|
+
- The prospect wants a personal guarantee or commitment the agent cannot make
|
|
155
|
+
- The prospect raises a concern that cannot be resolved from available knowledge
|
|
156
|
+
- The objection has been addressed but the prospect is still not moving forward after 3 attempts
|
|
157
|
+
- The prospect requests human contact — always respect this immediately
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Maxy Pricing
|
|
2
|
+
|
|
3
|
+
## Subscription Plans
|
|
4
|
+
|
|
5
|
+
### Solo — £20/month
|
|
6
|
+
For individuals. One user, one Maxy instance.
|
|
7
|
+
|
|
8
|
+
Includes:
|
|
9
|
+
- Maxy core assistant (calendar, reminders, messages, smart home)
|
|
10
|
+
- WhatsApp, voice, and web access
|
|
11
|
+
- Memory and context across conversations
|
|
12
|
+
- Claude Pro AI backbone (£16/month value included)
|
|
13
|
+
|
|
14
|
+
Hardware required: Maxy Pi (from £125, one-time purchase)
|
|
15
|
+
|
|
16
|
+
### Family — £60/month
|
|
17
|
+
For households. Multiple users, shared context with individual privacy.
|
|
18
|
+
|
|
19
|
+
Includes:
|
|
20
|
+
- Everything in Solo
|
|
21
|
+
- Multi-user support (family members each get their own profile)
|
|
22
|
+
- Family-aware coordination (shared calendar, household tasks, family reminders)
|
|
23
|
+
- Claude Max AI backbone (£80/month value included)
|
|
24
|
+
|
|
25
|
+
Hardware required: Maxy Pi (from £180 for Family-spec device, one-time purchase)
|
|
26
|
+
|
|
27
|
+
## Skill Packs — £5/month each, or all 6 for £20/month
|
|
28
|
+
|
|
29
|
+
Modular capabilities you add based on what you need:
|
|
30
|
+
|
|
31
|
+
| Skill Pack | What it does |
|
|
32
|
+
|-----------|-------------|
|
|
33
|
+
| **Home** | Smart home management, energy monitoring, household routines |
|
|
34
|
+
| **Finance** | Budget tracking, bill reminders, spending insights |
|
|
35
|
+
| **Wellness** | Health reminders, fitness tracking integration, wellbeing check-ins |
|
|
36
|
+
| **Professional** | Work calendar, meeting prep, email drafting, task management |
|
|
37
|
+
| **Family** | Family coordination, school schedules, activity planning, shared lists |
|
|
38
|
+
| **Travel** | Trip planning, booking assistance, itinerary management |
|
|
39
|
+
|
|
40
|
+
**Bundle deal:** All 6 plugin packs for £20/month (save £10/month vs buying individually).
|
|
41
|
+
|
|
42
|
+
## Premium Skills
|
|
43
|
+
|
|
44
|
+
### Beagle — Separate Product
|
|
45
|
+
Beagle is a premium booking agent for local services. It finds, compares, and books local service providers (plumbers, cleaners, electricians, etc.) on your behalf.
|
|
46
|
+
|
|
47
|
+
Beagle is a separate product with its own pricing — not included in the Maxy subscription or plugin pack bundles.
|
|
48
|
+
|
|
49
|
+
## Hardware
|
|
50
|
+
|
|
51
|
+
### Maxy Pi — from £125
|
|
52
|
+
Raspberry Pi-based home hub. Runs Maxy locally. Your data stays in your home.
|
|
53
|
+
|
|
54
|
+
- Solo spec: from £125
|
|
55
|
+
- Family spec: from £180 (more processing power for multi-user)
|
|
56
|
+
- One-time purchase, no rental or lease
|
|
57
|
+
|
|
58
|
+
### Maxy Mini — ~£370
|
|
59
|
+
Reachy Mini robot form factor. Physical presence in the home. Same Maxy brain, embodied.
|
|
60
|
+
|
|
61
|
+
- Desktop robot with screen and movement
|
|
62
|
+
- Voice interaction with physical presence
|
|
63
|
+
- Premium hardware option for those who want Maxy to feel more tangible
|
|
64
|
+
|
|
65
|
+
## Pricing Principles
|
|
66
|
+
|
|
67
|
+
- **Never apologise for the price.** The value is real. Frame cost as investment.
|
|
68
|
+
- **Always show what's included.** The Claude Pro/Max backbone alone costs £16-£80/month — Maxy wraps that in a complete assistant experience.
|
|
69
|
+
- **Lead with the plan, not the hardware.** Monthly subscription is the ongoing relationship. Hardware is the one-time setup cost.
|
|
70
|
+
- **Plugin packs are upsell, not barrier.** Core Maxy works without plugin packs. Packs add depth in specific areas.
|
|
71
|
+
- **The bundle is the anchor.** When discussing plugin packs, mention the all-6-for-£20 bundle first — it makes individual packs feel like a bargain.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Waitlist Capture
|
|
2
|
+
|
|
3
|
+
## When to Offer
|
|
4
|
+
|
|
5
|
+
After substantive engagement (3+ exchanges or a direct interest signal such as "how do I sign up", "I want this", "when can I start"), naturally offer the waitlist. Do not force it — let it flow from the conversation.
|
|
6
|
+
|
|
7
|
+
## Flow
|
|
8
|
+
|
|
9
|
+
1. Ask for their name and email
|
|
10
|
+
2. Confirm: "You're on the list! We'll be in touch as soon as your spot opens up."
|
|
11
|
+
|
|
12
|
+
If they decline, respect it and continue the conversation. Do not re-ask in the same session.
|
|
13
|
+
|
|
14
|
+
## What Happens Next
|
|
15
|
+
|
|
16
|
+
You do not write any data. The name and email collected in conversation are extracted by the admin team's periodic review job, which creates the Person node in the graph. The admin reviews all public conversations on a regular cycle.
|
|
17
|
+
|
|
18
|
+
## Tone
|
|
19
|
+
|
|
20
|
+
- Warm, not pushy
|
|
21
|
+
- One ask per session maximum
|
|
22
|
+
- Frame it as keeping them informed, not as a commitment
|
|
23
|
+
- If they've already expressed interest in a prior session, acknowledge that warmly
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scheduling
|
|
3
|
+
description: "Scheduling plugin. Provides calendar and appointment management tools. Phase 1 — stub implementation."
|
|
4
|
+
icon: 📅
|
|
5
|
+
tools: []
|
|
6
|
+
always: false
|
|
7
|
+
embed: false
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Scheduling
|
|
11
|
+
|
|
12
|
+
Calendar and appointment management. Phase 1 stub — not yet implemented.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
const server = new McpServer({
|
|
5
|
+
name: "maxy-scheduling",
|
|
6
|
+
version: "0.1.0",
|
|
7
|
+
});
|
|
8
|
+
server.tool("schedule-event", "Schedule an event or appointment", { summary: z.string(), startDate: z.string(), endDate: z.string().optional() }, async () => ({ content: [{ type: "text", text: "Scheduling is not available in Phase 0. This capability will be added in Phase 1." }] }));
|
|
9
|
+
server.tool("schedule-list", "List upcoming scheduled events", { from: z.string().optional(), to: z.string().optional() }, async () => ({ content: [{ type: "text", text: "Scheduling is not available in Phase 0. This capability will be added in Phase 1." }] }));
|
|
10
|
+
server.tool("schedule-cancel", "Cancel a scheduled event", { eventId: z.string() }, async () => ({ content: [{ type: "text", text: "Scheduling is not available in Phase 0. This capability will be added in Phase 1." }] }));
|
|
11
|
+
const transport = new StdioServerTransport();
|
|
12
|
+
await server.connect(transport);
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,iBAAiB;IACvB,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,MAAM,CAAC,IAAI,CACT,gBAAgB,EAChB,kCAAkC,EAClC,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,EAC9E,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,mFAAmF,EAAE,CAAC,EAAE,CAAC,CAClJ,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,eAAe,EACf,gCAAgC,EAChC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,EAC1D,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,mFAAmF,EAAE,CAAC,EAAE,CAAC,CAClJ,CAAC;AAEF,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,0BAA0B,EAC1B,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,EACvB,KAAK,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,mFAAmF,EAAE,CAAC,EAAE,CAAC,CAClJ,CAAC;AAEF,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@maxy/scheduling",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"start": "node dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@modelcontextprotocol/sdk": "^1.12.1"
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"typescript": "^5.7.0",
|
|
16
|
+
"@types/node": "^22.0.0"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: telegram
|
|
3
|
+
description: Guide users through connecting a Telegram bot — creating a bot via BotFather, finding user IDs, and configuring admin vs public bots.
|
|
4
|
+
metadata: {"taskmaster":{"emoji":"✈️"}}
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Telegram Setup
|
|
8
|
+
|
|
9
|
+
Walks users through connecting Telegram bots to Taskmaster. Covers bot creation, token configuration, finding numeric user IDs, and choosing between admin and public bot roles.
|
|
10
|
+
|
|
11
|
+
## When to activate
|
|
12
|
+
|
|
13
|
+
- User asks how to connect Telegram or set up a Telegram bot
|
|
14
|
+
- User asks about BotFather, bot tokens, or Telegram integration
|
|
15
|
+
- User needs to find their Telegram user ID for admin binding
|
|
16
|
+
- User asks about admin vs public bot configuration
|
|
17
|
+
- User is on the Setup page and asks about the Telegram section
|
|
18
|
+
|
|
19
|
+
## What it unlocks
|
|
20
|
+
|
|
21
|
+
- Telegram as a messaging channel — DMs and group conversations routed to the AI assistant
|
|
22
|
+
- Multi-bot support — separate admin and public bots with different access policies
|
|
23
|
+
- Admin routing — restrict a bot to admin-only access via numeric user ID bindings
|
|
24
|
+
|
|
25
|
+
## References
|
|
26
|
+
|
|
27
|
+
| Task | When to use | Reference |
|
|
28
|
+
|------|-------------|-----------|
|
|
29
|
+
| Guided setup | User wants help connecting Telegram | `references/setup-guide.md` |
|
|
30
|
+
|
|
31
|
+
Load the reference and follow its instructions.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { message } from "./tools/message.js";
|
|
5
|
+
import { messageHistory } from "./tools/message-history.js";
|
|
6
|
+
const server = new McpServer({
|
|
7
|
+
name: "maxy-messaging",
|
|
8
|
+
version: "0.1.0",
|
|
9
|
+
});
|
|
10
|
+
server.tool("message", "Send a message via Telegram. Supports text with HTML formatting and inline keyboards for interactive choices.", {
|
|
11
|
+
channel: z.literal("telegram").describe("Delivery channel"),
|
|
12
|
+
chatId: z
|
|
13
|
+
.union([z.string(), z.number()])
|
|
14
|
+
.describe("Telegram chat ID to send to"),
|
|
15
|
+
text: z.string().describe("Message text (HTML formatting supported)"),
|
|
16
|
+
parseMode: z
|
|
17
|
+
.enum(["HTML", "Markdown", "MarkdownV2"])
|
|
18
|
+
.optional()
|
|
19
|
+
.describe("Parse mode (default: HTML)"),
|
|
20
|
+
inlineKeyboard: z
|
|
21
|
+
.array(z.array(z.object({
|
|
22
|
+
text: z.string().describe("Button label"),
|
|
23
|
+
callbackData: z
|
|
24
|
+
.string()
|
|
25
|
+
.optional()
|
|
26
|
+
.describe("Callback data for button press"),
|
|
27
|
+
url: z.string().optional().describe("URL to open on button press"),
|
|
28
|
+
})))
|
|
29
|
+
.optional()
|
|
30
|
+
.describe("Inline keyboard rows for interactive buttons"),
|
|
31
|
+
}, async (params) => {
|
|
32
|
+
try {
|
|
33
|
+
const result = await message(params);
|
|
34
|
+
if (!result.sent) {
|
|
35
|
+
return {
|
|
36
|
+
content: [
|
|
37
|
+
{
|
|
38
|
+
type: "text",
|
|
39
|
+
text: `Message failed: ${result.error}`,
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
isError: true,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
content: [
|
|
47
|
+
{
|
|
48
|
+
type: "text",
|
|
49
|
+
text: `Message sent via ${result.channel} (ID: ${result.messageId})`,
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
return {
|
|
56
|
+
content: [
|
|
57
|
+
{
|
|
58
|
+
type: "text",
|
|
59
|
+
text: `Send failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
isError: true,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
server.tool("message-history", "Query conversation history from the message log.", {
|
|
67
|
+
channel: z.string().optional().describe("Filter by channel (telegram)"),
|
|
68
|
+
chatId: z.string().optional().describe("Filter by chat ID"),
|
|
69
|
+
limit: z.number().optional().describe("Max messages to return (default 20)"),
|
|
70
|
+
}, async ({ channel, chatId, limit }) => {
|
|
71
|
+
try {
|
|
72
|
+
const history = await messageHistory({ channel, chatId, limit });
|
|
73
|
+
if (history.length === 0) {
|
|
74
|
+
return {
|
|
75
|
+
content: [
|
|
76
|
+
{ type: "text", text: "No message history found." },
|
|
77
|
+
],
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
const formatted = history
|
|
81
|
+
.map((h) => `[${h.timestamp}] ${h.channel}/${h.chatId} (${h.role}): ${h.content.slice(0, 200)}${h.content.length > 200 ? "..." : ""}`)
|
|
82
|
+
.join("\n");
|
|
83
|
+
return {
|
|
84
|
+
content: [{ type: "text", text: formatted }],
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
return {
|
|
89
|
+
content: [
|
|
90
|
+
{
|
|
91
|
+
type: "text",
|
|
92
|
+
text: `History query failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
isError: true,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
const transport = new StdioServerTransport();
|
|
100
|
+
await server.connect(transport);
|
|
101
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface TelegramSendOptions {
|
|
2
|
+
chatId: string | number;
|
|
3
|
+
text: string;
|
|
4
|
+
parseMode?: "HTML" | "Markdown" | "MarkdownV2";
|
|
5
|
+
replyMarkup?: TelegramInlineKeyboard;
|
|
6
|
+
}
|
|
7
|
+
export interface TelegramInlineKeyboard {
|
|
8
|
+
inline_keyboard: Array<Array<{
|
|
9
|
+
text: string;
|
|
10
|
+
callback_data?: string;
|
|
11
|
+
url?: string;
|
|
12
|
+
}>>;
|
|
13
|
+
}
|
|
14
|
+
export declare function sendMessage(botToken: string, options: TelegramSendOptions): Promise<{
|
|
15
|
+
ok: boolean;
|
|
16
|
+
messageId?: number;
|
|
17
|
+
error?: string;
|
|
18
|
+
}>;
|
|
19
|
+
export declare function setWebhook(botToken: string, webhookUrl: string): Promise<{
|
|
20
|
+
ok: boolean;
|
|
21
|
+
error?: string;
|
|
22
|
+
}>;
|
|
23
|
+
export declare function getWebhookInfo(botToken: string): Promise<{
|
|
24
|
+
url: string;
|
|
25
|
+
pendingUpdateCount: number;
|
|
26
|
+
}>;
|
|
27
|
+
//# sourceMappingURL=telegram.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegram.d.ts","sourceRoot":"","sources":["../../src/lib/telegram.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,YAAY,CAAC;IAC/C,WAAW,CAAC,EAAE,sBAAsB,CAAC;CACtC;AAED,MAAM,WAAW,sBAAsB;IACrC,eAAe,EAAE,KAAK,CACpB,KAAK,CAAC;QACJ,IAAI,EAAE,MAAM,CAAC;QACb,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC,CACH,CAAC;CACH;AAED,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAyB9D;AAED,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAiB1C;AAED,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,kBAAkB,EAAE,MAAM,CAAA;CAAE,CAAC,CAWtD"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const TELEGRAM_API = "https://api.telegram.org";
|
|
2
|
+
export async function sendMessage(botToken, options) {
|
|
3
|
+
const res = await fetch(`${TELEGRAM_API}/bot${botToken}/sendMessage`, {
|
|
4
|
+
method: "POST",
|
|
5
|
+
headers: { "Content-Type": "application/json" },
|
|
6
|
+
body: JSON.stringify({
|
|
7
|
+
chat_id: options.chatId,
|
|
8
|
+
text: options.text,
|
|
9
|
+
parse_mode: options.parseMode ?? "HTML",
|
|
10
|
+
reply_markup: options.replyMarkup
|
|
11
|
+
? JSON.stringify(options.replyMarkup)
|
|
12
|
+
: undefined,
|
|
13
|
+
}),
|
|
14
|
+
});
|
|
15
|
+
const data = (await res.json());
|
|
16
|
+
if (!data.ok) {
|
|
17
|
+
return { ok: false, error: data.description ?? "Unknown Telegram error" };
|
|
18
|
+
}
|
|
19
|
+
return { ok: true, messageId: data.result?.message_id };
|
|
20
|
+
}
|
|
21
|
+
export async function setWebhook(botToken, webhookUrl) {
|
|
22
|
+
const res = await fetch(`${TELEGRAM_API}/bot${botToken}/setWebhook`, {
|
|
23
|
+
method: "POST",
|
|
24
|
+
headers: { "Content-Type": "application/json" },
|
|
25
|
+
body: JSON.stringify({ url: webhookUrl }),
|
|
26
|
+
});
|
|
27
|
+
const data = (await res.json());
|
|
28
|
+
if (!data.ok) {
|
|
29
|
+
return { ok: false, error: data.description ?? "Failed to set webhook" };
|
|
30
|
+
}
|
|
31
|
+
return { ok: true };
|
|
32
|
+
}
|
|
33
|
+
export async function getWebhookInfo(botToken) {
|
|
34
|
+
const res = await fetch(`${TELEGRAM_API}/bot${botToken}/getWebhookInfo`);
|
|
35
|
+
const data = (await res.json());
|
|
36
|
+
return {
|
|
37
|
+
url: data.result.url,
|
|
38
|
+
pendingUpdateCount: data.result.pending_update_count,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=telegram.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegram.js","sourceRoot":"","sources":["../../src/lib/telegram.ts"],"names":[],"mappings":"AAAA,MAAM,YAAY,GAAG,0BAA0B,CAAC;AAmBhD,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,QAAgB,EAChB,OAA4B;IAE5B,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,YAAY,OAAO,QAAQ,cAAc,EAAE;QACpE,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;YACnB,OAAO,EAAE,OAAO,CAAC,MAAM;YACvB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,UAAU,EAAE,OAAO,CAAC,SAAS,IAAI,MAAM;YACvC,YAAY,EAAE,OAAO,CAAC,WAAW;gBAC/B,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC;gBACrC,CAAC,CAAC,SAAS;SACd,CAAC;KACH,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAI7B,CAAC;IAEF,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,WAAW,IAAI,wBAAwB,EAAE,CAAC;IAC5E,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC;AAC1D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,QAAgB,EAChB,UAAkB;IAElB,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,YAAY,OAAO,QAAQ,aAAa,EAAE;QACnE,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC;KAC1C,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAG7B,CAAC;IAEF,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,WAAW,IAAI,uBAAuB,EAAE,CAAC;IAC3E,CAAC;IAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAAgB;IAEhB,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,GAAG,YAAY,OAAO,QAAQ,iBAAiB,CAChD,CAAC;IACF,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAE7B,CAAC;IACF,OAAO;QACL,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG;QACpB,kBAAkB,EAAE,IAAI,CAAC,MAAM,CAAC,oBAAoB;KACrD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
interface HistoryParams {
|
|
2
|
+
channel?: string;
|
|
3
|
+
chatId?: string;
|
|
4
|
+
accountId?: string;
|
|
5
|
+
limit?: number;
|
|
6
|
+
}
|
|
7
|
+
interface HistoryEntry {
|
|
8
|
+
channel: string;
|
|
9
|
+
chatId: string;
|
|
10
|
+
role: string;
|
|
11
|
+
content: string;
|
|
12
|
+
timestamp: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function messageHistory(params: HistoryParams): Promise<HistoryEntry[]>;
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=message-history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-history.d.ts","sourceRoot":"","sources":["../../src/tools/message-history.ts"],"names":[],"mappings":"AAiCA,UAAU,aAAa;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,YAAY;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAsB,cAAc,CAClC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,YAAY,EAAE,CAAC,CAyCzB"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import neo4j from "neo4j-driver";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
let driver = null;
|
|
5
|
+
function readPassword() {
|
|
6
|
+
if (process.env.NEO4J_PASSWORD)
|
|
7
|
+
return process.env.NEO4J_PASSWORD;
|
|
8
|
+
const passwordFile = resolve(process.env.PLATFORM_ROOT ?? resolve(import.meta.dirname, "../../../.."), "config/.neo4j-password");
|
|
9
|
+
try {
|
|
10
|
+
return readFileSync(passwordFile, "utf-8").trim();
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
throw new Error(`Neo4j password not found. Expected at ${passwordFile} or in NEO4J_PASSWORD env var.`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function getSession() {
|
|
17
|
+
if (!driver) {
|
|
18
|
+
const uri = process.env.NEO4J_URI ?? "bolt://localhost:7687";
|
|
19
|
+
const user = process.env.NEO4J_USER ?? "neo4j";
|
|
20
|
+
const password = readPassword();
|
|
21
|
+
driver = neo4j.driver(uri, neo4j.auth.basic(user, password));
|
|
22
|
+
}
|
|
23
|
+
return driver.session();
|
|
24
|
+
}
|
|
25
|
+
export async function messageHistory(params) {
|
|
26
|
+
const { channel, chatId, accountId, limit = 20 } = params;
|
|
27
|
+
const session = getSession();
|
|
28
|
+
try {
|
|
29
|
+
const conditions = ["m.accountId = $accountId"];
|
|
30
|
+
const queryParams = { accountId, limit };
|
|
31
|
+
if (channel) {
|
|
32
|
+
conditions.push("m.channel = $channel");
|
|
33
|
+
queryParams.channel = channel;
|
|
34
|
+
}
|
|
35
|
+
if (chatId) {
|
|
36
|
+
conditions.push("m.chatId = $chatId");
|
|
37
|
+
queryParams.chatId = chatId;
|
|
38
|
+
}
|
|
39
|
+
const query = `
|
|
40
|
+
MATCH (m:Communication)
|
|
41
|
+
WHERE ${conditions.join(" AND ")}
|
|
42
|
+
RETURN m
|
|
43
|
+
ORDER BY m.dateSent DESC
|
|
44
|
+
LIMIT $limit
|
|
45
|
+
`;
|
|
46
|
+
const result = await session.run(query, queryParams);
|
|
47
|
+
return result.records.map((record) => {
|
|
48
|
+
const m = record.get("m").properties;
|
|
49
|
+
return {
|
|
50
|
+
channel: m.channel,
|
|
51
|
+
chatId: m.chatId,
|
|
52
|
+
role: m.role,
|
|
53
|
+
content: m.content,
|
|
54
|
+
timestamp: m.dateSent,
|
|
55
|
+
};
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
await session.close();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=message-history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-history.js","sourceRoot":"","sources":["../../src/tools/message-history.ts"],"names":[],"mappings":"AAAA,OAAO,KAAoC,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,IAAI,MAAM,GAAkB,IAAI,CAAC;AAEjC,SAAS,YAAY;IACnB,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc;QAAE,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAElE,MAAM,YAAY,GAAG,OAAO,CAC1B,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,EACxE,wBAAwB,CACzB,CAAC;IAEF,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IACpD,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,yCAAyC,YAAY,gCAAgC,CACtF,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,UAAU;IACjB,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,uBAAuB,CAAC;QAC7D,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,OAAO,CAAC;QAC/C,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;QAChC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC;AAC1B,CAAC;AAiBD,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAqB;IAErB,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,GAAG,EAAE,EAAE,GAAG,MAAM,CAAC;IAE1D,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAE7B,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,CAAC,0BAA0B,CAAC,CAAC;QAChD,MAAM,WAAW,GAA4B,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;QAElE,IAAI,OAAO,EAAE,CAAC;YACZ,UAAU,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;YACxC,WAAW,CAAC,OAAO,GAAG,OAAO,CAAC;QAChC,CAAC;QACD,IAAI,MAAM,EAAE,CAAC;YACX,UAAU,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;YACtC,WAAW,CAAC,MAAM,GAAG,MAAM,CAAC;QAC9B,CAAC;QAED,MAAM,KAAK,GAAG;;cAEJ,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC;;;;KAIjC,CAAC;QAEF,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;QAErD,OAAO,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;YACnC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC;YACrC,OAAO;gBACL,OAAO,EAAE,CAAC,CAAC,OAAiB;gBAC5B,MAAM,EAAE,CAAC,CAAC,MAAgB;gBAC1B,IAAI,EAAE,CAAC,CAAC,IAAc;gBACtB,OAAO,EAAE,CAAC,CAAC,OAAiB;gBAC5B,SAAS,EAAE,CAAC,CAAC,QAAkB;aAChC,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
interface MessageParams {
|
|
2
|
+
channel: "telegram";
|
|
3
|
+
chatId: string | number;
|
|
4
|
+
text: string;
|
|
5
|
+
parseMode?: "HTML" | "Markdown" | "MarkdownV2";
|
|
6
|
+
inlineKeyboard?: Array<Array<{
|
|
7
|
+
text: string;
|
|
8
|
+
callbackData?: string;
|
|
9
|
+
url?: string;
|
|
10
|
+
}>>;
|
|
11
|
+
}
|
|
12
|
+
interface MessageResult {
|
|
13
|
+
sent: boolean;
|
|
14
|
+
channel: string;
|
|
15
|
+
messageId?: number;
|
|
16
|
+
error?: string;
|
|
17
|
+
}
|
|
18
|
+
export declare function message(params: MessageParams): Promise<MessageResult>;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=message.d.ts.map
|