doc2mcp 0.1.19 → 0.1.20

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 +91 -58
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/index.ts
4
4
  import { Command } from "commander";
5
- import pc8 from "picocolors";
5
+ import pc9 from "picocolors";
6
6
 
7
7
  // src/commands/account.ts
8
8
  import pc from "picocolors";
@@ -77,7 +77,7 @@ async function runWhoami() {
77
77
  import { createInterface } from "readline/promises";
78
78
  import { stdin as input, stdout as output } from "process";
79
79
  import ora2 from "ora";
80
- import pc7 from "picocolors";
80
+ import pc8 from "picocolors";
81
81
 
82
82
  // src/api.ts
83
83
  import pc2 from "picocolors";
@@ -139,8 +139,40 @@ function printError(error) {
139
139
  `);
140
140
  }
141
141
 
142
- // src/markdown.ts
142
+ // src/banner.ts
143
143
  import pc3 from "picocolors";
144
+ var LOGO = [
145
+ "\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2557 ",
146
+ "\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557",
147
+ "\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2554\u2588\u2588\u2588\u2588\u2554\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D",
148
+ "\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2554\u255D\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2554\u2550\u2550\u2550\u255D ",
149
+ "\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 \u255A\u2550\u255D \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2551 ",
150
+ "\u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D "
151
+ ];
152
+ var SHADES = [pc3.cyan, pc3.cyan, pc3.blue, pc3.blue, pc3.cyan, pc3.cyan];
153
+ var POWERED_BY = "meerutcodehub team";
154
+ function divider(width = 58) {
155
+ return pc3.dim("\u2500".repeat(width));
156
+ }
157
+ function printBanner() {
158
+ process.stdout.write("\n");
159
+ LOGO.forEach((line, index) => {
160
+ const color = SHADES[index] ?? pc3.cyan;
161
+ process.stdout.write(` ${pc3.bold(color(line))}
162
+ `);
163
+ });
164
+ process.stdout.write(`
165
+ ${divider()}
166
+ `);
167
+ process.stdout.write(
168
+ ` ${pc3.dim("powered by")} ${pc3.bold(pc3.cyan(POWERED_BY))}
169
+
170
+ `
171
+ );
172
+ }
173
+
174
+ // src/markdown.ts
175
+ import pc4 from "picocolors";
144
176
  var LINK = /\[([^\]]+)\]\(([^)]+)\)/g;
145
177
  var INLINE_CODE = /`([^`]+)`/g;
146
178
  var BOLD = /\*\*([^*]+)\*\*/g;
@@ -153,13 +185,13 @@ var BLOCKQUOTE = /^>\s?(.*)$/;
153
185
  function renderInline(text) {
154
186
  let out = text.replace(
155
187
  LINK,
156
- (_m, label, url) => `${pc3.cyan(pc3.underline(label))} ${pc3.dim(`(${url})`)}`
188
+ (_m, label, url) => `${pc4.cyan(pc4.underline(label))} ${pc4.dim(`(${url})`)}`
157
189
  );
158
- out = out.replace(INLINE_CODE, (_m, code) => pc3.yellow(code));
159
- out = out.replace(BOLD, (_m, bold) => pc3.bold(bold));
190
+ out = out.replace(INLINE_CODE, (_m, code) => pc4.yellow(code));
191
+ out = out.replace(BOLD, (_m, bold) => pc4.bold(bold));
160
192
  out = out.replace(
161
193
  ITALIC,
162
- (_m, prefix, italic) => `${prefix}${pc3.italic(italic)}`
194
+ (_m, prefix, italic) => `${prefix}${pc4.italic(italic)}`
163
195
  );
164
196
  return out;
165
197
  }
@@ -171,39 +203,39 @@ function renderMarkdown(markdown) {
171
203
  const fence = line.match(FENCE);
172
204
  if (fence) {
173
205
  if (inCode) {
174
- out.push(pc3.dim(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500"));
206
+ out.push(pc4.dim(" \u2514\u2500\u2500\u2500\u2500\u2500\u2500"));
175
207
  inCode = false;
176
208
  } else {
177
209
  const lang = fence[1] || "code";
178
- out.push(pc3.dim(` \u250C\u2500\u2500\u2500\u2500\u2500\u2500 ${lang}`));
210
+ out.push(pc4.dim(` \u250C\u2500\u2500\u2500\u2500\u2500\u2500 ${lang}`));
179
211
  inCode = true;
180
212
  }
181
213
  continue;
182
214
  }
183
215
  if (inCode) {
184
- out.push(` ${pc3.green(line)}`);
216
+ out.push(` ${pc4.green(line)}`);
185
217
  continue;
186
218
  }
187
219
  const heading = line.match(HEADING);
188
220
  if (heading) {
189
- out.push(pc3.bold(pc3.cyan(renderInline(heading[2] ?? ""))));
221
+ out.push(pc4.bold(pc4.cyan(renderInline(heading[2] ?? ""))));
190
222
  continue;
191
223
  }
192
224
  const ordered = line.match(ORDERED);
193
225
  if (ordered) {
194
226
  out.push(
195
- `${ordered[1] ?? ""}${pc3.cyan(`${ordered[2] ?? ""}.`)} ${renderInline(ordered[3] ?? "")}`
227
+ `${ordered[1] ?? ""}${pc4.cyan(`${ordered[2] ?? ""}.`)} ${renderInline(ordered[3] ?? "")}`
196
228
  );
197
229
  continue;
198
230
  }
199
231
  const bullet = line.match(BULLET);
200
232
  if (bullet) {
201
- out.push(`${bullet[1] ?? ""}${pc3.cyan("\u2022")} ${renderInline(bullet[2] ?? "")}`);
233
+ out.push(`${bullet[1] ?? ""}${pc4.cyan("\u2022")} ${renderInline(bullet[2] ?? "")}`);
202
234
  continue;
203
235
  }
204
236
  const quote = line.match(BLOCKQUOTE);
205
237
  if (quote) {
206
- out.push(`${pc3.dim("\u2502")} ${pc3.dim(renderInline(quote[1] ?? ""))}`);
238
+ out.push(`${pc4.dim("\u2502")} ${pc4.dim(renderInline(quote[1] ?? ""))}`);
207
239
  continue;
208
240
  }
209
241
  out.push(renderInline(line));
@@ -212,12 +244,12 @@ function renderMarkdown(markdown) {
212
244
  }
213
245
 
214
246
  // src/commands/convert.ts
215
- import pc6 from "picocolors";
247
+ import pc7 from "picocolors";
216
248
 
217
249
  // src/commands/login.ts
218
250
  import open from "open";
219
251
  import ora from "ora";
220
- import pc4 from "picocolors";
252
+ import pc5 from "picocolors";
221
253
  function sleep(ms) {
222
254
  return new Promise((resolve) => {
223
255
  setTimeout(resolve, ms);
@@ -235,13 +267,13 @@ async function runLogin() {
235
267
  spinner.stop();
236
268
  process.stdout.write(
237
269
  `
238
- ${pc4.cyan("Open this link to authorize:")}
239
- ${pc4.bold(start.verifyUrl)}
270
+ ${pc5.cyan("Open this link to authorize:")}
271
+ ${pc5.bold(start.verifyUrl)}
240
272
 
241
273
  `
242
274
  );
243
275
  process.stdout.write(
244
- `${pc4.dim("Code:")} ${pc4.bold(start.userCode)} ${pc4.dim("(also shown in browser)")}
276
+ `${pc5.dim("Code:")} ${pc5.bold(start.userCode)} ${pc5.dim("(also shown in browser)")}
245
277
 
246
278
  `
247
279
  );
@@ -249,7 +281,7 @@ ${pc4.bold(start.verifyUrl)}
249
281
  await open(start.verifyUrl);
250
282
  } catch {
251
283
  process.stdout.write(
252
- `${pc4.yellow("Could not auto-open browser. Open the link manually.")}
284
+ `${pc5.yellow("Could not auto-open browser. Open the link manually.")}
253
285
 
254
286
  `
255
287
  );
@@ -275,7 +307,7 @@ ${pc4.bold(start.verifyUrl)}
275
307
  user: poll.user
276
308
  });
277
309
  process.stdout.write(
278
- `${pc4.green("Logged in as")} ${poll.user.email}
310
+ `${pc5.green("Logged in as")} ${poll.user.email}
279
311
  `
280
312
  );
281
313
  return;
@@ -310,7 +342,7 @@ async function ensureLoggedIn() {
310
342
 
311
343
  // src/commands/install.ts
312
344
  import { confirm, multiselect } from "@clack/prompts";
313
- import pc5 from "picocolors";
345
+ import pc6 from "picocolors";
314
346
 
315
347
  // src/installers/detect.ts
316
348
  import { access } from "fs/promises";
@@ -497,8 +529,8 @@ async function promptInstall(install) {
497
529
  }
498
530
  await installToClient(client.id, client.configPath, install);
499
531
  process.stdout.write(
500
- `${pc5.green("Installed")} ${client.label}
501
- ${pc5.dim(client.configPath)}
532
+ `${pc6.green("Installed")} ${client.label}
533
+ ${pc6.dim(client.configPath)}
502
534
  `
503
535
  );
504
536
  }
@@ -508,7 +540,7 @@ async function runInstallCommand(projectId) {
508
540
  await ensureLoggedIn();
509
541
  const detail = await apiFetch(`/api/cli/projects/${projectId}`);
510
542
  if (!detail.install) {
511
- process.stderr.write(`${pc5.red("Project is not ready or missing install bundle.")}
543
+ process.stderr.write(`${pc6.red("Project is not ready or missing install bundle.")}
512
544
  `);
513
545
  process.exitCode = 1;
514
546
  return;
@@ -529,18 +561,18 @@ function sleep2(ms) {
529
561
  function printStatus(detail) {
530
562
  const { project } = detail;
531
563
  process.stdout.write(
532
- `\r${pc6.cyan("Status:")} ${project.status.padEnd(12)} ${pc6.dim(project.name)}`
564
+ `\r${pc7.cyan("Status:")} ${project.status.padEnd(12)} ${pc7.dim(project.name)}`
533
565
  );
534
566
  }
535
567
  async function convertUrlToProject(sourceUrl, options = { offerInstall: true }) {
536
568
  await ensureLoggedIn();
537
- process.stdout.write(`${pc6.bold("Converting")} ${sourceUrl}
569
+ process.stdout.write(`${pc7.bold("Converting")} ${sourceUrl}
538
570
  `);
539
571
  const created = await apiFetch("/api/cli/convert", {
540
572
  method: "POST",
541
573
  body: JSON.stringify({ sourceUrl })
542
574
  });
543
- process.stdout.write(`${pc6.dim("Project:")} ${created.id}
575
+ process.stdout.write(`${pc7.dim("Project:")} ${created.id}
544
576
  `);
545
577
  let delayMs = 2e3;
546
578
  const terminal = /* @__PURE__ */ new Set(["ready", "error"]);
@@ -562,29 +594,29 @@ async function convertUrlToProject(sourceUrl, options = { offerInstall: true })
562
594
  if (finalDetail.project.status === "error") {
563
595
  const lastLog = finalDetail.project.logs.at(-1);
564
596
  process.stderr.write(
565
- `${pc6.red("Conversion failed.")}${lastLog ? ` ${lastLog.message}` : ""}
597
+ `${pc7.red("Conversion failed.")}${lastLog ? ` ${lastLog.message}` : ""}
566
598
  `
567
599
  );
568
600
  process.exitCode = 1;
569
601
  return null;
570
602
  }
571
603
  if (!finalDetail.mcp || !finalDetail.install) {
572
- process.stderr.write(`${pc6.red("MCP ready but missing install bundle.")}
604
+ process.stderr.write(`${pc7.red("MCP ready but missing install bundle.")}
573
605
  `);
574
606
  process.exitCode = 1;
575
607
  return null;
576
608
  }
577
609
  process.stdout.write(`
578
- ${pc6.green("MCP ready")}
610
+ ${pc7.green("MCP ready")}
579
611
  `);
580
- process.stdout.write(`${pc6.bold("Server:")} ${finalDetail.mcp.serverName}
612
+ process.stdout.write(`${pc7.bold("Server:")} ${finalDetail.mcp.serverName}
581
613
  `);
582
- process.stdout.write(`${pc6.bold("URL:")} ${finalDetail.mcp.url}
614
+ process.stdout.write(`${pc7.bold("URL:")} ${finalDetail.mcp.url}
583
615
  `);
584
- process.stdout.write(`${pc6.bold("Token:")} ${finalDetail.mcp.token}
616
+ process.stdout.write(`${pc7.bold("Token:")} ${finalDetail.mcp.token}
585
617
  `);
586
618
  process.stdout.write(
587
- `${pc6.dim("Also listed in the doc2mcp marketplace when ready.")}
619
+ `${pc7.dim("Also listed in the doc2mcp marketplace when ready.")}
588
620
  `
589
621
  );
590
622
  if (options.offerInstall) {
@@ -605,16 +637,16 @@ async function runList() {
605
637
  await ensureLoggedIn();
606
638
  const data = await apiFetch("/api/cli/projects");
607
639
  if (data.projects.length === 0) {
608
- process.stdout.write(`${pc6.dim("No projects yet.")}
640
+ process.stdout.write(`${pc7.dim("No projects yet.")}
609
641
  `);
610
642
  return;
611
643
  }
612
644
  for (const project of data.projects) {
613
645
  process.stdout.write(
614
- `${pc6.bold(project.name)} ${pc6.dim(`[${project.status}]`)} ${project.source}
646
+ `${pc7.bold(project.name)} ${pc7.dim(`[${project.status}]`)} ${project.source}
615
647
  `
616
648
  );
617
- process.stdout.write(` ${pc6.dim(project.id)} ${project.sourceUrl ?? ""}
649
+ process.stdout.write(` ${pc7.dim(project.id)} ${project.sourceUrl ?? ""}
618
650
  `);
619
651
  }
620
652
  } catch (error) {
@@ -656,21 +688,21 @@ async function pickExistingProject() {
656
688
  const ready = await listReadyProjects();
657
689
  if (ready.length === 0) {
658
690
  process.stdout.write(
659
- `${pc7.yellow("No ready MCP projects yet.")} Paste a docs URL to create one.
691
+ `${pc8.yellow("No ready MCP projects yet.")} Paste a docs URL to create one.
660
692
  `
661
693
  );
662
694
  return null;
663
695
  }
664
- process.stdout.write(`${pc7.dim("Ready MCPs")}
696
+ process.stdout.write(`${pc8.dim("Ready MCPs")}
665
697
  `);
666
698
  ready.forEach((p, index) => {
667
699
  process.stdout.write(
668
- ` ${pc7.cyan(String(index + 1).padStart(2, " "))}. ${pc7.bold(p.name)} ${pc7.dim(p.sourceUrl ?? p.id)}
700
+ ` ${pc8.cyan(String(index + 1).padStart(2, " "))}. ${pc8.bold(p.name)} ${pc8.dim(p.sourceUrl ?? p.id)}
669
701
  `
670
702
  );
671
703
  });
672
704
  const choice = await readLine(
673
- `${pc7.bold(">")} choose number, paste URL, or paste project id: `
705
+ `${pc8.bold(">")} choose number, paste URL, or paste project id: `
674
706
  );
675
707
  if (!choice) {
676
708
  return null;
@@ -695,11 +727,11 @@ async function resolveProject(target) {
695
727
  return await apiFetch(`/api/cli/projects/${target}`);
696
728
  }
697
729
  process.stdout.write(
698
- `${pc7.dim("Paste a docs URL to create a new MCP, a project id, or press Enter to pick an existing one.")}
730
+ `${pc8.dim("Paste a docs URL to create a new MCP, a project id, or press Enter to pick an existing one.")}
699
731
 
700
732
  `
701
733
  );
702
- const first = await readLine(`${pc7.cyan("\u203A")} docs url or project id: `);
734
+ const first = await readLine(`${pc8.cyan("\u203A")} docs url or project id: `);
703
735
  if (!first) {
704
736
  return await pickExistingProject();
705
737
  }
@@ -739,19 +771,19 @@ async function askDocs(mcp, question) {
739
771
  }
740
772
  function renderAnswer(answer) {
741
773
  process.stdout.write(`
742
- ${pc7.green("\u25CF")} ${pc7.bold("doc2mcp")}
774
+ ${pc8.green("\u25CF")} ${pc8.bold("doc2mcp")}
743
775
 
744
776
  `);
745
777
  process.stdout.write(`${renderMarkdown(answer.answer.trim())}
746
778
  `);
747
779
  if (answer.sources && answer.sources.length > 0) {
748
780
  process.stdout.write(`
749
- ${pc7.dim("Sources")}
781
+ ${pc8.dim("Sources")}
750
782
  `);
751
783
  for (const source of answer.sources.slice(0, 6)) {
752
784
  process.stdout.write(
753
- ` ${pc7.cyan("\u2022")} ${source.title}
754
- ${pc7.dim(source.url)}
785
+ ` ${pc8.cyan("\u2022")} ${source.title}
786
+ ${pc8.dim(source.url)}
755
787
  `
756
788
  );
757
789
  }
@@ -778,7 +810,7 @@ async function runChat(target, options = {}) {
778
810
  }
779
811
  if (!detail.mcp) {
780
812
  process.stderr.write(
781
- `${pc7.red("That project is not ready yet.")} Check: ${pc7.bold("doc2mcp list")}
813
+ `${pc8.red("That project is not ready yet.")} Check: ${pc8.bold("doc2mcp list")}
782
814
  `
783
815
  );
784
816
  process.exitCode = 1;
@@ -789,23 +821,24 @@ async function runChat(target, options = {}) {
789
821
  await answerOnce(mcp, options.message);
790
822
  return;
791
823
  }
824
+ printBanner();
792
825
  const title = ` doc2mcp chat \xB7 ${detail.project.name} `;
793
826
  const bar = "\u2500".repeat(title.length);
794
827
  process.stdout.write(`
795
- ${pc7.cyan(`\u256D${bar}\u256E`)}
828
+ ${pc8.cyan(`\u256D${bar}\u256E`)}
796
829
  `);
797
- process.stdout.write(`${pc7.cyan("\u2502")}${pc7.bold(title)}${pc7.cyan("\u2502")}
830
+ process.stdout.write(`${pc8.cyan("\u2502")}${pc8.bold(title)}${pc8.cyan("\u2502")}
798
831
  `);
799
- process.stdout.write(`${pc7.cyan(`\u2570${bar}\u256F`)}
832
+ process.stdout.write(`${pc8.cyan(`\u2570${bar}\u256F`)}
800
833
  `);
801
834
  process.stdout.write(
802
- `${pc7.dim("Ask anything about these docs. Type /exit to quit.")}
835
+ `${pc8.dim("Ask anything about these docs. Type /exit to quit.")}
803
836
 
804
837
  `
805
838
  );
806
839
  let active = true;
807
840
  while (active) {
808
- const question = await readLine(`${pc7.cyan("\u203A")} `);
841
+ const question = await readLine(`${pc8.cyan("\u203A")} `);
809
842
  if (question === null) {
810
843
  active = false;
811
844
  break;
@@ -822,7 +855,7 @@ ${pc7.cyan(`\u256D${bar}\u256E`)}
822
855
  }
823
856
  process.stdout.write(
824
857
  `
825
- ${pc7.dim("Bye \u2014 your docs MCP stays live for your editor.")}
858
+ ${pc8.dim("Bye \u2014 your docs MCP stays live for your editor.")}
826
859
  `
827
860
  );
828
861
  } catch (error) {
@@ -833,7 +866,7 @@ ${pc7.dim("Bye \u2014 your docs MCP stays live for your editor.")}
833
866
 
834
867
  // src/index.ts
835
868
  var program = new Command();
836
- program.name("doc2mcp").description("Generate documentation MCP servers from your terminal").version("0.1.19", "-v, --version", "Print the installed CLI version");
869
+ program.name("doc2mcp").description("Generate documentation MCP servers from your terminal").version("0.1.20", "-v, --version", "Print the installed CLI version");
837
870
  program.command("login").description("Authorize the CLI via browser").action(async () => {
838
871
  await runLogin();
839
872
  });
@@ -864,7 +897,7 @@ program.argument("[url]", "Documentation URL to convert").action(async (url) =>
864
897
  }
865
898
  } catch {
866
899
  process.stderr.write(
867
- `${pc8.red("Error:")} Invalid URL. Example: doc2mcp https://docs.example.com
900
+ `${pc9.red("Error:")} Invalid URL. Example: doc2mcp https://docs.example.com
868
901
  `
869
902
  );
870
903
  process.exitCode = 1;
@@ -874,7 +907,7 @@ program.argument("[url]", "Documentation URL to convert").action(async (url) =>
874
907
  });
875
908
  program.parseAsync(process.argv).catch((error) => {
876
909
  const message = error instanceof Error ? error.message : "Unknown error";
877
- process.stderr.write(`${pc8.red("Error:")} ${message}
910
+ process.stderr.write(`${pc9.red("Error:")} ${message}
878
911
  `);
879
912
  process.exit(1);
880
913
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "doc2mcp",
3
- "version": "0.1.19",
3
+ "version": "0.1.20",
4
4
  "description": "Turn any documentation site into a hosted MCP server from your terminal — for Cursor, Claude, VS Code, Windsurf, and OpenAI agents.",
5
5
  "type": "module",
6
6
  "bin": {