litescope 0.6.0

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/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # litescope
2
+
3
+ Operations tooling for **SQLite**, **Cloudflare D1**, and **Turso** — an MCP
4
+ server for AI agents, plus schema diff, migrations, lint, point-in-time backups,
5
+ and a self-driving optimizer. This package is a thin installer that fetches the
6
+ prebuilt [Litescope](https://github.com/croc100/Litescope) binary for your
7
+ platform, so JavaScript and `wrangler` users can run it without a separate
8
+ install.
9
+
10
+ ```bash
11
+ # Run the latest without installing
12
+ npx litescope doctor app.db
13
+
14
+ # Diff your dev schema against live D1
15
+ npx litescope diff local.db d1://DB_ID
16
+
17
+ # Run it as an MCP server for Claude / Cursor
18
+ npx litescope mcp --allow-writes
19
+ ```
20
+
21
+ Install globally if you prefer:
22
+
23
+ ```bash
24
+ npm install -g litescope
25
+ litescope --version
26
+ ```
27
+
28
+ The binary is downloaded from the matching GitHub release on install (or on
29
+ first run) into the package's `vendor/` directory — macOS, Linux, and Windows
30
+ (amd64/arm64). No data leaves your machine.
31
+
32
+ Full documentation: **https://litescope-site.pages.dev/docs** ·
33
+ Source & license (AGPL-3.0): **https://github.com/croc100/Litescope**
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env node
2
+ // Launcher for the litescope binary. Ensures the platform binary is present
3
+ // (downloading it on first run if the postinstall step was skipped), then
4
+ // forwards all arguments and exit codes transparently.
5
+ "use strict";
6
+
7
+ const { spawn } = require("child_process");
8
+ const { ensureBinary } = require("../scripts/lib");
9
+
10
+ (async () => {
11
+ let bin;
12
+ try {
13
+ bin = await ensureBinary();
14
+ } catch (err) {
15
+ console.error(`litescope: could not obtain the binary: ${err.message}`);
16
+ console.error("Install manually from https://github.com/croc100/Litescope/releases");
17
+ process.exit(1);
18
+ }
19
+
20
+ const child = spawn(bin, process.argv.slice(2), { stdio: "inherit" });
21
+ child.on("error", (err) => {
22
+ console.error(`litescope: failed to start: ${err.message}`);
23
+ process.exit(1);
24
+ });
25
+ child.on("exit", (code, signal) => {
26
+ if (signal) process.kill(process.pid, signal);
27
+ else process.exit(code === null ? 1 : code);
28
+ });
29
+ })();
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "litescope",
3
+ "version": "0.6.0",
4
+ "description": "SQLite & Cloudflare D1 operations: MCP server, schema diff, migrations, lint, backups, autopilot. Run with `npx litescope`.",
5
+ "keywords": [
6
+ "sqlite",
7
+ "cloudflare",
8
+ "d1",
9
+ "turso",
10
+ "mcp",
11
+ "migration",
12
+ "schema-diff",
13
+ "wrangler"
14
+ ],
15
+ "homepage": "https://litescope-site.pages.dev",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/croc100/Litescope.git"
19
+ },
20
+ "license": "AGPL-3.0",
21
+ "bin": {
22
+ "litescope": "bin/litescope.js"
23
+ },
24
+ "files": [
25
+ "bin",
26
+ "scripts",
27
+ "README.md"
28
+ ],
29
+ "scripts": {
30
+ "postinstall": "node scripts/install.js"
31
+ },
32
+ "engines": {
33
+ "node": ">=16"
34
+ }
35
+ }
@@ -0,0 +1,16 @@
1
+ // postinstall: fetch the platform binary up front. If it fails (offline,
2
+ // air-gapped CI, --ignore-scripts), we don't fail the install — the launcher
3
+ // downloads it lazily on first run instead.
4
+ "use strict";
5
+
6
+ const { ensureBinary } = require("./lib");
7
+
8
+ ensureBinary()
9
+ .then((p) => {
10
+ console.log(`litescope: binary ready (${p})`);
11
+ })
12
+ .catch((err) => {
13
+ console.error(`litescope: postinstall download skipped: ${err.message}`);
14
+ console.error("litescope: the binary will be fetched on first run.");
15
+ // Exit 0 — never break `npm install` over this.
16
+ });
package/scripts/lib.js ADDED
@@ -0,0 +1,114 @@
1
+ // Shared install logic: resolve the platform's release asset, download it from
2
+ // GitHub Releases, and extract the binary. Zero runtime dependencies — archive
3
+ // extraction shells out to tar / unzip / Expand-Archive, which exist on every
4
+ // supported platform.
5
+ "use strict";
6
+
7
+ const fs = require("fs");
8
+ const path = require("path");
9
+ const https = require("https");
10
+ const { execFileSync } = require("child_process");
11
+ const { version } = require("../package.json");
12
+
13
+ const REPO = "croc100/Litescope";
14
+
15
+ // platformAsset maps the current Node platform/arch to a release asset name.
16
+ function platformAsset() {
17
+ const goarch = { x64: "amd64", arm64: "arm64" }[process.arch];
18
+ if (!goarch) throw new Error(`unsupported CPU architecture: ${process.arch}`);
19
+
20
+ let goos, ext, binName;
21
+ switch (process.platform) {
22
+ case "darwin":
23
+ goos = "darwin"; ext = "tar.gz"; binName = "litescope"; break;
24
+ case "linux":
25
+ goos = "linux"; ext = "tar.gz"; binName = "litescope"; break;
26
+ case "win32":
27
+ goos = "windows"; ext = "zip"; binName = "litescope.exe";
28
+ if (goarch !== "amd64") throw new Error("Windows is only supported on amd64");
29
+ break;
30
+ default:
31
+ throw new Error(`unsupported platform: ${process.platform}`);
32
+ }
33
+ const asset = `litescope_${version}_${goos}_${goarch}.${ext}`;
34
+ return { asset, ext, binName };
35
+ }
36
+
37
+ function vendorDir() {
38
+ return path.join(__dirname, "..", "vendor");
39
+ }
40
+
41
+ // binaryPath returns where the binary lives (it may not exist yet).
42
+ function binaryPath() {
43
+ const { binName } = platformAsset();
44
+ return path.join(vendorDir(), binName);
45
+ }
46
+
47
+ // ensureBinary returns the path to the litescope binary, downloading and
48
+ // extracting it on first use.
49
+ async function ensureBinary() {
50
+ const { asset, ext, binName } = platformAsset();
51
+ const dir = vendorDir();
52
+ const binPath = path.join(dir, binName);
53
+ if (fs.existsSync(binPath)) return binPath;
54
+
55
+ fs.mkdirSync(dir, { recursive: true });
56
+ const url = `https://github.com/${REPO}/releases/download/v${version}/${asset}`;
57
+ const archivePath = path.join(dir, asset);
58
+
59
+ await download(url, archivePath);
60
+ extract(archivePath, dir, ext);
61
+ fs.unlinkSync(archivePath);
62
+ if (process.platform !== "win32") fs.chmodSync(binPath, 0o755);
63
+ if (!fs.existsSync(binPath)) {
64
+ throw new Error(`archive did not contain ${binName}`);
65
+ }
66
+ return binPath;
67
+ }
68
+
69
+ function download(url, dest) {
70
+ return new Promise((resolve, reject) => {
71
+ const get = (u, redirects) => {
72
+ if (redirects > 6) return reject(new Error("too many redirects"));
73
+ https
74
+ .get(u, { headers: { "User-Agent": "litescope-npm" } }, (res) => {
75
+ if (
76
+ res.statusCode >= 300 &&
77
+ res.statusCode < 400 &&
78
+ res.headers.location
79
+ ) {
80
+ res.resume();
81
+ return get(res.headers.location, redirects + 1);
82
+ }
83
+ if (res.statusCode !== 200) {
84
+ res.resume();
85
+ return reject(new Error(`download failed (HTTP ${res.statusCode}) for ${u}`));
86
+ }
87
+ const file = fs.createWriteStream(dest);
88
+ res.pipe(file);
89
+ file.on("finish", () => file.close(() => resolve()));
90
+ file.on("error", reject);
91
+ })
92
+ .on("error", reject);
93
+ };
94
+ get(url, 0);
95
+ });
96
+ }
97
+
98
+ function extract(archive, dir, ext) {
99
+ if (ext === "zip") {
100
+ if (process.platform === "win32") {
101
+ execFileSync(
102
+ "powershell",
103
+ ["-NoProfile", "-Command", `Expand-Archive -Force -Path "${archive}" -DestinationPath "${dir}"`],
104
+ { stdio: "ignore" }
105
+ );
106
+ } else {
107
+ execFileSync("unzip", ["-o", archive, "-d", dir], { stdio: "ignore" });
108
+ }
109
+ } else {
110
+ execFileSync("tar", ["-xzf", archive, "-C", dir], { stdio: "ignore" });
111
+ }
112
+ }
113
+
114
+ module.exports = { ensureBinary, binaryPath, platformAsset, version };