@cloudgrid-io/mcp 0.5.5 → 0.6.1
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/package.json +1 -1
- package/src/corpus/examples/dashboard/index.html +121 -0
- package/src/corpus/examples/deck/index.html +180 -0
- package/src/corpus/examples/landing-page/index.html +98 -0
- package/src/corpus/examples/report/index.html +112 -0
- package/src/corpus/examples/web-app/index.html +125 -0
- package/src/corpus/install.md +2 -1
- package/src/corpus/skills-readme.md +3 -2
- package/src/corpus/templates/dashboard/index.html +118 -0
- package/src/corpus/templates/deck/index.html +149 -0
- package/src/corpus/templates/landing-page/index.html +97 -0
- package/src/corpus/templates/report/index.html +93 -0
- package/src/corpus/templates/web-app/index.html +99 -0
- package/src/corpus/usage.md +6 -5
- package/src/corpus/workflows/dashboard.md +31 -0
- package/src/corpus/workflows/landing-page.md +29 -0
- package/src/corpus/workflows/presentation.md +28 -0
- package/src/corpus/workflows/report.md +31 -0
- package/src/corpus/workflows/web-app.md +31 -0
- package/src/docs.js +14 -2
- package/src/tools.js +314 -76
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>{{DASHBOARD_TITLE}}</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
--bg: #0b0f17;
|
|
10
|
+
--panel: #121826;
|
|
11
|
+
--fg: #e8edf5;
|
|
12
|
+
--muted: #9aa7bd;
|
|
13
|
+
--accent: #5b8cff;
|
|
14
|
+
--good: #46d19e;
|
|
15
|
+
--border: #223049;
|
|
16
|
+
}
|
|
17
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
18
|
+
body {
|
|
19
|
+
background: var(--bg);
|
|
20
|
+
color: var(--fg);
|
|
21
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
22
|
+
-webkit-font-smoothing: antialiased;
|
|
23
|
+
padding: clamp(1.25rem, 4vw, 2.5rem);
|
|
24
|
+
}
|
|
25
|
+
header { margin-bottom: 1.75rem; }
|
|
26
|
+
h1 { font-size: clamp(1.6rem, 4vw, 2.3rem); letter-spacing: -0.02em; }
|
|
27
|
+
.status { color: var(--muted); margin-top: 0.35rem; }
|
|
28
|
+
.grid { display: grid; gap: 1.1rem; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
|
|
29
|
+
.card {
|
|
30
|
+
background: var(--panel); border: 1px solid var(--border);
|
|
31
|
+
border-radius: 14px; padding: 1.25rem 1.4rem;
|
|
32
|
+
}
|
|
33
|
+
.card .label { color: var(--muted); font-size: 0.85rem; }
|
|
34
|
+
.card .value { font-size: 2rem; font-weight: 600; margin: 0.35rem 0; font-variant-numeric: tabular-nums; }
|
|
35
|
+
.card .trend { font-size: 0.85rem; color: var(--good); }
|
|
36
|
+
.charts { display: grid; gap: 1.1rem; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); margin-top: 1.1rem; }
|
|
37
|
+
.chart-card { background: var(--panel); border: 1px solid var(--border); border-radius: 14px; padding: 1.25rem 1.4rem; }
|
|
38
|
+
.chart-card h2 { font-size: 1rem; color: var(--muted); font-weight: 600; margin-bottom: 0.9rem; }
|
|
39
|
+
svg { width: 100%; height: auto; display: block; }
|
|
40
|
+
</style>
|
|
41
|
+
</head>
|
|
42
|
+
<body>
|
|
43
|
+
<header>
|
|
44
|
+
<h1>{{DASHBOARD_TITLE}}</h1>
|
|
45
|
+
<div class="status">{{STATUS_LINE}}</div>
|
|
46
|
+
</header>
|
|
47
|
+
|
|
48
|
+
<!-- One card per KPI. -->
|
|
49
|
+
<section class="grid">
|
|
50
|
+
<div class="card">
|
|
51
|
+
<div class="label">{{KPI_1_LABEL}}</div>
|
|
52
|
+
<div class="value">{{KPI_1_VALUE}}</div>
|
|
53
|
+
<div class="trend">{{KPI_1_TREND}}</div>
|
|
54
|
+
</div>
|
|
55
|
+
<div class="card">
|
|
56
|
+
<div class="label">{{KPI_2_LABEL}}</div>
|
|
57
|
+
<div class="value">{{KPI_2_VALUE}}</div>
|
|
58
|
+
<div class="trend">{{KPI_2_TREND}}</div>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="card">
|
|
61
|
+
<div class="label">{{KPI_3_LABEL}}</div>
|
|
62
|
+
<div class="value">{{KPI_3_VALUE}}</div>
|
|
63
|
+
<div class="trend">{{KPI_3_TREND}}</div>
|
|
64
|
+
</div>
|
|
65
|
+
</section>
|
|
66
|
+
|
|
67
|
+
<section class="charts">
|
|
68
|
+
<div class="chart-card">
|
|
69
|
+
<h2>{{BAR_CHART_TITLE}}</h2>
|
|
70
|
+
<svg id="bar" viewBox="0 0 320 160" role="img" aria-label="Bar chart"></svg>
|
|
71
|
+
</div>
|
|
72
|
+
<div class="chart-card">
|
|
73
|
+
<h2>{{LINE_CHART_TITLE}}</h2>
|
|
74
|
+
<svg id="line" viewBox="0 0 320 160" role="img" aria-label="Line chart"></svg>
|
|
75
|
+
</div>
|
|
76
|
+
</section>
|
|
77
|
+
|
|
78
|
+
<script>
|
|
79
|
+
// Charts are hand-rolled inline SVG — no external library. Edit these arrays.
|
|
80
|
+
var barData = [{{BAR_DATA}}]; // e.g. 12, 19, 9, 22, 17
|
|
81
|
+
var lineData = [{{LINE_DATA}}]; // e.g. 4, 8, 6, 11, 9, 14
|
|
82
|
+
|
|
83
|
+
var NS = "http://www.w3.org/2000/svg";
|
|
84
|
+
function el(name, attrs) {
|
|
85
|
+
var n = document.createElementNS(NS, name);
|
|
86
|
+
for (var k in attrs) n.setAttribute(k, attrs[k]);
|
|
87
|
+
return n;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
(function drawBars() {
|
|
91
|
+
var svg = document.getElementById("bar");
|
|
92
|
+
var W = 320, H = 160, pad = 20;
|
|
93
|
+
var max = Math.max.apply(null, barData.concat([1]));
|
|
94
|
+
var bw = (W - pad * 2) / barData.length;
|
|
95
|
+
barData.forEach(function (v, i) {
|
|
96
|
+
var h = (v / max) * (H - pad * 2);
|
|
97
|
+
svg.appendChild(el("rect", {
|
|
98
|
+
x: pad + i * bw + bw * 0.15, y: H - pad - h,
|
|
99
|
+
width: bw * 0.7, height: h, rx: 3, fill: "var(--accent)"
|
|
100
|
+
}));
|
|
101
|
+
});
|
|
102
|
+
svg.appendChild(el("line", { x1: pad, y1: H - pad, x2: W - pad, y2: H - pad, stroke: "var(--border)" }));
|
|
103
|
+
})();
|
|
104
|
+
|
|
105
|
+
(function drawLine() {
|
|
106
|
+
var svg = document.getElementById("line");
|
|
107
|
+
var W = 320, H = 160, pad = 20;
|
|
108
|
+
var max = Math.max.apply(null, lineData.concat([1]));
|
|
109
|
+
var step = (W - pad * 2) / Math.max(1, lineData.length - 1);
|
|
110
|
+
var pts = lineData.map(function (v, i) {
|
|
111
|
+
return (pad + i * step) + "," + (H - pad - (v / max) * (H - pad * 2));
|
|
112
|
+
}).join(" ");
|
|
113
|
+
svg.appendChild(el("polyline", { points: pts, fill: "none", stroke: "var(--good)", "stroke-width": 2.5 }));
|
|
114
|
+
svg.appendChild(el("line", { x1: pad, y1: H - pad, x2: W - pad, y2: H - pad, stroke: "var(--border)" }));
|
|
115
|
+
})();
|
|
116
|
+
</script>
|
|
117
|
+
</body>
|
|
118
|
+
</html>
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>{{DECK_TITLE}}</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
--bg: #0b0f17;
|
|
10
|
+
--panel: #121826;
|
|
11
|
+
--fg: #e8edf5;
|
|
12
|
+
--muted: #9aa7bd;
|
|
13
|
+
--accent: #5b8cff;
|
|
14
|
+
--border: #223049;
|
|
15
|
+
}
|
|
16
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
17
|
+
html, body { height: 100%; }
|
|
18
|
+
body {
|
|
19
|
+
background: var(--bg);
|
|
20
|
+
color: var(--fg);
|
|
21
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
22
|
+
-webkit-font-smoothing: antialiased;
|
|
23
|
+
overflow: hidden;
|
|
24
|
+
}
|
|
25
|
+
#deck { position: relative; height: 100vh; width: 100vw; }
|
|
26
|
+
.slide {
|
|
27
|
+
position: absolute;
|
|
28
|
+
inset: 0;
|
|
29
|
+
display: none;
|
|
30
|
+
flex-direction: column;
|
|
31
|
+
justify-content: center;
|
|
32
|
+
padding: clamp(2rem, 8vw, 8rem);
|
|
33
|
+
gap: 1.25rem;
|
|
34
|
+
animation: fade 0.35s ease;
|
|
35
|
+
}
|
|
36
|
+
.slide.active { display: flex; }
|
|
37
|
+
@keyframes fade { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
|
|
38
|
+
.slide[data-role="title"] h1 {
|
|
39
|
+
font-size: clamp(2.5rem, 7vw, 5rem);
|
|
40
|
+
line-height: 1.05;
|
|
41
|
+
letter-spacing: -0.02em;
|
|
42
|
+
}
|
|
43
|
+
.slide[data-role="title"] p {
|
|
44
|
+
font-size: clamp(1.1rem, 2.5vw, 1.6rem);
|
|
45
|
+
color: var(--muted);
|
|
46
|
+
max-width: 40ch;
|
|
47
|
+
}
|
|
48
|
+
.slide h2 {
|
|
49
|
+
font-size: clamp(1.8rem, 4.5vw, 3rem);
|
|
50
|
+
letter-spacing: -0.01em;
|
|
51
|
+
}
|
|
52
|
+
.slide .body {
|
|
53
|
+
font-size: clamp(1.05rem, 2.2vw, 1.5rem);
|
|
54
|
+
color: var(--muted);
|
|
55
|
+
max-width: 60ch;
|
|
56
|
+
line-height: 1.5;
|
|
57
|
+
}
|
|
58
|
+
.slide .body ul { padding-left: 1.4em; display: grid; gap: 0.6em; }
|
|
59
|
+
.accent-bar {
|
|
60
|
+
width: 64px; height: 5px; border-radius: 99px;
|
|
61
|
+
background: var(--accent);
|
|
62
|
+
}
|
|
63
|
+
#chrome {
|
|
64
|
+
position: fixed; bottom: 0; left: 0; right: 0;
|
|
65
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
66
|
+
padding: 0.9rem 1.4rem;
|
|
67
|
+
border-top: 1px solid var(--border);
|
|
68
|
+
background: color-mix(in srgb, var(--panel) 85%, transparent);
|
|
69
|
+
backdrop-filter: blur(6px);
|
|
70
|
+
font-size: 0.85rem; color: var(--muted);
|
|
71
|
+
}
|
|
72
|
+
#chrome button {
|
|
73
|
+
background: transparent; color: var(--fg);
|
|
74
|
+
border: 1px solid var(--border); border-radius: 8px;
|
|
75
|
+
padding: 0.35rem 0.7rem; cursor: pointer; font: inherit;
|
|
76
|
+
}
|
|
77
|
+
#chrome button:hover { border-color: var(--accent); }
|
|
78
|
+
#counter { font-variant-numeric: tabular-nums; }
|
|
79
|
+
#progress {
|
|
80
|
+
position: fixed; top: 0; left: 0; height: 3px;
|
|
81
|
+
background: var(--accent); transition: width 0.3s ease; z-index: 10;
|
|
82
|
+
}
|
|
83
|
+
</style>
|
|
84
|
+
</head>
|
|
85
|
+
<body>
|
|
86
|
+
<div id="progress"></div>
|
|
87
|
+
<div id="deck">
|
|
88
|
+
<!-- SLIDES_START -->
|
|
89
|
+
<section class="slide active" data-role="title">
|
|
90
|
+
<div class="accent-bar"></div>
|
|
91
|
+
<h1>{{DECK_TITLE}}</h1>
|
|
92
|
+
<p>{{DECK_SUBTITLE}}</p>
|
|
93
|
+
</section>
|
|
94
|
+
|
|
95
|
+
<section class="slide">
|
|
96
|
+
<div class="accent-bar"></div>
|
|
97
|
+
<h2>{{SLIDE_1_HEADING}}</h2>
|
|
98
|
+
<div class="body">{{SLIDE_1_BODY}}</div>
|
|
99
|
+
</section>
|
|
100
|
+
|
|
101
|
+
<section class="slide">
|
|
102
|
+
<div class="accent-bar"></div>
|
|
103
|
+
<h2>{{SLIDE_2_HEADING}}</h2>
|
|
104
|
+
<div class="body">{{SLIDE_2_BODY}}</div>
|
|
105
|
+
</section>
|
|
106
|
+
<!-- Add more <section class="slide">...</section> blocks as needed. -->
|
|
107
|
+
<!-- SLIDES_END -->
|
|
108
|
+
</div>
|
|
109
|
+
|
|
110
|
+
<div id="chrome">
|
|
111
|
+
<span id="deck-name">{{DECK_TITLE}}</span>
|
|
112
|
+
<span>
|
|
113
|
+
<button id="prev" aria-label="Previous slide">Prev</button>
|
|
114
|
+
<span id="counter">1 / 1</span>
|
|
115
|
+
<button id="next" aria-label="Next slide">Next</button>
|
|
116
|
+
</span>
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
<script>
|
|
120
|
+
(function () {
|
|
121
|
+
var slides = Array.prototype.slice.call(document.querySelectorAll(".slide"));
|
|
122
|
+
var idx = 0;
|
|
123
|
+
var counter = document.getElementById("counter");
|
|
124
|
+
var progress = document.getElementById("progress");
|
|
125
|
+
|
|
126
|
+
function render() {
|
|
127
|
+
slides.forEach(function (s, i) { s.classList.toggle("active", i === idx); });
|
|
128
|
+
counter.textContent = (idx + 1) + " / " + slides.length;
|
|
129
|
+
progress.style.width = ((idx + 1) / slides.length * 100) + "%";
|
|
130
|
+
}
|
|
131
|
+
function go(delta) {
|
|
132
|
+
idx = Math.max(0, Math.min(slides.length - 1, idx + delta));
|
|
133
|
+
render();
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
document.getElementById("next").addEventListener("click", function () { go(1); });
|
|
137
|
+
document.getElementById("prev").addEventListener("click", function () { go(-1); });
|
|
138
|
+
document.addEventListener("keydown", function (e) {
|
|
139
|
+
if (e.key === "ArrowRight" || e.key === "PageDown" || e.key === " ") { go(1); e.preventDefault(); }
|
|
140
|
+
else if (e.key === "ArrowLeft" || e.key === "PageUp") { go(-1); e.preventDefault(); }
|
|
141
|
+
else if (e.key === "Home") { idx = 0; render(); }
|
|
142
|
+
else if (e.key === "End") { idx = slides.length - 1; render(); }
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
render();
|
|
146
|
+
})();
|
|
147
|
+
</script>
|
|
148
|
+
</body>
|
|
149
|
+
</html>
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>{{PRODUCT_NAME}}</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
--bg: #0b0f17;
|
|
10
|
+
--panel: #121826;
|
|
11
|
+
--fg: #e8edf5;
|
|
12
|
+
--muted: #9aa7bd;
|
|
13
|
+
--accent: #5b8cff;
|
|
14
|
+
--border: #223049;
|
|
15
|
+
}
|
|
16
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
17
|
+
body {
|
|
18
|
+
background: var(--bg);
|
|
19
|
+
color: var(--fg);
|
|
20
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
21
|
+
-webkit-font-smoothing: antialiased;
|
|
22
|
+
line-height: 1.5;
|
|
23
|
+
}
|
|
24
|
+
header, section, footer { padding: clamp(2rem, 6vw, 5rem) clamp(1.25rem, 6vw, 6rem); }
|
|
25
|
+
nav {
|
|
26
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
27
|
+
padding: 1.1rem clamp(1.25rem, 6vw, 6rem);
|
|
28
|
+
border-bottom: 1px solid var(--border);
|
|
29
|
+
}
|
|
30
|
+
nav .brand { font-weight: 600; letter-spacing: -0.01em; }
|
|
31
|
+
nav a { color: var(--muted); text-decoration: none; }
|
|
32
|
+
.hero { text-align: center; display: grid; gap: 1.25rem; place-items: center; }
|
|
33
|
+
.hero h1 {
|
|
34
|
+
font-size: clamp(2.4rem, 6vw, 4.5rem);
|
|
35
|
+
line-height: 1.05; letter-spacing: -0.02em; max-width: 20ch;
|
|
36
|
+
}
|
|
37
|
+
.hero p { font-size: clamp(1.05rem, 2.4vw, 1.5rem); color: var(--muted); max-width: 48ch; }
|
|
38
|
+
.cta {
|
|
39
|
+
display: inline-block; margin-top: 0.5rem;
|
|
40
|
+
background: var(--accent); color: #fff; text-decoration: none;
|
|
41
|
+
padding: 0.85rem 1.6rem; border-radius: 10px; font-weight: 600;
|
|
42
|
+
}
|
|
43
|
+
.cta:hover { filter: brightness(1.08); }
|
|
44
|
+
.features {
|
|
45
|
+
display: grid; gap: 1.25rem;
|
|
46
|
+
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
|
47
|
+
border-top: 1px solid var(--border);
|
|
48
|
+
}
|
|
49
|
+
.feature {
|
|
50
|
+
background: var(--panel); border: 1px solid var(--border);
|
|
51
|
+
border-radius: 14px; padding: 1.5rem;
|
|
52
|
+
}
|
|
53
|
+
.feature h3 { font-size: 1.15rem; margin-bottom: 0.5rem; letter-spacing: -0.01em; }
|
|
54
|
+
.feature p { color: var(--muted); }
|
|
55
|
+
.closing { text-align: center; border-top: 1px solid var(--border); display: grid; gap: 1.25rem; place-items: center; }
|
|
56
|
+
.closing h2 { font-size: clamp(1.8rem, 4.5vw, 3rem); letter-spacing: -0.01em; max-width: 24ch; }
|
|
57
|
+
footer { border-top: 1px solid var(--border); color: var(--muted); font-size: 0.9rem; text-align: center; }
|
|
58
|
+
</style>
|
|
59
|
+
</head>
|
|
60
|
+
<body>
|
|
61
|
+
<nav>
|
|
62
|
+
<span class="brand">{{PRODUCT_NAME}}</span>
|
|
63
|
+
<a class="cta" href="{{CTA_HREF}}">{{CTA_LABEL}}</a>
|
|
64
|
+
</nav>
|
|
65
|
+
|
|
66
|
+
<header class="hero">
|
|
67
|
+
<h1>{{HERO_HEADLINE}}</h1>
|
|
68
|
+
<p>{{HERO_SUBHEAD}}</p>
|
|
69
|
+
<a class="cta" href="{{CTA_HREF}}">{{CTA_LABEL}}</a>
|
|
70
|
+
</header>
|
|
71
|
+
|
|
72
|
+
<section class="features">
|
|
73
|
+
<!-- FEATURES_START -->
|
|
74
|
+
<div class="feature">
|
|
75
|
+
<h3>{{FEATURE_1_TITLE}}</h3>
|
|
76
|
+
<p>{{FEATURE_1_BODY}}</p>
|
|
77
|
+
</div>
|
|
78
|
+
<div class="feature">
|
|
79
|
+
<h3>{{FEATURE_2_TITLE}}</h3>
|
|
80
|
+
<p>{{FEATURE_2_BODY}}</p>
|
|
81
|
+
</div>
|
|
82
|
+
<div class="feature">
|
|
83
|
+
<h3>{{FEATURE_3_TITLE}}</h3>
|
|
84
|
+
<p>{{FEATURE_3_BODY}}</p>
|
|
85
|
+
</div>
|
|
86
|
+
<!-- Add more <div class="feature">...</div> blocks as needed. -->
|
|
87
|
+
<!-- FEATURES_END -->
|
|
88
|
+
</section>
|
|
89
|
+
|
|
90
|
+
<section class="closing">
|
|
91
|
+
<h2>{{CLOSING_HEADLINE}}</h2>
|
|
92
|
+
<a class="cta" href="{{CTA_HREF}}">{{CTA_LABEL}}</a>
|
|
93
|
+
</section>
|
|
94
|
+
|
|
95
|
+
<footer>{{FOOTER_TEXT}}</footer>
|
|
96
|
+
</body>
|
|
97
|
+
</html>
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>{{REPORT_TITLE}}</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
--bg: #0b0f17;
|
|
10
|
+
--panel: #121826;
|
|
11
|
+
--fg: #e8edf5;
|
|
12
|
+
--muted: #9aa7bd;
|
|
13
|
+
--accent: #5b8cff;
|
|
14
|
+
--border: #223049;
|
|
15
|
+
}
|
|
16
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
17
|
+
body {
|
|
18
|
+
background: var(--bg);
|
|
19
|
+
color: var(--fg);
|
|
20
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
21
|
+
-webkit-font-smoothing: antialiased;
|
|
22
|
+
line-height: 1.6;
|
|
23
|
+
}
|
|
24
|
+
.page {
|
|
25
|
+
max-width: 820px; margin: 0 auto;
|
|
26
|
+
padding: clamp(2rem, 6vw, 4.5rem) clamp(1.25rem, 5vw, 3.5rem);
|
|
27
|
+
}
|
|
28
|
+
header { border-bottom: 1px solid var(--border); padding-bottom: 1.5rem; margin-bottom: 2rem; }
|
|
29
|
+
.accent-bar { width: 64px; height: 5px; border-radius: 99px; background: var(--accent); margin-bottom: 1.1rem; }
|
|
30
|
+
h1 { font-size: clamp(1.9rem, 4.5vw, 2.8rem); line-height: 1.1; letter-spacing: -0.02em; }
|
|
31
|
+
.subtitle { color: var(--muted); font-size: 1.1rem; margin-top: 0.5rem; }
|
|
32
|
+
.meta { color: var(--muted); font-size: 0.9rem; margin-top: 0.75rem; }
|
|
33
|
+
.summary {
|
|
34
|
+
background: var(--panel); border: 1px solid var(--border);
|
|
35
|
+
border-radius: 12px; padding: 1.25rem 1.4rem; margin-bottom: 2rem; color: var(--muted);
|
|
36
|
+
}
|
|
37
|
+
section { margin-bottom: 2rem; }
|
|
38
|
+
section h2 { font-size: 1.35rem; letter-spacing: -0.01em; margin-bottom: 0.6rem; }
|
|
39
|
+
section p { color: var(--muted); }
|
|
40
|
+
table { width: 100%; border-collapse: collapse; margin-top: 0.5rem; }
|
|
41
|
+
th, td { text-align: left; padding: 0.6rem 0.75rem; border-bottom: 1px solid var(--border); }
|
|
42
|
+
th { color: var(--muted); font-size: 0.85rem; font-weight: 600; }
|
|
43
|
+
td { font-variant-numeric: tabular-nums; }
|
|
44
|
+
footer { border-top: 1px solid var(--border); padding-top: 1.25rem; color: var(--muted); font-size: 0.85rem; }
|
|
45
|
+
@media print {
|
|
46
|
+
:root { --bg: #ffffff; --panel: #f4f6fa; --fg: #10151f; --muted: #4a5568; --border: #d5dbe6; }
|
|
47
|
+
body { background: #fff; }
|
|
48
|
+
.page { padding: 0; }
|
|
49
|
+
}
|
|
50
|
+
</style>
|
|
51
|
+
</head>
|
|
52
|
+
<body>
|
|
53
|
+
<div class="page">
|
|
54
|
+
<header>
|
|
55
|
+
<div class="accent-bar"></div>
|
|
56
|
+
<h1>{{REPORT_TITLE}}</h1>
|
|
57
|
+
<div class="subtitle">{{REPORT_SUBTITLE}}</div>
|
|
58
|
+
<div class="meta">{{REPORT_DATE_LINE}}</div>
|
|
59
|
+
</header>
|
|
60
|
+
|
|
61
|
+
<div class="summary">{{REPORT_SUMMARY}}</div>
|
|
62
|
+
|
|
63
|
+
<!-- SECTIONS_START -->
|
|
64
|
+
<section>
|
|
65
|
+
<h2>{{SECTION_1_HEADING}}</h2>
|
|
66
|
+
<p>{{SECTION_1_BODY}}</p>
|
|
67
|
+
</section>
|
|
68
|
+
<section>
|
|
69
|
+
<h2>{{SECTION_2_HEADING}}</h2>
|
|
70
|
+
<p>{{SECTION_2_BODY}}</p>
|
|
71
|
+
</section>
|
|
72
|
+
<!-- Add more <section>...</section> blocks as needed. -->
|
|
73
|
+
<!-- SECTIONS_END -->
|
|
74
|
+
|
|
75
|
+
<section>
|
|
76
|
+
<h2>{{DATA_HEADING}}</h2>
|
|
77
|
+
<!-- Fill these rows with the data, or remove this whole section if there is none. -->
|
|
78
|
+
<table>
|
|
79
|
+
<thead>
|
|
80
|
+
<tr><th>{{COL_1}}</th><th>{{COL_2}}</th><th>{{COL_3}}</th></tr>
|
|
81
|
+
</thead>
|
|
82
|
+
<tbody>
|
|
83
|
+
<tr><td>{{R1C1}}</td><td>{{R1C2}}</td><td>{{R1C3}}</td></tr>
|
|
84
|
+
<tr><td>{{R2C1}}</td><td>{{R2C2}}</td><td>{{R2C3}}</td></tr>
|
|
85
|
+
<tr><td>{{R3C1}}</td><td>{{R3C2}}</td><td>{{R3C3}}</td></tr>
|
|
86
|
+
</tbody>
|
|
87
|
+
</table>
|
|
88
|
+
</section>
|
|
89
|
+
|
|
90
|
+
<footer>{{FOOTER_TEXT}}</footer>
|
|
91
|
+
</div>
|
|
92
|
+
</body>
|
|
93
|
+
</html>
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>{{APP_TITLE}}</title>
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
--bg: #0b0f17;
|
|
10
|
+
--panel: #121826;
|
|
11
|
+
--fg: #e8edf5;
|
|
12
|
+
--muted: #9aa7bd;
|
|
13
|
+
--accent: #5b8cff;
|
|
14
|
+
--border: #223049;
|
|
15
|
+
}
|
|
16
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
17
|
+
body {
|
|
18
|
+
background: var(--bg);
|
|
19
|
+
color: var(--fg);
|
|
20
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
21
|
+
-webkit-font-smoothing: antialiased;
|
|
22
|
+
min-height: 100vh;
|
|
23
|
+
display: grid; place-items: center;
|
|
24
|
+
padding: 1.5rem;
|
|
25
|
+
}
|
|
26
|
+
.app {
|
|
27
|
+
width: 100%; max-width: 420px;
|
|
28
|
+
background: var(--panel); border: 1px solid var(--border);
|
|
29
|
+
border-radius: 16px; padding: 1.75rem;
|
|
30
|
+
}
|
|
31
|
+
h1 { font-size: 1.5rem; letter-spacing: -0.01em; margin-bottom: 0.35rem; }
|
|
32
|
+
.subtitle { color: var(--muted); font-size: 0.95rem; margin-bottom: 1.4rem; }
|
|
33
|
+
label { display: block; font-size: 0.85rem; color: var(--muted); margin: 0.9rem 0 0.35rem; }
|
|
34
|
+
input, select {
|
|
35
|
+
width: 100%; font: inherit; color: var(--fg);
|
|
36
|
+
background: var(--bg); border: 1px solid var(--border);
|
|
37
|
+
border-radius: 10px; padding: 0.65rem 0.75rem;
|
|
38
|
+
}
|
|
39
|
+
input:focus, select:focus { outline: none; border-color: var(--accent); }
|
|
40
|
+
.row { display: flex; gap: 0.75rem; }
|
|
41
|
+
.row > * { flex: 1; }
|
|
42
|
+
.result {
|
|
43
|
+
margin-top: 1.5rem; padding: 1.1rem 1.25rem;
|
|
44
|
+
background: var(--bg); border: 1px solid var(--border); border-radius: 12px;
|
|
45
|
+
display: flex; align-items: baseline; justify-content: space-between;
|
|
46
|
+
}
|
|
47
|
+
.result .label { color: var(--muted); font-size: 0.85rem; }
|
|
48
|
+
.result .value { font-size: 1.6rem; font-weight: 600; font-variant-numeric: tabular-nums; }
|
|
49
|
+
</style>
|
|
50
|
+
</head>
|
|
51
|
+
<body>
|
|
52
|
+
<!-- Adapt this shell into the tool you need: rename the title, replace the
|
|
53
|
+
inputs, and rewrite compute() to produce the output. Keep all logic
|
|
54
|
+
inline. This starter reads two numeric inputs and shows their result. -->
|
|
55
|
+
<main class="app">
|
|
56
|
+
<h1>{{APP_TITLE}}</h1>
|
|
57
|
+
<p class="subtitle">{{APP_SUBTITLE}}</p>
|
|
58
|
+
|
|
59
|
+
<div class="row">
|
|
60
|
+
<div>
|
|
61
|
+
<label for="a">{{INPUT_A_LABEL}}</label>
|
|
62
|
+
<input id="a" type="number" value="0" inputmode="decimal" />
|
|
63
|
+
</div>
|
|
64
|
+
<div>
|
|
65
|
+
<label for="b">{{INPUT_B_LABEL}}</label>
|
|
66
|
+
<input id="b" type="number" value="0" inputmode="decimal" />
|
|
67
|
+
</div>
|
|
68
|
+
</div>
|
|
69
|
+
|
|
70
|
+
<div class="result">
|
|
71
|
+
<span class="label">{{RESULT_LABEL}}</span>
|
|
72
|
+
<span class="value" id="out">0</span>
|
|
73
|
+
</div>
|
|
74
|
+
</main>
|
|
75
|
+
|
|
76
|
+
<script>
|
|
77
|
+
(function () {
|
|
78
|
+
var a = document.getElementById("a");
|
|
79
|
+
var b = document.getElementById("b");
|
|
80
|
+
var out = document.getElementById("out");
|
|
81
|
+
|
|
82
|
+
// Replace this with the tool's real calculation.
|
|
83
|
+
function compute() {
|
|
84
|
+
var x = parseFloat(a.value) || 0;
|
|
85
|
+
var y = parseFloat(b.value) || 0;
|
|
86
|
+
return x + y;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function render() {
|
|
90
|
+
out.textContent = String(compute());
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
a.addEventListener("input", render);
|
|
94
|
+
b.addEventListener("input", render);
|
|
95
|
+
render();
|
|
96
|
+
})();
|
|
97
|
+
</script>
|
|
98
|
+
</body>
|
|
99
|
+
</html>
|
package/src/corpus/usage.md
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
# Using CloudGrid skills and MCP
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
Two surfaces expose the **same** CloudGrid actions — drop, login, claim, init,
|
|
4
|
+
plug, logs, share, feedback, brain:
|
|
5
5
|
|
|
6
|
-
- **Skills** — `SKILL.md` files an agent loads. They trigger from
|
|
7
|
-
(their `description`) or a slash command.
|
|
6
|
+
- **Skills** — `SKILL.md` files an agent loads (this repo). They trigger from
|
|
7
|
+
natural language (their `description`) or a slash command.
|
|
8
8
|
- **MCP server** — the same actions as MCP tools, for clients that speak the Model
|
|
9
|
-
Context Protocol.
|
|
9
|
+
Context Protocol. Published separately as
|
|
10
|
+
[`@cloudgrid-io/mcp`](https://github.com/cloudgrid-io/mcp).
|
|
10
11
|
|
|
11
12
|
Which one you use depends on the client. Pick your client below.
|
|
12
13
|
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: dashboard
|
|
3
|
+
when: The user wants to build a dashboard showing metrics, status, or KPIs with cards and charts.
|
|
4
|
+
summary: Fetch the dashboard template, fill it with the user's metrics and inline charts, deploy it, and return the live share URL.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Workflow: dashboard
|
|
8
|
+
|
|
9
|
+
Detect the intent ("build me a dashboard for X metrics / status") and follow
|
|
10
|
+
this recipe. Do not ask setup questions first; use sensible defaults and build.
|
|
11
|
+
|
|
12
|
+
1. **Fetch the template.** Call `gridctl_fetch("template", "dashboard")` to load
|
|
13
|
+
the self-contained HTML dashboard template.
|
|
14
|
+
2. **(Optional) Fetch the example.** Call `gridctl_fetch("example", "dashboard")`
|
|
15
|
+
to see a filled dashboard as a reference for structure and layout.
|
|
16
|
+
3. **Fill the template.** Replace the placeholders with the user's content:
|
|
17
|
+
- The dashboard title and (optional) status line.
|
|
18
|
+
- One metric card per KPI. Each card has a label, a value, and a trend note.
|
|
19
|
+
- The chart data: edit the inline data arrays that the hand-rolled SVG and
|
|
20
|
+
inline JS read from. Keep every chart inline — do not add an external chart
|
|
21
|
+
library or CDN.
|
|
22
|
+
- Keep it a single self-contained HTML file. Do not add external scripts,
|
|
23
|
+
stylesheets, fonts, or large embedded media.
|
|
24
|
+
4. **Deploy.** Deploy the filled HTML:
|
|
25
|
+
- Hosted MCP edition: call the drop tool with the HTML.
|
|
26
|
+
- Local MCP / CLI edition: write the HTML to a file and run `gridctl plug`.
|
|
27
|
+
A dashboard is an inspiration and deploys synchronously, so you get a URL
|
|
28
|
+
right away.
|
|
29
|
+
5. **Return the live share URL.** Give the user the URL that serves the dashboard.
|
|
30
|
+
|
|
31
|
+
Keep the whole flow tight: fetch, fill, deploy, share.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: landing-page
|
|
3
|
+
when: The user wants to build a landing page, marketing page, or product page for something.
|
|
4
|
+
summary: Fetch the landing-page template, fill it with the user's content, deploy it, and return the live share URL.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Workflow: landing-page
|
|
8
|
+
|
|
9
|
+
Detect the intent ("build me a landing page / marketing page for X") and follow
|
|
10
|
+
this recipe. Do not ask setup questions first; use sensible defaults and build.
|
|
11
|
+
|
|
12
|
+
1. **Fetch the template.** Call `gridctl_fetch("template", "landing-page")` to
|
|
13
|
+
load the self-contained HTML landing-page template.
|
|
14
|
+
2. **(Optional) Fetch the example.** Call `gridctl_fetch("example", "landing-page")`
|
|
15
|
+
to see a filled landing page as a reference for tone and structure.
|
|
16
|
+
3. **Fill the template.** Replace the placeholders with the user's content:
|
|
17
|
+
- The product name, hero headline, and subheadline.
|
|
18
|
+
- The call-to-action label and (optional) target.
|
|
19
|
+
- One block per feature. Each feature has a title and a short description.
|
|
20
|
+
- Keep it a single self-contained HTML file. Do not add external scripts,
|
|
21
|
+
stylesheets, fonts, or large embedded media.
|
|
22
|
+
4. **Deploy.** Deploy the filled HTML:
|
|
23
|
+
- Hosted MCP edition: call the drop tool with the HTML.
|
|
24
|
+
- Local MCP / CLI edition: write the HTML to a file and run `gridctl plug`.
|
|
25
|
+
A landing page is an inspiration and deploys synchronously, so you get a URL
|
|
26
|
+
right away.
|
|
27
|
+
5. **Return the live share URL.** Give the user the URL that serves the page.
|
|
28
|
+
|
|
29
|
+
Keep the whole flow tight: fetch, fill, deploy, share.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: presentation
|
|
3
|
+
when: The user wants to build a presentation, slide deck, or set of slides about a topic.
|
|
4
|
+
summary: Fetch the deck template, fill it with the user's content, deploy it, and return the live share URL.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Workflow: presentation
|
|
8
|
+
|
|
9
|
+
Detect the intent ("build me a presentation / deck / slides about X") and follow
|
|
10
|
+
this recipe. Do not ask setup questions first; use sensible defaults and build.
|
|
11
|
+
|
|
12
|
+
1. **Fetch the template.** Call `gridctl_fetch("template", "deck")` to load the
|
|
13
|
+
self-contained HTML deck template.
|
|
14
|
+
2. **(Optional) Fetch the example.** Call `gridctl_fetch("example", "deck")` to
|
|
15
|
+
see a filled deck as a reference for tone and structure.
|
|
16
|
+
3. **Fill the template.** Replace the placeholders with the user's content:
|
|
17
|
+
- The deck title and subtitle.
|
|
18
|
+
- One slide per key point. Each slide has a heading and body content.
|
|
19
|
+
- Keep it a single self-contained HTML file. Do not add external scripts,
|
|
20
|
+
stylesheets, fonts, or large embedded media.
|
|
21
|
+
4. **Deploy.** Deploy the filled HTML:
|
|
22
|
+
- Hosted MCP edition: call the drop tool with the HTML.
|
|
23
|
+
- Local MCP / CLI edition: write the HTML to a file and run `gridctl plug`.
|
|
24
|
+
An HTML deck is an inspiration and deploys synchronously, so you get a URL
|
|
25
|
+
right away.
|
|
26
|
+
5. **Return the live share URL.** Give the user the URL that serves the deck.
|
|
27
|
+
|
|
28
|
+
Keep the whole flow tight: fetch, fill, deploy, share.
|