usight 0.1.4 → 0.1.5
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/usight.js +3 -0
- package/lib/github.js +53 -35
- package/lib/runtime.js +13 -0
- package/package.json +1 -1
package/bin/usight.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { install, uninstall, list, setPath } from '../lib/widgets.js';
|
|
4
4
|
import { getConfig } from '../lib/config.js';
|
|
5
5
|
import { getWidgetsDir } from '../lib/ubersicht.js';
|
|
6
|
+
import { detectRuntime } from '../lib/runtime.js';
|
|
6
7
|
|
|
7
8
|
const [,, cmd, ...args] = process.argv;
|
|
8
9
|
|
|
@@ -22,9 +23,11 @@ const commands = {
|
|
|
22
23
|
},
|
|
23
24
|
config: () => {
|
|
24
25
|
const cfg = getConfig();
|
|
26
|
+
const runtime = detectRuntime();
|
|
25
27
|
console.log(`Cache path: ${cfg.cachePath}`);
|
|
26
28
|
console.log(`Widgets dir: ${getWidgetsDir()}`);
|
|
27
29
|
console.log(`Installed: ${Object.keys(cfg.widgets).length} widget(s)`);
|
|
30
|
+
if (runtime) console.log(`Runtime hint: ${runtime} (informational only)`);
|
|
28
31
|
},
|
|
29
32
|
help: () => help(),
|
|
30
33
|
};
|
package/lib/github.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { mkdirSync } from 'fs';
|
|
3
|
-
import {
|
|
1
|
+
import { gunzipSync } from 'zlib';
|
|
2
|
+
import { mkdirSync, writeFileSync } from 'fs';
|
|
3
|
+
import { join, dirname } from 'path';
|
|
4
4
|
|
|
5
5
|
// Parse "owner/repo" or full GitHub URL into { owner, repo }
|
|
6
6
|
export function parseRepo(input) {
|
|
7
7
|
if (!input) throw new Error('No repository specified');
|
|
8
8
|
|
|
9
|
-
// strip trailing .git and leading https://github.com/
|
|
10
9
|
const clean = input
|
|
11
10
|
.replace(/^https?:\/\/github\.com\//, '')
|
|
12
11
|
.replace(/\.git$/, '')
|
|
@@ -20,39 +19,58 @@ export function parseRepo(input) {
|
|
|
20
19
|
return { owner: parts[0], repo: parts[1] };
|
|
21
20
|
}
|
|
22
21
|
|
|
23
|
-
// Download GitHub tarball and extract into destDir
|
|
24
|
-
|
|
22
|
+
// Download GitHub tarball and extract into destDir.
|
|
23
|
+
// Uses native fetch (Node ≥18) + built-in zlib — no external tools, no git.
|
|
24
|
+
export async function downloadAndExtract(owner, repo, destDir) {
|
|
25
25
|
mkdirSync(destDir, { recursive: true });
|
|
26
26
|
|
|
27
27
|
const url = `https://api.github.com/repos/${owner}/${repo}/tarball/HEAD`;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
https.get(url, { headers: { 'User-Agent': 'usight-cli' } }, (res) => {
|
|
32
|
-
if (res.statusCode === 301 || res.statusCode === 302 || res.statusCode === 307) {
|
|
33
|
-
get(res.headers.location);
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
if (res.statusCode !== 200) {
|
|
37
|
-
reject(new Error(`GitHub returned HTTP ${res.statusCode} for ${owner}/${repo}`));
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// pipe into tar — strips the top-level GitHub-generated directory
|
|
42
|
-
const tar = spawn('tar', ['-xzf', '-', '-C', destDir, '--strip-components=1'], {
|
|
43
|
-
stdio: ['pipe', 'inherit', 'inherit'],
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
res.pipe(tar.stdin);
|
|
47
|
-
res.on('error', reject);
|
|
48
|
-
tar.on('error', reject);
|
|
49
|
-
tar.on('close', (code) => {
|
|
50
|
-
if (code === 0) resolve();
|
|
51
|
-
else reject(new Error(`tar exited with code ${code}`));
|
|
52
|
-
});
|
|
53
|
-
}).on('error', reject);
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
get(url);
|
|
28
|
+
const res = await fetch(url, {
|
|
29
|
+
redirect: 'follow',
|
|
30
|
+
headers: { 'User-Agent': 'usight-cli' },
|
|
57
31
|
});
|
|
32
|
+
|
|
33
|
+
if (!res.ok) {
|
|
34
|
+
throw new Error(`GitHub returned HTTP ${res.status} for ${owner}/${repo}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const compressed = Buffer.from(await res.arrayBuffer());
|
|
38
|
+
extractTar(gunzipSync(compressed), destDir);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Minimal tar extractor — enough for GitHub repo archives.
|
|
42
|
+
// ponytail: skips symlinks/hardlinks (rare in widget repos); add if you hit a case
|
|
43
|
+
export function extractTar(data, destDir) {
|
|
44
|
+
let offset = 0;
|
|
45
|
+
|
|
46
|
+
while (offset + 512 <= data.length) {
|
|
47
|
+
const header = data.subarray(offset, offset + 512);
|
|
48
|
+
offset += 512;
|
|
49
|
+
|
|
50
|
+
if (header.every(b => b === 0)) break; // end-of-archive sentinel
|
|
51
|
+
|
|
52
|
+
const name = nullStr(header.subarray(0, 100));
|
|
53
|
+
const size = parseInt(nullStr(header.subarray(124, 136)).trim(), 8) || 0;
|
|
54
|
+
const type = String.fromCharCode(header[156]);
|
|
55
|
+
|
|
56
|
+
// GitHub archives wrap everything in a top-level "owner-repo-sha/" dir — strip it
|
|
57
|
+
const stripped = name.split('/').slice(1).join('/');
|
|
58
|
+
|
|
59
|
+
if (stripped) {
|
|
60
|
+
const dest = join(destDir, stripped);
|
|
61
|
+
if (type === '5' || stripped.endsWith('/')) {
|
|
62
|
+
mkdirSync(dest, { recursive: true });
|
|
63
|
+
} else if (type === '0' || type === '\0') {
|
|
64
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
65
|
+
writeFileSync(dest, data.subarray(offset, offset + size));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
offset += Math.ceil(size / 512) * 512;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function nullStr(buf) {
|
|
74
|
+
const end = buf.indexOf(0);
|
|
75
|
+
return end === -1 ? buf.toString('utf8') : buf.subarray(0, end).toString('utf8');
|
|
58
76
|
}
|
package/lib/runtime.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
|
|
3
|
+
// Detect available JS runtimes in preference order.
|
|
4
|
+
// Informational only — usight's install logic never delegates to any of these.
|
|
5
|
+
export function detectRuntime() {
|
|
6
|
+
for (const tool of ['bun', 'pnpm', 'npm']) {
|
|
7
|
+
try {
|
|
8
|
+
execSync(`${tool} --version`, { stdio: 'pipe' });
|
|
9
|
+
return tool;
|
|
10
|
+
} catch {}
|
|
11
|
+
}
|
|
12
|
+
return null;
|
|
13
|
+
}
|