@quark.clip/quark 1.3.2 ā 1.3.3
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 +14 -0
- package/cli/bin/quark.js +27 -15
- package/cli/src/daemon.js +1 -0
- package/cli/src/installer.js +6 -3
- package/cli/src/network.js +9 -2
- package/dist/assets/{index-C6vSo0cw.js ā index-C-Yp6SQt.js} +15 -15
- package/dist/assets/index-Cj2OjxgG.css +1 -0
- package/dist/index.html +2 -2
- package/package.json +6 -2
- package/dist/assets/index-Bv59mame.css +0 -1
package/README.md
CHANGED
|
@@ -40,6 +40,20 @@ The operating system clipboard is fundamentally broken and stuck in the past:
|
|
|
40
40
|
|
|
41
41
|
No `.exe` files. No `.dmg` files. Just pure, cross-platform JavaScript.
|
|
42
42
|
|
|
43
|
+
### One-Click Install (macOS / Linux)
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
curl -fsSL https://raw.githubusercontent.com/sir-ad/quark/main/install.sh | sh
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### One-Click Install (Windows PowerShell)
|
|
50
|
+
|
|
51
|
+
```powershell
|
|
52
|
+
iex (irm https://raw.githubusercontent.com/sir-ad/quark/main/install.ps1)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Manual install
|
|
56
|
+
|
|
43
57
|
```bash
|
|
44
58
|
# Run instantly without installing (Temporary Session)
|
|
45
59
|
npx -y @quark.clip/quark start
|
package/cli/bin/quark.js
CHANGED
|
@@ -2,16 +2,22 @@
|
|
|
2
2
|
const { spawn } = require('child_process');
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const fs = require('fs');
|
|
5
|
+
const os = require('os');
|
|
5
6
|
const { installService, uninstallService } = require('../src/installer');
|
|
6
7
|
|
|
7
8
|
const command = process.argv[2] || 'help';
|
|
8
9
|
const daemonPath = path.join(__dirname, '../src/daemon.js');
|
|
9
10
|
const mcpPath = path.join(__dirname, '../src/mcp.js');
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
|
|
12
|
+
// Bug fix: write state files to ~/.quark/ instead of inside the package dir (which
|
|
13
|
+
// can be read-only when installed globally via npm).
|
|
14
|
+
const quarkDir = path.join(os.homedir(), '.quark');
|
|
15
|
+
fs.mkdirSync(quarkDir, { recursive: true });
|
|
16
|
+
const pidFile = path.join(quarkDir, 'quark.pid');
|
|
17
|
+
const logFile = path.join(quarkDir, 'quark.log');
|
|
12
18
|
|
|
13
19
|
switch (command) {
|
|
14
|
-
case 'run':
|
|
20
|
+
case 'run': {
|
|
15
21
|
console.log(`
|
|
16
22
|
o-------o
|
|
17
23
|
| \\ / |
|
|
@@ -23,8 +29,9 @@ switch (command) {
|
|
|
23
29
|
console.log('š” Press Ctrl+C to stop. Logs will appear below:');
|
|
24
30
|
require(daemonPath);
|
|
25
31
|
break;
|
|
32
|
+
}
|
|
26
33
|
|
|
27
|
-
case 'logs':
|
|
34
|
+
case 'logs': {
|
|
28
35
|
if (fs.existsSync(logFile)) {
|
|
29
36
|
console.log('š Tailing Quark logs... (Press Ctrl+C to exit)');
|
|
30
37
|
const tail = spawn('tail', ['-f', logFile], { stdio: 'inherit' });
|
|
@@ -33,8 +40,9 @@ switch (command) {
|
|
|
33
40
|
console.log('ā ļø No log file found at ' + logFile);
|
|
34
41
|
}
|
|
35
42
|
break;
|
|
43
|
+
}
|
|
36
44
|
|
|
37
|
-
case 'start':
|
|
45
|
+
case 'start': {
|
|
38
46
|
console.log(`
|
|
39
47
|
o-------o
|
|
40
48
|
| \\ / |
|
|
@@ -49,7 +57,9 @@ switch (command) {
|
|
|
49
57
|
}
|
|
50
58
|
const out = fs.openSync(logFile, 'a');
|
|
51
59
|
const err = fs.openSync(logFile, 'a');
|
|
52
|
-
|
|
60
|
+
// Bug fix: use process.execPath so the correct node binary is used even
|
|
61
|
+
// inside nvm / fnm / volta managed environments.
|
|
62
|
+
const child = spawn(process.execPath, [daemonPath], {
|
|
53
63
|
detached: true,
|
|
54
64
|
stdio: ['ignore', out, err]
|
|
55
65
|
});
|
|
@@ -58,8 +68,9 @@ switch (command) {
|
|
|
58
68
|
console.log('⨠Quark is now orbiting your clipboard in the background.');
|
|
59
69
|
console.log('š” Tip: Run `quark install` to make it start automatically on boot.');
|
|
60
70
|
break;
|
|
71
|
+
}
|
|
61
72
|
|
|
62
|
-
case 'stop':
|
|
73
|
+
case 'stop': {
|
|
63
74
|
if (fs.existsSync(pidFile)) {
|
|
64
75
|
const pid = fs.readFileSync(pidFile, 'utf8');
|
|
65
76
|
try {
|
|
@@ -73,6 +84,7 @@ switch (command) {
|
|
|
73
84
|
console.log('Quark is not running via manual start.');
|
|
74
85
|
}
|
|
75
86
|
break;
|
|
87
|
+
}
|
|
76
88
|
|
|
77
89
|
case 'install':
|
|
78
90
|
installService();
|
|
@@ -82,34 +94,33 @@ switch (command) {
|
|
|
82
94
|
uninstallService();
|
|
83
95
|
break;
|
|
84
96
|
|
|
85
|
-
case 'status':
|
|
97
|
+
case 'status': {
|
|
86
98
|
const isRunning = fs.existsSync(pidFile);
|
|
87
99
|
console.log(`\nš Quark Status`);
|
|
88
100
|
console.log(`----------------`);
|
|
89
101
|
console.log(`Manual Session: ${isRunning ? 'š¢ Running' : 'š“ Stopped'}`);
|
|
90
102
|
|
|
91
103
|
// Check OS Service Status
|
|
92
|
-
const os = require('os');
|
|
93
104
|
const platform = os.platform();
|
|
94
105
|
let serviceRunning = false;
|
|
95
106
|
try {
|
|
96
107
|
if (platform === 'darwin') {
|
|
97
108
|
const plistPath = path.join(os.homedir(), 'Library', 'LaunchAgents', 'com.quark.daemon.plist');
|
|
98
109
|
if (fs.existsSync(plistPath)) {
|
|
99
|
-
const
|
|
100
|
-
serviceRunning =
|
|
110
|
+
const svcOut = require('child_process').execSync('launchctl list | grep com.quark.daemon', { encoding: 'utf8' });
|
|
111
|
+
serviceRunning = svcOut.includes('com.quark.daemon');
|
|
101
112
|
}
|
|
102
113
|
} else if (platform === 'linux') {
|
|
103
114
|
const servicePath = path.join(os.homedir(), '.config', 'systemd', 'user', 'quark.service');
|
|
104
115
|
if (fs.existsSync(servicePath)) {
|
|
105
|
-
const
|
|
106
|
-
serviceRunning =
|
|
116
|
+
const svcOut = require('child_process').execSync('systemctl --user is-active quark.service', { encoding: 'utf8' });
|
|
117
|
+
serviceRunning = svcOut.trim() === 'active';
|
|
107
118
|
}
|
|
108
119
|
} else if (platform === 'win32') {
|
|
109
120
|
const vbsPath = path.join(process.env.APPDATA, 'Microsoft', 'Windows', 'Start Menu', 'Programs', 'Startup', 'quark.vbs');
|
|
110
121
|
if (fs.existsSync(vbsPath)) {
|
|
111
|
-
const
|
|
112
|
-
serviceRunning =
|
|
122
|
+
const svcOut = require('child_process').execSync('wmic process where "CommandLine like \'%daemon.js%\'" get ProcessId', { encoding: 'utf8' });
|
|
123
|
+
serviceRunning = svcOut.includes('ProcessId') && svcOut.trim().split('\n').length > 1;
|
|
113
124
|
}
|
|
114
125
|
}
|
|
115
126
|
} catch (e) {
|
|
@@ -122,6 +133,7 @@ switch (command) {
|
|
|
122
133
|
console.log(`\nš” Tip: Run 'quark install' to configure auto-start on boot.`);
|
|
123
134
|
}
|
|
124
135
|
break;
|
|
136
|
+
}
|
|
125
137
|
|
|
126
138
|
case 'mcp':
|
|
127
139
|
// Starts the MCP Stdio server (used by LLMs like Claude Desktop)
|
package/cli/src/daemon.js
CHANGED
|
@@ -160,6 +160,7 @@ function injectForTarget(app, result) {
|
|
|
160
160
|
function shutdown() {
|
|
161
161
|
logEvent('INFO', 'Shutting down Quark Daemon gracefully...');
|
|
162
162
|
clearInterval(pollInterval);
|
|
163
|
+
network.shutdown();
|
|
163
164
|
server.close(() => {
|
|
164
165
|
logEvent('INFO', 'MCP Bridge API closed.');
|
|
165
166
|
process.exit(0);
|
package/cli/src/installer.js
CHANGED
|
@@ -44,8 +44,10 @@ function installService() {
|
|
|
44
44
|
|
|
45
45
|
fs.mkdirSync(path.dirname(plistPath), { recursive: true });
|
|
46
46
|
fs.writeFileSync(plistPath, plistContent);
|
|
47
|
-
|
|
48
|
-
execSync(
|
|
47
|
+
// Use bootstrap/bootout (macOS 12+ preferred API) with load/unload as fallback
|
|
48
|
+
const uid = execSync('id -u', { encoding: 'utf8' }).trim();
|
|
49
|
+
try { execSync(`launchctl bootout gui/${uid} ${plistPath}`, { stdio: 'ignore' }); } catch(e) {}
|
|
50
|
+
execSync(`launchctl bootstrap gui/${uid} ${plistPath}`);
|
|
49
51
|
console.log('ā
macOS LaunchAgent installed and started.');
|
|
50
52
|
|
|
51
53
|
} else if (platform === 'linux') {
|
|
@@ -98,7 +100,8 @@ function uninstallService() {
|
|
|
98
100
|
if (platform === 'darwin') {
|
|
99
101
|
const plistPath = path.join(os.homedir(), 'Library', 'LaunchAgents', 'com.quark.daemon.plist');
|
|
100
102
|
if (fs.existsSync(plistPath)) {
|
|
101
|
-
execSync(
|
|
103
|
+
const uid = execSync('id -u', { encoding: 'utf8' }).trim();
|
|
104
|
+
try { execSync(`launchctl bootout gui/${uid} com.quark.daemon`, { stdio: 'ignore' }); } catch(e) {}
|
|
102
105
|
fs.unlinkSync(plistPath);
|
|
103
106
|
}
|
|
104
107
|
} else if (platform === 'linux') {
|
package/cli/src/network.js
CHANGED
|
@@ -88,7 +88,7 @@ function broadcast(text, html = null) {
|
|
|
88
88
|
nodeId: NODE_ID,
|
|
89
89
|
payload: { text, html }
|
|
90
90
|
});
|
|
91
|
-
|
|
91
|
+
|
|
92
92
|
peers.forEach((ws) => {
|
|
93
93
|
if (ws.readyState === WebSocket.OPEN) {
|
|
94
94
|
ws.send(payload);
|
|
@@ -96,4 +96,11 @@ function broadcast(text, html = null) {
|
|
|
96
96
|
});
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
function shutdown() {
|
|
100
|
+
peers.forEach((ws) => ws.terminate());
|
|
101
|
+
peers.clear();
|
|
102
|
+
if (wss) wss.close();
|
|
103
|
+
if (bonjourInstance) bonjourInstance.destroy();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
module.exports = { init, broadcast, shutdown };
|