@cloudgrid-io/mcp 0.6.0 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudgrid-io/mcp",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "MCP server for CloudGrid. Three editions: a local stdio server (full toolset), a hosted web server (light, CLI-free toolset), and a public docs server (search_cloudgrid_documentation) over MCP Streamable HTTP.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,121 @@
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>Service Health Dashboard</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>Service Health Dashboard</h1>
45
+ <div class="status">All systems operational — updated a moment ago</div>
46
+ </header>
47
+
48
+ <section class="grid">
49
+ <div class="card">
50
+ <div class="label">Requests / min</div>
51
+ <div class="value">18.4k</div>
52
+ <div class="trend">+6.2% vs last hour</div>
53
+ </div>
54
+ <div class="card">
55
+ <div class="label">p95 latency</div>
56
+ <div class="value">142ms</div>
57
+ <div class="trend">-11ms vs last hour</div>
58
+ </div>
59
+ <div class="card">
60
+ <div class="label">Error rate</div>
61
+ <div class="value">0.08%</div>
62
+ <div class="trend">within target</div>
63
+ </div>
64
+ <div class="card">
65
+ <div class="label">Uptime (30d)</div>
66
+ <div class="value">99.98%</div>
67
+ <div class="trend">no incidents</div>
68
+ </div>
69
+ </section>
70
+
71
+ <section class="charts">
72
+ <div class="chart-card">
73
+ <h2>Requests by region</h2>
74
+ <svg id="bar" viewBox="0 0 320 160" role="img" aria-label="Bar chart of requests by region"></svg>
75
+ </div>
76
+ <div class="chart-card">
77
+ <h2>Latency over the last 12 hours</h2>
78
+ <svg id="line" viewBox="0 0 320 160" role="img" aria-label="Line chart of latency over time"></svg>
79
+ </div>
80
+ </section>
81
+
82
+ <script>
83
+ var barData = [42, 58, 31, 49, 66, 38];
84
+ var lineData = [160, 154, 148, 151, 139, 142, 137, 144, 140, 135, 142, 138];
85
+
86
+ var NS = "http://www.w3.org/2000/svg";
87
+ function el(name, attrs) {
88
+ var n = document.createElementNS(NS, name);
89
+ for (var k in attrs) n.setAttribute(k, attrs[k]);
90
+ return n;
91
+ }
92
+
93
+ (function drawBars() {
94
+ var svg = document.getElementById("bar");
95
+ var W = 320, H = 160, pad = 20;
96
+ var max = Math.max.apply(null, barData.concat([1]));
97
+ var bw = (W - pad * 2) / barData.length;
98
+ barData.forEach(function (v, i) {
99
+ var h = (v / max) * (H - pad * 2);
100
+ svg.appendChild(el("rect", {
101
+ x: pad + i * bw + bw * 0.15, y: H - pad - h,
102
+ width: bw * 0.7, height: h, rx: 3, fill: "var(--accent)"
103
+ }));
104
+ });
105
+ svg.appendChild(el("line", { x1: pad, y1: H - pad, x2: W - pad, y2: H - pad, stroke: "var(--border)" }));
106
+ })();
107
+
108
+ (function drawLine() {
109
+ var svg = document.getElementById("line");
110
+ var W = 320, H = 160, pad = 20;
111
+ var max = Math.max.apply(null, lineData.concat([1]));
112
+ var step = (W - pad * 2) / Math.max(1, lineData.length - 1);
113
+ var pts = lineData.map(function (v, i) {
114
+ return (pad + i * step) + "," + (H - pad - (v / max) * (H - pad * 2));
115
+ }).join(" ");
116
+ svg.appendChild(el("polyline", { points: pts, fill: "none", stroke: "var(--good)", "stroke-width": 2.5 }));
117
+ svg.appendChild(el("line", { x1: pad, y1: H - pad, x2: W - pad, y2: H - pad, stroke: "var(--border)" }));
118
+ })();
119
+ </script>
120
+ </body>
121
+ </html>
@@ -0,0 +1,98 @@
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>Cadence</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">Cadence</span>
63
+ <a class="cta" href="#start">Start free</a>
64
+ </nav>
65
+
66
+ <header class="hero">
67
+ <h1>Ship your week in a single view</h1>
68
+ <p>Cadence turns scattered tasks, notes, and deadlines into one calm weekly plan your whole team can trust.</p>
69
+ <a class="cta" href="#start">Start free</a>
70
+ </header>
71
+
72
+ <section class="features">
73
+ <div class="feature">
74
+ <h3>One weekly board</h3>
75
+ <p>Every task, meeting, and milestone lands on a single board that resets each Monday so nothing slips.</p>
76
+ </div>
77
+ <div class="feature">
78
+ <h3>Automatic rollover</h3>
79
+ <p>Unfinished work carries forward with its context intact, so you never rebuild a plan from scratch.</p>
80
+ </div>
81
+ <div class="feature">
82
+ <h3>Quiet by design</h3>
83
+ <p>Notifications batch into two calm digests a day, keeping focus time genuinely free of interruptions.</p>
84
+ </div>
85
+ <div class="feature">
86
+ <h3>Shared without noise</h3>
87
+ <p>Teammates see the same board and status without a stream of pings, comments, or status meetings.</p>
88
+ </div>
89
+ </section>
90
+
91
+ <section class="closing" id="start">
92
+ <h2>Plan less, finish more this week</h2>
93
+ <a class="cta" href="#start">Start free</a>
94
+ </section>
95
+
96
+ <footer>Cadence — a sample landing page built on CloudGrid.</footer>
97
+ </body>
98
+ </html>
@@ -0,0 +1,112 @@
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>Q2 Support Operations Review</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>Q2 Support Operations Review</h1>
57
+ <div class="subtitle">Ticket volume, response times, and satisfaction</div>
58
+ <div class="meta">Prepared by the Support team, quarter ending June 30</div>
59
+ </header>
60
+
61
+ <div class="summary">
62
+ Support handled 12% more tickets than Q1 while cutting median first-response
63
+ time by nearly a third. Satisfaction held steady at 94%. The main risk into
64
+ Q3 is billing-related volume, which grew faster than headcount.
65
+ </div>
66
+
67
+ <section>
68
+ <h2>Volume and staffing</h2>
69
+ <p>
70
+ The team resolved 8,420 tickets across the quarter, up from 7,510 in Q1.
71
+ Two agents joined in May, bringing the desk to nine. Even so, the
72
+ tickets-per-agent load rose slightly, absorbed mostly by faster tooling
73
+ rather than longer hours.
74
+ </p>
75
+ </section>
76
+
77
+ <section>
78
+ <h2>Response and resolution</h2>
79
+ <p>
80
+ Median first-response time fell from 4.6 hours to 3.1 hours after the
81
+ canned-reply library was rebuilt. Full resolution time was flat, since the
82
+ slowest tickets are billing disputes that depend on the finance team.
83
+ </p>
84
+ </section>
85
+
86
+ <section>
87
+ <h2>Outlook</h2>
88
+ <p>
89
+ Billing questions are the fastest-growing category and the least
90
+ self-serviceable. The recommendation for Q3 is a dedicated billing macro
91
+ set plus a short help-center article, before adding more headcount.
92
+ </p>
93
+ </section>
94
+
95
+ <section>
96
+ <h2>Key metrics</h2>
97
+ <table>
98
+ <thead>
99
+ <tr><th>Metric</th><th>Q1</th><th>Q2</th></tr>
100
+ </thead>
101
+ <tbody>
102
+ <tr><td>Tickets resolved</td><td>7,510</td><td>8,420</td></tr>
103
+ <tr><td>Median first response</td><td>4.6h</td><td>3.1h</td></tr>
104
+ <tr><td>Satisfaction</td><td>93%</td><td>94%</td></tr>
105
+ </tbody>
106
+ </table>
107
+ </section>
108
+
109
+ <footer>A sample report built on CloudGrid. Figures are illustrative.</footer>
110
+ </div>
111
+ </body>
112
+ </html>
@@ -0,0 +1,125 @@
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>Tip Splitter</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 {
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 { outline: none; border-color: var(--accent); }
40
+ .row { display: flex; gap: 0.75rem; }
41
+ .row > * { flex: 1; }
42
+ .tips { display: flex; gap: 0.5rem; margin-top: 0.35rem; }
43
+ .tips button {
44
+ flex: 1; font: inherit; cursor: pointer;
45
+ background: var(--bg); color: var(--fg);
46
+ border: 1px solid var(--border); border-radius: 10px; padding: 0.55rem 0;
47
+ }
48
+ .tips button.active { border-color: var(--accent); color: var(--accent); }
49
+ .result {
50
+ margin-top: 1.5rem; padding: 1.1rem 1.25rem;
51
+ background: var(--bg); border: 1px solid var(--border); border-radius: 12px;
52
+ display: grid; gap: 0.6rem;
53
+ }
54
+ .result .line { display: flex; align-items: baseline; justify-content: space-between; }
55
+ .result .label { color: var(--muted); font-size: 0.85rem; }
56
+ .result .value { font-size: 1.15rem; font-weight: 600; font-variant-numeric: tabular-nums; }
57
+ .result .line.total .value { font-size: 1.7rem; color: var(--accent); }
58
+ </style>
59
+ </head>
60
+ <body>
61
+ <main class="app">
62
+ <h1>Tip Splitter</h1>
63
+ <p class="subtitle">Split a bill and tip evenly across the table.</p>
64
+
65
+ <label for="bill">Bill amount</label>
66
+ <input id="bill" type="number" min="0" step="0.01" value="86.40" inputmode="decimal" />
67
+
68
+ <label>Tip percentage</label>
69
+ <div class="tips" id="tips">
70
+ <button data-tip="10">10%</button>
71
+ <button data-tip="15" class="active">15%</button>
72
+ <button data-tip="18">18%</button>
73
+ <button data-tip="20">20%</button>
74
+ </div>
75
+
76
+ <label for="people">Number of people</label>
77
+ <input id="people" type="number" min="1" step="1" value="4" inputmode="numeric" />
78
+
79
+ <div class="result">
80
+ <div class="line">
81
+ <span class="label">Tip amount</span>
82
+ <span class="value" id="tipOut">0.00</span>
83
+ </div>
84
+ <div class="line total">
85
+ <span class="label">Each person pays</span>
86
+ <span class="value" id="perOut">0.00</span>
87
+ </div>
88
+ </div>
89
+ </main>
90
+
91
+ <script>
92
+ (function () {
93
+ var bill = document.getElementById("bill");
94
+ var people = document.getElementById("people");
95
+ var tips = document.getElementById("tips");
96
+ var tipOut = document.getElementById("tipOut");
97
+ var perOut = document.getElementById("perOut");
98
+ var tipPct = 15;
99
+
100
+ function render() {
101
+ var amount = parseFloat(bill.value) || 0;
102
+ var n = Math.max(1, parseInt(people.value, 10) || 1);
103
+ var tip = amount * (tipPct / 100);
104
+ var perPerson = (amount + tip) / n;
105
+ tipOut.textContent = tip.toFixed(2);
106
+ perOut.textContent = perPerson.toFixed(2);
107
+ }
108
+
109
+ tips.addEventListener("click", function (e) {
110
+ var btn = e.target.closest("button");
111
+ if (!btn) return;
112
+ tipPct = parseFloat(btn.getAttribute("data-tip"));
113
+ Array.prototype.forEach.call(tips.children, function (b) {
114
+ b.classList.toggle("active", b === btn);
115
+ });
116
+ render();
117
+ });
118
+
119
+ bill.addEventListener("input", render);
120
+ people.addEventListener("input", render);
121
+ render();
122
+ })();
123
+ </script>
124
+ </body>
125
+ </html>
@@ -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,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>
@@ -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,31 @@
1
+ ---
2
+ name: report
3
+ when: The user wants to build a report, one-pager, brief, or write-up with sections and data.
4
+ summary: Fetch the report template, fill it with the user's content, deploy it, and return the live share URL.
5
+ ---
6
+
7
+ # Workflow: report
8
+
9
+ Detect the intent ("build me a report / one-pager / brief 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", "report")` to load
13
+ the self-contained, print-friendly HTML report template.
14
+ 2. **(Optional) Fetch the example.** Call `gridctl_fetch("example", "report")`
15
+ to see a filled report as a reference for tone and structure.
16
+ 3. **Fill the template.** Replace the placeholders with the user's content:
17
+ - The report title, subtitle, and date line.
18
+ - A short summary paragraph.
19
+ - One block per section. Each section has a heading and body content.
20
+ - The data table area: fill the rows with the user's figures, or remove it
21
+ if there is no tabular data.
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 report is an inspiration and deploys synchronously, so you get a URL right
28
+ away.
29
+ 5. **Return the live share URL.** Give the user the URL that serves the report.
30
+
31
+ Keep the whole flow tight: fetch, fill, deploy, share.
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: web-app
3
+ when: The user wants to build a small interactive web app, tool, calculator, or mini single-page application.
4
+ summary: Fetch the web-app template, adapt its markup and inline JS to the user's tool, deploy it, and return the live share URL.
5
+ ---
6
+
7
+ # Workflow: web-app
8
+
9
+ Detect the intent ("build me a web app / tool / calculator that does X") and
10
+ follow this recipe. Do not ask setup questions first; use sensible defaults and
11
+ build.
12
+
13
+ 1. **Fetch the template.** Call `gridctl_fetch("template", "web-app")` to load
14
+ the self-contained interactive HTML app template.
15
+ 2. **(Optional) Fetch the example.** Call `gridctl_fetch("example", "web-app")`
16
+ to see a real working tool as a reference for structure and inline logic.
17
+ 3. **Adapt the template.** Rework the markup and inline JavaScript into the tool
18
+ the user asked for:
19
+ - Set the app title and heading.
20
+ - Build the input controls and output area for the tool's job.
21
+ - Put all behavior in the inline `<script>`; keep state in memory.
22
+ - Keep it a single self-contained HTML file. Do not add external scripts,
23
+ stylesheets, fonts, or CDNs — inline everything.
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 web app 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 app.
30
+
31
+ Keep the whole flow tight: fetch, adapt, deploy, share.