clawck 0.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/LICENSE +21 -0
- package/README.md +322 -0
- package/dist/cli/index.d.ts +14 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +233 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/clawck.d.ts +48 -0
- package/dist/core/clawck.d.ts.map +1 -0
- package/dist/core/clawck.js +119 -0
- package/dist/core/clawck.js.map +1 -0
- package/dist/core/database.d.ts +55 -0
- package/dist/core/database.d.ts.map +1 -0
- package/dist/core/database.js +329 -0
- package/dist/core/database.js.map +1 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +23 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/sync.d.ts +17 -0
- package/dist/core/sync.d.ts.map +1 -0
- package/dist/core/sync.js +91 -0
- package/dist/core/sync.js.map +1 -0
- package/dist/core/types.d.ts +186 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +34 -0
- package/dist/core/types.js.map +1 -0
- package/dist/dashboard/index.d.ts +6 -0
- package/dist/dashboard/index.d.ts.map +1 -0
- package/dist/dashboard/index.js +632 -0
- package/dist/dashboard/index.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/server/api.d.ts +15 -0
- package/dist/server/api.d.ts.map +1 -0
- package/dist/server/api.js +193 -0
- package/dist/server/api.js.map +1 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +9 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/mcp.d.ts +8 -0
- package/dist/server/mcp.d.ts.map +1 -0
- package/dist/server/mcp.js +277 -0
- package/dist/server/mcp.js.map +1 -0
- package/package.json +66 -0
|
@@ -0,0 +1,632 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* โฑ๏ธ๐ฆ Clawck โ Dashboard
|
|
4
|
+
* Self-contained HTML dashboard served by the Clawck server.
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.getDashboardHTML = getDashboardHTML;
|
|
8
|
+
function getDashboardHTML(port) {
|
|
9
|
+
return `<!DOCTYPE html>
|
|
10
|
+
<html lang="en">
|
|
11
|
+
<head>
|
|
12
|
+
<meta charset="UTF-8">
|
|
13
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
14
|
+
<title>Clawck โ AI Agent Time Tracker</title>
|
|
15
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
16
|
+
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&family=DM+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
17
|
+
<style>
|
|
18
|
+
:root {
|
|
19
|
+
--bg-primary: #0a0b0f;
|
|
20
|
+
--bg-secondary: #12141c;
|
|
21
|
+
--bg-card: #181a24;
|
|
22
|
+
--bg-hover: #1e2030;
|
|
23
|
+
--border: #2a2d3e;
|
|
24
|
+
--text-primary: #e8eaf0;
|
|
25
|
+
--text-secondary: #8b8fa3;
|
|
26
|
+
--text-muted: #5c5f73;
|
|
27
|
+
--accent: #ff6b35;
|
|
28
|
+
--accent-glow: rgba(255, 107, 53, 0.15);
|
|
29
|
+
--green: #34d399;
|
|
30
|
+
--green-dim: rgba(52, 211, 153, 0.15);
|
|
31
|
+
--blue: #60a5fa;
|
|
32
|
+
--blue-dim: rgba(96, 165, 250, 0.15);
|
|
33
|
+
--red: #f87171;
|
|
34
|
+
--red-dim: rgba(248, 113, 113, 0.15);
|
|
35
|
+
--yellow: #fbbf24;
|
|
36
|
+
--yellow-dim: rgba(251, 191, 36, 0.15);
|
|
37
|
+
--purple: #a78bfa;
|
|
38
|
+
--radius: 8px;
|
|
39
|
+
--radius-lg: 12px;
|
|
40
|
+
}
|
|
41
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
42
|
+
body {
|
|
43
|
+
font-family: 'DM Sans', -apple-system, sans-serif;
|
|
44
|
+
background: var(--bg-primary);
|
|
45
|
+
color: var(--text-primary);
|
|
46
|
+
min-height: 100vh;
|
|
47
|
+
line-height: 1.5;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* โโโ Header โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
|
51
|
+
.header {
|
|
52
|
+
background: var(--bg-secondary);
|
|
53
|
+
border-bottom: 1px solid var(--border);
|
|
54
|
+
padding: 16px 32px;
|
|
55
|
+
display: flex;
|
|
56
|
+
align-items: center;
|
|
57
|
+
justify-content: space-between;
|
|
58
|
+
position: sticky;
|
|
59
|
+
top: 0;
|
|
60
|
+
z-index: 100;
|
|
61
|
+
}
|
|
62
|
+
.logo {
|
|
63
|
+
font-family: 'JetBrains Mono', monospace;
|
|
64
|
+
font-size: 20px;
|
|
65
|
+
font-weight: 700;
|
|
66
|
+
color: var(--accent);
|
|
67
|
+
display: flex;
|
|
68
|
+
align-items: center;
|
|
69
|
+
gap: 10px;
|
|
70
|
+
}
|
|
71
|
+
.logo-icon { font-size: 24px; }
|
|
72
|
+
.logo-sub {
|
|
73
|
+
font-size: 11px;
|
|
74
|
+
font-weight: 400;
|
|
75
|
+
color: var(--text-muted);
|
|
76
|
+
font-family: 'DM Sans', sans-serif;
|
|
77
|
+
margin-left: 4px;
|
|
78
|
+
}
|
|
79
|
+
.header-right { display: flex; align-items: center; gap: 16px; }
|
|
80
|
+
.period-select {
|
|
81
|
+
background: var(--bg-card);
|
|
82
|
+
border: 1px solid var(--border);
|
|
83
|
+
color: var(--text-primary);
|
|
84
|
+
padding: 8px 14px;
|
|
85
|
+
border-radius: var(--radius);
|
|
86
|
+
font-family: 'DM Sans', sans-serif;
|
|
87
|
+
font-size: 13px;
|
|
88
|
+
cursor: pointer;
|
|
89
|
+
}
|
|
90
|
+
.refresh-btn {
|
|
91
|
+
background: var(--accent);
|
|
92
|
+
color: #fff;
|
|
93
|
+
border: none;
|
|
94
|
+
padding: 8px 18px;
|
|
95
|
+
border-radius: var(--radius);
|
|
96
|
+
font-family: 'DM Sans', sans-serif;
|
|
97
|
+
font-size: 13px;
|
|
98
|
+
font-weight: 600;
|
|
99
|
+
cursor: pointer;
|
|
100
|
+
transition: opacity 0.2s;
|
|
101
|
+
}
|
|
102
|
+
.refresh-btn:hover { opacity: 0.85; }
|
|
103
|
+
|
|
104
|
+
/* โโโ Layout โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
|
105
|
+
.main { padding: 28px 32px; max-width: 1400px; margin: 0 auto; }
|
|
106
|
+
|
|
107
|
+
/* โโโ Stat Cards โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
|
108
|
+
.stats-grid {
|
|
109
|
+
display: grid;
|
|
110
|
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
111
|
+
gap: 16px;
|
|
112
|
+
margin-bottom: 32px;
|
|
113
|
+
}
|
|
114
|
+
.stat-card {
|
|
115
|
+
background: var(--bg-card);
|
|
116
|
+
border: 1px solid var(--border);
|
|
117
|
+
border-radius: var(--radius-lg);
|
|
118
|
+
padding: 20px 22px;
|
|
119
|
+
}
|
|
120
|
+
.stat-label {
|
|
121
|
+
font-size: 12px;
|
|
122
|
+
font-weight: 500;
|
|
123
|
+
color: var(--text-muted);
|
|
124
|
+
text-transform: uppercase;
|
|
125
|
+
letter-spacing: 0.5px;
|
|
126
|
+
margin-bottom: 6px;
|
|
127
|
+
}
|
|
128
|
+
.stat-value {
|
|
129
|
+
font-family: 'JetBrains Mono', monospace;
|
|
130
|
+
font-size: 28px;
|
|
131
|
+
font-weight: 700;
|
|
132
|
+
line-height: 1.1;
|
|
133
|
+
}
|
|
134
|
+
.stat-sub {
|
|
135
|
+
font-size: 12px;
|
|
136
|
+
color: var(--text-secondary);
|
|
137
|
+
margin-top: 4px;
|
|
138
|
+
}
|
|
139
|
+
.stat-accent { color: var(--accent); }
|
|
140
|
+
.stat-green { color: var(--green); }
|
|
141
|
+
.stat-blue { color: var(--blue); }
|
|
142
|
+
|
|
143
|
+
/* โโโ Savings Banner โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
|
144
|
+
.savings-banner {
|
|
145
|
+
background: linear-gradient(135deg, rgba(52, 211, 153, 0.08) 0%, rgba(96, 165, 250, 0.06) 100%);
|
|
146
|
+
border: 1px solid rgba(52, 211, 153, 0.2);
|
|
147
|
+
border-radius: var(--radius-lg);
|
|
148
|
+
padding: 24px 28px;
|
|
149
|
+
margin-bottom: 32px;
|
|
150
|
+
display: flex;
|
|
151
|
+
align-items: center;
|
|
152
|
+
justify-content: space-between;
|
|
153
|
+
flex-wrap: wrap;
|
|
154
|
+
gap: 16px;
|
|
155
|
+
}
|
|
156
|
+
.savings-left h3 {
|
|
157
|
+
font-size: 14px;
|
|
158
|
+
color: var(--green);
|
|
159
|
+
font-weight: 600;
|
|
160
|
+
margin-bottom: 4px;
|
|
161
|
+
}
|
|
162
|
+
.savings-left .savings-amount {
|
|
163
|
+
font-family: 'JetBrains Mono', monospace;
|
|
164
|
+
font-size: 36px;
|
|
165
|
+
font-weight: 700;
|
|
166
|
+
color: var(--green);
|
|
167
|
+
}
|
|
168
|
+
.savings-left .savings-detail {
|
|
169
|
+
font-size: 13px;
|
|
170
|
+
color: var(--text-secondary);
|
|
171
|
+
margin-top: 4px;
|
|
172
|
+
}
|
|
173
|
+
.savings-right {
|
|
174
|
+
text-align: right;
|
|
175
|
+
}
|
|
176
|
+
.savings-right .equiv-hours {
|
|
177
|
+
font-family: 'JetBrains Mono', monospace;
|
|
178
|
+
font-size: 24px;
|
|
179
|
+
font-weight: 700;
|
|
180
|
+
color: var(--blue);
|
|
181
|
+
}
|
|
182
|
+
.savings-right .equiv-label {
|
|
183
|
+
font-size: 12px;
|
|
184
|
+
color: var(--text-secondary);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/* โโโ Sections โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
|
188
|
+
.section { margin-bottom: 32px; }
|
|
189
|
+
.section-header {
|
|
190
|
+
display: flex;
|
|
191
|
+
align-items: center;
|
|
192
|
+
justify-content: space-between;
|
|
193
|
+
margin-bottom: 16px;
|
|
194
|
+
}
|
|
195
|
+
.section-title {
|
|
196
|
+
font-size: 16px;
|
|
197
|
+
font-weight: 600;
|
|
198
|
+
color: var(--text-primary);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/* โโโ Tabs โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
|
202
|
+
.tabs {
|
|
203
|
+
display: flex;
|
|
204
|
+
gap: 2px;
|
|
205
|
+
background: var(--bg-secondary);
|
|
206
|
+
border-radius: var(--radius);
|
|
207
|
+
padding: 3px;
|
|
208
|
+
margin-bottom: 20px;
|
|
209
|
+
border: 1px solid var(--border);
|
|
210
|
+
width: fit-content;
|
|
211
|
+
}
|
|
212
|
+
.tab {
|
|
213
|
+
padding: 8px 18px;
|
|
214
|
+
border-radius: 6px;
|
|
215
|
+
font-size: 13px;
|
|
216
|
+
font-weight: 500;
|
|
217
|
+
cursor: pointer;
|
|
218
|
+
color: var(--text-secondary);
|
|
219
|
+
background: none;
|
|
220
|
+
border: none;
|
|
221
|
+
transition: all 0.2s;
|
|
222
|
+
font-family: 'DM Sans', sans-serif;
|
|
223
|
+
}
|
|
224
|
+
.tab:hover { color: var(--text-primary); }
|
|
225
|
+
.tab.active {
|
|
226
|
+
background: var(--bg-card);
|
|
227
|
+
color: var(--accent);
|
|
228
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.2);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/* โโโ Table โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
|
232
|
+
.table-wrap {
|
|
233
|
+
background: var(--bg-card);
|
|
234
|
+
border: 1px solid var(--border);
|
|
235
|
+
border-radius: var(--radius-lg);
|
|
236
|
+
overflow: hidden;
|
|
237
|
+
}
|
|
238
|
+
table { width: 100%; border-collapse: collapse; }
|
|
239
|
+
th {
|
|
240
|
+
text-align: left;
|
|
241
|
+
padding: 12px 16px;
|
|
242
|
+
font-size: 11px;
|
|
243
|
+
font-weight: 600;
|
|
244
|
+
text-transform: uppercase;
|
|
245
|
+
letter-spacing: 0.5px;
|
|
246
|
+
color: var(--text-muted);
|
|
247
|
+
background: var(--bg-secondary);
|
|
248
|
+
border-bottom: 1px solid var(--border);
|
|
249
|
+
}
|
|
250
|
+
td {
|
|
251
|
+
padding: 14px 16px;
|
|
252
|
+
font-size: 13px;
|
|
253
|
+
border-bottom: 1px solid var(--border);
|
|
254
|
+
color: var(--text-secondary);
|
|
255
|
+
}
|
|
256
|
+
tr:last-child td { border-bottom: none; }
|
|
257
|
+
tr:hover td { background: var(--bg-hover); }
|
|
258
|
+
.cell-mono {
|
|
259
|
+
font-family: 'JetBrains Mono', monospace;
|
|
260
|
+
font-size: 12px;
|
|
261
|
+
}
|
|
262
|
+
.cell-task {
|
|
263
|
+
color: var(--text-primary);
|
|
264
|
+
font-weight: 500;
|
|
265
|
+
max-width: 300px;
|
|
266
|
+
overflow: hidden;
|
|
267
|
+
text-overflow: ellipsis;
|
|
268
|
+
white-space: nowrap;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/* โโโ Badges โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
|
272
|
+
.badge {
|
|
273
|
+
display: inline-block;
|
|
274
|
+
padding: 3px 10px;
|
|
275
|
+
border-radius: 20px;
|
|
276
|
+
font-size: 11px;
|
|
277
|
+
font-weight: 600;
|
|
278
|
+
}
|
|
279
|
+
.badge-running { background: var(--accent-glow); color: var(--accent); }
|
|
280
|
+
.badge-completed { background: var(--green-dim); color: var(--green); }
|
|
281
|
+
.badge-failed { background: var(--red-dim); color: var(--red); }
|
|
282
|
+
.badge-paused { background: var(--yellow-dim); color: var(--yellow); }
|
|
283
|
+
.badge-cat {
|
|
284
|
+
background: var(--blue-dim);
|
|
285
|
+
color: var(--blue);
|
|
286
|
+
font-size: 10px;
|
|
287
|
+
padding: 2px 8px;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/* โโโ Breakdown Bars โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
|
291
|
+
.breakdown-list { display: flex; flex-direction: column; gap: 10px; }
|
|
292
|
+
.breakdown-row {
|
|
293
|
+
display: flex;
|
|
294
|
+
align-items: center;
|
|
295
|
+
gap: 12px;
|
|
296
|
+
}
|
|
297
|
+
.breakdown-label {
|
|
298
|
+
font-size: 13px;
|
|
299
|
+
font-weight: 500;
|
|
300
|
+
width: 140px;
|
|
301
|
+
flex-shrink: 0;
|
|
302
|
+
overflow: hidden;
|
|
303
|
+
text-overflow: ellipsis;
|
|
304
|
+
white-space: nowrap;
|
|
305
|
+
}
|
|
306
|
+
.breakdown-bar-wrap {
|
|
307
|
+
flex: 1;
|
|
308
|
+
height: 24px;
|
|
309
|
+
background: var(--bg-secondary);
|
|
310
|
+
border-radius: 4px;
|
|
311
|
+
overflow: hidden;
|
|
312
|
+
}
|
|
313
|
+
.breakdown-bar {
|
|
314
|
+
height: 100%;
|
|
315
|
+
background: var(--accent);
|
|
316
|
+
border-radius: 4px;
|
|
317
|
+
transition: width 0.6s ease;
|
|
318
|
+
min-width: 2px;
|
|
319
|
+
}
|
|
320
|
+
.breakdown-value {
|
|
321
|
+
font-family: 'JetBrains Mono', monospace;
|
|
322
|
+
font-size: 12px;
|
|
323
|
+
color: var(--text-secondary);
|
|
324
|
+
width: 80px;
|
|
325
|
+
text-align: right;
|
|
326
|
+
flex-shrink: 0;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/* โโโ Empty State โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
|
330
|
+
.empty {
|
|
331
|
+
text-align: center;
|
|
332
|
+
padding: 60px 20px;
|
|
333
|
+
color: var(--text-muted);
|
|
334
|
+
}
|
|
335
|
+
.empty-icon { font-size: 48px; margin-bottom: 16px; }
|
|
336
|
+
.empty-title { font-size: 18px; font-weight: 600; color: var(--text-secondary); margin-bottom: 8px; }
|
|
337
|
+
.empty-sub { font-size: 14px; }
|
|
338
|
+
.empty code {
|
|
339
|
+
background: var(--bg-secondary);
|
|
340
|
+
padding: 2px 8px;
|
|
341
|
+
border-radius: 4px;
|
|
342
|
+
font-family: 'JetBrains Mono', monospace;
|
|
343
|
+
font-size: 12px;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/* โโโ Two Column โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
|
347
|
+
.two-col {
|
|
348
|
+
display: grid;
|
|
349
|
+
grid-template-columns: 1fr 1fr;
|
|
350
|
+
gap: 20px;
|
|
351
|
+
}
|
|
352
|
+
@media (max-width: 900px) {
|
|
353
|
+
.two-col { grid-template-columns: 1fr; }
|
|
354
|
+
.stats-grid { grid-template-columns: repeat(2, 1fr); }
|
|
355
|
+
.savings-banner { flex-direction: column; text-align: left; }
|
|
356
|
+
.savings-right { text-align: left; }
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
.loading {
|
|
360
|
+
display: flex;
|
|
361
|
+
align-items: center;
|
|
362
|
+
justify-content: center;
|
|
363
|
+
padding: 60px;
|
|
364
|
+
color: var(--text-muted);
|
|
365
|
+
font-size: 14px;
|
|
366
|
+
}
|
|
367
|
+
.pulse { animation: pulse 1.5s infinite; }
|
|
368
|
+
@keyframes pulse {
|
|
369
|
+
0%, 100% { opacity: 1; }
|
|
370
|
+
50% { opacity: 0.4; }
|
|
371
|
+
}
|
|
372
|
+
</style>
|
|
373
|
+
</head>
|
|
374
|
+
<body>
|
|
375
|
+
<div class="header">
|
|
376
|
+
<div class="logo">
|
|
377
|
+
<span class="logo-icon">๐ฆ</span>
|
|
378
|
+
<span>Clawck</span>
|
|
379
|
+
<span class="logo-sub">Agent Time Tracker</span>
|
|
380
|
+
</div>
|
|
381
|
+
<div class="header-right">
|
|
382
|
+
<select class="period-select" id="periodSelect">
|
|
383
|
+
<option value="1">Today</option>
|
|
384
|
+
<option value="7" selected>Last 7 days</option>
|
|
385
|
+
<option value="14">Last 14 days</option>
|
|
386
|
+
<option value="30">Last 30 days</option>
|
|
387
|
+
<option value="90">Last 90 days</option>
|
|
388
|
+
</select>
|
|
389
|
+
<button class="refresh-btn" onclick="loadData()">Refresh</button>
|
|
390
|
+
</div>
|
|
391
|
+
</div>
|
|
392
|
+
|
|
393
|
+
<div class="main" id="app">
|
|
394
|
+
<div class="loading"><span class="pulse">โฑ๏ธ Loading Clawck data...</span></div>
|
|
395
|
+
</div>
|
|
396
|
+
|
|
397
|
+
<script>
|
|
398
|
+
const API = 'http://localhost:${port}/api';
|
|
399
|
+
let data = null;
|
|
400
|
+
|
|
401
|
+
async function loadData() {
|
|
402
|
+
const days = parseInt(document.getElementById('periodSelect').value);
|
|
403
|
+
const to = new Date().toISOString();
|
|
404
|
+
const from = new Date(Date.now() - days * 86400000).toISOString();
|
|
405
|
+
|
|
406
|
+
try {
|
|
407
|
+
const [tsRes, runRes, statsRes] = await Promise.all([
|
|
408
|
+
fetch(API + '/timesheet?from=' + from + '&to=' + to).then(r => r.json()),
|
|
409
|
+
fetch(API + '/running').then(r => r.json()),
|
|
410
|
+
fetch(API + '/stats').then(r => r.json()),
|
|
411
|
+
]);
|
|
412
|
+
data = { timesheet: tsRes, running: runRes, stats: statsRes };
|
|
413
|
+
render();
|
|
414
|
+
} catch (e) {
|
|
415
|
+
document.getElementById('app').innerHTML = \`
|
|
416
|
+
<div class="empty">
|
|
417
|
+
<div class="empty-icon">๐ฆ</div>
|
|
418
|
+
<div class="empty-title">Clawck is running but no data yet</div>
|
|
419
|
+
<div class="empty-sub">Start tracking: <code>clawck_start_task</code> via MCP or <code>POST /api/start</code></div>
|
|
420
|
+
</div>\`;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function render() {
|
|
425
|
+
if (!data) return;
|
|
426
|
+
const ts = data.timesheet;
|
|
427
|
+
const running = data.running;
|
|
428
|
+
const stats = data.stats;
|
|
429
|
+
|
|
430
|
+
const app = document.getElementById('app');
|
|
431
|
+
app.innerHTML = '';
|
|
432
|
+
|
|
433
|
+
// โโโ Stats Cards โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
434
|
+
const statsHTML = \`
|
|
435
|
+
<div class="stats-grid">
|
|
436
|
+
<div class="stat-card">
|
|
437
|
+
<div class="stat-label">Agent Hours</div>
|
|
438
|
+
<div class="stat-value stat-accent">\${ts.total_agent_hours.toFixed(1)}</div>
|
|
439
|
+
<div class="stat-sub">\${ts.total_entries} entries</div>
|
|
440
|
+
</div>
|
|
441
|
+
<div class="stat-card">
|
|
442
|
+
<div class="stat-label">Human Equiv Hours</div>
|
|
443
|
+
<div class="stat-value stat-blue">\${ts.total_human_equiv_hours.toFixed(1)}</div>
|
|
444
|
+
<div class="stat-sub">\${(ts.total_human_equiv_hours / (ts.total_agent_hours || 1)).toFixed(1)}x multiplier avg</div>
|
|
445
|
+
</div>
|
|
446
|
+
<div class="stat-card">
|
|
447
|
+
<div class="stat-label">Agent Cost</div>
|
|
448
|
+
<div class="stat-value">$\${ts.total_cost_usd.toFixed(2)}</div>
|
|
449
|
+
<div class="stat-sub">\${ts.total_tokens.toLocaleString()} tokens</div>
|
|
450
|
+
</div>
|
|
451
|
+
<div class="stat-card">
|
|
452
|
+
<div class="stat-label">Active Now</div>
|
|
453
|
+
<div class="stat-value" style="color: \${running.length > 0 ? 'var(--accent)' : 'var(--text-muted)'}">\${running.length}</div>
|
|
454
|
+
<div class="stat-sub">\${stats.agents} agents total</div>
|
|
455
|
+
</div>
|
|
456
|
+
</div>\`;
|
|
457
|
+
|
|
458
|
+
// โโโ Savings Banner โโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
459
|
+
const savingsHTML = ts.total_savings_usd > 0 ? \`
|
|
460
|
+
<div class="savings-banner">
|
|
461
|
+
<div class="savings-left">
|
|
462
|
+
<h3>๐ Estimated Value Delivered</h3>
|
|
463
|
+
<div class="savings-amount">$\${ts.total_savings_usd.toLocaleString(undefined, {minimumFractionDigits: 0, maximumFractionDigits: 0})}</div>
|
|
464
|
+
<div class="savings-detail">Based on human-equivalent hours ร avg hourly rates</div>
|
|
465
|
+
</div>
|
|
466
|
+
<div class="savings-right">
|
|
467
|
+
<div class="equiv-hours">\${ts.total_human_equiv_hours.toFixed(1)} hrs</div>
|
|
468
|
+
<div class="equiv-label">of human work completed by agents</div>
|
|
469
|
+
</div>
|
|
470
|
+
</div>\` : '';
|
|
471
|
+
|
|
472
|
+
// โโโ Tabs โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
473
|
+
const tabsHTML = \`
|
|
474
|
+
<div class="tabs">
|
|
475
|
+
<button class="tab active" onclick="showTab('entries', this)">Time Entries</button>
|
|
476
|
+
<button class="tab" onclick="showTab('projects', this)">By Project</button>
|
|
477
|
+
<button class="tab" onclick="showTab('agents', this)">By Agent</button>
|
|
478
|
+
<button class="tab" onclick="showTab('categories', this)">By Category</button>
|
|
479
|
+
</div>\`;
|
|
480
|
+
|
|
481
|
+
// โโโ Entries Table โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
482
|
+
const entriesRows = ts.entries.slice(0, 100).map(e => \`
|
|
483
|
+
<tr>
|
|
484
|
+
<td class="cell-mono">\${e.date}</td>
|
|
485
|
+
<td class="cell-task">\${esc(e.task)}</td>
|
|
486
|
+
<td>\${esc(e.project)}</td>
|
|
487
|
+
<td>\${esc(e.client)}</td>
|
|
488
|
+
<td>\${esc(e.agent)}</td>
|
|
489
|
+
<td><span class="badge badge-cat">\${e.category}</span></td>
|
|
490
|
+
<td class="cell-mono">\${formatDuration(e.duration_minutes)}</td>
|
|
491
|
+
<td class="cell-mono">\${e.human_equiv_hours.toFixed(1)}h</td>
|
|
492
|
+
<td class="cell-mono">$\${e.cost_usd.toFixed(4)}</td>
|
|
493
|
+
<td><span class="badge badge-\${e.status}">\${e.status}</span></td>
|
|
494
|
+
</tr>\`).join('');
|
|
495
|
+
|
|
496
|
+
const entriesHTML = ts.entries.length > 0 ? \`
|
|
497
|
+
<div class="table-wrap">
|
|
498
|
+
<table>
|
|
499
|
+
<thead>
|
|
500
|
+
<tr>
|
|
501
|
+
<th>Date</th><th>Task</th><th>Project</th><th>Client</th><th>Agent</th><th>Category</th><th>Duration</th><th>Human Equiv</th><th>Cost</th><th>Status</th>
|
|
502
|
+
</tr>
|
|
503
|
+
</thead>
|
|
504
|
+
<tbody>\${entriesRows}</tbody>
|
|
505
|
+
</table>
|
|
506
|
+
</div>\` : \`
|
|
507
|
+
<div class="empty">
|
|
508
|
+
<div class="empty-icon">๐</div>
|
|
509
|
+
<div class="empty-title">No entries yet</div>
|
|
510
|
+
<div class="empty-sub">Agents will appear here once they start clocking in</div>
|
|
511
|
+
</div>\`;
|
|
512
|
+
|
|
513
|
+
// โโโ By Project โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
514
|
+
const maxProjHours = Math.max(...ts.by_project.map(p => p.agent_hours), 0.1);
|
|
515
|
+
const projectsHTML = \`
|
|
516
|
+
<div class="table-wrap" style="padding: 20px;">
|
|
517
|
+
<div class="breakdown-list">
|
|
518
|
+
\${ts.by_project.map(p => \`
|
|
519
|
+
<div class="breakdown-row">
|
|
520
|
+
<div class="breakdown-label">\${esc(p.project)}</div>
|
|
521
|
+
<div class="breakdown-bar-wrap">
|
|
522
|
+
<div class="breakdown-bar" style="width: \${(p.agent_hours / maxProjHours * 100).toFixed(1)}%"></div>
|
|
523
|
+
</div>
|
|
524
|
+
<div class="breakdown-value">\${p.agent_hours.toFixed(1)}h โ \${p.human_equiv_hours.toFixed(1)}h</div>
|
|
525
|
+
</div>
|
|
526
|
+
\`).join('') || '<div class="empty-sub">No project data</div>'}
|
|
527
|
+
</div>
|
|
528
|
+
</div>\`;
|
|
529
|
+
|
|
530
|
+
// โโโ By Agent โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
531
|
+
const maxAgentHours = Math.max(...ts.by_agent.map(a => a.agent_hours), 0.1);
|
|
532
|
+
const agentsHTML = \`
|
|
533
|
+
<div class="table-wrap" style="padding: 20px;">
|
|
534
|
+
<div class="breakdown-list">
|
|
535
|
+
\${ts.by_agent.map(a => \`
|
|
536
|
+
<div class="breakdown-row">
|
|
537
|
+
<div class="breakdown-label">\${esc(a.agent)}</div>
|
|
538
|
+
<div class="breakdown-bar-wrap">
|
|
539
|
+
<div class="breakdown-bar" style="width: \${(a.agent_hours / maxAgentHours * 100).toFixed(1)}%; background: var(--blue)"></div>
|
|
540
|
+
</div>
|
|
541
|
+
<div class="breakdown-value">\${a.agent_hours.toFixed(1)}h ยท \${a.success_rate}%</div>
|
|
542
|
+
</div>
|
|
543
|
+
\`).join('') || '<div class="empty-sub">No agent data</div>'}
|
|
544
|
+
</div>
|
|
545
|
+
</div>\`;
|
|
546
|
+
|
|
547
|
+
// โโโ By Category โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
548
|
+
const maxCatHours = Math.max(...ts.by_category.map(c => c.agent_hours), 0.1);
|
|
549
|
+
const catColors = { research: '--purple', content: '--green', code: '--blue', data_entry: '--yellow', design: '--accent', communication: '--text-primary', analysis: '--purple', testing: '--red', planning: '--blue', other: '--text-muted' };
|
|
550
|
+
const catsHTML = \`
|
|
551
|
+
<div class="table-wrap" style="padding: 20px;">
|
|
552
|
+
<div class="breakdown-list">
|
|
553
|
+
\${ts.by_category.map(c => \`
|
|
554
|
+
<div class="breakdown-row">
|
|
555
|
+
<div class="breakdown-label">\${c.category}</div>
|
|
556
|
+
<div class="breakdown-bar-wrap">
|
|
557
|
+
<div class="breakdown-bar" style="width: \${(c.agent_hours / maxCatHours * 100).toFixed(1)}%; background: var(\${catColors[c.category] || '--accent'})"></div>
|
|
558
|
+
</div>
|
|
559
|
+
<div class="breakdown-value">\${c.agent_hours.toFixed(1)}h ยท $\${c.savings_usd.toFixed(0)} saved</div>
|
|
560
|
+
</div>
|
|
561
|
+
\`).join('') || '<div class="empty-sub">No category data</div>'}
|
|
562
|
+
</div>
|
|
563
|
+
</div>\`;
|
|
564
|
+
|
|
565
|
+
// โโโ Running Now โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
566
|
+
const runningHTML = running.length > 0 ? \`
|
|
567
|
+
<div class="section">
|
|
568
|
+
<div class="section-header">
|
|
569
|
+
<div class="section-title">โฑ๏ธ Running Now</div>
|
|
570
|
+
</div>
|
|
571
|
+
<div class="table-wrap">
|
|
572
|
+
<table>
|
|
573
|
+
<thead><tr><th>Agent</th><th>Task</th><th>Project</th><th>Client</th><th>Running For</th></tr></thead>
|
|
574
|
+
<tbody>
|
|
575
|
+
\${running.map(e => {
|
|
576
|
+
const mins = Math.round((Date.now() - new Date(e.start).getTime()) / 60000);
|
|
577
|
+
return \`<tr>
|
|
578
|
+
<td>\${esc(e.agent)}</td>
|
|
579
|
+
<td class="cell-task">\${esc(e.task)}</td>
|
|
580
|
+
<td>\${esc(e.project)}</td>
|
|
581
|
+
<td>\${esc(e.client)}</td>
|
|
582
|
+
<td class="cell-mono" style="color:var(--accent)">\${formatDuration(mins)}</td>
|
|
583
|
+
</tr>\`;
|
|
584
|
+
}).join('')}
|
|
585
|
+
</tbody>
|
|
586
|
+
</table>
|
|
587
|
+
</div>
|
|
588
|
+
</div>\` : '';
|
|
589
|
+
|
|
590
|
+
// โโโ Assemble โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
591
|
+
app.innerHTML = statsHTML + savingsHTML + runningHTML + \`
|
|
592
|
+
<div class="section">
|
|
593
|
+
\${tabsHTML}
|
|
594
|
+
<div id="tab-entries">\${entriesHTML}</div>
|
|
595
|
+
<div id="tab-projects" style="display:none">\${projectsHTML}</div>
|
|
596
|
+
<div id="tab-agents" style="display:none">\${agentsHTML}</div>
|
|
597
|
+
<div id="tab-categories" style="display:none">\${catsHTML}</div>
|
|
598
|
+
</div>\`;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
function showTab(name, btn) {
|
|
602
|
+
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
|
|
603
|
+
btn.classList.add('active');
|
|
604
|
+
['entries','projects','agents','categories'].forEach(t => {
|
|
605
|
+
const el = document.getElementById('tab-' + t);
|
|
606
|
+
if (el) el.style.display = t === name ? 'block' : 'none';
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
function formatDuration(mins) {
|
|
611
|
+
if (mins < 1) return '<1m';
|
|
612
|
+
if (mins < 60) return Math.round(mins) + 'm';
|
|
613
|
+
const h = Math.floor(mins / 60);
|
|
614
|
+
const m = Math.round(mins % 60);
|
|
615
|
+
return h + 'h ' + (m > 0 ? m + 'm' : '');
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
function esc(s) {
|
|
619
|
+
if (!s) return '';
|
|
620
|
+
const d = document.createElement('div');
|
|
621
|
+
d.textContent = s;
|
|
622
|
+
return d.innerHTML;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
document.getElementById('periodSelect').addEventListener('change', loadData);
|
|
626
|
+
loadData();
|
|
627
|
+
setInterval(loadData, 30000); // Auto-refresh every 30s
|
|
628
|
+
</script>
|
|
629
|
+
</body>
|
|
630
|
+
</html>`;
|
|
631
|
+
}
|
|
632
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/dashboard/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAEH,4CA+mBC;AA/mBD,SAAgB,gBAAgB,CAAC,IAAY;IAC3C,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCAqYuB,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAwO5B,CAAC;AACT,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* โฑ๏ธ๐ฆ Clawck
|
|
3
|
+
* Time tracking for AI agents. Toggl for the agentic era.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* import { Clawck } from 'clawck';
|
|
8
|
+
*
|
|
9
|
+
* const clawck = new Clawck({ default_client: 'acme-corp' });
|
|
10
|
+
*
|
|
11
|
+
* // Start tracking
|
|
12
|
+
* const entry = clawck.start({ task: 'Research grants', project: 'grant-research', category: 'research' });
|
|
13
|
+
*
|
|
14
|
+
* // ... agent does work ...
|
|
15
|
+
*
|
|
16
|
+
* // Stop tracking
|
|
17
|
+
* clawck.stop({ id: entry.id, status: 'completed', summary: 'Found 12 matching grants' });
|
|
18
|
+
*
|
|
19
|
+
* // Get timesheet
|
|
20
|
+
* const report = clawck.timesheet('2026-03-01', '2026-03-07');
|
|
21
|
+
* console.log(`Saved ${report.total_savings_usd} in human-equivalent work`);
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export { Clawck } from './core/clawck';
|
|
25
|
+
export { ClawckDB } from './core/database';
|
|
26
|
+
export { SyncManager } from './core/sync';
|
|
27
|
+
export { createServer, startServer } from './server/api';
|
|
28
|
+
export { startMCPServer } from './server/mcp';
|
|
29
|
+
export * from './core/types';
|
|
30
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,cAAc,cAAc,CAAC"}
|