clocktopus 1.0.6 → 1.0.7
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 +27 -150
- package/dist/dashboard/routes/monitor.js +15 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
CLI-based time-tracking automation for Clockify with idle monitoring, Jira integration, Google Calendar sync, and a web dashboard.
|
|
8
8
|
|
|
9
|
-
## Quick Start
|
|
9
|
+
## Quick Start
|
|
10
10
|
|
|
11
11
|
Most users only need the dashboard — a web UI to manage timers, connect integrations, and monitor idle time.
|
|
12
12
|
|
|
@@ -45,7 +45,7 @@ Open [http://localhost:4001](http://localhost:4001) in your browser.
|
|
|
45
45
|
|
|
46
46
|
That's it. Start/stop timers from the Home tab.
|
|
47
47
|
|
|
48
|
-
###
|
|
48
|
+
### Commands
|
|
49
49
|
|
|
50
50
|
| Command | Description |
|
|
51
51
|
| ----------------------- | ------------------------------------ |
|
|
@@ -53,6 +53,10 @@ That's it. Start/stop timers from the Home tab.
|
|
|
53
53
|
| `clocktopus serve` | Start dashboard as background daemon |
|
|
54
54
|
| `clocktopus serve:stop` | Stop the dashboard daemon |
|
|
55
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) |
|
|
56
60
|
|
|
57
61
|
### Desktop App (macOS)
|
|
58
62
|
|
|
@@ -68,9 +72,7 @@ The dashboard server must be running (`clocktopus serve`). See [desktop/README.m
|
|
|
68
72
|
|
|
69
73
|
---
|
|
70
74
|
|
|
71
|
-
##
|
|
72
|
-
|
|
73
|
-
For CLI-based workflows, scripting, and advanced features.
|
|
75
|
+
## Development
|
|
74
76
|
|
|
75
77
|
### Install from Source
|
|
76
78
|
|
|
@@ -81,105 +83,32 @@ bun install
|
|
|
81
83
|
bun run build
|
|
82
84
|
```
|
|
83
85
|
|
|
84
|
-
### Local
|
|
86
|
+
### Local Commands
|
|
85
87
|
|
|
86
88
|
When running from source, use `bun run clock` instead of `clocktopus`:
|
|
87
89
|
|
|
88
90
|
```bash
|
|
89
|
-
# Build
|
|
90
|
-
bun run build
|
|
91
|
+
bun run build # Build TypeScript
|
|
91
92
|
|
|
92
|
-
# Dashboard
|
|
93
93
|
bun run dashboard # Start dashboard (foreground)
|
|
94
|
-
|
|
95
|
-
# Timer
|
|
96
94
|
bun run clock start "Task" # Start a timer
|
|
97
95
|
bun run clock start -j PROJ-1 # Start with Jira ticket
|
|
98
96
|
bun run clock stop # Stop timer
|
|
99
97
|
bun run clock status # Check timer status
|
|
100
98
|
|
|
101
|
-
# Monitor
|
|
102
99
|
bun run monitor # Start idle monitor (PM2 daemon)
|
|
103
100
|
bun run monitor:stop # Stop monitor
|
|
104
101
|
bun run monitor:restart # Restart monitor
|
|
105
|
-
bun run monitor:status # Check monitor status
|
|
106
102
|
bun run monitor:logs # View monitor logs
|
|
107
103
|
|
|
108
|
-
# Google Calendar
|
|
109
104
|
bun run google-auth # Authenticate Google account
|
|
110
105
|
bun run log-calendar -t # Log today's events
|
|
111
|
-
|
|
112
|
-
# Database
|
|
113
106
|
bun run db:cleanup # Clean old session logs
|
|
114
107
|
```
|
|
115
108
|
|
|
116
|
-
### CLI Commands
|
|
117
|
-
|
|
118
|
-
#### Timer Management
|
|
119
|
-
|
|
120
|
-
```bash
|
|
121
|
-
# Start a timer (interactive project selection)
|
|
122
|
-
clocktopus start "Task description"
|
|
123
|
-
|
|
124
|
-
# Start with a Jira ticket (auto-fetches ticket title)
|
|
125
|
-
clocktopus start -j TICKET-123
|
|
126
|
-
|
|
127
|
-
# Stop the current timer
|
|
128
|
-
clocktopus stop
|
|
129
|
-
|
|
130
|
-
# Check timer status
|
|
131
|
-
clocktopus status
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
#### Idle Monitor
|
|
135
|
-
|
|
136
|
-
Automatically stops timers when you're idle (5 min) or lock your screen, and restarts when you're back.
|
|
137
|
-
|
|
138
|
-
```bash
|
|
139
|
-
# Run in foreground
|
|
140
|
-
clocktopus monitor
|
|
141
|
-
|
|
142
|
-
# Or manage via dashboard UI (Start/Stop/Restart buttons)
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
The dashboard's Idle Monitor buttons use PM2 under the hood:
|
|
146
|
-
|
|
147
|
-
| Action | What it does |
|
|
148
|
-
| ----------- | ------------------------------ |
|
|
149
|
-
| **Start** | Launches monitor as PM2 daemon |
|
|
150
|
-
| **Stop** | Stops the monitor daemon |
|
|
151
|
-
| **Restart** | Restarts after code changes |
|
|
152
|
-
|
|
153
|
-
#### Google Calendar Integration
|
|
154
|
-
|
|
155
|
-
Log Google Calendar events as Clockify time entries.
|
|
156
|
-
|
|
157
|
-
```bash
|
|
158
|
-
# Authenticate (one-time)
|
|
159
|
-
clocktopus google-auth
|
|
160
|
-
|
|
161
|
-
# Log events for a date range
|
|
162
|
-
clocktopus log-calendar -s 2025-07-21 -e 2025-07-22
|
|
163
|
-
|
|
164
|
-
# Log today's events
|
|
165
|
-
clocktopus log-calendar -t
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
For each event, you'll be prompted to select a Clockify project. Selections are cached by event name for recurring meetings.
|
|
169
|
-
|
|
170
|
-
#### Database Cleanup
|
|
171
|
-
|
|
172
|
-
```bash
|
|
173
|
-
# Delete session logs older than 5 days (default)
|
|
174
|
-
clocktopus db:cleanup
|
|
175
|
-
|
|
176
|
-
# Delete logs older than N days
|
|
177
|
-
clocktopus db:cleanup 10
|
|
178
|
-
```
|
|
179
|
-
|
|
180
109
|
### Configuration
|
|
181
110
|
|
|
182
|
-
All configuration is stored in a local SQLite database
|
|
111
|
+
All configuration is stored in a local SQLite database and managed through the dashboard Settings tab.
|
|
183
112
|
|
|
184
113
|
| Setting | How to configure |
|
|
185
114
|
| ---------------- | ------------------------------------------------ |
|
|
@@ -188,56 +117,23 @@ All configuration is stored in a local SQLite database (`data/sessions.db`) and
|
|
|
188
117
|
| Jira (API token) | Dashboard > Settings > "or use API token" |
|
|
189
118
|
| Google Calendar | Dashboard > Settings > Click "Connect Google" |
|
|
190
119
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
- **Jira**: OAuth tokens are exchanged through a [Cloudflare Worker proxy](docs/atlassian-proxy-flow.md) that holds the client secret securely. Users just click Connect.
|
|
194
|
-
- **Google**: Uses a Desktop-type OAuth client. Credentials are handled transparently.
|
|
195
|
-
- **Clockify**: Each user provides their own API key.
|
|
120
|
+
OAuth for Jira and Google is handled transparently through a [Cloudflare Worker proxy](docs/atlassian-proxy-flow.md) — no client credentials needed from users.
|
|
196
121
|
|
|
197
|
-
|
|
122
|
+
### Project Structure
|
|
198
123
|
|
|
199
|
-
Power users can override credentials via environment variables or a `.env` file:
|
|
200
|
-
|
|
201
|
-
```
|
|
202
|
-
CLOCKIFY_API_KEY="your_key"
|
|
203
|
-
ATLASSIAN_CLIENT_ID="your_id"
|
|
204
|
-
ATLASSIAN_CLIENT_SECRET="your_secret"
|
|
205
|
-
GOOGLE_CLIENT_ID="your_id"
|
|
206
|
-
GOOGLE_CLIENT_SECRET="your_secret"
|
|
207
124
|
```
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
### Shell Aliases
|
|
223
|
-
|
|
224
|
-
For quick access, add to `~/.zshrc`:
|
|
225
|
-
|
|
226
|
-
```bash
|
|
227
|
-
CLOCKTOPUS_PATH="$HOME/Projects/Personal/clocktopus"
|
|
228
|
-
|
|
229
|
-
clockto() {
|
|
230
|
-
cd "$CLOCKTOPUS_PATH" || return
|
|
231
|
-
bun run "$@"
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
alias cbuild="clockto build"
|
|
235
|
-
alias cstart="clockto clock start"
|
|
236
|
-
alias cstop="clockto clock stop"
|
|
237
|
-
alias mstart="clockto monitor"
|
|
238
|
-
alias mstop="clockto monitor:stop"
|
|
239
|
-
alias mrestart="clockto monitor:restart"
|
|
240
|
-
alias mlogs="clockto monitor:logs"
|
|
125
|
+
clocktopus/
|
|
126
|
+
├── index.ts # CLI entry point (Commander)
|
|
127
|
+
├── clockify.ts # Clockify API client
|
|
128
|
+
├── lib/ # Core libraries (db, auth, credentials)
|
|
129
|
+
├── dashboard/ # Web dashboard (Hono server)
|
|
130
|
+
│ ├── server.ts # Dashboard server
|
|
131
|
+
│ ├── views.ts # HTML/CSS/JS (single-page app)
|
|
132
|
+
│ └── routes/ # API routes
|
|
133
|
+
├── desktop/ # Tauri macOS menu bar app
|
|
134
|
+
├── proxy/ # Cloudflare Worker (OAuth proxy)
|
|
135
|
+
├── scripts/ # Google auth & calendar scripts
|
|
136
|
+
└── data/ # SQLite DB & config (gitignored)
|
|
241
137
|
```
|
|
242
138
|
|
|
243
139
|
---
|
|
@@ -246,37 +142,18 @@ alias mlogs="clockto monitor:logs"
|
|
|
246
142
|
|
|
247
143
|
### No notifications on macOS
|
|
248
144
|
|
|
249
|
-
Go to **System Settings > Notifications** and ensure **terminal-notifier**
|
|
145
|
+
Go to **System Settings > Notifications** and ensure **terminal-notifier** has notifications enabled.
|
|
250
146
|
|
|
251
147
|
### Monitor not detecting display off
|
|
252
148
|
|
|
253
|
-
|
|
149
|
+
Enable **Require password immediately** in System Settings > Lock Screen.
|
|
254
150
|
|
|
255
|
-
### Linux
|
|
151
|
+
### Linux
|
|
256
152
|
|
|
257
153
|
```bash
|
|
258
154
|
apt install libxss-dev pkg-config build-essential
|
|
259
155
|
```
|
|
260
156
|
|
|
261
|
-
---
|
|
262
|
-
|
|
263
|
-
## Project Structure
|
|
264
|
-
|
|
265
|
-
```
|
|
266
|
-
clocktopus/
|
|
267
|
-
├── index.ts # CLI entry point (Commander)
|
|
268
|
-
├── clockify.ts # Clockify API client
|
|
269
|
-
├── lib/ # Core libraries (db, auth, credentials)
|
|
270
|
-
├── dashboard/ # Web dashboard (Hono server)
|
|
271
|
-
│ ├── server.ts # Dashboard server
|
|
272
|
-
│ ├── views.ts # HTML/CSS/JS (single-page app)
|
|
273
|
-
│ └── routes/ # API routes
|
|
274
|
-
├── desktop/ # Tauri macOS menu bar app
|
|
275
|
-
├── proxy/ # Cloudflare Worker (OAuth proxy)
|
|
276
|
-
├── scripts/ # Google auth & calendar scripts
|
|
277
|
-
└── data/ # SQLite DB & config (gitignored)
|
|
278
|
-
```
|
|
279
|
-
|
|
280
157
|
## License
|
|
281
158
|
|
|
282
159
|
MIT
|
|
@@ -5,6 +5,7 @@ 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
9
|
const monitorRoutes = new Hono();
|
|
9
10
|
function pm2Exec(command) {
|
|
10
11
|
try {
|
|
@@ -20,15 +21,15 @@ monitorRoutes.get('/monitor/status', (c) => {
|
|
|
20
21
|
try {
|
|
21
22
|
const output = execSync('bunx pm2 jlist', { encoding: 'utf-8', timeout: 10000 });
|
|
22
23
|
const processes = JSON.parse(output);
|
|
23
|
-
const
|
|
24
|
-
if (!
|
|
24
|
+
const proc = processes.find((p) => p.name === PM2_NAME);
|
|
25
|
+
if (!proc) {
|
|
25
26
|
return c.json({ running: false, status: 'not found' });
|
|
26
27
|
}
|
|
27
28
|
return c.json({
|
|
28
|
-
running:
|
|
29
|
-
status:
|
|
30
|
-
uptime:
|
|
31
|
-
restarts:
|
|
29
|
+
running: proc.pm2_env.status === 'online',
|
|
30
|
+
status: proc.pm2_env.status,
|
|
31
|
+
uptime: proc.pm2_env.pm_uptime,
|
|
32
|
+
restarts: proc.pm2_env.restart_time,
|
|
32
33
|
});
|
|
33
34
|
}
|
|
34
35
|
catch {
|
|
@@ -37,15 +38,20 @@ monitorRoutes.get('/monitor/status', (c) => {
|
|
|
37
38
|
});
|
|
38
39
|
monitorRoutes.post('/monitor/start', (c) => {
|
|
39
40
|
const bunPath = execSync('which bun', { encoding: 'utf-8' }).trim();
|
|
40
|
-
|
|
41
|
+
// Delete any existing process to avoid duplicates
|
|
42
|
+
try {
|
|
43
|
+
execSync(`bunx pm2 delete ${PM2_NAME}`, { stdio: 'ignore' });
|
|
44
|
+
}
|
|
45
|
+
catch { }
|
|
46
|
+
const result = pm2Exec(`bunx pm2 start ${SCRIPT_PATH} --name ${PM2_NAME} --interpreter ${bunPath} -- monitor`);
|
|
41
47
|
return c.json(result);
|
|
42
48
|
});
|
|
43
49
|
monitorRoutes.post('/monitor/stop', (c) => {
|
|
44
|
-
const result = pm2Exec(
|
|
50
|
+
const result = pm2Exec(`bunx pm2 stop ${PM2_NAME}`);
|
|
45
51
|
return c.json(result);
|
|
46
52
|
});
|
|
47
53
|
monitorRoutes.post('/monitor/restart', (c) => {
|
|
48
|
-
const result = pm2Exec(
|
|
54
|
+
const result = pm2Exec(`bunx pm2 restart ${PM2_NAME}`);
|
|
49
55
|
return c.json(result);
|
|
50
56
|
});
|
|
51
57
|
export default monitorRoutes;
|