shardstitch 0.0.6 → 0.0.8
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 +3 -1
- package/cli.js +81 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -28,7 +28,9 @@ The same trick fixes a bloated session in the *same* tool. Long AI chats accumul
|
|
|
28
28
|
|
|
29
29
|
## 22 supported AI tools
|
|
30
30
|
|
|
31
|
-
Claude Code, Claude Desktop, Cursor, Codex CLI, Gemini CLI, Windsurf, Aider, Kiro, Amazon Q Developer, DeepSeek,
|
|
31
|
+
Claude Code, Claude Desktop, Cursor, Codex CLI, Gemini CLI, Windsurf, Aider, Kiro, Amazon Q Developer, DeepSeek, OpenCode, Trae, Factory Droid, OpenClaw, Amp, Cline, Roo Code, Kilo Code, Crush, Kimi, Qwen Code, and Antigravity.
|
|
32
|
+
|
|
33
|
+
**Coming soon:** Cody, Continue, Replit Agent, JetBrains AI, Tabnine.
|
|
32
34
|
|
|
33
35
|
## 7 surfaces
|
|
34
36
|
|
package/cli.js
CHANGED
|
@@ -16,6 +16,28 @@ const INSTALL_DIR = join(os.homedir(), ".shardstitch", "app");
|
|
|
16
16
|
const ACTIVATION_FILE = join(os.homedir(), ".shardstitch", "activation.json");
|
|
17
17
|
const MACHINE_SALT = "shardstitch-activation/1";
|
|
18
18
|
|
|
19
|
+
// --- Supply-chain hardening -------------------------------------------------
|
|
20
|
+
// The binary SHA-256 is baked into this file at release time. No external
|
|
21
|
+
// checksums.json needed — Polar delivers the file, we verify the hash locally.
|
|
22
|
+
// Update these after every build before publishing.
|
|
23
|
+
const CHECKSUMS = {
|
|
24
|
+
windows: "14642911d2f2fee8baf92ad30948b96e01dbd66167bab3ab0cbf443a33ea58a6",
|
|
25
|
+
linux: "14642911d2f2fee8baf92ad30948b96e01dbd66167bab3ab0cbf443a33ea58a6",
|
|
26
|
+
mac: "14642911d2f2fee8baf92ad30948b96e01dbd66167bab3ab0cbf443a33ea58a6",
|
|
27
|
+
};
|
|
28
|
+
const TRUSTED_DOWNLOAD_HOST_SUFFIXES = [
|
|
29
|
+
"shardstitch.com",
|
|
30
|
+
"polar.sh",
|
|
31
|
+
"polarsource.com",
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
function isTrustedHost(hostname) {
|
|
35
|
+
const h = (hostname || "").toLowerCase();
|
|
36
|
+
return TRUSTED_DOWNLOAD_HOST_SUFFIXES.some(
|
|
37
|
+
(suffix) => h === suffix || h.endsWith("." + suffix)
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
|
|
19
41
|
const PLATFORM = process.platform === "win32" ? "windows"
|
|
20
42
|
: process.platform === "darwin" ? "mac"
|
|
21
43
|
: "linux";
|
|
@@ -109,8 +131,22 @@ function downloadFile(url, dest) {
|
|
|
109
131
|
const tmp = dest + ".tmp";
|
|
110
132
|
const file = createWriteStream(tmp);
|
|
111
133
|
|
|
112
|
-
function follow(
|
|
113
|
-
|
|
134
|
+
function follow(rawUrl) {
|
|
135
|
+
let u;
|
|
136
|
+
try {
|
|
137
|
+
u = new URL(rawUrl);
|
|
138
|
+
} catch {
|
|
139
|
+
return reject(new Error(`Refusing to download: invalid URL`));
|
|
140
|
+
}
|
|
141
|
+
// Fail closed on protocol downgrade or untrusted host (blocks open-redirect
|
|
142
|
+
// / MITM from pointing the download at an attacker-controlled binary).
|
|
143
|
+
if (u.protocol !== "https:") {
|
|
144
|
+
return reject(new Error(`Refusing non-HTTPS download (${u.protocol})`));
|
|
145
|
+
}
|
|
146
|
+
if (!isTrustedHost(u.hostname)) {
|
|
147
|
+
return reject(new Error(`Refusing download from untrusted host: ${u.hostname}`));
|
|
148
|
+
}
|
|
149
|
+
https.get(rawUrl, { headers: { "User-Agent": "ShardStitch-Installer/1.0" } }, (res) => {
|
|
114
150
|
if (res.statusCode === 301 || res.statusCode === 302) {
|
|
115
151
|
return follow(res.headers.location);
|
|
116
152
|
}
|
|
@@ -138,6 +174,17 @@ function downloadFile(url, dest) {
|
|
|
138
174
|
});
|
|
139
175
|
}
|
|
140
176
|
|
|
177
|
+
function sha256File(path) {
|
|
178
|
+
return new Promise((resolve, reject) => {
|
|
179
|
+
const hash = createHash("sha256");
|
|
180
|
+
const stream = fs.createReadStream(path);
|
|
181
|
+
stream.on("data", (chunk) => hash.update(chunk));
|
|
182
|
+
stream.on("end", () => resolve(hash.digest("hex")));
|
|
183
|
+
stream.on("error", reject);
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
|
|
141
188
|
async function cmdInstall(key) {
|
|
142
189
|
key = key.trim();
|
|
143
190
|
console.log();
|
|
@@ -191,12 +238,43 @@ async function cmdInstall(key) {
|
|
|
191
238
|
|
|
192
239
|
try {
|
|
193
240
|
await downloadFile(downloadUrl, exePath);
|
|
194
|
-
if (PLATFORM !== "windows") chmodSync(exePath, 0o755);
|
|
195
241
|
} catch (e) {
|
|
196
242
|
console.log(` ✗ Download failed: ${e.message}`);
|
|
197
243
|
process.exit(1);
|
|
198
244
|
}
|
|
199
245
|
|
|
246
|
+
// Integrity check — verify the downloaded binary's SHA-256 against the manifest
|
|
247
|
+
// on our pinned domain BEFORE making it executable or running it. Fails closed.
|
|
248
|
+
const allowUnverified = process.argv.includes("--allow-unverified");
|
|
249
|
+
try {
|
|
250
|
+
const expected = (CHECKSUMS[PLATFORM] || "").toLowerCase();
|
|
251
|
+
const actual = (await sha256File(exePath)).toLowerCase();
|
|
252
|
+
if (!expected) {
|
|
253
|
+
throw new Error(`no published checksum for platform "${PLATFORM}"`);
|
|
254
|
+
}
|
|
255
|
+
if (actual !== expected) {
|
|
256
|
+
try { fs.unlinkSync(exePath); } catch {}
|
|
257
|
+
console.log(" ✗ Integrity check FAILED — the downloaded file does not match");
|
|
258
|
+
console.log(" the published checksum and was deleted. Do NOT run it.");
|
|
259
|
+
console.log(` expected ${expected}`);
|
|
260
|
+
console.log(` actual ${actual}`);
|
|
261
|
+
console.log(" Report this to support@shardstitch.com.");
|
|
262
|
+
process.exit(1);
|
|
263
|
+
}
|
|
264
|
+
console.log(" ✓ Integrity verified (SHA-256).");
|
|
265
|
+
} catch (e) {
|
|
266
|
+
if (!allowUnverified) {
|
|
267
|
+
try { fs.unlinkSync(exePath); } catch {}
|
|
268
|
+
console.log(` ✗ Could not verify download integrity: ${e.message}`);
|
|
269
|
+
console.log(" Aborting for safety. Re-run with --allow-unverified to override");
|
|
270
|
+
console.log(" (not recommended), or contact support@shardstitch.com.");
|
|
271
|
+
process.exit(1);
|
|
272
|
+
}
|
|
273
|
+
console.log(` ! Skipping integrity check (--allow-unverified): ${e.message}`);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (PLATFORM !== "windows") chmodSync(exePath, 0o755);
|
|
277
|
+
|
|
200
278
|
saveActivation(key);
|
|
201
279
|
|
|
202
280
|
console.log(` ✓ Installed to ${exePath}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "shardstitch",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
4
4
|
"description": "ShardStitch — capture your AI coding session (git diff, dependency graph, intent) and stitch it into the next tool. 22 AI tools supported. 100% local, zero telemetry. https://shardstitch.com",
|
|
5
5
|
"homepage": "https://shardstitch.com",
|
|
6
6
|
"bugs": {
|