@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,174 @@
|
|
|
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 { join } from "node:path";
|
|
5
|
+
import * as cloudflared from "./lib/cloudflared.js";
|
|
6
|
+
const server = new McpServer({
|
|
7
|
+
name: "cloudflare",
|
|
8
|
+
version: "0.1.0",
|
|
9
|
+
});
|
|
10
|
+
// ===================================================================
|
|
11
|
+
// Cloudflare Tunnel tools
|
|
12
|
+
// ===================================================================
|
|
13
|
+
server.tool("tunnel-status", "Full Cloudflare Tunnel status: installed, version, authenticated, running, domain, URLs.", {
|
|
14
|
+
domain: z.string().optional().describe("The bare domain (e.g. 'maxy.bot'). If omitted, domain info is excluded."),
|
|
15
|
+
}, async ({ domain }) => {
|
|
16
|
+
try {
|
|
17
|
+
const status = cloudflared.getStatus(domain);
|
|
18
|
+
return {
|
|
19
|
+
content: [{ type: "text", text: JSON.stringify(status, null, 2) }],
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
return {
|
|
24
|
+
content: [{ type: "text", text: `Failed: ${err instanceof Error ? err.message : String(err)}` }],
|
|
25
|
+
isError: true,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
server.tool("tunnel-install", "Install the cloudflared binary if not already present.", {}, async () => {
|
|
30
|
+
const { execFileSync } = await import("node:child_process");
|
|
31
|
+
if (cloudflared.isInstalled()) {
|
|
32
|
+
const v = cloudflared.version();
|
|
33
|
+
return {
|
|
34
|
+
content: [{ type: "text", text: `cloudflared is already installed (v${v}).` }],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
const arch = process.arch === "arm64" ? "arm64" : "amd64";
|
|
39
|
+
const debUrl = `https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-${arch}.deb`;
|
|
40
|
+
execFileSync("curl", ["-fsSL", debUrl, "-o", "/tmp/cloudflared.deb"], { timeout: 60000 });
|
|
41
|
+
execFileSync("sudo", ["dpkg", "-i", "/tmp/cloudflared.deb"], { timeout: 30000 });
|
|
42
|
+
execFileSync("rm", ["-f", "/tmp/cloudflared.deb"]);
|
|
43
|
+
return {
|
|
44
|
+
content: [{ type: "text", text: `cloudflared installed (v${cloudflared.version()}).` }],
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
return {
|
|
49
|
+
content: [{ type: "text", text: `Installation failed: ${err instanceof Error ? err.message : String(err)}` }],
|
|
50
|
+
isError: true,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
server.tool("tunnel-login", "Start Cloudflare authentication. Returns a URL (and QR code data) that the user must visit to authorise this device. On a headless device, scan the QR code with your phone.", {}, async () => {
|
|
55
|
+
if (!cloudflared.isInstalled()) {
|
|
56
|
+
return {
|
|
57
|
+
content: [{ type: "text", text: "cloudflared is not installed. Run tunnel-install first." }],
|
|
58
|
+
isError: true,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
if (cloudflared.isAuthenticated()) {
|
|
62
|
+
return {
|
|
63
|
+
content: [{ type: "text", text: "Already authenticated with Cloudflare." }],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
const login = cloudflared.startLogin();
|
|
68
|
+
// Wait up to 15 seconds for the auth URL to appear in output
|
|
69
|
+
const startTime = Date.now();
|
|
70
|
+
while (!login.authUrl && Date.now() - startTime < 15000) {
|
|
71
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
72
|
+
}
|
|
73
|
+
if (!login.authUrl) {
|
|
74
|
+
login.process.kill();
|
|
75
|
+
return {
|
|
76
|
+
content: [{ type: "text", text: "Timed out waiting for Cloudflare auth URL. Check cloudflared logs." }],
|
|
77
|
+
isError: true,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
content: [
|
|
82
|
+
{
|
|
83
|
+
type: "text",
|
|
84
|
+
text: `Cloudflare authentication started.\n\nVisit this URL to authorise this device:\n${login.authUrl}\n\nOn a headless device, use qr-generate to create a QR code for this URL, then scan it with your phone.\n\nWaiting for authentication to complete...`,
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
return {
|
|
91
|
+
content: [{ type: "text", text: `Login failed: ${err instanceof Error ? err.message : String(err)}` }],
|
|
92
|
+
isError: true,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
server.tool("tunnel-create", "Create a Cloudflare Tunnel and route DNS for admin.{domain} and public.{domain}.", {
|
|
97
|
+
domain: z.string().describe("The bare domain (e.g. 'maxy.bot'). Subdomains admin. and public. are created automatically."),
|
|
98
|
+
tunnelName: z.string().optional().describe("Human-readable tunnel name (default: derived from domain)"),
|
|
99
|
+
}, async ({ domain, tunnelName }) => {
|
|
100
|
+
if (!cloudflared.isInstalled()) {
|
|
101
|
+
return {
|
|
102
|
+
content: [{ type: "text", text: "cloudflared is not installed. Run tunnel-install first." }],
|
|
103
|
+
isError: true,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
if (!cloudflared.isAuthenticated()) {
|
|
107
|
+
return {
|
|
108
|
+
content: [{ type: "text", text: "Not authenticated with Cloudflare. Run tunnel-login first." }],
|
|
109
|
+
isError: true,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
const name = tunnelName ?? domain.replace(/\./g, "-");
|
|
114
|
+
const result = cloudflared.createTunnel(name);
|
|
115
|
+
cloudflared.routeDns(result.tunnelId, `admin.${domain}`);
|
|
116
|
+
cloudflared.routeDns(result.tunnelId, `public.${domain}`);
|
|
117
|
+
const configPath = cloudflared.writeConfig(result.tunnelId, result.credentialsFile, domain, 19200);
|
|
118
|
+
return {
|
|
119
|
+
content: [
|
|
120
|
+
{
|
|
121
|
+
type: "text",
|
|
122
|
+
text: `Tunnel created.\n\n ID: ${result.tunnelId}\n Name: ${result.tunnelName}\n DNS: admin.${domain} → tunnel\n DNS: public.${domain} → tunnel\n Config: ${configPath}\n\nUse tunnel-enable to start the tunnel.`,
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
return {
|
|
129
|
+
content: [{ type: "text", text: `Create failed: ${err instanceof Error ? err.message : String(err)}` }],
|
|
130
|
+
isError: true,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
server.tool("tunnel-enable", "Start the Cloudflare Tunnel process. The tunnel must be created first via tunnel-create.", {
|
|
135
|
+
tunnelId: z.string().describe("Tunnel UUID from tunnel-create"),
|
|
136
|
+
domain: z.string().describe("The bare domain (e.g. 'maxy.bot')"),
|
|
137
|
+
}, async ({ tunnelId, domain }) => {
|
|
138
|
+
try {
|
|
139
|
+
const credentialsFile = join(process.env.HOME ?? "/root", `.cloudflared/${tunnelId}.json`);
|
|
140
|
+
const configPath = cloudflared.writeConfig(tunnelId, credentialsFile, domain, 19200);
|
|
141
|
+
cloudflared.startTunnel(configPath);
|
|
142
|
+
return {
|
|
143
|
+
content: [
|
|
144
|
+
{
|
|
145
|
+
type: "text",
|
|
146
|
+
text: `Tunnel started.\n\n Admin: https://admin.${domain}\n Public: https://public.${domain}`,
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
catch (err) {
|
|
152
|
+
return {
|
|
153
|
+
content: [{ type: "text", text: `Enable failed: ${err instanceof Error ? err.message : String(err)}` }],
|
|
154
|
+
isError: true,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
server.tool("tunnel-disable", "Stop the Cloudflare Tunnel process. Config is preserved for re-enabling.", {}, async () => {
|
|
159
|
+
try {
|
|
160
|
+
cloudflared.stopTunnel();
|
|
161
|
+
return {
|
|
162
|
+
content: [{ type: "text", text: "Tunnel stopped. Config preserved — use tunnel-enable to restart." }],
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
return {
|
|
167
|
+
content: [{ type: "text", text: `Disable failed: ${err instanceof Error ? err.message : String(err)}` }],
|
|
168
|
+
isError: true,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
const transport = new StdioServerTransport();
|
|
173
|
+
await server.connect(transport);
|
|
174
|
+
//# 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,45 @@
|
|
|
1
|
+
import { type ChildProcess } from "node:child_process";
|
|
2
|
+
export declare function findBinary(): string | null;
|
|
3
|
+
export declare function isInstalled(): boolean;
|
|
4
|
+
export declare function version(): string | null;
|
|
5
|
+
export declare function isAuthenticated(): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Start the cloudflared login flow.
|
|
8
|
+
* Returns the auth URL that the user must visit (or encode as QR code).
|
|
9
|
+
* This is a long-running process — it waits for the user to authenticate
|
|
10
|
+
* in their browser. The process completes when cert.pem is written.
|
|
11
|
+
*/
|
|
12
|
+
export declare function startLogin(): {
|
|
13
|
+
authUrl: string;
|
|
14
|
+
process: ChildProcess;
|
|
15
|
+
};
|
|
16
|
+
interface TunnelCreateResult {
|
|
17
|
+
tunnelId: string;
|
|
18
|
+
tunnelName: string;
|
|
19
|
+
credentialsFile: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function createTunnel(name: string): TunnelCreateResult;
|
|
22
|
+
export declare function routeDns(tunnelId: string, hostname: string): void;
|
|
23
|
+
interface TunnelInfo {
|
|
24
|
+
id: string;
|
|
25
|
+
name: string;
|
|
26
|
+
}
|
|
27
|
+
export declare function listTunnels(): TunnelInfo[];
|
|
28
|
+
export declare function writeConfig(tunnelId: string, credentialsFile: string, domain: string, port: number): string;
|
|
29
|
+
export interface TunnelStatus {
|
|
30
|
+
installed: boolean;
|
|
31
|
+
version: string | null;
|
|
32
|
+
authenticated: boolean;
|
|
33
|
+
running: boolean;
|
|
34
|
+
pid: number | null;
|
|
35
|
+
domain: string | null;
|
|
36
|
+
adminUrl: string | null;
|
|
37
|
+
publicUrl: string | null;
|
|
38
|
+
upSince: number | null;
|
|
39
|
+
restartCount: number;
|
|
40
|
+
}
|
|
41
|
+
export declare function getStatus(domain?: string): TunnelStatus;
|
|
42
|
+
export declare function startTunnel(configPath: string): void;
|
|
43
|
+
export declare function stopTunnel(): void;
|
|
44
|
+
export {};
|
|
45
|
+
//# sourceMappingURL=cloudflared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudflared.d.ts","sourceRoot":"","sources":["../../src/lib/cloudflared.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAiB5E,wBAAgB,UAAU,IAAI,MAAM,GAAG,IAAI,CAsB1C;AAED,wBAAgB,WAAW,IAAI,OAAO,CAErC;AAED,wBAAgB,OAAO,IAAI,MAAM,GAAG,IAAI,CAUvC;AAQD,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,IAAI;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,YAAY,CAAA;CAAE,CAmCvE;AAMD,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,CA4B7D;AAED,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAcjE;AAED,UAAU,UAAU;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAgB,WAAW,IAAI,UAAU,EAAE,CAc1C;AAMD,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,MAAM,CAkBR;AAcD,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,wBAAgB,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,YAAY,CAavD;AAED,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAapD;AA8BD,wBAAgB,UAAU,IAAI,IAAI,CAsBjC"}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { execFileSync, spawn } from "node:child_process";
|
|
2
|
+
import { existsSync, writeFileSync, mkdirSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { homedir } from "node:os";
|
|
5
|
+
// ---------------------------------------------------------------------------
|
|
6
|
+
// Binary detection
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
let cachedBinaryPath = null;
|
|
9
|
+
const SEARCH_PATHS = [
|
|
10
|
+
"/usr/local/bin/cloudflared",
|
|
11
|
+
"/usr/bin/cloudflared",
|
|
12
|
+
join(homedir(), ".local/bin/cloudflared"),
|
|
13
|
+
];
|
|
14
|
+
export function findBinary() {
|
|
15
|
+
if (cachedBinaryPath)
|
|
16
|
+
return cachedBinaryPath;
|
|
17
|
+
// Try `which` first
|
|
18
|
+
try {
|
|
19
|
+
cachedBinaryPath = execFileSync("which", ["cloudflared"], {
|
|
20
|
+
encoding: "utf-8",
|
|
21
|
+
timeout: 5000,
|
|
22
|
+
}).trim();
|
|
23
|
+
return cachedBinaryPath;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// not on PATH
|
|
27
|
+
}
|
|
28
|
+
for (const p of SEARCH_PATHS) {
|
|
29
|
+
if (existsSync(p)) {
|
|
30
|
+
cachedBinaryPath = p;
|
|
31
|
+
return p;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
export function isInstalled() {
|
|
37
|
+
return findBinary() !== null;
|
|
38
|
+
}
|
|
39
|
+
export function version() {
|
|
40
|
+
const bin = findBinary();
|
|
41
|
+
if (!bin)
|
|
42
|
+
return null;
|
|
43
|
+
try {
|
|
44
|
+
const out = execFileSync(bin, ["--version"], { encoding: "utf-8", timeout: 5000 });
|
|
45
|
+
const match = out.match(/cloudflared version (\S+)/);
|
|
46
|
+
return match?.[1] ?? out.trim();
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Authentication
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
const CERT_PATH = join(homedir(), ".cloudflared/cert.pem");
|
|
56
|
+
export function isAuthenticated() {
|
|
57
|
+
return existsSync(CERT_PATH);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Start the cloudflared login flow.
|
|
61
|
+
* Returns the auth URL that the user must visit (or encode as QR code).
|
|
62
|
+
* This is a long-running process — it waits for the user to authenticate
|
|
63
|
+
* in their browser. The process completes when cert.pem is written.
|
|
64
|
+
*/
|
|
65
|
+
export function startLogin() {
|
|
66
|
+
const bin = findBinary();
|
|
67
|
+
if (!bin)
|
|
68
|
+
throw new Error("cloudflared is not installed");
|
|
69
|
+
const child = spawn(bin, ["tunnel", "login"], {
|
|
70
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
71
|
+
});
|
|
72
|
+
let authUrl = "";
|
|
73
|
+
let stderrBuffer = "";
|
|
74
|
+
// cloudflared prints the auth URL to stderr
|
|
75
|
+
child.stderr?.on("data", (chunk) => {
|
|
76
|
+
stderrBuffer += chunk.toString();
|
|
77
|
+
const match = stderrBuffer.match(/(https:\/\/dash\.cloudflare\.com\/argotunnel[^\s]+)/);
|
|
78
|
+
if (match && !authUrl) {
|
|
79
|
+
authUrl = match[1];
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
// Also check stdout (some versions print there)
|
|
83
|
+
child.stdout?.on("data", (chunk) => {
|
|
84
|
+
const text = chunk.toString();
|
|
85
|
+
const match = text.match(/(https:\/\/dash\.cloudflare\.com\/argotunnel[^\s]+)/);
|
|
86
|
+
if (match && !authUrl) {
|
|
87
|
+
authUrl = match[1];
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
return {
|
|
91
|
+
get authUrl() {
|
|
92
|
+
return authUrl;
|
|
93
|
+
},
|
|
94
|
+
process: child,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
export function createTunnel(name) {
|
|
98
|
+
const bin = findBinary();
|
|
99
|
+
if (!bin)
|
|
100
|
+
throw new Error("cloudflared is not installed");
|
|
101
|
+
// Check for existing tunnel with this name
|
|
102
|
+
const existing = listTunnels().find((t) => t.name === name);
|
|
103
|
+
if (existing) {
|
|
104
|
+
const credentialsFile = join(homedir(), `.cloudflared/${existing.id}.json`);
|
|
105
|
+
return {
|
|
106
|
+
tunnelId: existing.id,
|
|
107
|
+
tunnelName: existing.name,
|
|
108
|
+
credentialsFile,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
const output = execFileSync(bin, ["tunnel", "create", name], {
|
|
112
|
+
encoding: "utf-8",
|
|
113
|
+
timeout: 30000,
|
|
114
|
+
});
|
|
115
|
+
// Parse tunnel ID from output: "Created tunnel {name} with id {uuid}"
|
|
116
|
+
const match = output.match(/with id ([a-f0-9-]+)/);
|
|
117
|
+
if (!match)
|
|
118
|
+
throw new Error(`Failed to parse tunnel ID from: ${output}`);
|
|
119
|
+
const tunnelId = match[1];
|
|
120
|
+
const credentialsFile = join(homedir(), `.cloudflared/${tunnelId}.json`);
|
|
121
|
+
return { tunnelId, tunnelName: name, credentialsFile };
|
|
122
|
+
}
|
|
123
|
+
export function routeDns(tunnelId, hostname) {
|
|
124
|
+
const bin = findBinary();
|
|
125
|
+
if (!bin)
|
|
126
|
+
throw new Error("cloudflared is not installed");
|
|
127
|
+
try {
|
|
128
|
+
execFileSync(bin, ["tunnel", "route", "dns", "--overwrite-dns", tunnelId, hostname], {
|
|
129
|
+
encoding: "utf-8",
|
|
130
|
+
timeout: 30000,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
135
|
+
// "already exists" is success
|
|
136
|
+
if (!msg.includes("already exists"))
|
|
137
|
+
throw err;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
export function listTunnels() {
|
|
141
|
+
const bin = findBinary();
|
|
142
|
+
if (!bin)
|
|
143
|
+
return [];
|
|
144
|
+
try {
|
|
145
|
+
const output = execFileSync(bin, ["tunnel", "list", "--output", "json"], {
|
|
146
|
+
encoding: "utf-8",
|
|
147
|
+
timeout: 15000,
|
|
148
|
+
});
|
|
149
|
+
const tunnels = JSON.parse(output);
|
|
150
|
+
return tunnels.map((t) => ({ id: t.id, name: t.name }));
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return [];
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// ---------------------------------------------------------------------------
|
|
157
|
+
// Config generation
|
|
158
|
+
// ---------------------------------------------------------------------------
|
|
159
|
+
export function writeConfig(tunnelId, credentialsFile, domain, port) {
|
|
160
|
+
const configDir = join(homedir(), ".cloudflared");
|
|
161
|
+
mkdirSync(configDir, { recursive: true });
|
|
162
|
+
const configPath = join(configDir, `tunnel-${tunnelId}.yml`);
|
|
163
|
+
const yaml = `tunnel: ${tunnelId}
|
|
164
|
+
credentials-file: ${credentialsFile}
|
|
165
|
+
|
|
166
|
+
ingress:
|
|
167
|
+
- hostname: admin.${domain}
|
|
168
|
+
service: http://localhost:${port}
|
|
169
|
+
- hostname: public.${domain}
|
|
170
|
+
service: http://localhost:${port}
|
|
171
|
+
- service: http_status:404
|
|
172
|
+
`;
|
|
173
|
+
writeFileSync(configPath, yaml, "utf-8");
|
|
174
|
+
return configPath;
|
|
175
|
+
}
|
|
176
|
+
// ---------------------------------------------------------------------------
|
|
177
|
+
// Process management
|
|
178
|
+
// ---------------------------------------------------------------------------
|
|
179
|
+
let tunnelProcess = null;
|
|
180
|
+
let tunnelUpSince = null;
|
|
181
|
+
let suppressRestart = false;
|
|
182
|
+
let restartCount = 0;
|
|
183
|
+
const BACKOFF = [5_000, 10_000, 20_000, 30_000];
|
|
184
|
+
let healthInterval = null;
|
|
185
|
+
export function getStatus(domain) {
|
|
186
|
+
return {
|
|
187
|
+
installed: isInstalled(),
|
|
188
|
+
version: version(),
|
|
189
|
+
authenticated: isAuthenticated(),
|
|
190
|
+
running: tunnelProcess !== null && tunnelProcess.exitCode === null,
|
|
191
|
+
pid: tunnelProcess?.pid ?? null,
|
|
192
|
+
domain: domain ?? null,
|
|
193
|
+
adminUrl: domain ? `https://admin.${domain}` : null,
|
|
194
|
+
publicUrl: domain ? `https://public.${domain}` : null,
|
|
195
|
+
upSince: tunnelUpSince,
|
|
196
|
+
restartCount,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
export function startTunnel(configPath) {
|
|
200
|
+
const bin = findBinary();
|
|
201
|
+
if (!bin)
|
|
202
|
+
throw new Error("cloudflared is not installed");
|
|
203
|
+
if (tunnelProcess && tunnelProcess.exitCode === null) {
|
|
204
|
+
throw new Error("Tunnel is already running");
|
|
205
|
+
}
|
|
206
|
+
suppressRestart = false;
|
|
207
|
+
restartCount = 0;
|
|
208
|
+
spawnTunnel(bin, configPath);
|
|
209
|
+
startHealthCheck(bin, configPath);
|
|
210
|
+
}
|
|
211
|
+
function spawnTunnel(bin, configPath) {
|
|
212
|
+
tunnelProcess = spawn(bin, ["tunnel", "--config", configPath, "run"], {
|
|
213
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
214
|
+
});
|
|
215
|
+
tunnelUpSince = Date.now();
|
|
216
|
+
tunnelProcess.on("exit", (code) => {
|
|
217
|
+
tunnelUpSince = null;
|
|
218
|
+
if (!suppressRestart) {
|
|
219
|
+
const delay = BACKOFF[Math.min(restartCount, BACKOFF.length - 1)];
|
|
220
|
+
restartCount++;
|
|
221
|
+
setTimeout(() => {
|
|
222
|
+
if (!suppressRestart)
|
|
223
|
+
spawnTunnel(bin, configPath);
|
|
224
|
+
}, delay);
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
function startHealthCheck(bin, configPath) {
|
|
229
|
+
if (healthInterval)
|
|
230
|
+
clearInterval(healthInterval);
|
|
231
|
+
healthInterval = setInterval(() => {
|
|
232
|
+
if (tunnelProcess && tunnelProcess.exitCode !== null && !suppressRestart) {
|
|
233
|
+
spawnTunnel(bin, configPath);
|
|
234
|
+
}
|
|
235
|
+
}, 30_000);
|
|
236
|
+
}
|
|
237
|
+
export function stopTunnel() {
|
|
238
|
+
suppressRestart = true;
|
|
239
|
+
if (healthInterval) {
|
|
240
|
+
clearInterval(healthInterval);
|
|
241
|
+
healthInterval = null;
|
|
242
|
+
}
|
|
243
|
+
if (tunnelProcess && tunnelProcess.exitCode === null) {
|
|
244
|
+
tunnelProcess.kill("SIGTERM");
|
|
245
|
+
// Force kill after 5 seconds
|
|
246
|
+
const timeout = setTimeout(() => {
|
|
247
|
+
if (tunnelProcess && tunnelProcess.exitCode === null) {
|
|
248
|
+
tunnelProcess.kill("SIGKILL");
|
|
249
|
+
}
|
|
250
|
+
}, 5000);
|
|
251
|
+
tunnelProcess.on("exit", () => clearTimeout(timeout));
|
|
252
|
+
}
|
|
253
|
+
tunnelProcess = null;
|
|
254
|
+
tunnelUpSince = null;
|
|
255
|
+
}
|
|
256
|
+
//# sourceMappingURL=cloudflared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudflared.js","sourceRoot":"","sources":["../../src/lib/cloudflared.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@maxy/cloudflare",
|
|
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,110 @@
|
|
|
1
|
+
# Cloudflare Tunnel Setup Guide
|
|
2
|
+
|
|
3
|
+
## Prerequisites
|
|
4
|
+
|
|
5
|
+
- A Cloudflare account (free at cloudflare.com)
|
|
6
|
+
- A domain on Cloudflare (see "Getting a domain on Cloudflare" below)
|
|
7
|
+
- Access to the control panel Setup page on the local network
|
|
8
|
+
|
|
9
|
+
### Getting a domain on Cloudflare
|
|
10
|
+
|
|
11
|
+
The tunnel needs a domain managed by Cloudflare. There are two paths:
|
|
12
|
+
|
|
13
|
+
**Option A: Buy a new domain through Cloudflare**
|
|
14
|
+
1. Go to cloudflare.com → **Domains** → **Buy a domain**
|
|
15
|
+
2. Search for a domain name and purchase it (Cloudflare sells at cost, no markup)
|
|
16
|
+
3. The domain is automatically set up — no further DNS configuration needed
|
|
17
|
+
|
|
18
|
+
**Option B: Add an existing domain**
|
|
19
|
+
If the user already owns a domain through another registrar (GoDaddy, Namecheap, etc.):
|
|
20
|
+
1. Go to cloudflare.com → **Domains** → **Onboard a domain**
|
|
21
|
+
2. Enter the domain and select the **Free** plan
|
|
22
|
+
3. Cloudflare scans existing DNS records and imports them — review the list to make sure everything is there (website, email, etc.)
|
|
23
|
+
4. Cloudflare shows two nameservers (e.g. `anna.ns.cloudflare.com`, `bob.ns.cloudflare.com`)
|
|
24
|
+
5. Go to the domain registrar and replace the existing nameservers with the Cloudflare ones
|
|
25
|
+
6. Wait for propagation (usually minutes, can take up to 24 hours)
|
|
26
|
+
7. Cloudflare shows the domain as **Active** once propagation is complete
|
|
27
|
+
|
|
28
|
+
**Will my website go down?** No. Cloudflare imports all existing DNS records in step 3, so traffic continues to reach the same servers as before. Cloudflare sits in front as a proxy — existing websites, email, and other services keep working. The only thing that changes is which nameservers answer DNS queries. If in doubt, check the imported records match what the registrar had before switching.
|
|
29
|
+
|
|
30
|
+
Once the domain is active on Cloudflare, Taskmaster uses it to create two subdomains automatically. Any domain works — including ones with a `www` prefix (e.g. `www.mybusiness.com`).
|
|
31
|
+
|
|
32
|
+
## Setup Flow
|
|
33
|
+
|
|
34
|
+
The entire setup is done from the **Setup page** in the control panel. Look for the **Cloudflare** row in the setup cards.
|
|
35
|
+
|
|
36
|
+
### Step 1: Install cloudflared
|
|
37
|
+
|
|
38
|
+
The Setup page checks whether cloudflared is installed automatically.
|
|
39
|
+
|
|
40
|
+
- If it shows "Not Installed", tap **Install** — the system handles it
|
|
41
|
+
- If auto-install fails (e.g. on an unsupported platform), the UI shows manual install instructions specific to the device's OS
|
|
42
|
+
- Once installed, the status updates automatically
|
|
43
|
+
|
|
44
|
+
### Step 2: Authenticate with Cloudflare
|
|
45
|
+
|
|
46
|
+
Tap **Connect** on the Cloudflare card. This opens a browser window on the device:
|
|
47
|
+
|
|
48
|
+
- Sign in to the Cloudflare account if prompted
|
|
49
|
+
- A list of domains (zones) appears — select the domain to use for the tunnel
|
|
50
|
+
- A confirmation dialog appears: "Authorize Tunnel for [domain]" — click **Authorize**
|
|
51
|
+
- The browser confirms success and the Setup page updates automatically
|
|
52
|
+
|
|
53
|
+
The user needs a Cloudflare account with at least one active domain before this step. If they don't have one, guide them through the prerequisites above first.
|
|
54
|
+
|
|
55
|
+
### Step 3: Create the tunnel
|
|
56
|
+
|
|
57
|
+
Tap **Set up** to open the wizard. It shows the two endpoints that will be created automatically:
|
|
58
|
+
|
|
59
|
+
- **Control panel** — `admin.{domain}` — for remote access to the setup and admin interface
|
|
60
|
+
- **Public chat** — `public.{domain}` — for customers to reach the chat
|
|
61
|
+
|
|
62
|
+
There is nothing to fill in — both addresses are derived from the domain authorised in Step 2. The tunnel creates the DNS records (CNAMEs) for both automatically — no need to touch the Cloudflare dashboard.
|
|
63
|
+
|
|
64
|
+
### Step 4: Set a remote password
|
|
65
|
+
|
|
66
|
+
The wizard's second step asks for a username and password. This protects the control panel when accessed from the public internet via `admin.{domain}`.
|
|
67
|
+
|
|
68
|
+
Explain to the user:
|
|
69
|
+
- This is separate from the device PIN (which is for local network access only)
|
|
70
|
+
- These credentials work for all accounts on the device (like a router admin password)
|
|
71
|
+
- The password must be at least 8 characters, contain a number, contain a special character, and have no leading/trailing spaces
|
|
72
|
+
- The wizard shows a live checklist of password requirements as they type
|
|
73
|
+
|
|
74
|
+
### Step 5: Enable Tunnel
|
|
75
|
+
|
|
76
|
+
The wizard's final step shows a summary and an **Enable Tunnel** button. Once enabled:
|
|
77
|
+
|
|
78
|
+
- The control panel is live at `https://admin.{domain}` — requires the username and password set in Step 4
|
|
79
|
+
- The public chat is live at `https://public.{domain}/chat/{account-slug}`
|
|
80
|
+
- Local network access continues to work with just the PIN
|
|
81
|
+
|
|
82
|
+
## After Setup
|
|
83
|
+
|
|
84
|
+
The Cloudflare card on the Setup page shows the tunnel status and the admin hostname. Tapping the card opens an info panel with connection details and the public chat URL.
|
|
85
|
+
|
|
86
|
+
## Troubleshooting
|
|
87
|
+
|
|
88
|
+
### Tunnel won't start
|
|
89
|
+
- Check the Cloudflare card on the Setup page for status details
|
|
90
|
+
- If authentication has expired, tap **Log in** again to re-authenticate
|
|
91
|
+
- If the credentials file is missing, the tunnel may need to be recreated via the wizard
|
|
92
|
+
|
|
93
|
+
### DNS not resolving
|
|
94
|
+
- DNS propagation can take 1-5 minutes after tunnel creation
|
|
95
|
+
- Verify the tunnel is running (green status on the Setup page)
|
|
96
|
+
- Check the Cloudflare dashboard to confirm the CNAME records exist for both `admin.{domain}` and `public.{domain}`
|
|
97
|
+
|
|
98
|
+
### Remote login issues
|
|
99
|
+
- After 5 failed login attempts, there's a 15-minute lockout — wait for it to expire
|
|
100
|
+
- The password can be reset from the Setup page on the local network
|
|
101
|
+
|
|
102
|
+
### Changing domain
|
|
103
|
+
- Disable the tunnel from the Setup page
|
|
104
|
+
- Re-authenticate with Cloudflare using the new domain
|
|
105
|
+
- Run the wizard again — it will create new DNS records for the new domain
|
|
106
|
+
- Old DNS records can be removed from the Cloudflare dashboard
|
|
107
|
+
|
|
108
|
+
## Agent Tools
|
|
109
|
+
|
|
110
|
+
The tunnel tools (`tunnel_status`, `tunnel_enable`, `tunnel_disable`) give the agent visibility and control over the tunnel. Use these when the user asks about tunnel status or wants to enable/disable remotely via chat. For initial setup, always direct users to the Setup page wizard.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: contacts
|
|
3
|
+
description: "CRM contacts plugin. Provides contact-create, contact-lookup, contact-update, and contact-list tools for managing the customer contact graph."
|
|
4
|
+
icon: 👥
|
|
5
|
+
tools:
|
|
6
|
+
- contact-create
|
|
7
|
+
- contact-lookup
|
|
8
|
+
- contact-update
|
|
9
|
+
- contact-list
|
|
10
|
+
always: true
|
|
11
|
+
embed: false
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Contacts
|
|
15
|
+
|
|
16
|
+
Manages customer contact records in the knowledge graph. Admin agent only — the public agent has no write access.
|
|
17
|
+
|
|
18
|
+
Tools are available via the `contacts` MCP server.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|