naro-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.
Files changed (2) hide show
  1. package/dist/index.js +152 -9
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -108,8 +108,149 @@ function controlPlaneUrl(env = process.env) {
108
108
 
109
109
  // ../../packages/sdk/src/callback-server.ts
110
110
  import { createServer } from "http";
111
- var DONE_HTML = "<html><body><p>\u2705 Logged in. You can close this tab and return to the terminal.</p></body></html>";
112
- var FAIL_HTML = "<html><body><p>Login failed. You can close this tab and return to the terminal.</p></body></html>";
111
+
112
+ // ../../packages/sdk/src/callback-page.ts
113
+ function escapeHtml(value) {
114
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
115
+ }
116
+ var FAVICON = `data:image/svg+xml,${encodeURIComponent(
117
+ '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><rect width="32" height="32" rx="8" fill="#ededed"/><text x="16" y="23" text-anchor="middle" fill="#000" font-family="system-ui,sans-serif" font-size="20" font-weight="700">n</text></svg>'
118
+ )}`;
119
+ var CHECK_ICON = '<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M5 12.5 10 17.5 19 7.5" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg>';
120
+ var CROSS_ICON = '<svg viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M7 7 17 17M17 7 7 17" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg>';
121
+ var STYLES = `
122
+ *{box-sizing:border-box}
123
+ :root{
124
+ --bg:#000;--surface:#0a0a0a;--surface-2:#111;--border:#232323;
125
+ --text:#ededed;--muted:#a1a1a1;--faint:#6f6f6f;
126
+ --sans:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
127
+ --mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
128
+ }
129
+ html{color-scheme:dark;-webkit-font-smoothing:antialiased}
130
+ body{
131
+ margin:0;min-height:100vh;display:grid;place-items:center;padding:24px;
132
+ background:var(--bg);color:var(--text);font-family:var(--sans);
133
+ font-size:14px;line-height:1.5;letter-spacing:-.006em;
134
+ }
135
+ body::before{
136
+ content:"";position:fixed;inset:0;pointer-events:none;
137
+ background:radial-gradient(62% 46% at 50% 0%,var(--glow),transparent 72%);
138
+ }
139
+ .card{
140
+ position:relative;width:100%;max-width:400px;padding:34px 32px 28px;
141
+ background:var(--surface);border:1px solid var(--border);border-radius:14px;
142
+ text-align:center;animation:rise .4s cubic-bezier(.2,.7,.3,1) both;
143
+ }
144
+ .brand{
145
+ display:inline-flex;align-items:center;gap:8px;
146
+ font-size:14px;font-weight:600;letter-spacing:-.02em;color:var(--muted);
147
+ }
148
+ .brand-mark{
149
+ display:inline-grid;width:22px;height:22px;place-items:center;
150
+ background:var(--text);color:#000;border-radius:6px;
151
+ font-size:12px;font-weight:700;line-height:1;
152
+ }
153
+ .glyph{
154
+ width:52px;height:52px;margin:26px auto 20px;display:grid;place-items:center;
155
+ border-radius:50%;color:var(--tone);
156
+ background:var(--tone-soft);border:1px solid var(--tone-edge);
157
+ }
158
+ .glyph svg{width:26px;height:26px}
159
+ .glyph path{stroke-dasharray:32;stroke-dashoffset:32;animation:draw .5s .15s cubic-bezier(.2,.7,.3,1) forwards}
160
+ h1{margin:0 0 8px;font-size:19px;font-weight:600;letter-spacing:-.02em}
161
+ p{margin:0 auto;max-width:32ch;color:var(--muted)}
162
+ .detail{
163
+ margin-top:18px;padding:10px 12px;text-align:left;word-break:break-word;
164
+ background:var(--surface-2);border:1px solid var(--border);border-radius:8px;
165
+ font-family:var(--mono);font-size:12.5px;color:var(--muted);
166
+ }
167
+ .hint{
168
+ display:flex;align-items:center;gap:10px;margin-top:22px;padding:10px 12px;
169
+ background:var(--surface-2);border:1px solid var(--border);border-radius:8px;text-align:left;
170
+ }
171
+ .hint-label{
172
+ flex:none;font-size:10px;font-weight:600;letter-spacing:.09em;color:var(--faint);
173
+ }
174
+ .hint code{font-family:var(--mono);font-size:13px;color:var(--text)}
175
+ .hint code::before{content:"$ ";color:var(--faint)}
176
+ footer{margin-top:20px;font-size:12.5px;color:var(--faint)}
177
+ @keyframes rise{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
178
+ @keyframes draw{to{stroke-dashoffset:0}}
179
+ @media (prefers-reduced-motion:reduce){
180
+ .card{animation:none}
181
+ .glyph path{animation:none;stroke-dashoffset:0}
182
+ }
183
+ `;
184
+ var TONES = {
185
+ success: {
186
+ color: "#4ade80",
187
+ soft: "rgba(74,222,128,.12)",
188
+ edge: "rgba(74,222,128,.3)",
189
+ glow: "rgba(74,222,128,.09)",
190
+ icon: CHECK_ICON
191
+ },
192
+ failure: {
193
+ color: "#ff5c5c",
194
+ soft: "rgba(255,92,92,.12)",
195
+ edge: "rgba(255,92,92,.3)",
196
+ glow: "rgba(255,92,92,.09)",
197
+ icon: CROSS_ICON
198
+ }
199
+ };
200
+ function page(options) {
201
+ const tone = TONES[options.tone];
202
+ const title = escapeHtml(options.title);
203
+ const detail = options.detail ? `<div class="detail">${escapeHtml(options.detail)}</div>` : "";
204
+ return `<!doctype html>
205
+ <html lang="en">
206
+ <head>
207
+ <meta charset="utf-8">
208
+ <meta name="viewport" content="width=device-width,initial-scale=1">
209
+ <title>${title} \xB7 naro</title>
210
+ <link rel="icon" href="${FAVICON}">
211
+ <style>:root{--tone:${tone.color};--tone-soft:${tone.soft};--tone-edge:${tone.edge};--glow:${tone.glow}}${STYLES}</style>
212
+ </head>
213
+ <body>
214
+ <main class="card">
215
+ <span class="brand"><span class="brand-mark">n</span>naro</span>
216
+ <div class="glyph">${tone.icon}</div>
217
+ <h1>${title}</h1>
218
+ <p>${escapeHtml(options.message)}</p>
219
+ ${detail}
220
+ <div class="hint">
221
+ <span class="hint-label">${escapeHtml(options.hint.label)}</span>
222
+ <code>${escapeHtml(options.hint.command)}</code>
223
+ </div>
224
+ <footer>You can close this tab.</footer>
225
+ </main>
226
+ </body>
227
+ </html>`;
228
+ }
229
+ function successPage() {
230
+ return page({
231
+ tone: "success",
232
+ title: "You're signed in",
233
+ message: "The CLI saved your session. Head back to the terminal to keep going.",
234
+ hint: { label: "NEXT", command: "naro deploy" }
235
+ });
236
+ }
237
+ function failurePage(reason) {
238
+ return page({
239
+ tone: "failure",
240
+ title: "Sign-in failed",
241
+ message: "Nothing was saved. Return to the terminal and try again.",
242
+ detail: reason,
243
+ hint: { label: "RETRY", command: "naro login" }
244
+ });
245
+ }
246
+
247
+ // ../../packages/sdk/src/callback-server.ts
248
+ function sendPage(res, status, html) {
249
+ res.statusCode = status;
250
+ res.setHeader("content-type", "text/html; charset=utf-8");
251
+ res.setHeader("cache-control", "no-store");
252
+ res.end(html);
253
+ }
113
254
  async function startCallbackServer() {
114
255
  let resolveCode;
115
256
  let rejectCode;
@@ -127,18 +268,20 @@ async function startCallbackServer() {
127
268
  const error51 = url2.searchParams.get("error");
128
269
  const code = url2.searchParams.get("code");
129
270
  if (error51) {
130
- res.setHeader("content-type", "text/html");
131
- res.end(FAIL_HTML);
271
+ const description = url2.searchParams.get("error_description");
272
+ sendPage(res, 200, failurePage(description ?? error51));
132
273
  rejectCode(new Error(`GitHub authorization failed: ${error51}`));
133
274
  return;
134
275
  }
135
276
  if (!code) {
136
- res.statusCode = 400;
137
- res.end("Missing code");
277
+ sendPage(
278
+ res,
279
+ 400,
280
+ failurePage("The callback carried no authorization code.")
281
+ );
138
282
  return;
139
283
  }
140
- res.setHeader("content-type", "text/html");
141
- res.end(DONE_HTML);
284
+ sendPage(res, 200, successPage());
142
285
  resolveCode(code);
143
286
  });
144
287
  await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve));
@@ -16059,7 +16202,7 @@ function toolErrorJson(error51) {
16059
16202
  // src/server.ts
16060
16203
  function createServer2(deps) {
16061
16204
  const server = new Server(
16062
- { name: "naro", version: "0.6.0" },
16205
+ { name: "naro", version: "0.6.1" },
16063
16206
  { capabilities: { tools: {} } }
16064
16207
  );
16065
16208
  server.setRequestHandler(ListToolsRequestSchema, () => ({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "naro-mcp",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "naro-mcp": "./dist/index.js"
@@ -15,15 +15,15 @@
15
15
  "dependencies": {
16
16
  "@modelcontextprotocol/sdk": "^1.0.0",
17
17
  "@supabase/supabase-js": "2.112.3",
18
- "naro-cli": "0.6.0"
18
+ "naro-cli": "0.6.1"
19
19
  },
20
20
  "devDependencies": {
21
21
  "tsup": "8.5.0",
22
22
  "tsx": "4.23.12",
23
23
  "typescript": "7.0.2",
24
24
  "vitest": "3.2.7",
25
- "@next-deploy/sdk": "0.1.0",
26
- "@next-deploy/config": "0.1.0"
25
+ "@next-deploy/config": "0.1.0",
26
+ "@next-deploy/sdk": "0.1.0"
27
27
  },
28
28
  "scripts": {
29
29
  "build": "tsup",