clocktopus 1.1.1 → 1.1.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/dist/index.js +3 -1
- package/dist/lib/ensure-native-addons.js +76 -0
- package/package.json +3 -2
- package/scripts/postinstall.cjs +67 -0
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();
|
|
@@ -186,7 +187,7 @@ program
|
|
|
186
187
|
const eligible = latestSession.isAutoCompleted && completedAt > twoHoursAgo && !!latestSession.projectId;
|
|
187
188
|
if (!eligible)
|
|
188
189
|
return;
|
|
189
|
-
await clockify.startTimer(workspaceId, latestSession.projectId, latestSession.description);
|
|
190
|
+
await clockify.startTimer(workspaceId, latestSession.projectId, latestSession.description, latestSession.jiraTicket ?? undefined);
|
|
190
191
|
console.log(chalk.green('Timer restarted for the last used project.'));
|
|
191
192
|
lastResumeAt = Date.now();
|
|
192
193
|
}
|
|
@@ -290,6 +291,7 @@ program
|
|
|
290
291
|
.command('monitor')
|
|
291
292
|
.description('Start idle monitor as a background daemon.')
|
|
292
293
|
.action(async () => {
|
|
294
|
+
ensureNativeAddons();
|
|
293
295
|
const { execSync } = await import('child_process');
|
|
294
296
|
const bunPath = execSync('which bun', { encoding: 'utf-8' }).trim();
|
|
295
297
|
const scriptPath = path.join(__dirname, 'index.js');
|
|
@@ -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.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -10,12 +10,13 @@
|
|
|
10
10
|
"files": [
|
|
11
11
|
"dist",
|
|
12
12
|
"data/.gitkeep",
|
|
13
|
+
"scripts/postinstall.cjs",
|
|
13
14
|
"!dist/desktop"
|
|
14
15
|
],
|
|
15
16
|
"scripts": {
|
|
16
17
|
"build": "bunx tsc",
|
|
17
18
|
"prepublishOnly": "bunx tsc",
|
|
18
|
-
"postinstall": "node
|
|
19
|
+
"postinstall": "node scripts/postinstall.cjs",
|
|
19
20
|
"lint": "eslint . --ext .ts",
|
|
20
21
|
"clock": "bun dist/index.js",
|
|
21
22
|
"monitor": "bun dist/index.js monitor",
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { execSync } = require('child_process');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const nativeModules = ['macos-notification-state', 'desktop-idle'];
|
|
7
|
+
|
|
8
|
+
function findNodeGyp() {
|
|
9
|
+
// Try plain node-gyp first (globally installed)
|
|
10
|
+
try {
|
|
11
|
+
execSync('node-gyp --version', { stdio: 'ignore' });
|
|
12
|
+
return 'node-gyp';
|
|
13
|
+
} catch {}
|
|
14
|
+
|
|
15
|
+
// Try npx (comes with Node.js)
|
|
16
|
+
try {
|
|
17
|
+
execSync('npx --version', { stdio: 'ignore' });
|
|
18
|
+
return 'npx node-gyp';
|
|
19
|
+
} catch {}
|
|
20
|
+
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function rebuildModule(moduleName, nodeGypCmd) {
|
|
25
|
+
let modulePath;
|
|
26
|
+
try {
|
|
27
|
+
modulePath = path.dirname(require.resolve(`${moduleName}/package.json`));
|
|
28
|
+
} catch {
|
|
29
|
+
// Module not installed (e.g. optional dependency on wrong platform)
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const bindingGyp = path.join(modulePath, 'binding.gyp');
|
|
34
|
+
try {
|
|
35
|
+
require('fs').accessSync(bindingGyp);
|
|
36
|
+
} catch {
|
|
37
|
+
// No binding.gyp, not a native module
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
console.log(`Building native addon: ${moduleName}...`);
|
|
43
|
+
execSync(`${nodeGypCmd} rebuild`, { cwd: modulePath, stdio: 'inherit' });
|
|
44
|
+
console.log(`Built ${moduleName} successfully.`);
|
|
45
|
+
} catch (err) {
|
|
46
|
+
console.warn(`Warning: Failed to build ${moduleName}. The monitor feature may not work.`);
|
|
47
|
+
console.warn(` You can try manually: cd ${modulePath} && npx node-gyp rebuild`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Only build on macOS — these are macOS-only native addons
|
|
52
|
+
if (process.platform !== 'darwin') {
|
|
53
|
+
console.log('Skipping native addon build (not macOS).');
|
|
54
|
+
process.exit(0);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const nodeGypCmd = findNodeGyp();
|
|
58
|
+
if (!nodeGypCmd) {
|
|
59
|
+
console.warn('Warning: node-gyp not found. Native addons were not built.');
|
|
60
|
+
console.warn(' Install node-gyp: npm install -g node-gyp');
|
|
61
|
+
console.warn(' Then rebuild: cd node_modules/macos-notification-state && node-gyp rebuild');
|
|
62
|
+
process.exit(0);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
for (const mod of nativeModules) {
|
|
66
|
+
rebuildModule(mod, nodeGypCmd);
|
|
67
|
+
}
|