clocktopus 1.1.2 → 1.1.4
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 +16 -0
- package/dist/dashboard/routes/monitor.js +6 -5
- package/dist/index.js +11 -8
- package/dist/lib/ensure-native-addons.js +76 -0
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -150,6 +150,22 @@ Go to **System Settings > Notifications** and ensure **terminal-notifier** has n
|
|
|
150
150
|
|
|
151
151
|
Enable **Require password immediately** in System Settings > Lock Screen.
|
|
152
152
|
|
|
153
|
+
### Bun installs an old version
|
|
154
|
+
|
|
155
|
+
Bun caches registry data aggressively. Clear the cache and reinstall:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
bun pm cache rm && bun i -g clocktopus@latest
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Native addons not built (untrusted postinstall)
|
|
162
|
+
|
|
163
|
+
If `bun install -g` skips the postinstall script, the monitor will auto-build native addons on first run (requires Node.js for `npx`). Alternatively, trust the package and reinstall:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
bun pm trust clocktopus && bun i -g clocktopus
|
|
167
|
+
```
|
|
168
|
+
|
|
153
169
|
### Linux
|
|
154
170
|
|
|
155
171
|
```bash
|
|
@@ -7,6 +7,7 @@ const __dirname = path.dirname(__filename);
|
|
|
7
7
|
const SCRIPT_PATH = path.resolve(__dirname, '../../index.js');
|
|
8
8
|
const isDev = SCRIPT_PATH.includes('/Projects/') || SCRIPT_PATH.includes('/src/');
|
|
9
9
|
const PM2_NAME = isDev ? 'clocktopus-monitor-dev' : 'clocktopus-monitor';
|
|
10
|
+
const pm2Bin = path.resolve(__dirname, '../../node_modules/.bin/pm2');
|
|
10
11
|
const monitorRoutes = new Hono();
|
|
11
12
|
function pm2Exec(command) {
|
|
12
13
|
try {
|
|
@@ -20,7 +21,7 @@ function pm2Exec(command) {
|
|
|
20
21
|
}
|
|
21
22
|
monitorRoutes.get('/monitor/status', (c) => {
|
|
22
23
|
try {
|
|
23
|
-
const output = execSync('
|
|
24
|
+
const output = execSync('${pm2Bin} jlist', { encoding: 'utf-8', timeout: 10000 });
|
|
24
25
|
const processes = JSON.parse(output);
|
|
25
26
|
const proc = processes.find((p) => p.name === PM2_NAME);
|
|
26
27
|
if (!proc) {
|
|
@@ -41,18 +42,18 @@ monitorRoutes.post('/monitor/start', (c) => {
|
|
|
41
42
|
const bunPath = execSync('which bun', { encoding: 'utf-8' }).trim();
|
|
42
43
|
// Delete any existing process to avoid duplicates
|
|
43
44
|
try {
|
|
44
|
-
execSync(
|
|
45
|
+
execSync(`${pm2Bin} delete ${PM2_NAME}`, { stdio: 'ignore' });
|
|
45
46
|
}
|
|
46
47
|
catch { }
|
|
47
|
-
const result = pm2Exec(
|
|
48
|
+
const result = pm2Exec(`${pm2Bin} start ${SCRIPT_PATH} --name ${PM2_NAME} --interpreter ${bunPath} -- monitor:run`);
|
|
48
49
|
return c.json(result);
|
|
49
50
|
});
|
|
50
51
|
monitorRoutes.post('/monitor/stop', (c) => {
|
|
51
|
-
const result = pm2Exec(
|
|
52
|
+
const result = pm2Exec(`${pm2Bin} stop ${PM2_NAME}`);
|
|
52
53
|
return c.json(result);
|
|
53
54
|
});
|
|
54
55
|
monitorRoutes.post('/monitor/restart', (c) => {
|
|
55
|
-
const result = pm2Exec(
|
|
56
|
+
const result = pm2Exec(`${pm2Bin} restart ${PM2_NAME}`);
|
|
56
57
|
return c.json(result);
|
|
57
58
|
});
|
|
58
59
|
export default monitorRoutes;
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import { fileURLToPath } from 'url';
|
|
|
9
9
|
import { completeLatestSession, getLatestSession } from './lib/db.js';
|
|
10
10
|
import { stopJiraTimer } from './lib/jira.js';
|
|
11
11
|
import { startDashboard } from './dashboard/server.js';
|
|
12
|
+
import { ensureNativeAddons } from './lib/ensure-native-addons.js';
|
|
12
13
|
const __filename = fileURLToPath(import.meta.url);
|
|
13
14
|
const __dirname = path.dirname(__filename);
|
|
14
15
|
const program = new Command();
|
|
@@ -286,19 +287,21 @@ program
|
|
|
286
287
|
const isDev = __dirname.includes('/Projects/') || __dirname.includes('/src/');
|
|
287
288
|
const MONITOR_PM2_NAME = isDev ? 'clocktopus-monitor-dev' : 'clocktopus-monitor';
|
|
288
289
|
const DASH_PM2_NAME = isDev ? 'clocktopus-dash-dev' : 'clocktopus-dash';
|
|
290
|
+
const pm2Bin = path.join(__dirname, '..', 'node_modules', '.bin', 'pm2');
|
|
289
291
|
program
|
|
290
292
|
.command('monitor')
|
|
291
293
|
.description('Start idle monitor as a background daemon.')
|
|
292
294
|
.action(async () => {
|
|
295
|
+
ensureNativeAddons();
|
|
293
296
|
const { execSync } = await import('child_process');
|
|
294
297
|
const bunPath = execSync('which bun', { encoding: 'utf-8' }).trim();
|
|
295
298
|
const scriptPath = path.join(__dirname, 'index.js');
|
|
296
299
|
try {
|
|
297
300
|
try {
|
|
298
|
-
execSync(
|
|
301
|
+
execSync(`${pm2Bin} delete ${MONITOR_PM2_NAME}`, { stdio: 'ignore' });
|
|
299
302
|
}
|
|
300
303
|
catch { }
|
|
301
|
-
execSync(
|
|
304
|
+
execSync(`${pm2Bin} start ${scriptPath} --name ${MONITOR_PM2_NAME} --interpreter ${bunPath} -- monitor:run`, {
|
|
302
305
|
stdio: 'inherit',
|
|
303
306
|
});
|
|
304
307
|
console.log(chalk.green('Idle monitor started in background.'));
|
|
@@ -315,7 +318,7 @@ program
|
|
|
315
318
|
.action(async () => {
|
|
316
319
|
const { execSync } = await import('child_process');
|
|
317
320
|
try {
|
|
318
|
-
execSync(
|
|
321
|
+
execSync(`${pm2Bin} stop ${MONITOR_PM2_NAME}`, { stdio: 'inherit' });
|
|
319
322
|
}
|
|
320
323
|
catch {
|
|
321
324
|
console.log(chalk.yellow('Monitor is not running.'));
|
|
@@ -327,7 +330,7 @@ program
|
|
|
327
330
|
.action(async () => {
|
|
328
331
|
const { execSync } = await import('child_process');
|
|
329
332
|
try {
|
|
330
|
-
execSync(
|
|
333
|
+
execSync(`${pm2Bin} logs ${MONITOR_PM2_NAME} --lines 50`, { stdio: 'inherit' });
|
|
331
334
|
}
|
|
332
335
|
catch {
|
|
333
336
|
console.log(chalk.yellow('Monitor is not running.'));
|
|
@@ -342,10 +345,10 @@ program
|
|
|
342
345
|
const scriptPath = path.join(__dirname, 'index.js');
|
|
343
346
|
try {
|
|
344
347
|
try {
|
|
345
|
-
execSync(
|
|
348
|
+
execSync(`${pm2Bin} delete ${DASH_PM2_NAME}`, { stdio: 'ignore' });
|
|
346
349
|
}
|
|
347
350
|
catch { }
|
|
348
|
-
execSync(
|
|
351
|
+
execSync(`${pm2Bin} start ${scriptPath} --name ${DASH_PM2_NAME} --interpreter ${bunPath} -- dash`, {
|
|
349
352
|
stdio: 'inherit',
|
|
350
353
|
});
|
|
351
354
|
console.log(chalk.green('Dashboard running at http://localhost:4001'));
|
|
@@ -362,7 +365,7 @@ program
|
|
|
362
365
|
.action(async () => {
|
|
363
366
|
const { execSync } = await import('child_process');
|
|
364
367
|
try {
|
|
365
|
-
execSync(
|
|
368
|
+
execSync(`${pm2Bin} stop ${DASH_PM2_NAME}`, { stdio: 'inherit' });
|
|
366
369
|
}
|
|
367
370
|
catch {
|
|
368
371
|
console.log(chalk.yellow('Dashboard is not running.'));
|
|
@@ -374,7 +377,7 @@ program
|
|
|
374
377
|
.action(async () => {
|
|
375
378
|
const { execSync } = await import('child_process');
|
|
376
379
|
try {
|
|
377
|
-
execSync(
|
|
380
|
+
execSync(`${pm2Bin} logs ${DASH_PM2_NAME} --lines 50`, { stdio: 'inherit' });
|
|
378
381
|
}
|
|
379
382
|
catch {
|
|
380
383
|
console.log(chalk.yellow('Dashboard is not running.'));
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { execSync } from 'child_process';
|
|
2
|
+
import { createRequire } from 'module';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
6
|
+
const NATIVE_MODULES = [
|
|
7
|
+
{ name: 'macos-notification-state', addonName: 'notificationstate' },
|
|
8
|
+
{ name: 'desktop-idle', addonName: 'desktopIdle' },
|
|
9
|
+
];
|
|
10
|
+
function hasBuiltAddon(moduleName, addonName) {
|
|
11
|
+
try {
|
|
12
|
+
const modulePath = path.dirname(require.resolve(`${moduleName}/package.json`));
|
|
13
|
+
const nodePath = path.join(modulePath, 'build', 'Release', `${addonName}.node`);
|
|
14
|
+
return fs.existsSync(nodePath);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function findNodeGyp() {
|
|
21
|
+
try {
|
|
22
|
+
execSync('node-gyp --version', { stdio: 'ignore' });
|
|
23
|
+
return 'node-gyp';
|
|
24
|
+
}
|
|
25
|
+
catch { }
|
|
26
|
+
try {
|
|
27
|
+
execSync('npx --version', { stdio: 'ignore' });
|
|
28
|
+
return 'npx node-gyp';
|
|
29
|
+
}
|
|
30
|
+
catch { }
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
function buildModule(moduleName, nodeGypCmd) {
|
|
34
|
+
let modulePath;
|
|
35
|
+
try {
|
|
36
|
+
modulePath = path.dirname(require.resolve(`${moduleName}/package.json`));
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
if (!fs.existsSync(path.join(modulePath, 'binding.gyp')))
|
|
42
|
+
return false;
|
|
43
|
+
try {
|
|
44
|
+
console.log(`Building native addon: ${moduleName}...`);
|
|
45
|
+
execSync(`${nodeGypCmd} rebuild`, { cwd: modulePath, stdio: 'inherit' });
|
|
46
|
+
console.log(`Built ${moduleName} successfully.`);
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export function ensureNativeAddons() {
|
|
54
|
+
if (process.platform !== 'darwin')
|
|
55
|
+
return;
|
|
56
|
+
const missing = NATIVE_MODULES.filter((m) => !hasBuiltAddon(m.name, m.addonName));
|
|
57
|
+
if (missing.length === 0)
|
|
58
|
+
return;
|
|
59
|
+
console.log(`Native addons not built: ${missing.map((m) => m.name).join(', ')}. Attempting to build...`);
|
|
60
|
+
const nodeGypCmd = findNodeGyp();
|
|
61
|
+
if (!nodeGypCmd) {
|
|
62
|
+
console.warn('Warning: node-gyp not found. Native addons could not be built.');
|
|
63
|
+
console.warn(' Install Node.js (includes npx) then restart, or run:');
|
|
64
|
+
console.warn(' bun pm trust clocktopus && bun install -g clocktopus');
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const failed = [];
|
|
68
|
+
for (const mod of missing) {
|
|
69
|
+
if (!buildModule(mod.name, nodeGypCmd)) {
|
|
70
|
+
failed.push(mod.name);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (failed.length > 0) {
|
|
74
|
+
console.warn(`Warning: Failed to build: ${failed.join(', ')}. Monitor features may not work.`);
|
|
75
|
+
}
|
|
76
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clocktopus",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -21,9 +21,9 @@
|
|
|
21
21
|
"clock": "bun dist/index.js",
|
|
22
22
|
"monitor": "bun dist/index.js monitor",
|
|
23
23
|
"monitor:stop": "bun dist/index.js monitor:stop",
|
|
24
|
-
"monitor:restart": "
|
|
24
|
+
"monitor:restart": "node_modules/.bin/pm2 restart clocktopus-monitor-dev",
|
|
25
25
|
"monitor:logs": "bun dist/index.js monitor:logs",
|
|
26
|
-
"monitor:status": "
|
|
26
|
+
"monitor:status": "node_modules/.bin/pm2 status clocktopus-monitor-dev",
|
|
27
27
|
"prepare": "husky",
|
|
28
28
|
"dashboard": "bun -e \"import('./dist/dashboard/server.js').then(m => m.startDashboard())\"",
|
|
29
29
|
"db:cleanup": "bun dist/scripts/db-cleanup.js",
|