@opencoven/coven-code 0.0.12 → 0.0.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/bin/coven-code +2 -2
- package/checksums.json +17 -0
- package/install.js +50 -5
- package/package.json +2 -1
package/bin/coven-code
CHANGED
|
@@ -7,12 +7,12 @@ const os = require('os');
|
|
|
7
7
|
const fs = require('fs');
|
|
8
8
|
|
|
9
9
|
const ext = os.platform() === 'win32' ? '.exe' : '';
|
|
10
|
-
const binary = path.join(__dirname, '..', 'native', `coven-code`);
|
|
10
|
+
const binary = path.join(__dirname, '..', 'native', `coven-code${ext}`);
|
|
11
11
|
|
|
12
12
|
if (!fs.existsSync(binary)) {
|
|
13
13
|
console.error(
|
|
14
14
|
'coven-code: native binary not found.\n' +
|
|
15
|
-
'Try reinstalling: npm install -g /coven-code\n' +
|
|
15
|
+
'Try reinstalling: npm install -g @opencoven/coven-code\n' +
|
|
16
16
|
`Expected: ${binary}`
|
|
17
17
|
);
|
|
18
18
|
process.exit(1);
|
package/checksums.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"coven-code-windows-x86_64.zip": {
|
|
3
|
+
"sha256": "72745630211c6921018a779df724c99637af73e84168ffe851758c61bf680bdd"
|
|
4
|
+
},
|
|
5
|
+
"coven-code-linux-x86_64.tar.gz": {
|
|
6
|
+
"sha256": "223c1eedaad620af6df5ae776164f4b6d905ab28b55e07bc258601f5841bd366"
|
|
7
|
+
},
|
|
8
|
+
"coven-code-linux-aarch64.tar.gz": {
|
|
9
|
+
"sha256": "221eae094f6edb6d28ccdcc5bda90cf1c89e24d3a677bb4f7de51d8f1eff062f"
|
|
10
|
+
},
|
|
11
|
+
"coven-code-macos-x86_64.tar.gz": {
|
|
12
|
+
"sha256": "fd0ee2c2c605142198c48aa9c15adf6b7ee979aa47ef8b3f55edacb32251217d"
|
|
13
|
+
},
|
|
14
|
+
"coven-code-macos-aarch64.tar.gz": {
|
|
15
|
+
"sha256": "8b78b0475f32a233dab7a650f574ebd2f31a308fdcf79548697ebbb3107e3269"
|
|
16
|
+
}
|
|
17
|
+
}
|
package/install.js
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
const https = require('https');
|
|
5
|
-
const http = require('http');
|
|
6
5
|
const fs = require('fs');
|
|
7
6
|
const path = require('path');
|
|
8
7
|
const os = require('os');
|
|
8
|
+
const crypto = require('crypto');
|
|
9
9
|
const { execFileSync } = require('child_process');
|
|
10
10
|
|
|
11
11
|
const pkg = require('./package.json');
|
|
12
|
+
const checksums = require('./checksums.json');
|
|
12
13
|
const VERSION = pkg.version;
|
|
13
14
|
const REPO = 'OpenCoven/coven-code';
|
|
14
15
|
const BASE_URL = `https://github.com/${REPO}/releases/download/v${VERSION}`;
|
|
@@ -41,13 +42,29 @@ function getPlatform() {
|
|
|
41
42
|
|
|
42
43
|
function download(url, dest) {
|
|
43
44
|
return new Promise((resolve, reject) => {
|
|
45
|
+
const parsed = new URL(url);
|
|
46
|
+
if (parsed.protocol !== 'https:') {
|
|
47
|
+
reject(new Error(`Refusing to download non-HTTPS URL: ${url}`));
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
44
51
|
const file = fs.createWriteStream(dest);
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (res.statusCode === 301 || res.statusCode === 302) {
|
|
52
|
+
https.get(url, (res) => {
|
|
53
|
+
if ([301, 302, 303, 307, 308].includes(res.statusCode)) {
|
|
48
54
|
file.close();
|
|
49
55
|
try { fs.unlinkSync(dest); } catch (_) {}
|
|
50
|
-
|
|
56
|
+
if (!res.headers.location) {
|
|
57
|
+
reject(new Error(`Redirect without Location header downloading ${url}`));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
let location;
|
|
61
|
+
try {
|
|
62
|
+
location = new URL(res.headers.location, url).toString();
|
|
63
|
+
} catch (err) {
|
|
64
|
+
reject(err);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
download(location, dest).then(resolve).catch(reject);
|
|
51
68
|
return;
|
|
52
69
|
}
|
|
53
70
|
if (res.statusCode !== 200) {
|
|
@@ -69,6 +86,31 @@ function download(url, dest) {
|
|
|
69
86
|
});
|
|
70
87
|
}
|
|
71
88
|
|
|
89
|
+
function sha256File(filePath) {
|
|
90
|
+
const hash = crypto.createHash('sha256');
|
|
91
|
+
const bytes = fs.readFileSync(filePath);
|
|
92
|
+
hash.update(bytes);
|
|
93
|
+
return hash.digest('hex');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function expectedSha256(archiveName) {
|
|
97
|
+
const entry = checksums[archiveName];
|
|
98
|
+
if (!entry || typeof entry.sha256 !== 'string') {
|
|
99
|
+
throw new Error(`Missing SHA-256 checksum for ${archiveName} in checksums.json`);
|
|
100
|
+
}
|
|
101
|
+
return entry.sha256;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function verifyChecksum(filePath, archiveName) {
|
|
105
|
+
const expected = expectedSha256(archiveName).toLowerCase();
|
|
106
|
+
const actual = sha256File(filePath).toLowerCase();
|
|
107
|
+
if (actual !== expected) {
|
|
108
|
+
throw new Error(
|
|
109
|
+
`Checksum mismatch for ${archiveName}: expected ${expected}, got ${actual}`
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
72
114
|
async function main() {
|
|
73
115
|
const { artifact, ext, archive } = getPlatform();
|
|
74
116
|
const archiveName = `${artifact}${archive}`;
|
|
@@ -87,6 +129,9 @@ async function main() {
|
|
|
87
129
|
console.log(` ${url}`);
|
|
88
130
|
await download(url, tmpPath);
|
|
89
131
|
|
|
132
|
+
console.log('coven-code: verifying checksum...');
|
|
133
|
+
verifyChecksum(tmpPath, archiveName);
|
|
134
|
+
|
|
90
135
|
console.log('coven-code: extracting...');
|
|
91
136
|
if (archive === '.zip') {
|
|
92
137
|
execFileSync('powershell', [
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opencoven/coven-code",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13",
|
|
4
4
|
"description": "Open-source, multi-provider agentic coding TUI for the terminal — OpenCoven fork of Claurst",
|
|
5
5
|
"license": "GPL-3.0-only",
|
|
6
6
|
"repository": {
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"files": [
|
|
32
32
|
"bin/",
|
|
33
33
|
"install.js",
|
|
34
|
+
"checksums.json",
|
|
34
35
|
"README.md",
|
|
35
36
|
"ATTRIBUTION.md"
|
|
36
37
|
],
|