docshark 0.1.12 → 0.1.16

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/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.1.13](https://github.com/Michael-Obele/docshark/compare/v0.1.12...v0.1.13) (2026-03-12)
4
+
5
+
6
+ ### ✨ Features
7
+
8
+ * add workflow to cleanup release-please branches on pull request closure ([b250d35](https://github.com/Michael-Obele/docshark/commit/b250d352df810998ed4eb9a1876bf5149c2e9d7d))
9
+ * enhance update command with check and quiet options in CLI ([9f91aba](https://github.com/Michael-Obele/docshark/commit/9f91abafccaa21c9fb43dba5a5548b473a4dc266))
10
+ * implement Bun-first update command and version notification in CLI ([ce31a13](https://github.com/Michael-Obele/docshark/commit/ce31a132d91e3302699afe51f6295a9b0b815e20))
11
+
3
12
  ## [0.1.12](https://github.com/Michael-Obele/docshark/compare/v0.1.11...v0.1.12) (2026-03-12)
4
13
 
5
14
 
@@ -0,0 +1,10 @@
1
+ type RunUpdateOptions = {
2
+ checkOnly?: boolean;
3
+ quiet?: boolean;
4
+ };
5
+ export declare function maybeNotifyAboutUpdate(options: {
6
+ commandName: string;
7
+ stdioMode: boolean;
8
+ }): Promise<void>;
9
+ export declare function runUpdateCommand(options?: RunUpdateOptions): Promise<void>;
10
+ export {};
@@ -0,0 +1,186 @@
1
+ import { spawn } from "node:child_process";
2
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
3
+ import { homedir } from "node:os";
4
+ import { basename, dirname, join } from "node:path";
5
+ import { VERSION } from "./version.js";
6
+ const PACKAGE_NAME = "docshark";
7
+ const REGISTRY_LATEST_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
8
+ const UPDATE_CHECK_TTL_MS = 12 * 60 * 60 * 1000;
9
+ const REQUEST_TIMEOUT_MS = 2500;
10
+ export async function maybeNotifyAboutUpdate(options) {
11
+ if (shouldSkipUpdateNotice(options)) {
12
+ return;
13
+ }
14
+ const latestVersion = await getLatestVersion();
15
+ if (!latestVersion || compareVersions(latestVersion, VERSION) <= 0) {
16
+ return;
17
+ }
18
+ console.error(`\nA newer DocShark version is available: ${VERSION} -> ${latestVersion}.`);
19
+ console.error(`Run \"docshark update\" or \"bun add -g ${PACKAGE_NAME}@latest\".\n`);
20
+ }
21
+ export async function runUpdateCommand(options = {}) {
22
+ const latestVersion = await getLatestVersion({ forceRefresh: true });
23
+ if (!latestVersion) {
24
+ printFallbackUpdateCommand("Could not check the npm registry for the latest DocShark release.", options.quiet);
25
+ process.exit(1);
26
+ return;
27
+ }
28
+ const hasUpdate = compareVersions(latestVersion, VERSION) > 0;
29
+ if (options.checkOnly) {
30
+ if (!options.quiet) {
31
+ if (hasUpdate) {
32
+ console.log(`\nUpdate available: ${VERSION} -> ${latestVersion}.\n`);
33
+ }
34
+ else {
35
+ console.log(`\nDocShark is already up to date (${VERSION}).\n`);
36
+ }
37
+ }
38
+ process.exit(hasUpdate ? 10 : 0);
39
+ return;
40
+ }
41
+ if (!hasUpdate) {
42
+ if (!options.quiet) {
43
+ console.log(`\nDocShark is already up to date (${VERSION}).\n`);
44
+ }
45
+ return;
46
+ }
47
+ const bunPath = resolveBunExecutable();
48
+ if (!bunPath) {
49
+ printFallbackUpdateCommand(`A newer version is available (${VERSION} -> ${latestVersion}), but Bun was not detected on PATH.`, options.quiet);
50
+ process.exit(1);
51
+ return;
52
+ }
53
+ if (!options.quiet) {
54
+ console.log(`\nUpdating DocShark ${VERSION} -> ${latestVersion} with Bun...\n`);
55
+ }
56
+ const exitCode = await spawnProcess(bunPath, [
57
+ "add",
58
+ "-g",
59
+ `${PACKAGE_NAME}@latest`,
60
+ ]);
61
+ if (exitCode !== 0) {
62
+ printFallbackUpdateCommand(`The Bun update command exited with code ${exitCode}.`, options.quiet);
63
+ process.exit(exitCode ?? 1);
64
+ }
65
+ if (!options.quiet) {
66
+ console.log(`\nDocShark was updated to ${latestVersion}.\n`);
67
+ }
68
+ }
69
+ function shouldSkipUpdateNotice(options) {
70
+ if (options.stdioMode || options.commandName === "update") {
71
+ return true;
72
+ }
73
+ if (!process.stdout.isTTY || !process.stderr.isTTY || process.env.CI) {
74
+ return true;
75
+ }
76
+ const rawFlag = process.env.DOCSHARK_DISABLE_UPDATE_CHECK?.trim().toLowerCase();
77
+ return rawFlag === "1" || rawFlag === "true" || rawFlag === "yes";
78
+ }
79
+ async function getLatestVersion(options) {
80
+ if (!options?.forceRefresh) {
81
+ const cached = await readCachedUpdateCheck();
82
+ if (cached && Date.now() - cached.checkedAt < UPDATE_CHECK_TTL_MS) {
83
+ return cached.latestVersion;
84
+ }
85
+ }
86
+ const latestVersion = await fetchLatestVersion();
87
+ if (!latestVersion) {
88
+ const cached = await readCachedUpdateCheck();
89
+ return cached?.latestVersion ?? null;
90
+ }
91
+ await writeCachedUpdateCheck({
92
+ latestVersion,
93
+ checkedAt: Date.now(),
94
+ });
95
+ return latestVersion;
96
+ }
97
+ async function fetchLatestVersion() {
98
+ try {
99
+ const response = await fetch(REGISTRY_LATEST_URL, {
100
+ headers: { accept: "application/json" },
101
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
102
+ });
103
+ if (!response.ok) {
104
+ return null;
105
+ }
106
+ const payload = (await response.json());
107
+ return typeof payload.version === "string" ? payload.version : null;
108
+ }
109
+ catch {
110
+ return null;
111
+ }
112
+ }
113
+ async function readCachedUpdateCheck() {
114
+ try {
115
+ const contents = await readFile(getUpdateCachePath(), "utf8");
116
+ const parsed = JSON.parse(contents);
117
+ if (typeof parsed.latestVersion !== "string" ||
118
+ typeof parsed.checkedAt !== "number") {
119
+ return null;
120
+ }
121
+ return {
122
+ latestVersion: parsed.latestVersion,
123
+ checkedAt: parsed.checkedAt,
124
+ };
125
+ }
126
+ catch {
127
+ return null;
128
+ }
129
+ }
130
+ async function writeCachedUpdateCheck(cache) {
131
+ try {
132
+ const cachePath = getUpdateCachePath();
133
+ await mkdir(dirname(cachePath), { recursive: true });
134
+ await writeFile(cachePath, JSON.stringify(cache), "utf8");
135
+ }
136
+ catch {
137
+ // Best-effort cache only.
138
+ }
139
+ }
140
+ function getUpdateCachePath() {
141
+ const baseCacheDir = process.env.XDG_CACHE_HOME || join(homedir(), ".cache");
142
+ return join(baseCacheDir, PACKAGE_NAME, "update-check.json");
143
+ }
144
+ function resolveBunExecutable() {
145
+ if (typeof Bun !== "undefined") {
146
+ const bunOnPath = Bun.which("bun");
147
+ if (bunOnPath) {
148
+ return bunOnPath;
149
+ }
150
+ }
151
+ return basename(process.execPath).startsWith("bun") ? process.execPath : null;
152
+ }
153
+ function compareVersions(left, right) {
154
+ const leftParts = left.split(".");
155
+ const rightParts = right.split(".");
156
+ const length = Math.max(leftParts.length, rightParts.length);
157
+ for (let index = 0; index < length; index += 1) {
158
+ const leftValue = parseNumericVersionPart(leftParts[index]);
159
+ const rightValue = parseNumericVersionPart(rightParts[index]);
160
+ if (leftValue !== rightValue) {
161
+ return leftValue - rightValue;
162
+ }
163
+ }
164
+ return 0;
165
+ }
166
+ function parseNumericVersionPart(part) {
167
+ if (!part) {
168
+ return 0;
169
+ }
170
+ const match = part.match(/^(\d+)/);
171
+ return match ? Number.parseInt(match[1], 10) : 0;
172
+ }
173
+ function spawnProcess(command, args) {
174
+ return new Promise((resolve, reject) => {
175
+ const child = spawn(command, args, { stdio: "inherit" });
176
+ child.on("error", reject);
177
+ child.on("exit", (code) => resolve(code));
178
+ });
179
+ }
180
+ function printFallbackUpdateCommand(reason, quiet = false) {
181
+ if (quiet) {
182
+ return;
183
+ }
184
+ console.error(`\n${reason}`);
185
+ console.error(`Run \"bun add -g ${PACKAGE_NAME}@latest\" to update DocShark.\n`);
186
+ }
package/dist/cli.js CHANGED
@@ -1,22 +1,30 @@
1
1
  #!/usr/bin/env bun
2
2
  // src/cli.ts — DocShark CLI entry point
3
- import { Command } from "commander";
3
+ import { cac } from "cac";
4
4
  import { startHttpServer } from "./http.js";
5
5
  import { StdioTransport } from "@tmcp/transport-stdio";
6
6
  import { server, db, searchEngine, libraryService } from "./server.js";
7
+ import { maybeNotifyAboutUpdate, runUpdateCommand } from "./cli-update.js";
7
8
  import { VERSION } from "./version.js";
8
- const program = new Command()
9
- .name("docshark")
10
- .description("🦈 Documentation MCP Server — scrape, index, and search any doc website")
11
- .version(VERSION, "-v, --version", "output the current version");
12
- program
13
- .command("start", { isDefault: true })
9
+ const useColor = process.stdout.isTTY;
10
+ const color = {
11
+ reset: "\x1b[0m",
12
+ bold: "\x1b[1m",
13
+ dim: "\x1b[2m",
14
+ cyan: "\x1b[36m",
15
+ yellow: "\x1b[33m",
16
+ gray: "\x1b[90m",
17
+ };
18
+ const cli = cac("docshark");
19
+ cli
20
+ .command("", "Start the MCP server")
21
+ .alias("start")
14
22
  .alias("s")
15
- .description("Start the MCP server (aliases: s, -s)")
16
- .option("-p, --port <port>", "HTTP server port", "6380")
23
+ .option("-p, --port <port>", "HTTP server port", { default: "6380" })
17
24
  .option("-S, --stdio", "Run in STDIO mode (for Claude Desktop, Cursor, etc.)")
18
- .option("-D, --data-dir <path>", "Data directory", "")
25
+ .option("-D, --data-dir <path>", "Data directory")
19
26
  .action(async (opts) => {
27
+ await maybeNotifyForCommand("start", opts.stdio === true);
20
28
  if (opts.dataDir) {
21
29
  process.env.DOCSHARK_DATA_DIR = opts.dataDir;
22
30
  }
@@ -30,14 +38,70 @@ program
30
38
  await startHttpServer(parseInt(opts.port));
31
39
  }
32
40
  });
33
- program
34
- .command("add <url>")
41
+ const helpCommands = [
42
+ {
43
+ name: "start",
44
+ aliases: ["s", "-s"],
45
+ args: "",
46
+ description: "Start server",
47
+ },
48
+ {
49
+ name: "add",
50
+ aliases: ["a", "-a"],
51
+ args: "<url>",
52
+ description: "Add & crawl library",
53
+ },
54
+ {
55
+ name: "search",
56
+ aliases: ["f", "-f"],
57
+ args: "<query>",
58
+ description: "Search docs",
59
+ },
60
+ {
61
+ name: "list",
62
+ aliases: ["l", "-l"],
63
+ args: "",
64
+ description: "List libraries",
65
+ },
66
+ {
67
+ name: "refresh",
68
+ aliases: ["r", "-r"],
69
+ args: "<name>",
70
+ description: "Refresh library",
71
+ },
72
+ {
73
+ name: "remove",
74
+ aliases: ["rm", "-rm"],
75
+ args: "<name>",
76
+ description: "Remove library",
77
+ },
78
+ {
79
+ name: "get",
80
+ aliases: ["g", "-g"],
81
+ args: "[url]",
82
+ description: "Get page markdown",
83
+ },
84
+ {
85
+ name: "update",
86
+ aliases: ["u", "-u"],
87
+ args: "",
88
+ description: "Update DocShark",
89
+ },
90
+ {
91
+ name: "info",
92
+ aliases: ["i", "-i"],
93
+ args: "<name>",
94
+ description: "Library info + pages",
95
+ },
96
+ ];
97
+ cli
98
+ .command("add <url>", "Add a documentation library and start crawling")
35
99
  .alias("a")
36
- .description("Add a documentation library and start crawling (aliases: a, -a)")
37
100
  .option("-n, --name <name>", "Library name (auto-generated from URL if omitted)")
38
- .option("-d, --depth <n>", "Max crawl depth", "3")
101
+ .option("-d, --depth <n>", "Max crawl depth", { default: "3" })
39
102
  .option("-V, --lib-version <version>", "Library version")
40
103
  .action(async (url, opts) => {
104
+ await maybeNotifyForCommand("add");
41
105
  db.init();
42
106
  try {
43
107
  const lib = await libraryService.add({
@@ -57,13 +121,36 @@ program
57
121
  process.exit(1);
58
122
  }
59
123
  });
60
- program
61
- .command("search <query>")
124
+ cli.command("help [command]", "Show help for a command").action((command) => {
125
+ if (command) {
126
+ printCommandHelp(command);
127
+ return;
128
+ }
129
+ printRootHelp();
130
+ });
131
+ cli
132
+ .command("rename <current-name> <new-name>", "Rename an existing documentation library")
133
+ .alias("mv")
134
+ .action(async (currentName, newName) => {
135
+ await maybeNotifyForCommand("rename");
136
+ db.init();
137
+ try {
138
+ const library = libraryService.rename({ currentName, newName });
139
+ console.log(`\nāœ… Renamed library to "${library.display_name}" (${library.name}).\n`);
140
+ }
141
+ catch (err) {
142
+ const message = err instanceof Error ? err.message : "Unknown error";
143
+ console.error(`\nāŒ ${message}\n`);
144
+ process.exit(1);
145
+ }
146
+ });
147
+ cli
148
+ .command("search <query>", "Search indexed documentation")
62
149
  .alias("f")
63
- .description("Search indexed documentation (aliases: f, -f)")
64
150
  .option("-l, --library <name>", "Filter by library")
65
- .option("-m, --limit <n>", "Max results", "5")
151
+ .option("-m, --limit <n>", "Max results", { default: "5" })
66
152
  .action(async (query, opts) => {
153
+ await maybeNotifyForCommand("search");
67
154
  db.init();
68
155
  const results = searchEngine.search(query, {
69
156
  library: opts.library,
@@ -80,12 +167,12 @@ program
80
167
  console.log(`Source: ${r.page_url}\n`);
81
168
  }
82
169
  });
83
- program
84
- .command("list")
170
+ cli
171
+ .command("list", "List indexed libraries")
85
172
  .alias("l")
86
- .description("List indexed libraries (aliases: l, -l)")
87
- .option("-s, --status <status>", "Filter by status (indexed, crawling, error, all)", "all")
88
- .action((opts) => {
173
+ .option("-s, --status <status>", "Filter by status (indexed, crawling, error, all)", { default: "all" })
174
+ .action(async (opts) => {
175
+ await maybeNotifyForCommand("list");
89
176
  db.init();
90
177
  const libs = db.listLibraries(opts.status);
91
178
  if (libs.length === 0) {
@@ -101,11 +188,11 @@ program
101
188
  "Last Crawled": l.last_crawled_at || "never",
102
189
  })));
103
190
  });
104
- program
105
- .command("refresh <name>")
191
+ cli
192
+ .command("refresh <name>", "Refresh an existing documentation library")
106
193
  .alias("r")
107
- .description("Refresh an existing documentation library (aliases: r, -r)")
108
194
  .action(async (name) => {
195
+ await maybeNotifyForCommand("refresh");
109
196
  db.init();
110
197
  try {
111
198
  const lib = db.getLibraryByName(name);
@@ -122,11 +209,11 @@ program
122
209
  process.exit(1);
123
210
  }
124
211
  });
125
- program
126
- .command("remove <name>")
212
+ cli
213
+ .command("remove <name>", "Remove a documentation library and its index")
127
214
  .alias("rm")
128
- .description("Remove a documentation library and its index (aliases: rm, -rm)")
129
- .action((name) => {
215
+ .action(async (name) => {
216
+ await maybeNotifyForCommand("remove");
130
217
  db.init();
131
218
  try {
132
219
  const lib = db.getLibraryByName(name);
@@ -140,13 +227,13 @@ program
140
227
  process.exit(1);
141
228
  }
142
229
  });
143
- program
144
- .command("get [url]")
230
+ cli
231
+ .command("get [url]", "Get the full markdown content of a specific indexed page")
145
232
  .alias("g")
146
- .description("Get the full markdown content of a specific indexed page (aliases: g, -g)")
147
233
  .option("-l, --library <name>", "Library name to search within")
148
234
  .option("-p, --path <path>", "Relative path within the library")
149
- .action((url, opts) => {
235
+ .action(async (url, opts) => {
236
+ await maybeNotifyForCommand("get");
150
237
  if (!url && (!opts.library || !opts.path)) {
151
238
  console.error(`\nāŒ Please provide either a URL, or both --library and --path\n`);
152
239
  process.exit(1);
@@ -162,8 +249,20 @@ program
162
249
  console.log(page.content_markdown);
163
250
  console.log("\n");
164
251
  });
252
+ cli
253
+ .command("update", "Update the global Bun installation of DocShark")
254
+ .alias("u")
255
+ .option("-c, --check", "Only check whether a newer DocShark version is available")
256
+ .option("-q, --quiet", "Suppress DocShark status output and rely on exit codes")
257
+ .action(async (opts) => {
258
+ await maybeNotifyForCommand("update");
259
+ await runUpdateCommand({
260
+ checkOnly: opts.check,
261
+ quiet: opts.quiet,
262
+ });
263
+ });
165
264
  // Intercept manual short flags (e.g., -l instead of l) so they act as command aliases
166
- const args = process.argv;
265
+ const args = process.argv.slice(2);
167
266
  const cmdAliases = {
168
267
  "-s": "start",
169
268
  "-a": "add",
@@ -173,15 +272,31 @@ const cmdAliases = {
173
272
  "-rm": "remove",
174
273
  "-g": "get",
175
274
  "-i": "info",
275
+ "-u": "update",
176
276
  };
177
- if (args[2] && cmdAliases[args[2]]) {
178
- args[2] = cmdAliases[args[2]];
277
+ const normalizedArgs = [...args];
278
+ if (normalizedArgs[0] && cmdAliases[normalizedArgs[0]]) {
279
+ normalizedArgs[0] = cmdAliases[normalizedArgs[0]];
280
+ }
281
+ const helpRequest = getHelpRequest(normalizedArgs);
282
+ if (helpRequest === "root") {
283
+ printRootHelp();
284
+ process.exit(0);
285
+ }
286
+ if (helpRequest && helpRequest !== "root") {
287
+ printCommandHelp(helpRequest);
288
+ process.exit(0);
179
289
  }
180
- program
181
- .command("info <name>")
290
+ if (normalizedArgs.includes("-v") || normalizedArgs.includes("--version")) {
291
+ printVersion();
292
+ process.exit(0);
293
+ }
294
+ const parseArgv = [process.argv[0], process.argv[1], ...normalizedArgs];
295
+ cli
296
+ .command("info <name>", "Get information about a library and list its pages")
182
297
  .alias("i")
183
- .description("Get information about a library and list its pages (aliases: i, -i)")
184
- .action((name) => {
298
+ .action(async (name) => {
299
+ await maybeNotifyForCommand("info");
185
300
  db.init();
186
301
  const lib = db.getLibraryByName(name);
187
302
  if (!lib) {
@@ -207,7 +322,13 @@ program
207
322
  console.log(`\nNo pages found for this library.\n`);
208
323
  }
209
324
  });
210
- program.parse(args);
325
+ try {
326
+ cli.parse(parseArgv, { run: false });
327
+ await cli.runMatchedCommand();
328
+ }
329
+ catch (error) {
330
+ handleCliError(error);
331
+ }
211
332
  /** Helper to wait for a crawl job to finish (CLI blocking mode) */
212
333
  async function waitForCrawl(jobId) {
213
334
  const { jobManager } = await import("./server.js");
@@ -232,3 +353,94 @@ async function waitForCrawl(jobId) {
232
353
  check();
233
354
  });
234
355
  }
356
+ async function maybeNotifyForCommand(commandName, stdioMode = false) {
357
+ await maybeNotifyAboutUpdate({ commandName, stdioMode });
358
+ }
359
+ function getHelpRequest(args) {
360
+ if (args.length === 0) {
361
+ return null;
362
+ }
363
+ if (args[0] === "-h" || args[0] === "--help") {
364
+ return "root";
365
+ }
366
+ if (args[0] === "help") {
367
+ return args[1] ? normalizeCommandName(args[1]) : "root";
368
+ }
369
+ if (args[1] === "help") {
370
+ return normalizeCommandName(args[0]);
371
+ }
372
+ if (args.includes("-h") || args.includes("--help")) {
373
+ return normalizeCommandName(args[0]);
374
+ }
375
+ return null;
376
+ }
377
+ function normalizeCommandName(name) {
378
+ return cmdAliases[name] ?? name;
379
+ }
380
+ function printVersion() {
381
+ console.log(`${paint("DocShark", color.cyan)} ${VERSION}`);
382
+ }
383
+ function printRootHelp() {
384
+ printHeader();
385
+ console.log(`${paint("USAGE", color.gray)}`);
386
+ console.log(` docshark [options] [command]\n`);
387
+ console.log(`${paint("OPTIONS", color.gray)}`);
388
+ console.log(` ${paint("-v, --version", color.cyan).padEnd(18)} Show version`);
389
+ console.log(` ${paint("-h, --help", color.cyan).padEnd(18)} Show this help\n`);
390
+ console.log(`${paint("COMMANDS", color.gray)}`);
391
+ const rows = helpCommands.map((command) => ({
392
+ primary: [
393
+ command.name,
394
+ ...command.aliases.filter((alias) => !alias.startsWith("-")),
395
+ ].join(", "),
396
+ shortAliases: command.aliases.filter((alias) => alias.startsWith("-")),
397
+ args: command.args,
398
+ description: command.description,
399
+ }));
400
+ const primaryWidth = Math.max(...rows.map((row) => row.primary.length));
401
+ const argsWidth = Math.max(...rows.map((row) => row.args.length));
402
+ for (const row of rows) {
403
+ const aliasSuffix = row.shortAliases.length > 0
404
+ ? ` [aliases: ${row.shortAliases.join(", ")}]`
405
+ : "";
406
+ const label = `${row.primary.padEnd(primaryWidth)}${row.args ? ` ${row.args.padEnd(argsWidth)}` : `${"".padEnd(argsWidth + 1)}`}${aliasSuffix}`.trimEnd();
407
+ console.log(` ${paint(label.padEnd(36), color.cyan)} ${row.description}`);
408
+ }
409
+ console.log(`\n${paint("Run `docshark help <command>` for more information.", color.dim)}`);
410
+ }
411
+ function printCommandHelp(commandName) {
412
+ const command = helpCommands.find((item) => item.name === normalizeCommandName(commandName));
413
+ printHeader();
414
+ if (!command) {
415
+ console.log(`${paint(`Unknown command: ${commandName}`, color.cyan)}\n`);
416
+ printRootHelp();
417
+ return;
418
+ }
419
+ console.log(`${paint("USAGE", color.gray)}`);
420
+ console.log(` docshark ${command.name} ${command.args ? paint(command.args, color.yellow) : ""}`.trimEnd());
421
+ console.log(``);
422
+ console.log(`${paint("ALIASES", color.gray)}`);
423
+ console.log(` ${command.aliases.join(", ")}\n`);
424
+ console.log(`${paint("SUMMARY", color.gray)}`);
425
+ console.log(` ${command.description}\n`);
426
+ console.log(`${paint("Run `docshark help` to see all commands.", color.dim)}`);
427
+ }
428
+ function printHeader() {
429
+ console.log();
430
+ console.log(`${paint("🦈 DocShark", color.cyan)} ${paint("Documentation MCP Server", color.bold)}`);
431
+ console.log(` ${paint("Scrape • Index • Search any docs site", color.dim)}\n`);
432
+ }
433
+ function paint(text, code) {
434
+ if (!useColor) {
435
+ return text;
436
+ }
437
+ return `${code}${text}${color.reset}`;
438
+ }
439
+ function handleCliError(error) {
440
+ const message = error instanceof Error ? error.message : "Unknown command error";
441
+ const prettyMessage = message.startsWith("Unused args:")
442
+ ? "Too many arguments passed. Run `docshark help <command>` for usage."
443
+ : message;
444
+ console.error(`\nāŒ ${prettyMessage}\n`);
445
+ process.exit(1);
446
+ }
package/dist/server.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- import { McpServer } from 'tmcp';
2
- import * as v from 'valibot';
3
- import { Database } from './storage/db.js';
4
- import { SearchEngine } from './storage/search.js';
5
- import { LibraryService } from './services/library.js';
6
- import { JobManager } from './jobs/manager.js';
7
- import { EventBus } from './jobs/events.js';
1
+ import { McpServer } from "tmcp";
2
+ import * as v from "valibot";
3
+ import { Database } from "./storage/db.js";
4
+ import { SearchEngine } from "./storage/search.js";
5
+ import { LibraryService } from "./services/library.js";
6
+ import { JobManager } from "./jobs/manager.js";
7
+ import { EventBus } from "./jobs/events.js";
8
8
  export declare const db: Database;
9
9
  export declare const eventBus: EventBus;
10
10
  export declare const searchEngine: SearchEngine;