clocktopus 1.0.7 → 1.1.0

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 CHANGED
@@ -47,16 +47,18 @@ That's it. Start/stop timers from the Home tab.
47
47
 
48
48
  ### Commands
49
49
 
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 (foreground) |
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 PM2_NAME = 'clocktopus-monitor';
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('Monitor system idle time and screen state, and stop the Clockify timer if idle or screen is off.')
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) {
@@ -275,6 +275,56 @@ program
275
275
  .action(() => {
276
276
  startDashboard();
277
277
  });
278
+ const isDev = __dirname.includes('/Projects/') || __dirname.includes('/src/');
279
+ const MONITOR_PM2_NAME = isDev ? 'clocktopus-monitor-dev' : 'clocktopus-monitor';
280
+ const DASH_PM2_NAME = isDev ? 'clocktopus-dash-dev' : 'clocktopus-dash';
281
+ program
282
+ .command('monitor')
283
+ .description('Start idle monitor as a background daemon.')
284
+ .action(async () => {
285
+ const { execSync } = await import('child_process');
286
+ const bunPath = execSync('which bun', { encoding: 'utf-8' }).trim();
287
+ const scriptPath = path.join(__dirname, 'index.js');
288
+ try {
289
+ try {
290
+ execSync(`bunx pm2 delete ${MONITOR_PM2_NAME}`, { stdio: 'ignore' });
291
+ }
292
+ catch { }
293
+ execSync(`bunx pm2 start ${scriptPath} --name ${MONITOR_PM2_NAME} --interpreter ${bunPath} -- monitor:run`, {
294
+ stdio: 'inherit',
295
+ });
296
+ console.log(chalk.green('Idle monitor started in background.'));
297
+ console.log(chalk.gray(' Stop: clocktopus monitor:stop'));
298
+ console.log(chalk.gray(' Logs: clocktopus monitor:logs'));
299
+ }
300
+ catch {
301
+ console.error(chalk.red('Failed to start monitor.'));
302
+ }
303
+ });
304
+ program
305
+ .command('monitor:stop')
306
+ .description('Stop the idle monitor daemon.')
307
+ .action(async () => {
308
+ const { execSync } = await import('child_process');
309
+ try {
310
+ execSync(`bunx pm2 stop ${MONITOR_PM2_NAME}`, { stdio: 'inherit' });
311
+ }
312
+ catch {
313
+ console.log(chalk.yellow('Monitor is not running.'));
314
+ }
315
+ });
316
+ program
317
+ .command('monitor:logs')
318
+ .description('Show idle monitor logs.')
319
+ .action(async () => {
320
+ const { execSync } = await import('child_process');
321
+ try {
322
+ execSync(`bunx pm2 logs ${MONITOR_PM2_NAME} --lines 50`, { stdio: 'inherit' });
323
+ }
324
+ catch {
325
+ console.log(chalk.yellow('Monitor is not running.'));
326
+ }
327
+ });
278
328
  program
279
329
  .command('serve')
280
330
  .description('Start dashboard as a background daemon (PM2).')
@@ -283,12 +333,11 @@ program
283
333
  const bunPath = execSync('which bun', { encoding: 'utf-8' }).trim();
284
334
  const scriptPath = path.join(__dirname, 'index.js');
285
335
  try {
286
- // Stop existing if running
287
336
  try {
288
- execSync('bunx pm2 delete clocktopus-dash', { stdio: 'ignore' });
337
+ execSync(`bunx pm2 delete ${DASH_PM2_NAME}`, { stdio: 'ignore' });
289
338
  }
290
339
  catch { }
291
- execSync(`bunx pm2 start ${scriptPath} --name clocktopus-dash --interpreter ${bunPath} -- dash`, {
340
+ execSync(`bunx pm2 start ${scriptPath} --name ${DASH_PM2_NAME} --interpreter ${bunPath} -- dash`, {
292
341
  stdio: 'inherit',
293
342
  });
294
343
  console.log(chalk.green('Dashboard running at http://localhost:4001'));
@@ -305,7 +354,7 @@ program
305
354
  .action(async () => {
306
355
  const { execSync } = await import('child_process');
307
356
  try {
308
- execSync('bunx pm2 stop clocktopus-dash', { stdio: 'inherit' });
357
+ execSync(`bunx pm2 stop ${DASH_PM2_NAME}`, { stdio: 'inherit' });
309
358
  }
310
359
  catch {
311
360
  console.log(chalk.yellow('Dashboard is not running.'));
@@ -317,7 +366,7 @@ program
317
366
  .action(async () => {
318
367
  const { execSync } = await import('child_process');
319
368
  try {
320
- execSync('bunx pm2 logs clocktopus-dash --lines 50', { stdio: 'inherit' });
369
+ execSync(`bunx pm2 logs ${DASH_PM2_NAME} --lines 50`, { stdio: 'inherit' });
321
370
  }
322
371
  catch {
323
372
  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
- const DB_DIR = path.join(process.cwd(), 'data/db');
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clocktopus",
3
- "version": "1.0.7",
3
+ "version": "1.1.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -18,12 +18,11 @@
18
18
  "postinstall": "cd node_modules/macos-notification-state && node-gyp rebuild 2>/dev/null; cd ../desktop-idle && node-gyp rebuild 2>/dev/null; true",
19
19
  "lint": "eslint . --ext .ts",
20
20
  "clock": "bun dist/index.js",
21
- "clockd": "bunx pm2 start dist/index.js --name clocktopus --",
22
- "monitor": "bun run clockd monitor",
23
- "monitor:restart": "bunx pm2 restart clocktopus",
24
- "monitor:stop": "bunx pm2 stop clocktopus",
25
- "monitor:logs": "bunx pm2 logs clocktopus",
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",