docshark 0.1.12 → 0.1.13
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 +9 -0
- package/README.md +13 -4
- package/dist/cli-update.d.ts +10 -0
- package/dist/cli-update.js +186 -0
- package/dist/cli.js +25 -1
- package/dist/tools/list-libraries.d.ts +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
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
|
|
package/README.md
CHANGED
|
@@ -64,11 +64,10 @@ bunx docshark search "schema validation"
|
|
|
64
64
|
|
|
65
65
|
To install DocShark globally as a CLI tool:
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
# Using npm
|
|
69
|
-
npm install -g docshark
|
|
67
|
+
DocShark is intended to be installed and run with Bun.
|
|
70
68
|
|
|
71
|
-
|
|
69
|
+
```bash
|
|
70
|
+
# Global Bun installation
|
|
72
71
|
bun add -g docshark
|
|
73
72
|
```
|
|
74
73
|
|
|
@@ -76,8 +75,18 @@ After installation, you can use the `docshark` command:
|
|
|
76
75
|
|
|
77
76
|
```bash
|
|
78
77
|
docshark list
|
|
78
|
+
|
|
79
|
+
# Update the global Bun installation when a new release is published
|
|
80
|
+
docshark update
|
|
81
|
+
|
|
82
|
+
# Script-friendly update check
|
|
83
|
+
docshark update --check --quiet
|
|
79
84
|
```
|
|
80
85
|
|
|
86
|
+
Interactive CLI runs will also let you know when a newer version is available. Update notices are intentionally skipped for MCP `stdio` mode so they never interfere with protocol output.
|
|
87
|
+
|
|
88
|
+
For scripts, `docshark update --check` exits `0` when current, `10` when a newer version is available, and `1` when the version check could not be completed.
|
|
89
|
+
|
|
81
90
|
## 🔌 MCP Integration
|
|
82
91
|
|
|
83
92
|
### VS Code (GitHub Copilot / MCP Extension)
|
|
@@ -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
|
@@ -4,6 +4,7 @@ import { Command } from "commander";
|
|
|
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
9
|
const program = new Command()
|
|
9
10
|
.name("docshark")
|
|
@@ -162,6 +163,18 @@ program
|
|
|
162
163
|
console.log(page.content_markdown);
|
|
163
164
|
console.log("\n");
|
|
164
165
|
});
|
|
166
|
+
program
|
|
167
|
+
.command("update")
|
|
168
|
+
.alias("u")
|
|
169
|
+
.description("Update the global Bun installation of DocShark (aliases: u, -u)")
|
|
170
|
+
.option("-c, --check", "Only check whether a newer DocShark version is available")
|
|
171
|
+
.option("-q, --quiet", "Suppress DocShark status output and rely on exit codes")
|
|
172
|
+
.action(async (opts) => {
|
|
173
|
+
await runUpdateCommand({
|
|
174
|
+
checkOnly: opts.check,
|
|
175
|
+
quiet: opts.quiet,
|
|
176
|
+
});
|
|
177
|
+
});
|
|
165
178
|
// Intercept manual short flags (e.g., -l instead of l) so they act as command aliases
|
|
166
179
|
const args = process.argv;
|
|
167
180
|
const cmdAliases = {
|
|
@@ -173,6 +186,7 @@ const cmdAliases = {
|
|
|
173
186
|
"-rm": "remove",
|
|
174
187
|
"-g": "get",
|
|
175
188
|
"-i": "info",
|
|
189
|
+
"-u": "update",
|
|
176
190
|
};
|
|
177
191
|
if (args[2] && cmdAliases[args[2]]) {
|
|
178
192
|
args[2] = cmdAliases[args[2]];
|
|
@@ -207,7 +221,17 @@ program
|
|
|
207
221
|
console.log(`\nNo pages found for this library.\n`);
|
|
208
222
|
}
|
|
209
223
|
});
|
|
210
|
-
program.
|
|
224
|
+
program.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
225
|
+
const commandName = actionCommand.name();
|
|
226
|
+
const options = typeof actionCommand.opts === "function"
|
|
227
|
+
? actionCommand.opts()
|
|
228
|
+
: {};
|
|
229
|
+
await maybeNotifyAboutUpdate({
|
|
230
|
+
commandName,
|
|
231
|
+
stdioMode: commandName === "start" && options.stdio === true,
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
await program.parseAsync(args);
|
|
211
235
|
/** Helper to wait for a crawl job to finish (CLI blocking mode) */
|
|
212
236
|
async function waitForCrawl(jobId) {
|
|
213
237
|
const { jobManager } = await import("./server.js");
|
|
@@ -5,7 +5,7 @@ export declare function createListLibrariesTool(db: Database): {
|
|
|
5
5
|
name: "list_libraries";
|
|
6
6
|
description: string;
|
|
7
7
|
schema: v.ObjectSchema<{
|
|
8
|
-
readonly status: v.OptionalSchema<v.SchemaWithPipe<readonly [v.PicklistSchema<["indexed", "crawling", "error", "all"], undefined>, v.DescriptionAction<"
|
|
8
|
+
readonly status: v.OptionalSchema<v.SchemaWithPipe<readonly [v.PicklistSchema<["indexed", "crawling", "error", "all"], undefined>, v.DescriptionAction<"error" | "crawling" | "indexed" | "all", "Filter by indexing status. Default: \"all\".">]>, "all">;
|
|
9
9
|
}, undefined>;
|
|
10
10
|
};
|
|
11
11
|
handler: ({ status }: {
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "0.1.
|
|
1
|
+
export declare const VERSION = "0.1.13";
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// This file is automatically updated by release-please
|
|
2
|
-
export const VERSION = '0.1.
|
|
2
|
+
export const VERSION = '0.1.13'; // x-release-please-version
|