clocktopus 1.10.1 → 1.10.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.
@@ -3,11 +3,11 @@ import { execSync } from 'child_process';
3
3
  import path from 'path';
4
4
  import { fileURLToPath } from 'url';
5
5
  import { createRequire } from 'module';
6
+ import { IS_DEV } from '../../lib/constants.js';
6
7
  const __filename = fileURLToPath(import.meta.url);
7
8
  const __dirname = path.dirname(__filename);
8
9
  const SCRIPT_PATH = path.resolve(__dirname, '../../index.js');
9
- const isDev = SCRIPT_PATH.includes('/Projects/') || SCRIPT_PATH.includes('/src/');
10
- const PM2_NAME = isDev ? 'clocktopus-monitor-dev' : 'clocktopus-monitor';
10
+ const PM2_NAME = IS_DEV ? 'clocktopus-monitor-dev' : 'clocktopus-monitor';
11
11
  const pm2Bin = path.join(path.dirname(createRequire(import.meta.url).resolve('pm2')), 'bin', 'pm2');
12
12
  const bunBin = (() => {
13
13
  try {
@@ -13,14 +13,15 @@ export function indexPage() {
13
13
  <style>
14
14
  * { box-sizing: border-box; margin: 0; padding: 0; }
15
15
  html.browser { background: #0d1117; }
16
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: transparent; color: #e1e4e8; padding: 2rem; }
16
+ html { border-radius: 12px; overflow: hidden; height: 100vh; background: transparent; }
17
+ body { border-radius: 12px; height: 100vh; overflow-y: auto; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: transparent; color: #e1e4e8; padding: 2rem; }
17
18
  h1 { font-size: 1.8rem; margin-bottom: 0; color: #fff; }
18
19
  h2 { font-size: 1.1rem; color: #fff; margin-bottom: 1rem; }
19
20
 
20
21
  /* Nav */
21
22
  .header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 1.5rem; }
22
- .nav { display: flex; gap: 0.25rem; background: #1c1f26; border-radius: 10px; padding: 0.3rem; }
23
- .nav-btn { margin-top: 0; padding: 0.5rem 1.25rem; border: none; border-radius: 6px; background: transparent; color: #8b949e; font-size: 0.9rem; cursor: pointer; }
23
+ .nav { display: flex; gap: 0.25rem; background: #1c1f26; border-radius: 10px; padding: 0.3rem; flex-wrap: nowrap; }
24
+ .nav-btn { margin-top: 0; padding: 0.5rem 0.85rem; border: none; border-radius: 6px; background: transparent; color: #8b949e; font-size: 0.9rem; cursor: pointer; white-space: nowrap; }
24
25
  .nav-btn:hover { color: #e1e4e8; }
25
26
  .nav-btn.active { background: #30363d; color: #fff; }
26
27
  .tab-content { display: none; }
@@ -112,7 +113,7 @@ export function indexPage() {
112
113
  .header { flex-direction: column; gap: 0; align-items: stretch; margin-bottom: 1rem; }
113
114
  .header h1 { display: none; }
114
115
  .nav { justify-content: center; flex-wrap: wrap; }
115
- .nav-btn { padding: 0.5rem 1rem; font-size: 0.8rem; }
116
+ .nav-btn { padding: 0.4rem 0.7rem; font-size: 0.8rem; }
116
117
  }
117
118
  /* Project toggles */
118
119
  .project-item { display: flex; align-items: center; gap: 0.75rem; padding: 0.4rem 0; border-bottom: 1px solid #21262d; }
@@ -147,6 +148,7 @@ export function indexPage() {
147
148
  <h1>Clocktopus</h1>
148
149
  <div class="nav">
149
150
  <button class="nav-btn active" onclick="switchTab('home')" id="nav-home">Home</button>
151
+ <button class="nav-btn" onclick="switchTab('sessions')" id="nav-sessions">Sessions</button>
150
152
  <button class="nav-btn" onclick="switchTab('projects')" id="nav-projects">Projects</button>
151
153
  <button class="nav-btn" onclick="switchTab('calendar')" id="nav-calendar">Calendar</button>
152
154
  <button class="nav-btn" onclick="switchTab('settings')" id="nav-settings">Settings</button>
@@ -262,30 +264,33 @@ export function indexPage() {
262
264
  </div>
263
265
  </div>
264
266
 
265
- <!-- Session History -->
266
- <div class="card card-full">
267
- <h2>Recent Sessions</h2>
268
- <div id="sessions-container" class="table-wrap">
269
- <table class="sessions-table">
270
- <thead>
271
- <tr>
272
- <th>Description</th>
273
- <th>Project</th>
274
- <th>Started</th>
275
- <th>Duration</th>
276
- <th>Jira</th>
277
- <th></th>
278
- </tr>
279
- </thead>
280
- <tbody id="sessions-body">
281
- <tr><td colspan="6" class="empty-state">Loading...</td></tr>
282
- </tbody>
283
- </table>
284
- <div id="pagination" style="display:none; margin-top:1rem; align-items:center; justify-content:center; gap:0.75rem; flex-wrap:wrap;">
285
- <button id="prev-btn" onclick="changePage(-1)" style="background:#30363d; margin-top:0; padding:0.3rem 0.75rem;" disabled>&lt;</button>
286
- <span id="page-info" style="font-size:0.85rem; color:#8b949e;"></span>
287
- <button id="next-btn" onclick="changePage(1)" style="background:#30363d; margin-top:0; padding:0.3rem 0.75rem;">&gt;</button>
288
- </div>
267
+ </div>
268
+ </div>
269
+
270
+ <!-- SESSIONS TAB -->
271
+ <div id="tab-sessions" class="tab-content">
272
+ <div class="card card-full">
273
+ <h2>Recent Sessions</h2>
274
+ <div id="sessions-container" class="table-wrap">
275
+ <table class="sessions-table">
276
+ <thead>
277
+ <tr>
278
+ <th>Description</th>
279
+ <th>Project</th>
280
+ <th>Started</th>
281
+ <th>Duration</th>
282
+ <th>Jira</th>
283
+ <th></th>
284
+ </tr>
285
+ </thead>
286
+ <tbody id="sessions-body">
287
+ <tr><td colspan="6" class="empty-state">Loading...</td></tr>
288
+ </tbody>
289
+ </table>
290
+ <div id="pagination" style="display:none; margin-top:1rem; align-items:center; justify-content:center; gap:0.75rem; flex-wrap:wrap;">
291
+ <button id="prev-btn" onclick="changePage(-1)" style="background:#30363d; margin-top:0; padding:0.3rem 0.75rem;" disabled>&lt;</button>
292
+ <span id="page-info" style="font-size:0.85rem; color:#8b949e;"></span>
293
+ <button id="next-btn" onclick="changePage(1)" style="background:#30363d; margin-top:0; padding:0.3rem 0.75rem;">&gt;</button>
289
294
  </div>
290
295
  </div>
291
296
  </div>
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ import { execSync } from 'child_process';
9
9
  import { closeStaleOpenSessions, completeLatestSession, getLatestSession, setSessionJiraWorklogId } from './lib/db.js';
10
10
  import { isClockifyEnabled } from './lib/credentials.js';
11
11
  import { ensureNativeAddons } from './lib/ensure-native-addons.js';
12
- import { DASHBOARD_PORT, DASHBOARD_URL } from './lib/constants.js';
12
+ import { DASHBOARD_PORT, DASHBOARD_URL, IS_DEV } from './lib/constants.js';
13
13
  const __filename = fileURLToPath(import.meta.url);
14
14
  const __dirname = path.dirname(__filename);
15
15
  const program = new Command();
@@ -398,9 +398,8 @@ program
398
398
  const { startDashboard } = await import('./dashboard/server.js');
399
399
  startDashboard();
400
400
  });
401
- const isDev = __dirname.includes('/Projects/') || __dirname.includes('/src/');
402
- const MONITOR_PM2_NAME = isDev ? 'clocktopus-monitor-dev' : 'clocktopus-monitor';
403
- const DASH_PM2_NAME = isDev ? 'clocktopus-dash-dev' : 'clocktopus-dash';
401
+ const MONITOR_PM2_NAME = IS_DEV ? 'clocktopus-monitor-dev' : 'clocktopus-monitor';
402
+ const DASH_PM2_NAME = IS_DEV ? 'clocktopus-dash-dev' : 'clocktopus-dash';
404
403
  const pm2Bin = path.join(path.dirname(createRequire(import.meta.url).resolve('pm2')), 'bin', 'pm2');
405
404
  const bunBin = (() => {
406
405
  try {
@@ -1,3 +1,25 @@
1
+ import * as path from 'path';
2
+ /**
3
+ * True only when running from the clocktopus source repo (e.g. `bun run`
4
+ * during local development). Bun-linked global installs live under
5
+ * `node_modules/` and must NOT be flagged as dev — otherwise PM2 names and
6
+ * data paths pick up the dev variants. Set CLOCKTOPUS_DEV=1 to force on.
7
+ */
8
+ export const IS_DEV = (() => {
9
+ const override = process.env.CLOCKTOPUS_DEV;
10
+ if (override != null && override !== '') {
11
+ return override === '1' || override.toLowerCase() === 'true';
12
+ }
13
+ try {
14
+ const scriptDir = path.dirname(new URL(import.meta.url).pathname);
15
+ if (scriptDir.includes('/node_modules/'))
16
+ return false;
17
+ return scriptDir.includes('/Projects/') || scriptDir.includes('/src/');
18
+ }
19
+ catch {
20
+ return false;
21
+ }
22
+ })();
1
23
  /**
2
24
  * Dashboard HTTP port. Override via CLOCKTOPUS_PORT env var if 4001 is busy.
3
25
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clocktopus",
3
- "version": "1.10.1",
3
+ "version": "1.10.3",
4
4
  "description": "Time-tracking automation for Clockify with idle monitoring, Jira integration, Google Calendar sync, CLI, web dashboard, and desktop app.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",