@marionette-app/cli 1.3.2
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/marionette.js +24 -0
- package/package.json +28 -0
- package/scripts/bootstrap.js +96 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const { spawn } = require('child_process');
|
|
8
|
+
|
|
9
|
+
const installDir = path.join(os.homedir(), '.marionette', 'app');
|
|
10
|
+
const isWindows = process.platform === 'win32';
|
|
11
|
+
const realBin = path.join(installDir, 'bin', isWindows ? 'marionette.cmd' : 'marionette');
|
|
12
|
+
|
|
13
|
+
const args = process.argv.slice(2);
|
|
14
|
+
const command = args[0];
|
|
15
|
+
|
|
16
|
+
if (fs.existsSync(realBin)) {
|
|
17
|
+
const child = spawn(realBin, args, { stdio: 'inherit', shell: isWindows });
|
|
18
|
+
child.on('exit', (code) => process.exit(code ?? 0));
|
|
19
|
+
} else if (!command || command === 'setup') {
|
|
20
|
+
require('../scripts/bootstrap.js')();
|
|
21
|
+
} else {
|
|
22
|
+
console.error('Marionette is not installed yet. Run: marionette setup');
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@marionette-app/cli",
|
|
3
|
+
"version": "1.3.2",
|
|
4
|
+
"description": "Real-time monitoring for Claude Code sessions",
|
|
5
|
+
"bin": {
|
|
6
|
+
"marionette": "./bin/marionette.js"
|
|
7
|
+
},
|
|
8
|
+
"engines": {
|
|
9
|
+
"node": ">=18"
|
|
10
|
+
},
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/yarin-mag/Marionette"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"claude",
|
|
18
|
+
"claude-code",
|
|
19
|
+
"ai",
|
|
20
|
+
"monitoring",
|
|
21
|
+
"mcp",
|
|
22
|
+
"dashboard"
|
|
23
|
+
],
|
|
24
|
+
"files": [
|
|
25
|
+
"bin/",
|
|
26
|
+
"scripts/"
|
|
27
|
+
]
|
|
28
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const https = require('https');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const os = require('os');
|
|
7
|
+
const { execSync, execFileSync } = require('child_process');
|
|
8
|
+
|
|
9
|
+
module.exports = function bootstrap() {
|
|
10
|
+
const version = require('../package.json').version;
|
|
11
|
+
const platform = process.platform;
|
|
12
|
+
const arch = process.arch;
|
|
13
|
+
const isWindows = platform === 'win32';
|
|
14
|
+
|
|
15
|
+
let artifact;
|
|
16
|
+
if (platform === 'linux') {
|
|
17
|
+
artifact = 'marionette-linux-x64.tar.gz';
|
|
18
|
+
} else if (platform === 'darwin') {
|
|
19
|
+
artifact = arch === 'arm64'
|
|
20
|
+
? 'marionette-macos-arm64.tar.gz'
|
|
21
|
+
: 'marionette-macos-x64.tar.gz';
|
|
22
|
+
} else if (isWindows) {
|
|
23
|
+
artifact = 'marionette-windows-x64.zip';
|
|
24
|
+
} else {
|
|
25
|
+
console.error(`Unsupported platform: ${platform}`);
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const url = `https://github.com/yarin-mag/Marionette/releases/download/v${version}/${artifact}`;
|
|
30
|
+
const installDir = path.join(os.homedir(), '.marionette', 'app');
|
|
31
|
+
const tmpFile = path.join(os.tmpdir(), artifact);
|
|
32
|
+
const realBin = path.join(installDir, 'bin', isWindows ? 'marionette.cmd' : 'marionette');
|
|
33
|
+
|
|
34
|
+
console.log(`Installing Marionette v${version}...`);
|
|
35
|
+
console.log(`Downloading ${artifact}...`);
|
|
36
|
+
|
|
37
|
+
download(url, tmpFile, () => {
|
|
38
|
+
console.log('Extracting...');
|
|
39
|
+
fs.mkdirSync(installDir, { recursive: true });
|
|
40
|
+
|
|
41
|
+
if (isWindows) {
|
|
42
|
+
execSync(`tar -xf "${tmpFile}" -C "${installDir}" --strip-components=1`, { stdio: 'inherit' });
|
|
43
|
+
} else {
|
|
44
|
+
execSync(`tar -xzf "${tmpFile}" -C "${installDir}" --strip-components=1`, { stdio: 'inherit' });
|
|
45
|
+
fs.chmodSync(realBin, 0o755);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
try { fs.unlinkSync(tmpFile); } catch (_) {}
|
|
49
|
+
|
|
50
|
+
console.log('Running setup...');
|
|
51
|
+
execFileSync(realBin, ['setup'], { stdio: 'inherit', shell: isWindows });
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
function download(url, dest, callback) {
|
|
56
|
+
const file = fs.createWriteStream(dest);
|
|
57
|
+
|
|
58
|
+
function get(urlStr) {
|
|
59
|
+
https.get(urlStr, (res) => {
|
|
60
|
+
if (res.statusCode === 301 || res.statusCode === 302) {
|
|
61
|
+
file.destroy();
|
|
62
|
+
get(res.headers.location);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (res.statusCode !== 200) {
|
|
66
|
+
console.error(`Download failed: HTTP ${res.statusCode}\nURL: ${urlStr}`);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const total = parseInt(res.headers['content-length'] || '0', 10);
|
|
71
|
+
let received = 0;
|
|
72
|
+
|
|
73
|
+
res.on('data', (chunk) => {
|
|
74
|
+
received += chunk.length;
|
|
75
|
+
if (total) {
|
|
76
|
+
const pct = Math.round((received / total) * 100);
|
|
77
|
+
process.stdout.write(`\r ${pct}%`);
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
res.pipe(file);
|
|
82
|
+
file.on('finish', () => {
|
|
83
|
+
file.close(() => {
|
|
84
|
+
if (total) process.stdout.write('\n');
|
|
85
|
+
callback();
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
}).on('error', (err) => {
|
|
89
|
+
fs.unlink(dest, () => {});
|
|
90
|
+
console.error(`Download error: ${err.message}`);
|
|
91
|
+
process.exit(1);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
get(url);
|
|
96
|
+
}
|