synapse-mcp 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/README.md +607 -0
- package/dist/constants.d.ts +23 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +58 -0
- package/dist/constants.js.map +1 -0
- package/dist/formatters/index.d.ts +275 -0
- package/dist/formatters/index.d.ts.map +1 -0
- package/dist/formatters/index.js +461 -0
- package/dist/formatters/index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +178 -0
- package/dist/index.js.map +1 -0
- package/dist/schemas/common.d.ts +48 -0
- package/dist/schemas/common.d.ts.map +1 -0
- package/dist/schemas/common.js +69 -0
- package/dist/schemas/common.js.map +1 -0
- package/dist/schemas/discriminator.d.ts +20 -0
- package/dist/schemas/discriminator.d.ts.map +1 -0
- package/dist/schemas/discriminator.js +25 -0
- package/dist/schemas/discriminator.js.map +1 -0
- package/dist/schemas/flux/compose.d.ts +93 -0
- package/dist/schemas/flux/compose.d.ts.map +1 -0
- package/dist/schemas/flux/compose.js +112 -0
- package/dist/schemas/flux/compose.js.map +1 -0
- package/dist/schemas/flux/container.d.ts +144 -0
- package/dist/schemas/flux/container.d.ts.map +1 -0
- package/dist/schemas/flux/container.js +163 -0
- package/dist/schemas/flux/container.js.map +1 -0
- package/dist/schemas/flux/docker.d.ts +91 -0
- package/dist/schemas/flux/docker.d.ts.map +1 -0
- package/dist/schemas/flux/docker.js +101 -0
- package/dist/schemas/flux/docker.js.map +1 -0
- package/dist/schemas/flux/host.d.ts +61 -0
- package/dist/schemas/flux/host.d.ts.map +1 -0
- package/dist/schemas/flux/host.js +72 -0
- package/dist/schemas/flux/host.js.map +1 -0
- package/dist/schemas/flux/index.d.ts +20 -0
- package/dist/schemas/flux/index.d.ts.map +1 -0
- package/dist/schemas/flux/index.js +88 -0
- package/dist/schemas/flux/index.js.map +1 -0
- package/dist/schemas/index.d.ts +11 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +11 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/scout/index.d.ts +151 -0
- package/dist/schemas/scout/index.d.ts.map +1 -0
- package/dist/schemas/scout/index.js +41 -0
- package/dist/schemas/scout/index.js.map +1 -0
- package/dist/schemas/scout/logs.d.ts +48 -0
- package/dist/schemas/scout/logs.d.ts.map +1 -0
- package/dist/schemas/scout/logs.js +47 -0
- package/dist/schemas/scout/logs.js.map +1 -0
- package/dist/schemas/scout/simple.d.ts +68 -0
- package/dist/schemas/scout/simple.d.ts.map +1 -0
- package/dist/schemas/scout/simple.js +75 -0
- package/dist/schemas/scout/simple.js.map +1 -0
- package/dist/schemas/scout/zfs.d.ts +37 -0
- package/dist/schemas/scout/zfs.d.ts.map +1 -0
- package/dist/schemas/scout/zfs.js +36 -0
- package/dist/schemas/scout/zfs.js.map +1 -0
- package/dist/schemas/unified.d.ts +674 -0
- package/dist/schemas/unified.d.ts.map +1 -0
- package/dist/schemas/unified.js +453 -0
- package/dist/schemas/unified.js.map +1 -0
- package/dist/services/compose.d.ts +107 -0
- package/dist/services/compose.d.ts.map +1 -0
- package/dist/services/compose.js +308 -0
- package/dist/services/compose.js.map +1 -0
- package/dist/services/container.d.ts +69 -0
- package/dist/services/container.d.ts.map +1 -0
- package/dist/services/container.js +111 -0
- package/dist/services/container.js.map +1 -0
- package/dist/services/docker.d.ts +243 -0
- package/dist/services/docker.d.ts.map +1 -0
- package/dist/services/docker.js +812 -0
- package/dist/services/docker.js.map +1 -0
- package/dist/services/file-service.d.ts +79 -0
- package/dist/services/file-service.d.ts.map +1 -0
- package/dist/services/file-service.js +226 -0
- package/dist/services/file-service.js.map +1 -0
- package/dist/services/interfaces.d.ts +537 -0
- package/dist/services/interfaces.d.ts.map +1 -0
- package/dist/services/interfaces.js +2 -0
- package/dist/services/interfaces.js.map +1 -0
- package/dist/services/ssh-pool-exec.d.ts +10 -0
- package/dist/services/ssh-pool-exec.d.ts.map +1 -0
- package/dist/services/ssh-pool-exec.js +10 -0
- package/dist/services/ssh-pool-exec.js.map +1 -0
- package/dist/services/ssh-pool.d.ts +66 -0
- package/dist/services/ssh-pool.d.ts.map +1 -0
- package/dist/services/ssh-pool.js +253 -0
- package/dist/services/ssh-pool.js.map +1 -0
- package/dist/services/ssh-service.d.ts +39 -0
- package/dist/services/ssh-service.d.ts.map +1 -0
- package/dist/services/ssh-service.js +143 -0
- package/dist/services/ssh-service.js.map +1 -0
- package/dist/services/ssh.d.ts +37 -0
- package/dist/services/ssh.d.ts.map +1 -0
- package/dist/services/ssh.js +50 -0
- package/dist/services/ssh.js.map +1 -0
- package/dist/tools/flux.d.ts +14 -0
- package/dist/tools/flux.d.ts.map +1 -0
- package/dist/tools/flux.js +86 -0
- package/dist/tools/flux.js.map +1 -0
- package/dist/tools/index.d.ts +7 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +43 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/scout.d.ts +14 -0
- package/dist/tools/scout.d.ts.map +1 -0
- package/dist/tools/scout.js +96 -0
- package/dist/tools/scout.js.map +1 -0
- package/dist/tools/unified.d.ts +7 -0
- package/dist/tools/unified.d.ts.map +1 -0
- package/dist/tools/unified.js +827 -0
- package/dist/tools/unified.js.map +1 -0
- package/dist/types.d.ts +93 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/errors.d.ts +60 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +131 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/help.d.ts +69 -0
- package/dist/utils/help.d.ts.map +1 -0
- package/dist/utils/help.js +259 -0
- package/dist/utils/help.js.map +1 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/path-security.d.ts +64 -0
- package/dist/utils/path-security.d.ts.map +1 -0
- package/dist/utils/path-security.js +138 -0
- package/dist/utils/path-security.js.map +1 -0
- package/package.json +85 -0
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formatting utilities for homelab MCP responses
|
|
3
|
+
*
|
|
4
|
+
* Provides consistent markdown formatting for container, host, and Docker data.
|
|
5
|
+
*/
|
|
6
|
+
import { CHARACTER_LIMIT } from "../constants.js";
|
|
7
|
+
import { formatBytes } from "../services/docker.js";
|
|
8
|
+
// Re-export formatBytes for convenience
|
|
9
|
+
export { formatBytes };
|
|
10
|
+
/**
|
|
11
|
+
* Truncate text if it exceeds CHARACTER_LIMIT
|
|
12
|
+
*/
|
|
13
|
+
export function truncateIfNeeded(text) {
|
|
14
|
+
if (text.length <= CHARACTER_LIMIT)
|
|
15
|
+
return text;
|
|
16
|
+
return (text.slice(0, CHARACTER_LIMIT - 100) +
|
|
17
|
+
"\n\n... [Output truncated. Use pagination or filters to reduce results.]");
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Format container list as markdown
|
|
21
|
+
*/
|
|
22
|
+
export function formatContainersMarkdown(containers, total, offset, hasMore) {
|
|
23
|
+
if (containers.length === 0) {
|
|
24
|
+
return "No containers found matching the specified criteria.";
|
|
25
|
+
}
|
|
26
|
+
const lines = [`## Containers (${offset + 1}-${offset + containers.length} of ${total})`, ""];
|
|
27
|
+
for (const c of containers) {
|
|
28
|
+
const stateEmoji = c.state === "running" ? "🟢" : c.state === "paused" ? "🟡" : "🔴";
|
|
29
|
+
const ports = c.ports
|
|
30
|
+
.filter((p) => p.hostPort)
|
|
31
|
+
.map((p) => `${p.hostPort}→${p.containerPort}`)
|
|
32
|
+
.join(", ");
|
|
33
|
+
lines.push(`${stateEmoji} **${c.name}** (${c.hostName})`);
|
|
34
|
+
lines.push(` Image: ${c.image} | Status: ${c.status}`);
|
|
35
|
+
if (ports)
|
|
36
|
+
lines.push(` Ports: ${ports}`);
|
|
37
|
+
lines.push("");
|
|
38
|
+
}
|
|
39
|
+
if (hasMore) {
|
|
40
|
+
lines.push(`*More results available. Use offset=${offset + containers.length} to see next page.*`);
|
|
41
|
+
}
|
|
42
|
+
return lines.join("\n");
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Format container logs as markdown
|
|
46
|
+
*/
|
|
47
|
+
export function formatLogsMarkdown(logs, container, host) {
|
|
48
|
+
if (logs.length === 0) {
|
|
49
|
+
return `No logs found for container '${container}' on ${host}.`;
|
|
50
|
+
}
|
|
51
|
+
const lines = [`## Logs: ${container} (${host})`, "", "```"];
|
|
52
|
+
for (const log of logs) {
|
|
53
|
+
const ts = log.timestamp.slice(11, 19);
|
|
54
|
+
lines.push(`[${ts}] ${log.message}`);
|
|
55
|
+
}
|
|
56
|
+
lines.push("```");
|
|
57
|
+
return lines.join("\n");
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Format single container stats as markdown
|
|
61
|
+
*/
|
|
62
|
+
export function formatStatsMarkdown(stats, host) {
|
|
63
|
+
const s = stats[0];
|
|
64
|
+
return `## Stats: ${s.containerName} (${host})
|
|
65
|
+
|
|
66
|
+
| Metric | Value |
|
|
67
|
+
|--------|-------|
|
|
68
|
+
| CPU | ${s.cpuPercent.toFixed(1)}% |
|
|
69
|
+
| Memory | ${formatBytes(s.memoryUsage)} / ${formatBytes(s.memoryLimit)} (${s.memoryPercent.toFixed(1)}%) |
|
|
70
|
+
| Network RX | ${formatBytes(s.networkRx)} |
|
|
71
|
+
| Network TX | ${formatBytes(s.networkTx)} |
|
|
72
|
+
| Block Read | ${formatBytes(s.blockRead)} |
|
|
73
|
+
| Block Write | ${formatBytes(s.blockWrite)} |`;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Format multiple container stats as markdown table
|
|
77
|
+
*/
|
|
78
|
+
export function formatMultiStatsMarkdown(allStats) {
|
|
79
|
+
if (allStats.length === 0)
|
|
80
|
+
return "No running containers found.";
|
|
81
|
+
const lines = [
|
|
82
|
+
"## Container Resource Usage",
|
|
83
|
+
"",
|
|
84
|
+
"| Container | Host | CPU% | Memory | Mem% |",
|
|
85
|
+
"|-----------|------|------|--------|------|"
|
|
86
|
+
];
|
|
87
|
+
for (const { stats, host } of allStats) {
|
|
88
|
+
lines.push(`| ${stats.containerName} | ${host} | ${stats.cpuPercent.toFixed(1)}% | ${formatBytes(stats.memoryUsage)} | ${stats.memoryPercent.toFixed(1)}% |`);
|
|
89
|
+
}
|
|
90
|
+
return lines.join("\n");
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Format container inspection as markdown
|
|
94
|
+
*/
|
|
95
|
+
export function formatInspectMarkdown(info, host) {
|
|
96
|
+
const config = info.Config;
|
|
97
|
+
const state = info.State;
|
|
98
|
+
const mounts = info.Mounts || [];
|
|
99
|
+
const network = info.NetworkSettings;
|
|
100
|
+
const lines = [
|
|
101
|
+
`## Container: ${info.Name.replace(/^\//, "")} (${host})`,
|
|
102
|
+
"",
|
|
103
|
+
"### State",
|
|
104
|
+
`- Status: ${state.Status}`,
|
|
105
|
+
`- Running: ${state.Running}`,
|
|
106
|
+
`- Started: ${state.StartedAt}`,
|
|
107
|
+
`- Restart Count: ${info.RestartCount}`,
|
|
108
|
+
"",
|
|
109
|
+
"### Configuration",
|
|
110
|
+
`- Image: ${config.Image}`,
|
|
111
|
+
`- Command: ${(config.Cmd || []).join(" ")}`,
|
|
112
|
+
`- Working Dir: ${config.WorkingDir || "/"}`,
|
|
113
|
+
""
|
|
114
|
+
];
|
|
115
|
+
if (config.Env && config.Env.length > 0) {
|
|
116
|
+
lines.push("### Environment Variables");
|
|
117
|
+
for (const env of config.Env.slice(0, 20)) {
|
|
118
|
+
const [key] = env.split("=");
|
|
119
|
+
const isSensitive = /password|secret|key|token|api/i.test(key);
|
|
120
|
+
lines.push(`- ${isSensitive ? `${key}=****` : env}`);
|
|
121
|
+
}
|
|
122
|
+
if (config.Env.length > 20)
|
|
123
|
+
lines.push(`- ... and ${config.Env.length - 20} more`);
|
|
124
|
+
lines.push("");
|
|
125
|
+
}
|
|
126
|
+
if (mounts.length > 0) {
|
|
127
|
+
lines.push("### Mounts");
|
|
128
|
+
for (const m of mounts) {
|
|
129
|
+
lines.push(`- ${m.Source} → ${m.Destination} (${m.Mode || "rw"})`);
|
|
130
|
+
}
|
|
131
|
+
lines.push("");
|
|
132
|
+
}
|
|
133
|
+
if (network.Ports) {
|
|
134
|
+
lines.push("### Ports");
|
|
135
|
+
for (const [containerPort, bindings] of Object.entries(network.Ports)) {
|
|
136
|
+
if (bindings && bindings.length > 0) {
|
|
137
|
+
for (const b of bindings) {
|
|
138
|
+
lines.push(`- ${b.HostIp || "0.0.0.0"}:${b.HostPort} → ${containerPort}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
lines.push("");
|
|
143
|
+
}
|
|
144
|
+
if (network.Networks && Object.keys(network.Networks).length > 0) {
|
|
145
|
+
lines.push("### Networks");
|
|
146
|
+
for (const networkName of Object.keys(network.Networks)) {
|
|
147
|
+
lines.push(`- ${networkName}`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return lines.join("\n");
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Format host status as markdown table
|
|
154
|
+
*/
|
|
155
|
+
export function formatHostStatusMarkdown(status) {
|
|
156
|
+
const lines = [
|
|
157
|
+
"## Homelab Host Status",
|
|
158
|
+
"",
|
|
159
|
+
"| Host | Status | Containers | Running |",
|
|
160
|
+
"|------|--------|------------|---------|"
|
|
161
|
+
];
|
|
162
|
+
for (const h of status) {
|
|
163
|
+
const statusEmoji = h.connected ? "🟢" : "🔴";
|
|
164
|
+
const statusText = h.connected ? "Online" : `Offline (${h.error || "Unknown"})`;
|
|
165
|
+
lines.push(`| ${h.name} | ${statusEmoji} ${statusText} | ${h.containerCount} | ${h.runningCount} |`);
|
|
166
|
+
}
|
|
167
|
+
return lines.join("\n");
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Format search results as markdown
|
|
171
|
+
*/
|
|
172
|
+
export function formatSearchResultsMarkdown(containers, query, total) {
|
|
173
|
+
if (containers.length === 0)
|
|
174
|
+
return `No containers found matching '${query}'.`;
|
|
175
|
+
const lines = [`## Search Results for '${query}' (${total} matches)`, ""];
|
|
176
|
+
for (const c of containers) {
|
|
177
|
+
const stateEmoji = c.state === "running" ? "🟢" : c.state === "paused" ? "🟡" : "🔴";
|
|
178
|
+
lines.push(`${stateEmoji} **${c.name}** (${c.hostName})`);
|
|
179
|
+
lines.push(` Image: ${c.image} | State: ${c.state}`);
|
|
180
|
+
lines.push("");
|
|
181
|
+
}
|
|
182
|
+
return lines.join("\n");
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Format Docker info as markdown
|
|
186
|
+
*/
|
|
187
|
+
export function formatDockerInfoMarkdown(results) {
|
|
188
|
+
const lines = ["## Docker System Info", ""];
|
|
189
|
+
for (const { host, info } of results) {
|
|
190
|
+
lines.push(`### ${host}`);
|
|
191
|
+
if (info.dockerVersion === "error") {
|
|
192
|
+
lines.push(`❌ Error: ${info.os}`);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
lines.push(`- Docker: ${info.dockerVersion} (API ${info.apiVersion})`);
|
|
196
|
+
lines.push(`- OS: ${info.os} (${info.arch})`);
|
|
197
|
+
lines.push(`- Kernel: ${info.kernelVersion}`);
|
|
198
|
+
lines.push(`- CPUs: ${info.cpus} | Memory: ${formatBytes(info.memoryBytes)}`);
|
|
199
|
+
lines.push(`- Storage: ${info.storageDriver} @ ${info.rootDir}`);
|
|
200
|
+
lines.push(`- Containers: ${info.containersRunning} running / ${info.containersTotal} total`);
|
|
201
|
+
lines.push(`- Images: ${info.images}`);
|
|
202
|
+
}
|
|
203
|
+
lines.push("");
|
|
204
|
+
}
|
|
205
|
+
return lines.join("\n");
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Format Docker disk usage as markdown
|
|
209
|
+
*/
|
|
210
|
+
export function formatDockerDfMarkdown(results) {
|
|
211
|
+
const lines = ["## Docker Disk Usage", ""];
|
|
212
|
+
for (const { host, usage } of results) {
|
|
213
|
+
lines.push(`### ${host}`, "", "| Type | Count | Size | Reclaimable |", "|------|-------|------|-------------|");
|
|
214
|
+
lines.push(`| Images | ${usage.images.total} (${usage.images.active} active) | ${formatBytes(usage.images.size)} | ${formatBytes(usage.images.reclaimable)} |`);
|
|
215
|
+
lines.push(`| Containers | ${usage.containers.total} (${usage.containers.running} running) | ${formatBytes(usage.containers.size)} | ${formatBytes(usage.containers.reclaimable)} |`);
|
|
216
|
+
lines.push(`| Volumes | ${usage.volumes.total} (${usage.volumes.active} active) | ${formatBytes(usage.volumes.size)} | ${formatBytes(usage.volumes.reclaimable)} |`);
|
|
217
|
+
lines.push(`| Build Cache | ${usage.buildCache.total} | ${formatBytes(usage.buildCache.size)} | ${formatBytes(usage.buildCache.reclaimable)} |`);
|
|
218
|
+
lines.push(`| **Total** | | **${formatBytes(usage.totalSize)}** | **${formatBytes(usage.totalReclaimable)}** |`);
|
|
219
|
+
lines.push("");
|
|
220
|
+
}
|
|
221
|
+
return lines.join("\n");
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Format prune results as markdown
|
|
225
|
+
*/
|
|
226
|
+
export function formatPruneMarkdown(allResults) {
|
|
227
|
+
const lines = ["## Prune Results", ""];
|
|
228
|
+
let totalReclaimed = 0;
|
|
229
|
+
let totalDeleted = 0;
|
|
230
|
+
for (const { host, results } of allResults) {
|
|
231
|
+
lines.push(`### ${host}`, "", "| Type | Items Deleted | Space Reclaimed |", "|------|---------------|-----------------|");
|
|
232
|
+
for (const r of results) {
|
|
233
|
+
lines.push(`| ${r.type} | ${r.itemsDeleted} | ${formatBytes(r.spaceReclaimed)} |`);
|
|
234
|
+
totalReclaimed += r.spaceReclaimed;
|
|
235
|
+
totalDeleted += r.itemsDeleted;
|
|
236
|
+
}
|
|
237
|
+
lines.push("");
|
|
238
|
+
}
|
|
239
|
+
lines.push(`**Total: ${totalDeleted} items deleted, ${formatBytes(totalReclaimed)} reclaimed**`);
|
|
240
|
+
return lines.join("\n");
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Format host resources as markdown
|
|
244
|
+
*/
|
|
245
|
+
export function formatHostResourcesMarkdown(results) {
|
|
246
|
+
const lines = ["## Host Resources", ""];
|
|
247
|
+
for (const { host, resources, error } of results) {
|
|
248
|
+
lines.push(`### ${host}`);
|
|
249
|
+
if (error || !resources) {
|
|
250
|
+
lines.push(`❌ ${error || "Unknown error"}`);
|
|
251
|
+
lines.push("");
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
lines.push(`- **Hostname:** ${resources.hostname}`);
|
|
255
|
+
lines.push(`- **Uptime:** ${resources.uptime}`);
|
|
256
|
+
lines.push(`- **Load:** ${resources.loadAverage.join(", ")}`);
|
|
257
|
+
lines.push(`- **CPU:** ${resources.cpu.cores} cores @ ${resources.cpu.usagePercent}%`);
|
|
258
|
+
lines.push(`- **Memory:** ${resources.memory.usedMB} MB / ${resources.memory.totalMB} MB (${resources.memory.usagePercent}%)`);
|
|
259
|
+
if (resources.disk.length > 0) {
|
|
260
|
+
lines.push("", "**Disks:**");
|
|
261
|
+
for (const d of resources.disk) {
|
|
262
|
+
lines.push(`- ${d.mount}: ${d.usedGB}G / ${d.totalGB}G (${d.usagePercent}%)`);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
lines.push("");
|
|
266
|
+
}
|
|
267
|
+
return lines.join("\n");
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Format images list as markdown table
|
|
271
|
+
*/
|
|
272
|
+
export function formatImagesMarkdown(images, total, offset) {
|
|
273
|
+
if (images.length === 0)
|
|
274
|
+
return "No images found.";
|
|
275
|
+
const lines = [
|
|
276
|
+
"## Docker Images",
|
|
277
|
+
"",
|
|
278
|
+
`Showing ${images.length} of ${total} images (offset: ${offset})`,
|
|
279
|
+
"",
|
|
280
|
+
"| ID | Tags | Size | Host | Containers |",
|
|
281
|
+
"|-----|------|------|------|------------|"
|
|
282
|
+
];
|
|
283
|
+
for (const img of images) {
|
|
284
|
+
const tags = img.tags.slice(0, 2).join(", ") + (img.tags.length > 2 ? "..." : "");
|
|
285
|
+
lines.push(`| ${img.id} | ${tags} | ${formatBytes(img.size)} | ${img.hostName} | ${img.containers} |`);
|
|
286
|
+
}
|
|
287
|
+
return lines.join("\n");
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Format compose project list as markdown
|
|
291
|
+
*/
|
|
292
|
+
export function formatComposeListMarkdown(projects, host, total, offset, hasMore) {
|
|
293
|
+
if (projects.length === 0)
|
|
294
|
+
return `No compose projects found on ${host}.`;
|
|
295
|
+
const header = total !== undefined
|
|
296
|
+
? `## Compose Projects on ${host} (${(offset || 0) + 1}-${(offset || 0) + projects.length} of ${total})`
|
|
297
|
+
: `## Compose Projects on ${host}`;
|
|
298
|
+
const lines = [header, "", "| Project | Status | Services |", "|---------|--------|----------|"];
|
|
299
|
+
for (const p of projects) {
|
|
300
|
+
const statusEmoji = p.status === "running" ? "🟢" : p.status === "partial" ? "🟡" : "🔴";
|
|
301
|
+
lines.push(`| ${p.name} | ${statusEmoji} ${p.status} | ${p.services.length || "-"} |`);
|
|
302
|
+
}
|
|
303
|
+
if (hasMore) {
|
|
304
|
+
lines.push("");
|
|
305
|
+
lines.push(`*More results available. Use offset=${(offset || 0) + projects.length} to see next page.*`);
|
|
306
|
+
}
|
|
307
|
+
return lines.join("\n");
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Format compose project status as markdown
|
|
311
|
+
*/
|
|
312
|
+
export function formatComposeStatusMarkdown(project, totalServices, offset, hasMore) {
|
|
313
|
+
const statusEmoji = project.status === "running" ? "🟢" : project.status === "partial" ? "🟡" : "🔴";
|
|
314
|
+
const serviceInfo = totalServices !== undefined
|
|
315
|
+
? ` - Services ${(offset || 0) + 1}-${(offset || 0) + project.services.length} of ${totalServices}`
|
|
316
|
+
: "";
|
|
317
|
+
const lines = [`## ${project.name} (${statusEmoji} ${project.status})${serviceInfo}`, ""];
|
|
318
|
+
if (project.services.length === 0) {
|
|
319
|
+
lines.push("No services found.");
|
|
320
|
+
}
|
|
321
|
+
else {
|
|
322
|
+
lines.push("| Service | Status | Health | Ports |", "|---------|--------|--------|-------|");
|
|
323
|
+
for (const svc of project.services) {
|
|
324
|
+
const health = svc.health || "-";
|
|
325
|
+
const ports = svc.publishers?.map((p) => `${p.publishedPort}→${p.targetPort}`).join(", ") || "-";
|
|
326
|
+
const svcEmoji = svc.status === "running" ? "🟢" : "🔴";
|
|
327
|
+
lines.push(`| ${svc.name} | ${svcEmoji} ${svc.status} | ${health} | ${ports} |`);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
if (hasMore) {
|
|
331
|
+
lines.push("");
|
|
332
|
+
lines.push(`*More services available. Use offset=${(offset || 0) + project.services.length} to see next page.*`);
|
|
333
|
+
}
|
|
334
|
+
return lines.join("\n");
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Format container inspect summary as markdown (condensed version)
|
|
338
|
+
*/
|
|
339
|
+
export function formatInspectSummaryMarkdown(summary) {
|
|
340
|
+
const lines = [
|
|
341
|
+
`## ${summary.name} (${summary.host})`,
|
|
342
|
+
"",
|
|
343
|
+
"| Field | Value |",
|
|
344
|
+
"|-------|-------|",
|
|
345
|
+
`| ID | ${summary.id} |`,
|
|
346
|
+
`| Image | ${summary.image} |`,
|
|
347
|
+
`| State | ${summary.state} |`,
|
|
348
|
+
`| Started | ${summary.started?.slice(0, 19) || "-"} |`,
|
|
349
|
+
`| Restarts | ${summary.restartCount} |`,
|
|
350
|
+
`| Networks | ${summary.networks.join(", ") || "-"} |`,
|
|
351
|
+
`| Ports | ${summary.ports.join(", ") || "-"} |`,
|
|
352
|
+
`| Mounts | ${summary.mounts.length} |`,
|
|
353
|
+
`| Env Vars | ${summary.env_count} |`,
|
|
354
|
+
`| Labels | ${summary.labels_count} |`
|
|
355
|
+
];
|
|
356
|
+
if (summary.mounts.length > 0 && summary.mounts.length <= 5) {
|
|
357
|
+
lines.push("", "**Mounts:**");
|
|
358
|
+
for (const m of summary.mounts) {
|
|
359
|
+
lines.push(`- ${m.src} → ${m.dst} (${m.type})`);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return lines.join("\n");
|
|
363
|
+
}
|
|
364
|
+
// ===== Scout Formatters =====
|
|
365
|
+
/**
|
|
366
|
+
* Format file read result as markdown
|
|
367
|
+
*/
|
|
368
|
+
export function formatScoutReadMarkdown(host, path, content, size, truncated) {
|
|
369
|
+
const lines = [
|
|
370
|
+
`## 📄 ${host}:${path}`,
|
|
371
|
+
"",
|
|
372
|
+
`**Size:** ${formatBytes(size)}${truncated ? " (truncated)" : ""}`,
|
|
373
|
+
"",
|
|
374
|
+
"```",
|
|
375
|
+
content,
|
|
376
|
+
"```"
|
|
377
|
+
];
|
|
378
|
+
if (truncated) {
|
|
379
|
+
lines.push("");
|
|
380
|
+
lines.push("⚠️ *File was truncated to fit size limit*");
|
|
381
|
+
}
|
|
382
|
+
return truncateIfNeeded(lines.join("\n"));
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Format directory listing as markdown
|
|
386
|
+
*/
|
|
387
|
+
export function formatScoutListMarkdown(host, path, listing) {
|
|
388
|
+
return truncateIfNeeded([`## 📁 ${host}:${path}`, "", "```", listing, "```"].join("\n"));
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Format tree output as markdown
|
|
392
|
+
*/
|
|
393
|
+
export function formatScoutTreeMarkdown(host, path, tree, depth) {
|
|
394
|
+
return truncateIfNeeded([`## 🌳 ${host}:${path} (depth: ${depth})`, "", "```", tree, "```"].join("\n"));
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Format command execution result as markdown
|
|
398
|
+
*/
|
|
399
|
+
export function formatScoutExecMarkdown(host, path, command, stdout, exitCode) {
|
|
400
|
+
const statusEmoji = exitCode === 0 ? "✅" : "❌";
|
|
401
|
+
return truncateIfNeeded([
|
|
402
|
+
`## ${statusEmoji} Command: ${host}:${path}`,
|
|
403
|
+
"",
|
|
404
|
+
`**Command:** \`${command}\``,
|
|
405
|
+
`**Exit:** ${exitCode}`,
|
|
406
|
+
"",
|
|
407
|
+
"**Output:**",
|
|
408
|
+
"```",
|
|
409
|
+
stdout,
|
|
410
|
+
"```"
|
|
411
|
+
].join("\n"));
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Format find results as markdown
|
|
415
|
+
*/
|
|
416
|
+
export function formatScoutFindMarkdown(host, path, pattern, results) {
|
|
417
|
+
const lines = results.split("\n").filter((l) => l.trim());
|
|
418
|
+
return truncateIfNeeded([
|
|
419
|
+
`## 🔍 Find: ${host}:${path}`,
|
|
420
|
+
"",
|
|
421
|
+
`**Pattern:** \`${pattern}\``,
|
|
422
|
+
`**Results:** ${lines.length} files`,
|
|
423
|
+
"",
|
|
424
|
+
"```",
|
|
425
|
+
results,
|
|
426
|
+
"```"
|
|
427
|
+
].join("\n"));
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* Format file transfer result as markdown
|
|
431
|
+
*/
|
|
432
|
+
export function formatScoutTransferMarkdown(sourceHost, sourcePath, targetHost, targetPath, bytesTransferred, warning) {
|
|
433
|
+
const lines = [
|
|
434
|
+
`## 📦 Transfer Complete`,
|
|
435
|
+
"",
|
|
436
|
+
`**From:** ${sourceHost}:${sourcePath}`,
|
|
437
|
+
`**To:** ${targetHost}:${targetPath}`,
|
|
438
|
+
`**Size:** ${formatBytes(bytesTransferred)}`
|
|
439
|
+
];
|
|
440
|
+
if (warning) {
|
|
441
|
+
lines.push("");
|
|
442
|
+
lines.push(`⚠️ ${warning}`);
|
|
443
|
+
}
|
|
444
|
+
return lines.join("\n");
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Format file diff result as markdown
|
|
448
|
+
*/
|
|
449
|
+
export function formatScoutDiffMarkdown(host1, path1, host2, path2, diff) {
|
|
450
|
+
return truncateIfNeeded([
|
|
451
|
+
`## 📊 Diff`,
|
|
452
|
+
"",
|
|
453
|
+
`**File 1:** ${host1}:${path1}`,
|
|
454
|
+
`**File 2:** ${host2}:${path2}`,
|
|
455
|
+
"",
|
|
456
|
+
"```diff",
|
|
457
|
+
diff,
|
|
458
|
+
"```"
|
|
459
|
+
].join("\n"));
|
|
460
|
+
}
|
|
461
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/formatters/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAIpD,wCAAwC;AACxC,OAAO,EAAE,WAAW,EAAE,CAAC;AAEvB;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,IAAI,IAAI,CAAC,MAAM,IAAI,eAAe;QAAE,OAAO,IAAI,CAAC;IAChD,OAAO,CACL,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,GAAG,GAAG,CAAC;QACpC,0EAA0E,CAC3E,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,wBAAwB,CACtC,UAA2B,EAC3B,KAAa,EACb,MAAc,EACd,OAAgB;IAEhB,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,OAAO,sDAAsD,CAAC;IAChE,CAAC;IAED,MAAM,KAAK,GAAG,CAAC,kBAAkB,MAAM,GAAG,CAAC,IAAI,MAAM,GAAG,UAAU,CAAC,MAAM,OAAO,KAAK,GAAG,EAAE,EAAE,CAAC,CAAC;IAE9F,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QACrF,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK;aAClB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC;aACzB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;aAC9C,IAAI,CAAC,IAAI,CAAC,CAAC;QAEd,KAAK,CAAC,IAAI,CAAC,GAAG,UAAU,MAAM,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC;QAC1D,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,KAAK,cAAc,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;QACzD,IAAI,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,aAAa,KAAK,EAAE,CAAC,CAAC;QAC5C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IAED,IAAI,OAAO,EAAE,CAAC;QACZ,KAAK,CAAC,IAAI,CACR,uCAAuC,MAAM,GAAG,UAAU,CAAC,MAAM,qBAAqB,CACvF,CAAC;IACJ,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAAmD,EACnD,SAAiB,EACjB,IAAY;IAEZ,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,gCAAgC,SAAS,QAAQ,IAAI,GAAG,CAAC;IAClE,CAAC;IAED,MAAM,KAAK,GAAG,CAAC,YAAY,SAAS,KAAK,IAAI,GAAG,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;IAC7D,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,EAAE,GAAG,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACvC,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IACvC,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAElB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAiBD;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAuB,EAAE,IAAY;IACvE,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACnB,OAAO,aAAa,CAAC,CAAC,aAAa,KAAK,IAAI;;;;UAIpC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;aACpB,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;iBACrF,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC;iBACxB,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC;iBACxB,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC;kBACvB,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC;AAChD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,wBAAwB,CACtC,QAAwD;IAExD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,8BAA8B,CAAC;IAEjE,MAAM,KAAK,GAAG;QACZ,6BAA6B;QAC7B,EAAE;QACF,6CAA6C;QAC7C,6CAA6C;KAC9C,CAAC;IAEF,KAAK,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,QAAQ,EAAE,CAAC;QACvC,KAAK,CAAC,IAAI,CACR,KAAK,KAAK,CAAC,aAAa,MAAM,IAAI,MAAM,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,WAAW,CAAC,KAAK,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAClJ,CAAC;IACJ,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AA8BD;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAA0B,EAAE,IAAY;IAC5E,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;IACzB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;IACjC,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC;IAErC,MAAM,KAAK,GAAG;QACZ,iBAAiB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,IAAI,GAAG;QACzD,EAAE;QACF,WAAW;QACX,aAAa,KAAK,CAAC,MAAM,EAAE;QAC3B,cAAc,KAAK,CAAC,OAAO,EAAE;QAC7B,cAAc,KAAK,CAAC,SAAS,EAAE;QAC/B,oBAAoB,IAAI,CAAC,YAAY,EAAE;QACvC,EAAE;QACF,mBAAmB;QACnB,YAAY,MAAM,CAAC,KAAK,EAAE;QAC1B,cAAc,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;QAC5C,kBAAkB,MAAM,CAAC,UAAU,IAAI,GAAG,EAAE;QAC5C,EAAE;KACH,CAAC;IAEF,IAAI,MAAM,CAAC,GAAG,IAAI,MAAM,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxC,KAAK,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;QACxC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;YAC1C,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC7B,MAAM,WAAW,GAAG,gCAAgC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC/D,KAAK,CAAC,IAAI,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;QACvD,CAAC;QACD,IAAI,MAAM,CAAC,GAAG,CAAC,MAAM,GAAG,EAAE;YAAE,KAAK,CAAC,IAAI,CAAC,aAAa,MAAM,CAAC,GAAG,CAAC,MAAM,GAAG,EAAE,OAAO,CAAC,CAAC;QACnF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACzB,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACvB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,WAAW,KAAK,CAAC,CAAC,IAAI,IAAI,IAAI,GAAG,CAAC,CAAC;QACrE,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IAED,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACxB,KAAK,MAAM,CAAC,aAAa,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACtE,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACpC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;oBACzB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,IAAI,SAAS,IAAI,CAAC,CAAC,QAAQ,MAAM,aAAa,EAAE,CAAC,CAAC;gBAC5E,CAAC;YACH,CAAC;QACH,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IAED,IAAI,OAAO,CAAC,QAAQ,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACjE,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC3B,KAAK,MAAM,WAAW,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;YACxD,KAAK,CAAC,IAAI,CAAC,KAAK,WAAW,EAAE,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAaD;;GAEG;AACH,MAAM,UAAU,wBAAwB,CAAC,MAAyB;IAChE,MAAM,KAAK,GAAG;QACZ,wBAAwB;QACxB,EAAE;QACF,0CAA0C;QAC1C,0CAA0C;KAC3C,CAAC;IAEF,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,MAAM,WAAW,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QAC9C,MAAM,UAAU,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,KAAK,IAAI,SAAS,GAAG,CAAC;QAChF,KAAK,CAAC,IAAI,CACR,KAAK,CAAC,CAAC,IAAI,MAAM,WAAW,IAAI,UAAU,MAAM,CAAC,CAAC,cAAc,MAAM,CAAC,CAAC,YAAY,IAAI,CACzF,CAAC;IACJ,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,2BAA2B,CACzC,UAA2B,EAC3B,KAAa,EACb,KAAa;IAEb,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,iCAAiC,KAAK,IAAI,CAAC;IAE/E,MAAM,KAAK,GAAG,CAAC,0BAA0B,KAAK,MAAM,KAAK,WAAW,EAAE,EAAE,CAAC,CAAC;IAE1E,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QACrF,KAAK,CAAC,IAAI,CAAC,GAAG,UAAU,MAAM,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC;QAC1D,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,KAAK,aAAa,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;QACvD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAoBD;;GAEG;AACH,MAAM,UAAU,wBAAwB,CACtC,OAAwD;IAExD,MAAM,KAAK,GAAG,CAAC,uBAAuB,EAAE,EAAE,CAAC,CAAC;IAE5C,KAAK,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,OAAO,EAAE,CAAC;QACrC,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;QAC1B,IAAI,IAAI,CAAC,aAAa,KAAK,OAAO,EAAE,CAAC;YACnC,KAAK,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;QACpC,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,aAAa,IAAI,CAAC,aAAa,SAAS,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;YACvE,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC;YAC9C,KAAK,CAAC,IAAI,CAAC,aAAa,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC;YAC9C,KAAK,CAAC,IAAI,CAAC,WAAW,IAAI,CAAC,IAAI,cAAc,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;YAC9E,KAAK,CAAC,IAAI,CAAC,cAAc,IAAI,CAAC,aAAa,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;YACjE,KAAK,CAAC,IAAI,CAAC,iBAAiB,IAAI,CAAC,iBAAiB,cAAc,IAAI,CAAC,eAAe,QAAQ,CAAC,CAAC;YAC9F,KAAK,CAAC,IAAI,CAAC,aAAa,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QACzC,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAcD;;GAEG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAAwD;IAExD,MAAM,KAAK,GAAG,CAAC,sBAAsB,EAAE,EAAE,CAAC,CAAC;IAE3C,KAAK,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,OAAO,EAAE,CAAC;QACtC,KAAK,CAAC,IAAI,CACR,OAAO,IAAI,EAAE,EACb,EAAE,EACF,uCAAuC,EACvC,uCAAuC,CACxC,CAAC;QACF,KAAK,CAAC,IAAI,CACR,cAAc,KAAK,CAAC,MAAM,CAAC,KAAK,KAAK,KAAK,CAAC,MAAM,CAAC,MAAM,cAAc,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CACpJ,CAAC;QACF,KAAK,CAAC,IAAI,CACR,kBAAkB,KAAK,CAAC,UAAU,CAAC,KAAK,KAAK,KAAK,CAAC,UAAU,CAAC,OAAO,eAAe,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAC1K,CAAC;QACF,KAAK,CAAC,IAAI,CACR,eAAe,KAAK,CAAC,OAAO,CAAC,KAAK,KAAK,KAAK,CAAC,OAAO,CAAC,MAAM,cAAc,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CACzJ,CAAC;QACF,KAAK,CAAC,IAAI,CACR,mBAAmB,KAAK,CAAC,UAAU,CAAC,KAAK,MAAM,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,WAAW,CAAC,KAAK,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CACrI,CAAC;QACF,KAAK,CAAC,IAAI,CACR,qBAAqB,WAAW,CAAC,KAAK,CAAC,SAAS,CAAC,UAAU,WAAW,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,CACrG,CAAC;QACF,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAWD;;GAEG;AACH,MAAM,UAAU,mBAAmB,CACjC,UAA2D;IAE3D,MAAM,KAAK,GAAG,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC;IAEvC,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,KAAK,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,UAAU,EAAE,CAAC;QAC3C,KAAK,CAAC,IAAI,CACR,OAAO,IAAI,EAAE,EACb,EAAE,EACF,4CAA4C,EAC5C,4CAA4C,CAC7C,CAAC;QAEF,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,YAAY,MAAM,WAAW,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;YACnF,cAAc,IAAI,CAAC,CAAC,cAAc,CAAC;YACnC,YAAY,IAAI,CAAC,CAAC,YAAY,CAAC;QACjC,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,YAAY,YAAY,mBAAmB,WAAW,CAAC,cAAc,CAAC,cAAc,CAAC,CAAC;IAEjG,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AA0BD;;GAEG;AACH,MAAM,UAAU,2BAA2B,CACzC,OAAiF;IAEjF,MAAM,KAAK,GAAG,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC;IAExC,KAAK,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,OAAO,EAAE,CAAC;QACjD,KAAK,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;QAE1B,IAAI,KAAK,IAAI,CAAC,SAAS,EAAE,CAAC;YACxB,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,IAAI,eAAe,EAAE,CAAC,CAAC;YAC5C,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACf,SAAS;QACX,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,mBAAmB,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;QACpD,KAAK,CAAC,IAAI,CAAC,iBAAiB,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC;QAChD,KAAK,CAAC,IAAI,CAAC,eAAe,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC9D,KAAK,CAAC,IAAI,CAAC,cAAc,SAAS,CAAC,GAAG,CAAC,KAAK,YAAY,SAAS,CAAC,GAAG,CAAC,YAAY,GAAG,CAAC,CAAC;QACvF,KAAK,CAAC,IAAI,CACR,iBAAiB,SAAS,CAAC,MAAM,CAAC,MAAM,SAAS,SAAS,CAAC,MAAM,CAAC,OAAO,QAAQ,SAAS,CAAC,MAAM,CAAC,YAAY,IAAI,CACnH,CAAC;QAEF,IAAI,SAAS,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;YAC7B,KAAK,MAAM,CAAC,IAAI,SAAS,CAAC,IAAI,EAAE,CAAC;gBAC/B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,MAAM,OAAO,CAAC,CAAC,OAAO,MAAM,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC;YAChF,CAAC;QACH,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACjB,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAmB,EAAE,KAAa,EAAE,MAAc;IACrF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,kBAAkB,CAAC;IAEnD,MAAM,KAAK,GAAG;QACZ,kBAAkB;QAClB,EAAE;QACF,WAAW,MAAM,CAAC,MAAM,OAAO,KAAK,oBAAoB,MAAM,GAAG;QACjE,EAAE;QACF,0CAA0C;QAC1C,2CAA2C;KAC5C,CAAC;IAEF,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QACzB,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAClF,KAAK,CAAC,IAAI,CACR,KAAK,GAAG,CAAC,EAAE,MAAM,IAAI,MAAM,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,QAAQ,MAAM,GAAG,CAAC,UAAU,IAAI,CAC3F,CAAC;IACJ,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,yBAAyB,CACvC,QAA0B,EAC1B,IAAY,EACZ,KAAc,EACd,MAAe,EACf,OAAiB;IAEjB,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,gCAAgC,IAAI,GAAG,CAAC;IAE1E,MAAM,MAAM,GACV,KAAK,KAAK,SAAS;QACjB,CAAC,CAAC,0BAA0B,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,OAAO,KAAK,GAAG;QACxG,CAAC,CAAC,0BAA0B,IAAI,EAAE,CAAC;IAEvC,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,EAAE,EAAE,iCAAiC,EAAE,iCAAiC,CAAC,CAAC;IAEjG,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QACzF,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,MAAM,WAAW,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC;IACzF,CAAC;IAED,IAAI,OAAO,EAAE,CAAC;QACZ,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CACR,uCAAuC,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,qBAAqB,CAC5F,CAAC;IACJ,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,2BAA2B,CACzC,OAAuB,EACvB,aAAsB,EACtB,MAAe,EACf,OAAiB;IAEjB,MAAM,WAAW,GACf,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAEnF,MAAM,WAAW,GACf,aAAa,KAAK,SAAS;QACzB,CAAC,CAAC,eAAe,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,OAAO,aAAa,EAAE;QACnG,CAAC,CAAC,EAAE,CAAC;IAET,MAAM,KAAK,GAAG,CAAC,MAAM,OAAO,CAAC,IAAI,KAAK,WAAW,IAAI,OAAO,CAAC,MAAM,IAAI,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC;IAE1F,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClC,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IACnC,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,uCAAuC,EAAE,uCAAuC,CAAC,CAAC;QAE7F,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACnC,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC;YACjC,MAAM,KAAK,GACT,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC;YACrF,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;YACxD,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,MAAM,QAAQ,IAAI,GAAG,CAAC,MAAM,MAAM,MAAM,MAAM,KAAK,IAAI,CAAC,CAAC;QACnF,CAAC;IACH,CAAC;IAED,IAAI,OAAO,EAAE,CAAC;QACZ,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CACR,wCAAwC,CAAC,MAAM,IAAI,CAAC,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,qBAAqB,CACrG,CAAC;IACJ,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAqBD;;GAEG;AACH,MAAM,UAAU,4BAA4B,CAAC,OAAgC;IAC3E,MAAM,KAAK,GAAG;QACZ,MAAM,OAAO,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI,GAAG;QACtC,EAAE;QACF,mBAAmB;QACnB,mBAAmB;QACnB,UAAU,OAAO,CAAC,EAAE,IAAI;QACxB,aAAa,OAAO,CAAC,KAAK,IAAI;QAC9B,aAAa,OAAO,CAAC,KAAK,IAAI;QAC9B,eAAe,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,GAAG,IAAI;QACvD,gBAAgB,OAAO,CAAC,YAAY,IAAI;QACxC,gBAAgB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI;QACtD,aAAa,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI;QAChD,cAAc,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI;QACvC,gBAAgB,OAAO,CAAC,SAAS,IAAI;QACrC,cAAc,OAAO,CAAC,YAAY,IAAI;KACvC,CAAC;IAEF,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QAC5D,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;QAC9B,KAAK,MAAM,CAAC,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,+BAA+B;AAE/B;;GAEG;AACH,MAAM,UAAU,uBAAuB,CACrC,IAAY,EACZ,IAAY,EACZ,OAAe,EACf,IAAY,EACZ,SAAkB;IAElB,MAAM,KAAK,GAAG;QACZ,SAAS,IAAI,IAAI,IAAI,EAAE;QACvB,EAAE;QACF,aAAa,WAAW,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,EAAE;QAClE,EAAE;QACF,KAAK;QACL,OAAO;QACP,KAAK;KACN,CAAC;IAEF,IAAI,SAAS,EAAE,CAAC;QACd,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;IAC1D,CAAC;IAED,OAAO,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAY,EAAE,IAAY,EAAE,OAAe;IACjF,OAAO,gBAAgB,CAAC,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3F,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB,CACrC,IAAY,EACZ,IAAY,EACZ,IAAY,EACZ,KAAa;IAEb,OAAO,gBAAgB,CACrB,CAAC,SAAS,IAAI,IAAI,IAAI,YAAY,KAAK,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAC/E,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB,CACrC,IAAY,EACZ,IAAY,EACZ,OAAe,EACf,MAAc,EACd,QAAgB;IAEhB,MAAM,WAAW,GAAG,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAE/C,OAAO,gBAAgB,CACrB;QACE,MAAM,WAAW,aAAa,IAAI,IAAI,IAAI,EAAE;QAC5C,EAAE;QACF,kBAAkB,OAAO,IAAI;QAC7B,aAAa,QAAQ,EAAE;QACvB,EAAE;QACF,aAAa;QACb,KAAK;QACL,MAAM;QACN,KAAK;KACN,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB,CACrC,IAAY,EACZ,IAAY,EACZ,OAAe,EACf,OAAe;IAEf,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IAE1D,OAAO,gBAAgB,CACrB;QACE,eAAe,IAAI,IAAI,IAAI,EAAE;QAC7B,EAAE;QACF,kBAAkB,OAAO,IAAI;QAC7B,gBAAgB,KAAK,CAAC,MAAM,QAAQ;QACpC,EAAE;QACF,KAAK;QACL,OAAO;QACP,KAAK;KACN,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,2BAA2B,CACzC,UAAkB,EAClB,UAAkB,EAClB,UAAkB,EAClB,UAAkB,EAClB,gBAAwB,EACxB,OAAgB;IAEhB,MAAM,KAAK,GAAG;QACZ,yBAAyB;QACzB,EAAE;QACF,aAAa,UAAU,IAAI,UAAU,EAAE;QACvC,WAAW,UAAU,IAAI,UAAU,EAAE;QACrC,aAAa,WAAW,CAAC,gBAAgB,CAAC,EAAE;KAC7C,CAAC;IAEF,IAAI,OAAO,EAAE,CAAC;QACZ,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,MAAM,OAAO,EAAE,CAAC,CAAC;IAC9B,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB,CACrC,KAAa,EACb,KAAa,EACb,KAAa,EACb,KAAa,EACb,IAAY;IAEZ,OAAO,gBAAgB,CACrB;QACE,YAAY;QACZ,EAAE;QACF,eAAe,KAAK,IAAI,KAAK,EAAE;QAC/B,eAAe,KAAK,IAAI,KAAK,EAAE;QAC/B,EAAE;QACF,SAAS;QACT,IAAI;QACJ,KAAK;KACN,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
5
|
+
import express from "express";
|
|
6
|
+
import rateLimit from "express-rate-limit";
|
|
7
|
+
import { registerTools } from "./tools/index.js";
|
|
8
|
+
import { createDefaultContainer } from "./services/container.js";
|
|
9
|
+
// Server metadata
|
|
10
|
+
const SERVER_NAME = "homelab-mcp-server";
|
|
11
|
+
const SERVER_VERSION = "1.0.0";
|
|
12
|
+
// Global service container instance
|
|
13
|
+
let globalContainer;
|
|
14
|
+
/**
|
|
15
|
+
* Create and configure the MCP server
|
|
16
|
+
*/
|
|
17
|
+
function createServer() {
|
|
18
|
+
const server = new McpServer({
|
|
19
|
+
name: SERVER_NAME,
|
|
20
|
+
version: SERVER_VERSION
|
|
21
|
+
});
|
|
22
|
+
// Create and register service container
|
|
23
|
+
globalContainer = createDefaultContainer();
|
|
24
|
+
// Register all homelab tools
|
|
25
|
+
registerTools(server, globalContainer);
|
|
26
|
+
return server;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Run server with stdio transport (for Claude Code, local integrations)
|
|
30
|
+
*/
|
|
31
|
+
async function runStdio() {
|
|
32
|
+
const server = createServer();
|
|
33
|
+
const transport = new StdioServerTransport();
|
|
34
|
+
await server.connect(transport);
|
|
35
|
+
// Log to stderr (stdout is reserved for MCP protocol)
|
|
36
|
+
console.error(`${SERVER_NAME} v${SERVER_VERSION} running on stdio`);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Rate limiter for HTTP API
|
|
40
|
+
*/
|
|
41
|
+
const limiter = rateLimit({
|
|
42
|
+
windowMs: 60 * 1000, // 1 minute
|
|
43
|
+
max: 100, // 100 requests per minute
|
|
44
|
+
standardHeaders: true,
|
|
45
|
+
legacyHeaders: false,
|
|
46
|
+
message: { error: "Too many requests, please try again later" }
|
|
47
|
+
});
|
|
48
|
+
/**
|
|
49
|
+
* Run server with HTTP transport (for remote access, multiple clients)
|
|
50
|
+
*/
|
|
51
|
+
async function runHTTP() {
|
|
52
|
+
const server = createServer();
|
|
53
|
+
const app = express();
|
|
54
|
+
app.use(express.json());
|
|
55
|
+
// Request logging middleware
|
|
56
|
+
app.use((req, _res, next) => {
|
|
57
|
+
const timestamp = new Date().toISOString();
|
|
58
|
+
const forwarded = req.headers["x-forwarded-for"] || req.headers["x-real-ip"] || "";
|
|
59
|
+
console.error(`[${timestamp}] ${req.method} ${req.path} from ${req.ip} (fwd: ${forwarded})`);
|
|
60
|
+
next();
|
|
61
|
+
});
|
|
62
|
+
// Health check endpoint (no rate limiting)
|
|
63
|
+
app.get("/health", (_req, res) => {
|
|
64
|
+
res.json({ status: "ok", server: SERVER_NAME, version: SERVER_VERSION });
|
|
65
|
+
});
|
|
66
|
+
// MCP endpoint - stateless JSON mode with rate limiting
|
|
67
|
+
app.post("/mcp", limiter, async (req, res) => {
|
|
68
|
+
const transport = new StreamableHTTPServerTransport({
|
|
69
|
+
sessionIdGenerator: undefined,
|
|
70
|
+
enableJsonResponse: true
|
|
71
|
+
});
|
|
72
|
+
res.on("close", () => transport.close());
|
|
73
|
+
await server.connect(transport);
|
|
74
|
+
await transport.handleRequest(req, res, req.body);
|
|
75
|
+
});
|
|
76
|
+
const port = parseInt(process.env.HOMELAB_PORT || "3000", 10);
|
|
77
|
+
const host = process.env.HOMELAB_HOST || "127.0.0.1";
|
|
78
|
+
app.listen(port, host, () => {
|
|
79
|
+
console.error(`${SERVER_NAME} v${SERVER_VERSION} running on http://${host}:${port}/mcp`);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Print usage information
|
|
84
|
+
*/
|
|
85
|
+
function printUsage() {
|
|
86
|
+
console.log(`
|
|
87
|
+
${SERVER_NAME} v${SERVER_VERSION}
|
|
88
|
+
|
|
89
|
+
MCP server for managing homelab Docker infrastructure across multiple hosts.
|
|
90
|
+
|
|
91
|
+
USAGE:
|
|
92
|
+
node dist/index.js [--stdio | --http]
|
|
93
|
+
|
|
94
|
+
OPTIONS:
|
|
95
|
+
--stdio Run with stdio transport (default, for Claude Code)
|
|
96
|
+
--http Run with HTTP transport (for remote access)
|
|
97
|
+
--help Show this help message
|
|
98
|
+
|
|
99
|
+
CONFIGURATION:
|
|
100
|
+
Create a config file at one of these locations (checked in order):
|
|
101
|
+
1. Path specified by HOMELAB_CONFIG_FILE env var
|
|
102
|
+
2. ./homelab.config.json (current directory)
|
|
103
|
+
3. ~/.config/homelab-mcp/config.json
|
|
104
|
+
4. ~/.homelab-mcp.json
|
|
105
|
+
|
|
106
|
+
Example config file:
|
|
107
|
+
{
|
|
108
|
+
"hosts": [
|
|
109
|
+
{"name": "unraid", "host": "unraid.local", "port": 2375, "protocol": "http"},
|
|
110
|
+
{"name": "proxmox", "host": "proxmox.local", "port": 2375, "protocol": "http"},
|
|
111
|
+
{"name": "local", "host": "localhost", "dockerSocketPath": "/var/run/docker.sock"}
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
ENVIRONMENT VARIABLES:
|
|
116
|
+
HOMELAB_CONFIG_FILE Path to config file (optional, overrides default paths)
|
|
117
|
+
HOMELAB_HOSTS_CONFIG JSON config as env var (fallback if no config file)
|
|
118
|
+
HOMELAB_PORT HTTP server port (default: 3000)
|
|
119
|
+
HOMELAB_HOST HTTP server bind address (default: 127.0.0.1)
|
|
120
|
+
|
|
121
|
+
CLAUDE CODE CONFIG (~/.claude/claude_code_config.json):
|
|
122
|
+
{
|
|
123
|
+
"mcpServers": {
|
|
124
|
+
"homelab": {
|
|
125
|
+
"command": "node",
|
|
126
|
+
"args": ["/path/to/homelab-mcp-server/dist/index.js"],
|
|
127
|
+
"env": {
|
|
128
|
+
"HOMELAB_CONFIG_FILE": "/path/to/your/homelab.config.json"
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
`);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Graceful shutdown handler
|
|
137
|
+
*/
|
|
138
|
+
async function shutdown(signal) {
|
|
139
|
+
console.error(`\nReceived ${signal}, shutting down gracefully...`);
|
|
140
|
+
if (globalContainer) {
|
|
141
|
+
await globalContainer.cleanup();
|
|
142
|
+
}
|
|
143
|
+
console.error("Cleanup complete");
|
|
144
|
+
process.exit(0);
|
|
145
|
+
}
|
|
146
|
+
// Register signal handlers for graceful shutdown
|
|
147
|
+
process.on("SIGINT", () => {
|
|
148
|
+
shutdown("SIGINT").catch((error) => {
|
|
149
|
+
console.error("Error during shutdown:", error);
|
|
150
|
+
process.exit(1);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
process.on("SIGTERM", () => {
|
|
154
|
+
shutdown("SIGTERM").catch((error) => {
|
|
155
|
+
console.error("Error during shutdown:", error);
|
|
156
|
+
process.exit(1);
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
// Main entry point
|
|
160
|
+
const args = process.argv.slice(2);
|
|
161
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
162
|
+
printUsage();
|
|
163
|
+
process.exit(0);
|
|
164
|
+
}
|
|
165
|
+
const transportMode = args.includes("--http") ? "http" : "stdio";
|
|
166
|
+
if (transportMode === "http") {
|
|
167
|
+
runHTTP().catch((error) => {
|
|
168
|
+
console.error("Server error:", error);
|
|
169
|
+
process.exit(1);
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
runStdio().catch((error) => {
|
|
174
|
+
console.error("Server error:", error);
|
|
175
|
+
process.exit(1);
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=index.js.map
|