clocktopus 1.0.7 → 1.1.1
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 +12 -10
- package/dist/dashboard/routes/monitor.js +3 -2
- package/dist/index.js +64 -7
- package/dist/lib/db.js +9 -1
- package/dist/lib/jira.js +8 -2
- package/package.json +7 -8
package/README.md
CHANGED
|
@@ -47,16 +47,18 @@ That's it. Start/stop timers from the Home tab.
|
|
|
47
47
|
|
|
48
48
|
### Commands
|
|
49
49
|
|
|
50
|
-
| Command
|
|
51
|
-
|
|
|
52
|
-
| `clocktopus dash`
|
|
53
|
-
| `clocktopus serve`
|
|
54
|
-
| `clocktopus serve:stop`
|
|
55
|
-
| `clocktopus serve:logs`
|
|
56
|
-
| `clocktopus start`
|
|
57
|
-
| `clocktopus stop`
|
|
58
|
-
| `clocktopus status`
|
|
59
|
-
| `clocktopus monitor`
|
|
50
|
+
| Command | Description |
|
|
51
|
+
| ------------------------- | --------------------------------------- |
|
|
52
|
+
| `clocktopus dash` | Start dashboard (foreground) |
|
|
53
|
+
| `clocktopus serve` | Start dashboard as background daemon |
|
|
54
|
+
| `clocktopus serve:stop` | Stop the dashboard daemon |
|
|
55
|
+
| `clocktopus serve:logs` | View dashboard daemon logs |
|
|
56
|
+
| `clocktopus start` | Start a timer (interactive) |
|
|
57
|
+
| `clocktopus stop` | Stop the current timer |
|
|
58
|
+
| `clocktopus status` | Check timer status |
|
|
59
|
+
| `clocktopus monitor` | Start idle monitor as background daemon |
|
|
60
|
+
| `clocktopus monitor:stop` | Stop the idle monitor |
|
|
61
|
+
| `clocktopus monitor:logs` | View idle monitor logs |
|
|
60
62
|
|
|
61
63
|
### Desktop App (macOS)
|
|
62
64
|
|
|
@@ -5,7 +5,8 @@ import { fileURLToPath } from 'url';
|
|
|
5
5
|
const __filename = fileURLToPath(import.meta.url);
|
|
6
6
|
const __dirname = path.dirname(__filename);
|
|
7
7
|
const SCRIPT_PATH = path.resolve(__dirname, '../../index.js');
|
|
8
|
-
const
|
|
8
|
+
const isDev = SCRIPT_PATH.includes('/Projects/') || SCRIPT_PATH.includes('/src/');
|
|
9
|
+
const PM2_NAME = isDev ? 'clocktopus-monitor-dev' : 'clocktopus-monitor';
|
|
9
10
|
const monitorRoutes = new Hono();
|
|
10
11
|
function pm2Exec(command) {
|
|
11
12
|
try {
|
|
@@ -43,7 +44,7 @@ monitorRoutes.post('/monitor/start', (c) => {
|
|
|
43
44
|
execSync(`bunx pm2 delete ${PM2_NAME}`, { stdio: 'ignore' });
|
|
44
45
|
}
|
|
45
46
|
catch { }
|
|
46
|
-
const result = pm2Exec(`bunx pm2 start ${SCRIPT_PATH} --name ${PM2_NAME} --interpreter ${bunPath} -- monitor`);
|
|
47
|
+
const result = pm2Exec(`bunx pm2 start ${SCRIPT_PATH} --name ${PM2_NAME} --interpreter ${bunPath} -- monitor:run`);
|
|
47
48
|
return c.json(result);
|
|
48
49
|
});
|
|
49
50
|
monitorRoutes.post('/monitor/stop', (c) => {
|
package/dist/index.js
CHANGED
|
@@ -137,8 +137,8 @@ function sleep(ms) {
|
|
|
137
137
|
return new Promise((res) => setTimeout(res, ms));
|
|
138
138
|
}
|
|
139
139
|
program
|
|
140
|
-
.command('monitor')
|
|
141
|
-
.description('
|
|
140
|
+
.command('monitor:run', { hidden: true })
|
|
141
|
+
.description('Run monitor in foreground (used by PM2).')
|
|
142
142
|
.action(async () => {
|
|
143
143
|
const { workspaceId, userId } = await getWorkspaceAndUser();
|
|
144
144
|
async function stopTimerAndLog(reason) {
|
|
@@ -201,6 +201,9 @@ program
|
|
|
201
201
|
if (!getSessionState) {
|
|
202
202
|
throw new Error('getSessionState not found in module');
|
|
203
203
|
}
|
|
204
|
+
// Verify the native addon actually works before setting up polling
|
|
205
|
+
const initialState = getSessionState();
|
|
206
|
+
console.log(chalk.gray(`Initial session state: ${initialState}`));
|
|
204
207
|
pollInterval = setInterval(async () => {
|
|
205
208
|
try {
|
|
206
209
|
const state = getSessionState();
|
|
@@ -217,6 +220,11 @@ program
|
|
|
217
220
|
}
|
|
218
221
|
catch (error) {
|
|
219
222
|
console.error('Error polling session state:', error);
|
|
223
|
+
if (pollInterval) {
|
|
224
|
+
clearInterval(pollInterval);
|
|
225
|
+
pollInterval = null;
|
|
226
|
+
console.error(chalk.red('Display monitoring disabled due to repeated errors.'));
|
|
227
|
+
}
|
|
220
228
|
}
|
|
221
229
|
}, 3000);
|
|
222
230
|
}
|
|
@@ -275,6 +283,56 @@ program
|
|
|
275
283
|
.action(() => {
|
|
276
284
|
startDashboard();
|
|
277
285
|
});
|
|
286
|
+
const isDev = __dirname.includes('/Projects/') || __dirname.includes('/src/');
|
|
287
|
+
const MONITOR_PM2_NAME = isDev ? 'clocktopus-monitor-dev' : 'clocktopus-monitor';
|
|
288
|
+
const DASH_PM2_NAME = isDev ? 'clocktopus-dash-dev' : 'clocktopus-dash';
|
|
289
|
+
program
|
|
290
|
+
.command('monitor')
|
|
291
|
+
.description('Start idle monitor as a background daemon.')
|
|
292
|
+
.action(async () => {
|
|
293
|
+
const { execSync } = await import('child_process');
|
|
294
|
+
const bunPath = execSync('which bun', { encoding: 'utf-8' }).trim();
|
|
295
|
+
const scriptPath = path.join(__dirname, 'index.js');
|
|
296
|
+
try {
|
|
297
|
+
try {
|
|
298
|
+
execSync(`bunx pm2 delete ${MONITOR_PM2_NAME}`, { stdio: 'ignore' });
|
|
299
|
+
}
|
|
300
|
+
catch { }
|
|
301
|
+
execSync(`bunx pm2 start ${scriptPath} --name ${MONITOR_PM2_NAME} --interpreter ${bunPath} -- monitor:run`, {
|
|
302
|
+
stdio: 'inherit',
|
|
303
|
+
});
|
|
304
|
+
console.log(chalk.green('Idle monitor started in background.'));
|
|
305
|
+
console.log(chalk.gray(' Stop: clocktopus monitor:stop'));
|
|
306
|
+
console.log(chalk.gray(' Logs: clocktopus monitor:logs'));
|
|
307
|
+
}
|
|
308
|
+
catch {
|
|
309
|
+
console.error(chalk.red('Failed to start monitor.'));
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
program
|
|
313
|
+
.command('monitor:stop')
|
|
314
|
+
.description('Stop the idle monitor daemon.')
|
|
315
|
+
.action(async () => {
|
|
316
|
+
const { execSync } = await import('child_process');
|
|
317
|
+
try {
|
|
318
|
+
execSync(`bunx pm2 stop ${MONITOR_PM2_NAME}`, { stdio: 'inherit' });
|
|
319
|
+
}
|
|
320
|
+
catch {
|
|
321
|
+
console.log(chalk.yellow('Monitor is not running.'));
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
program
|
|
325
|
+
.command('monitor:logs')
|
|
326
|
+
.description('Show idle monitor logs.')
|
|
327
|
+
.action(async () => {
|
|
328
|
+
const { execSync } = await import('child_process');
|
|
329
|
+
try {
|
|
330
|
+
execSync(`bunx pm2 logs ${MONITOR_PM2_NAME} --lines 50`, { stdio: 'inherit' });
|
|
331
|
+
}
|
|
332
|
+
catch {
|
|
333
|
+
console.log(chalk.yellow('Monitor is not running.'));
|
|
334
|
+
}
|
|
335
|
+
});
|
|
278
336
|
program
|
|
279
337
|
.command('serve')
|
|
280
338
|
.description('Start dashboard as a background daemon (PM2).')
|
|
@@ -283,12 +341,11 @@ program
|
|
|
283
341
|
const bunPath = execSync('which bun', { encoding: 'utf-8' }).trim();
|
|
284
342
|
const scriptPath = path.join(__dirname, 'index.js');
|
|
285
343
|
try {
|
|
286
|
-
// Stop existing if running
|
|
287
344
|
try {
|
|
288
|
-
execSync(
|
|
345
|
+
execSync(`bunx pm2 delete ${DASH_PM2_NAME}`, { stdio: 'ignore' });
|
|
289
346
|
}
|
|
290
347
|
catch { }
|
|
291
|
-
execSync(`bunx pm2 start ${scriptPath} --name
|
|
348
|
+
execSync(`bunx pm2 start ${scriptPath} --name ${DASH_PM2_NAME} --interpreter ${bunPath} -- dash`, {
|
|
292
349
|
stdio: 'inherit',
|
|
293
350
|
});
|
|
294
351
|
console.log(chalk.green('Dashboard running at http://localhost:4001'));
|
|
@@ -305,7 +362,7 @@ program
|
|
|
305
362
|
.action(async () => {
|
|
306
363
|
const { execSync } = await import('child_process');
|
|
307
364
|
try {
|
|
308
|
-
execSync(
|
|
365
|
+
execSync(`bunx pm2 stop ${DASH_PM2_NAME}`, { stdio: 'inherit' });
|
|
309
366
|
}
|
|
310
367
|
catch {
|
|
311
368
|
console.log(chalk.yellow('Dashboard is not running.'));
|
|
@@ -317,7 +374,7 @@ program
|
|
|
317
374
|
.action(async () => {
|
|
318
375
|
const { execSync } = await import('child_process');
|
|
319
376
|
try {
|
|
320
|
-
execSync(
|
|
377
|
+
execSync(`bunx pm2 logs ${DASH_PM2_NAME} --lines 50`, { stdio: 'inherit' });
|
|
321
378
|
}
|
|
322
379
|
catch {
|
|
323
380
|
console.log(chalk.yellow('Dashboard is not running.'));
|
package/dist/lib/db.js
CHANGED
|
@@ -2,7 +2,15 @@ import * as fs from 'fs';
|
|
|
2
2
|
import * as path from 'path';
|
|
3
3
|
import { Database } from 'bun:sqlite';
|
|
4
4
|
import { z } from 'zod';
|
|
5
|
-
|
|
5
|
+
function getDataDir() {
|
|
6
|
+
const scriptDir = path.dirname(new URL(import.meta.url).pathname);
|
|
7
|
+
const isDev = scriptDir.includes('/Projects/') || scriptDir.includes('/src/');
|
|
8
|
+
if (isDev) {
|
|
9
|
+
return path.join(process.cwd(), 'data/db');
|
|
10
|
+
}
|
|
11
|
+
return path.join(process.env.HOME || '~', '.clocktopus', 'data');
|
|
12
|
+
}
|
|
13
|
+
const DB_DIR = getDataDir();
|
|
6
14
|
const DB_PATH = path.join(DB_DIR, 'sessions.db');
|
|
7
15
|
if (!fs.existsSync(DB_DIR)) {
|
|
8
16
|
fs.mkdirSync(DB_DIR, { recursive: true });
|
package/dist/lib/jira.js
CHANGED
|
@@ -21,7 +21,10 @@ async function jiraApiRequest(endpoint, method, body) {
|
|
|
21
21
|
return response.data;
|
|
22
22
|
}
|
|
23
23
|
catch (error) {
|
|
24
|
-
if (error
|
|
24
|
+
if (axios.isAxiosError(error)) {
|
|
25
|
+
console.error('Error making Jira API request (OAuth):', error.message, error.response?.data);
|
|
26
|
+
}
|
|
27
|
+
else if (error instanceof Error) {
|
|
25
28
|
console.error('Error making Jira API request (OAuth):', error.message);
|
|
26
29
|
}
|
|
27
30
|
return null;
|
|
@@ -49,7 +52,10 @@ async function jiraApiRequest(endpoint, method, body) {
|
|
|
49
52
|
return response.data;
|
|
50
53
|
}
|
|
51
54
|
catch (error) {
|
|
52
|
-
if (error
|
|
55
|
+
if (axios.isAxiosError(error)) {
|
|
56
|
+
console.error('Error making Jira API request:', error.message, error.response?.data);
|
|
57
|
+
}
|
|
58
|
+
else if (error instanceof Error) {
|
|
53
59
|
console.error('Error making Jira API request:', error.message);
|
|
54
60
|
}
|
|
55
61
|
return null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clocktopus",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -15,15 +15,14 @@
|
|
|
15
15
|
"scripts": {
|
|
16
16
|
"build": "bunx tsc",
|
|
17
17
|
"prepublishOnly": "bunx tsc",
|
|
18
|
-
"postinstall": "
|
|
18
|
+
"postinstall": "node -e \"var p=require('path').dirname(require.resolve('macos-notification-state/package.json')); require('child_process').execSync('node-gyp rebuild',{cwd:p,stdio:'inherit'})\" 2>/dev/null; node -e \"var p=require('path').dirname(require.resolve('desktop-idle/package.json')); require('child_process').execSync('node-gyp rebuild',{cwd:p,stdio:'inherit'})\" 2>/dev/null; true",
|
|
19
19
|
"lint": "eslint . --ext .ts",
|
|
20
20
|
"clock": "bun dist/index.js",
|
|
21
|
-
"
|
|
22
|
-
"monitor": "bun
|
|
23
|
-
"monitor:restart": "bunx pm2 restart clocktopus",
|
|
24
|
-
"monitor:
|
|
25
|
-
"monitor:
|
|
26
|
-
"monitor:status": "bunx pm2 status clocktopus",
|
|
21
|
+
"monitor": "bun dist/index.js monitor",
|
|
22
|
+
"monitor:stop": "bun dist/index.js monitor:stop",
|
|
23
|
+
"monitor:restart": "bunx pm2 restart clocktopus-monitor-dev",
|
|
24
|
+
"monitor:logs": "bun dist/index.js monitor:logs",
|
|
25
|
+
"monitor:status": "bunx pm2 status clocktopus-monitor-dev",
|
|
27
26
|
"prepare": "husky",
|
|
28
27
|
"dashboard": "bun -e \"import('./dist/dashboard/server.js').then(m => m.startDashboard())\"",
|
|
29
28
|
"db:cleanup": "bun dist/scripts/db-cleanup.js",
|