clawck 0.1.0 → 0.3.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.
Files changed (80) hide show
  1. package/README.md +223 -151
  2. package/dist/cli/index.js +926 -30
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/core/clawck.d.ts +16 -3
  5. package/dist/core/clawck.d.ts.map +1 -1
  6. package/dist/core/clawck.js +48 -14
  7. package/dist/core/clawck.js.map +1 -1
  8. package/dist/core/database.d.ts +4 -4
  9. package/dist/core/database.d.ts.map +1 -1
  10. package/dist/core/database.js +85 -104
  11. package/dist/core/database.js.map +1 -1
  12. package/dist/core/patterns.d.ts +7 -0
  13. package/dist/core/patterns.d.ts.map +1 -0
  14. package/dist/core/patterns.js +36 -0
  15. package/dist/core/patterns.js.map +1 -0
  16. package/dist/core/types.d.ts +31 -0
  17. package/dist/core/types.d.ts.map +1 -1
  18. package/dist/core/types.js.map +1 -1
  19. package/dist/core/webhooks.d.ts +22 -0
  20. package/dist/core/webhooks.d.ts.map +1 -0
  21. package/dist/core/webhooks.js +70 -0
  22. package/dist/core/webhooks.js.map +1 -0
  23. package/dist/dashboard/index.d.ts.map +1 -1
  24. package/dist/dashboard/index.js +7 -1
  25. package/dist/dashboard/index.js.map +1 -1
  26. package/dist/hooks/adapters.d.ts +8 -0
  27. package/dist/hooks/adapters.d.ts.map +1 -0
  28. package/dist/hooks/adapters.js +138 -0
  29. package/dist/hooks/adapters.js.map +1 -0
  30. package/dist/hooks/handler.d.ts +9 -0
  31. package/dist/hooks/handler.d.ts.map +1 -0
  32. package/dist/hooks/handler.js +90 -0
  33. package/dist/hooks/handler.js.map +1 -0
  34. package/dist/hooks/index.d.ts +10 -0
  35. package/dist/hooks/index.d.ts.map +1 -0
  36. package/dist/hooks/index.js +23 -0
  37. package/dist/hooks/index.js.map +1 -0
  38. package/dist/hooks/install.d.ts +16 -0
  39. package/dist/hooks/install.d.ts.map +1 -0
  40. package/dist/hooks/install.js +239 -0
  41. package/dist/hooks/install.js.map +1 -0
  42. package/dist/hooks/session.d.ts +10 -0
  43. package/dist/hooks/session.d.ts.map +1 -0
  44. package/dist/hooks/session.js +72 -0
  45. package/dist/hooks/session.js.map +1 -0
  46. package/dist/hooks/stdin.d.ts +6 -0
  47. package/dist/hooks/stdin.d.ts.map +1 -0
  48. package/dist/hooks/stdin.js +38 -0
  49. package/dist/hooks/stdin.js.map +1 -0
  50. package/dist/hooks/types.d.ts +23 -0
  51. package/dist/hooks/types.d.ts.map +1 -0
  52. package/dist/hooks/types.js +7 -0
  53. package/dist/hooks/types.js.map +1 -0
  54. package/dist/reports/html.d.ts +13 -0
  55. package/dist/reports/html.d.ts.map +1 -0
  56. package/dist/reports/html.js +321 -0
  57. package/dist/reports/html.js.map +1 -0
  58. package/dist/reports/pdf.d.ts +13 -0
  59. package/dist/reports/pdf.d.ts.map +1 -0
  60. package/dist/reports/pdf.js +169 -0
  61. package/dist/reports/pdf.js.map +1 -0
  62. package/dist/server/api.d.ts.map +1 -1
  63. package/dist/server/api.js +18 -2
  64. package/dist/server/api.js.map +1 -1
  65. package/dist/server/mcp.d.ts.map +1 -1
  66. package/dist/server/mcp.js +140 -32
  67. package/dist/server/mcp.js.map +1 -1
  68. package/docs/skills/clawck-setup.md +131 -0
  69. package/docs/skills/clawck-usage.md +148 -0
  70. package/docs/snippets/claude-md.txt +24 -0
  71. package/docs/snippets/hooks-claude.json +16 -0
  72. package/docs/snippets/hooks-cline.txt +10 -0
  73. package/docs/snippets/hooks-codex.json +16 -0
  74. package/docs/snippets/hooks-cursor.json +16 -0
  75. package/docs/snippets/hooks-gemini.json +16 -0
  76. package/docs/snippets/hooks-windsurf.json +16 -0
  77. package/docs/snippets/mcp-config.json +7 -0
  78. package/docs/snippets/openclaw-agent-md.txt +18 -0
  79. package/docs/snippets/openclaw-heartbeat-md.txt +17 -0
  80. package/package.json +6 -3
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ /**
3
+ * ⏱️🦀 Clawck — Session File Management
4
+ * Persists hook session state as JSON files (not SQLite) to avoid DB lock issues.
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.saveSession = saveSession;
11
+ exports.loadSession = loadSession;
12
+ exports.clearSession = clearSession;
13
+ exports.cleanStaleSessions = cleanStaleSessions;
14
+ const fs_1 = __importDefault(require("fs"));
15
+ const path_1 = __importDefault(require("path"));
16
+ function sessionsDir(dataDir) {
17
+ return path_1.default.join(dataDir, 'hooks', 'sessions');
18
+ }
19
+ function sessionPath(dataDir, sessionId) {
20
+ // Sanitize session ID to prevent path traversal
21
+ const safe = sessionId.replace(/[^a-zA-Z0-9_-]/g, '_');
22
+ return path_1.default.join(sessionsDir(dataDir), `${safe}.json`);
23
+ }
24
+ function saveSession(dataDir, sessionId, state) {
25
+ const dir = sessionsDir(dataDir);
26
+ fs_1.default.mkdirSync(dir, { recursive: true });
27
+ fs_1.default.writeFileSync(sessionPath(dataDir, sessionId), JSON.stringify(state));
28
+ }
29
+ function loadSession(dataDir, sessionId) {
30
+ const filePath = sessionPath(dataDir, sessionId);
31
+ if (!fs_1.default.existsSync(filePath))
32
+ return null;
33
+ try {
34
+ return JSON.parse(fs_1.default.readFileSync(filePath, 'utf-8'));
35
+ }
36
+ catch {
37
+ return null;
38
+ }
39
+ }
40
+ function clearSession(dataDir, sessionId) {
41
+ const filePath = sessionPath(dataDir, sessionId);
42
+ try {
43
+ fs_1.default.unlinkSync(filePath);
44
+ }
45
+ catch {
46
+ // Already gone — fine
47
+ }
48
+ }
49
+ function cleanStaleSessions(dataDir, maxAgeMs = 86400000) {
50
+ const dir = sessionsDir(dataDir);
51
+ if (!fs_1.default.existsSync(dir))
52
+ return 0;
53
+ let cleaned = 0;
54
+ const now = Date.now();
55
+ for (const file of fs_1.default.readdirSync(dir)) {
56
+ if (!file.endsWith('.json'))
57
+ continue;
58
+ const filePath = path_1.default.join(dir, file);
59
+ try {
60
+ const stat = fs_1.default.statSync(filePath);
61
+ if (now - stat.mtimeMs > maxAgeMs) {
62
+ fs_1.default.unlinkSync(filePath);
63
+ cleaned++;
64
+ }
65
+ }
66
+ catch {
67
+ // Skip files we can't stat
68
+ }
69
+ }
70
+ return cleaned;
71
+ }
72
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/hooks/session.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;AAgBH,kCAIC;AAED,kCAQC;AAED,oCAOC;AAED,gDAsBC;AA7DD,4CAAoB;AACpB,gDAAwB;AAGxB,SAAS,WAAW,CAAC,OAAe;IAClC,OAAO,cAAI,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;AACjD,CAAC;AAED,SAAS,WAAW,CAAC,OAAe,EAAE,SAAiB;IACrD,gDAAgD;IAChD,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC,CAAC;IACvD,OAAO,cAAI,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,GAAG,IAAI,OAAO,CAAC,CAAC;AACzD,CAAC;AAED,SAAgB,WAAW,CAAC,OAAe,EAAE,SAAiB,EAAE,KAAmB;IACjF,MAAM,GAAG,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IACjC,YAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACvC,YAAE,CAAC,aAAa,CAAC,WAAW,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC;AAC3E,CAAC;AAED,SAAgB,WAAW,CAAC,OAAe,EAAE,SAAiB;IAC5D,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACjD,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1C,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAgB,YAAY,CAAC,OAAe,EAAE,SAAiB;IAC7D,MAAM,QAAQ,GAAG,WAAW,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACjD,IAAI,CAAC;QACH,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,sBAAsB;IACxB,CAAC;AACH,CAAC;AAED,SAAgB,kBAAkB,CAAC,OAAe,EAAE,QAAQ,GAAG,QAAQ;IACrE,MAAM,GAAG,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IACjC,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC;IAElC,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAEvB,KAAK,MAAM,IAAI,IAAI,YAAE,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE,SAAS;QACtC,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,YAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACnC,IAAI,GAAG,GAAG,IAAI,CAAC,OAAO,GAAG,QAAQ,EAAE,CAAC;gBAClC,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;gBACxB,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,2BAA2B;QAC7B,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * ⏱️🦀 Clawck — Stdin Reader
3
+ * Reads JSON from stdin with timeout protection.
4
+ */
5
+ export declare function readStdin(timeoutMs?: number): Promise<string>;
6
+ //# sourceMappingURL=stdin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdin.d.ts","sourceRoot":"","sources":["../../src/hooks/stdin.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,wBAAgB,SAAS,CAAC,SAAS,SAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAmC3D"}
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ /**
3
+ * ⏱️🦀 Clawck — Stdin Reader
4
+ * Reads JSON from stdin with timeout protection.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.readStdin = readStdin;
8
+ function readStdin(timeoutMs = 1000) {
9
+ // No piped data if running in a TTY
10
+ if (process.stdin.isTTY) {
11
+ return Promise.resolve('');
12
+ }
13
+ return new Promise((resolve) => {
14
+ const chunks = [];
15
+ let resolved = false;
16
+ const finish = () => {
17
+ if (resolved)
18
+ return;
19
+ resolved = true;
20
+ process.stdin.removeAllListeners();
21
+ resolve(Buffer.concat(chunks).toString('utf-8'));
22
+ };
23
+ const timer = setTimeout(finish, timeoutMs);
24
+ process.stdin.on('data', (chunk) => {
25
+ chunks.push(chunk);
26
+ });
27
+ process.stdin.on('end', () => {
28
+ clearTimeout(timer);
29
+ finish();
30
+ });
31
+ process.stdin.on('error', () => {
32
+ clearTimeout(timer);
33
+ finish();
34
+ });
35
+ process.stdin.resume();
36
+ });
37
+ }
38
+ //# sourceMappingURL=stdin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdin.js","sourceRoot":"","sources":["../../src/hooks/stdin.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAEH,8BAmCC;AAnCD,SAAgB,SAAS,CAAC,SAAS,GAAG,IAAI;IACxC,oCAAoC;IACpC,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACxB,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC7B,CAAC;IAED,OAAO,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,EAAE;QACrC,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,QAAQ,GAAG,KAAK,CAAC;QAErB,MAAM,MAAM,GAAG,GAAG,EAAE;YAClB,IAAI,QAAQ;gBAAE,OAAO;YACrB,QAAQ,GAAG,IAAI,CAAC;YAChB,OAAO,CAAC,KAAK,CAAC,kBAAkB,EAAE,CAAC;YACnC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QACnD,CAAC,CAAC;QAEF,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QAE5C,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YACzC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YAC3B,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,EAAE,CAAC;QACX,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YAC7B,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,EAAE,CAAC;QACX,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;IACzB,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * ⏱️🦀 Clawck — Hook Types
3
+ * Type definitions for platform hook integration.
4
+ */
5
+ export type HookEvent = 'start' | 'stop';
6
+ export type Platform = 'claude' | 'gemini' | 'cursor' | 'cline' | 'windsurf' | 'codex' | 'unknown';
7
+ export interface HookContext {
8
+ platform: Platform;
9
+ session_id: string;
10
+ task: string;
11
+ project?: string;
12
+ agent?: string;
13
+ model?: string;
14
+ cwd?: string;
15
+ raw: unknown;
16
+ }
17
+ export interface SessionState {
18
+ entry_id: string;
19
+ platform: Platform;
20
+ started_at: string;
21
+ session_id: string;
22
+ }
23
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/hooks/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;AAEzC,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,GAAG,SAAS,CAAC;AAEnG,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,QAAQ,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,QAAQ,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB"}
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ /**
3
+ * ⏱️🦀 Clawck — Hook Types
4
+ * Type definitions for platform hook integration.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/hooks/types.ts"],"names":[],"mappings":";AAAA;;;GAGG"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * ⏱️🦀 Clawck — HTML Report Generation
3
+ * Generates interactive timesheet HTML reports.
4
+ */
5
+ import { TimesheetSummary, ClawckEntry } from '../core/types';
6
+ export interface HTMLReportOptions {
7
+ title?: string;
8
+ clientName?: string;
9
+ dateRange: string;
10
+ rawEntries?: ClawckEntry[];
11
+ }
12
+ export declare function generateTimesheetHTML(summary: TimesheetSummary, options: HTMLReportOptions): string;
13
+ //# sourceMappingURL=html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/reports/html.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE9D,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,WAAW,EAAE,CAAC;CAC5B;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,gBAAgB,EACzB,OAAO,EAAE,iBAAiB,GACzB,MAAM,CAkPR"}
@@ -0,0 +1,321 @@
1
+ "use strict";
2
+ /**
3
+ * ⏱️🦀 Clawck — HTML Report Generation
4
+ * Generates interactive timesheet HTML reports.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.generateTimesheetHTML = generateTimesheetHTML;
8
+ function generateTimesheetHTML(summary, options) {
9
+ const title = options.title || 'Clawck Timesheet Report';
10
+ const entries = summary.entries;
11
+ const rawEntries = options.rawEntries || [];
12
+ // Group entries by date for calendar
13
+ const byDate = new Map();
14
+ for (const e of entries) {
15
+ const d = byDate.get(e.date) || { count: 0, hours: 0 };
16
+ d.count++;
17
+ d.hours += e.duration_minutes / 60;
18
+ byDate.set(e.date, d);
19
+ }
20
+ // Build CSV string
21
+ const csvHeader = 'Date,Agent,Client,Project,Task,Category,Duration (min),Tokens,Cost,Human Equiv Hrs,Status,Approved';
22
+ const csvRows = entries.map(e => {
23
+ const esc = (s) => `"${s.replace(/"/g, '""')}"`;
24
+ return [e.date, esc(e.agent), esc(e.client), esc(e.project), esc(e.task), e.category,
25
+ e.duration_minutes.toFixed(2), e.tokens_total, e.cost_usd.toFixed(4),
26
+ e.human_equiv_hours.toFixed(2), e.status, e.approved ? 'yes' : 'no'].join(',');
27
+ });
28
+ const csvContent = [csvHeader, ...csvRows].join('\\n');
29
+ // Calendar range
30
+ const startDate = summary.period_start.split('T')[0];
31
+ const endDate = summary.period_end.split('T')[0];
32
+ // Max hours for color scaling
33
+ const maxHours = Math.max(...[...byDate.values()].map(d => d.hours), 1);
34
+ // Build calendar HTML
35
+ const calendarDays = buildCalendarDays(startDate, endDate, byDate, maxHours);
36
+ // Build Gantt data from raw entries
37
+ const ganttHTML = buildGanttChart(rawEntries);
38
+ return `<!DOCTYPE html>
39
+ <html lang="en">
40
+ <head>
41
+ <meta charset="UTF-8">
42
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
43
+ <title>${escapeHtml(title)}</title>
44
+ <link rel="preconnect" href="https://fonts.googleapis.com">
45
+ <link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
46
+ <style>
47
+ :root {
48
+ --bg: #0f1117;
49
+ --surface: #1a1d27;
50
+ --surface2: #242836;
51
+ --border: #2d3348;
52
+ --text: #e4e6ed;
53
+ --text-dim: #8b8fa3;
54
+ --accent: #6c63ff;
55
+ --green: #4ade80;
56
+ --red: #f87171;
57
+ --orange: #fb923c;
58
+ --blue: #60a5fa;
59
+ --cyan: #22d3ee;
60
+ --purple: #a78bfa;
61
+ --pink: #f472b6;
62
+ }
63
+ * { margin: 0; padding: 0; box-sizing: border-box; }
64
+ body { background: var(--bg); color: var(--text); font-family: 'DM Sans', sans-serif; padding: 2rem; }
65
+ .mono { font-family: 'JetBrains Mono', monospace; }
66
+ h1 { font-size: 1.8rem; font-weight: 700; margin-bottom: 0.25rem; }
67
+ .subtitle { color: var(--text-dim); font-size: 0.95rem; margin-bottom: 0.5rem; }
68
+ .meta { color: var(--text-dim); font-size: 0.8rem; margin-bottom: 1.5rem; }
69
+
70
+ /* Summary Cards */
71
+ .cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 1rem; margin-bottom: 2rem; }
72
+ .card { background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 1.2rem; }
73
+ .card-label { font-size: 0.75rem; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.3rem; }
74
+ .card-value { font-family: 'JetBrains Mono', monospace; font-size: 1.4rem; font-weight: 600; }
75
+ .card-value.green { color: var(--green); }
76
+ .card-value.blue { color: var(--blue); }
77
+ .card-value.accent { color: var(--accent); }
78
+ .card-value.orange { color: var(--orange); }
79
+
80
+ /* Tabs */
81
+ .tabs { display: flex; gap: 0; border-bottom: 1px solid var(--border); margin-bottom: 1.5rem; }
82
+ .tab { padding: 0.7rem 1.5rem; cursor: pointer; color: var(--text-dim); font-size: 0.9rem; font-weight: 500; border-bottom: 2px solid transparent; transition: all 0.2s; }
83
+ .tab:hover { color: var(--text); }
84
+ .tab.active { color: var(--accent); border-bottom-color: var(--accent); }
85
+ .tab-content { display: none; }
86
+ .tab-content.active { display: block; }
87
+
88
+ /* Calendar */
89
+ .calendar-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
90
+ .cal-header { font-size: 0.7rem; color: var(--text-dim); text-align: center; padding: 4px; font-weight: 600; }
91
+ .cal-day { background: var(--surface); border: 1px solid var(--border); border-radius: 6px; padding: 6px; min-height: 60px; font-size: 0.75rem; }
92
+ .cal-day.empty { background: transparent; border-color: transparent; }
93
+ .cal-day .day-num { font-weight: 600; margin-bottom: 2px; }
94
+ .cal-day .day-info { font-family: 'JetBrains Mono', monospace; font-size: 0.65rem; color: var(--text-dim); }
95
+ .cal-day.has-entries { border-color: var(--accent); }
96
+
97
+ /* Table */
98
+ .data-table { width: 100%; border-collapse: collapse; font-size: 0.82rem; }
99
+ .data-table th { background: var(--surface2); padding: 8px 10px; text-align: left; font-weight: 600; font-size: 0.75rem; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.03em; cursor: pointer; user-select: none; border-bottom: 1px solid var(--border); white-space: nowrap; }
100
+ .data-table th:hover { color: var(--text); }
101
+ .data-table td { padding: 7px 10px; border-bottom: 1px solid var(--border); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 200px; }
102
+ .data-table tr:hover td { background: var(--surface); }
103
+ .data-table .mono { font-family: 'JetBrains Mono', monospace; font-size: 0.78rem; }
104
+ .status-completed { color: var(--green); }
105
+ .status-running { color: var(--orange); }
106
+ .status-failed { color: var(--red); }
107
+
108
+ /* Gantt */
109
+ .gantt-container { overflow-x: auto; }
110
+ .gantt-row { display: flex; align-items: center; margin-bottom: 4px; min-height: 28px; }
111
+ .gantt-label { width: 120px; flex-shrink: 0; font-size: 0.75rem; color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
112
+ .gantt-bars { flex: 1; position: relative; height: 22px; background: var(--surface); border-radius: 4px; }
113
+ .gantt-bar { position: absolute; height: 18px; top: 2px; border-radius: 3px; opacity: 0.85; min-width: 3px; }
114
+ .gantt-bar[title]:hover { opacity: 1; }
115
+ .gantt-axis { display: flex; margin-left: 120px; margin-bottom: 8px; }
116
+ .gantt-tick { flex: 1; font-size: 0.65rem; color: var(--text-dim); font-family: 'JetBrains Mono', monospace; }
117
+
118
+ /* CSV */
119
+ .csv-container { position: relative; }
120
+ .csv-pre { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 1rem; overflow-x: auto; font-family: 'JetBrains Mono', monospace; font-size: 0.75rem; line-height: 1.6; white-space: pre; max-height: 500px; }
121
+ .copy-btn { position: absolute; top: 8px; right: 8px; background: var(--accent); color: #fff; border: none; border-radius: 6px; padding: 6px 14px; cursor: pointer; font-size: 0.78rem; font-weight: 500; }
122
+ .copy-btn:hover { opacity: 0.9; }
123
+
124
+ /* Category colors */
125
+ .cat-research { background: var(--blue); }
126
+ .cat-content { background: var(--purple); }
127
+ .cat-code { background: var(--green); }
128
+ .cat-data_entry { background: var(--cyan); }
129
+ .cat-design { background: var(--pink); }
130
+ .cat-communication { background: var(--orange); }
131
+ .cat-analysis { background: #818cf8; }
132
+ .cat-testing { background: #fbbf24; }
133
+ .cat-planning { background: #34d399; }
134
+ .cat-other { background: var(--text-dim); }
135
+ </style>
136
+ </head>
137
+ <body>
138
+ <h1>${escapeHtml(title)}</h1>
139
+ ${options.clientName ? `<div class="subtitle">Client: ${escapeHtml(options.clientName)}</div>` : ''}
140
+ <div class="subtitle">Period: ${escapeHtml(options.dateRange)}</div>
141
+ <div class="meta">Generated ${new Date().toISOString()}</div>
142
+
143
+ <div class="cards">
144
+ <div class="card"><div class="card-label">Agent Hours</div><div class="card-value mono blue">${summary.total_agent_hours.toFixed(2)}</div></div>
145
+ <div class="card"><div class="card-label">Human Equiv</div><div class="card-value mono accent">${summary.total_human_equiv_hours.toFixed(2)} hrs</div></div>
146
+ <div class="card"><div class="card-label">Cost</div><div class="card-value mono orange">$${summary.total_cost_usd.toFixed(2)}</div></div>
147
+ <div class="card"><div class="card-label">Savings</div><div class="card-value mono green">$${summary.total_savings_usd.toFixed(0)}</div></div>
148
+ <div class="card"><div class="card-label">Entries</div><div class="card-value mono">${summary.total_entries}</div></div>
149
+ <div class="card"><div class="card-label">Tokens</div><div class="card-value mono">${summary.total_tokens.toLocaleString()}</div></div>
150
+ </div>
151
+
152
+ <div class="tabs">
153
+ <div class="tab active" data-tab="calendar">Calendar</div>
154
+ <div class="tab" data-tab="table">Table</div>
155
+ <div class="tab" data-tab="gantt">Gantt</div>
156
+ <div class="tab" data-tab="csv">CSV</div>
157
+ </div>
158
+
159
+ <div id="tab-calendar" class="tab-content active">
160
+ <div class="calendar-grid">
161
+ <div class="cal-header">Sun</div><div class="cal-header">Mon</div><div class="cal-header">Tue</div>
162
+ <div class="cal-header">Wed</div><div class="cal-header">Thu</div><div class="cal-header">Fri</div><div class="cal-header">Sat</div>
163
+ ${calendarDays}
164
+ </div>
165
+ </div>
166
+
167
+ <div id="tab-table" class="tab-content">
168
+ <table class="data-table" id="entries-table">
169
+ <thead>
170
+ <tr>
171
+ <th data-col="0">Date</th><th data-col="1">Agent</th><th data-col="2">Client</th>
172
+ <th data-col="3">Project</th><th data-col="4">Task</th><th data-col="5">Category</th>
173
+ <th data-col="6">Duration</th><th data-col="7">Tokens</th><th data-col="8">Cost</th>
174
+ <th data-col="9">Human Equiv</th><th data-col="10">Status</th><th data-col="11">Approved</th>
175
+ </tr>
176
+ </thead>
177
+ <tbody>
178
+ ${entries.map(e => `<tr>
179
+ <td class="mono">${e.date}</td><td>${escapeHtml(e.agent)}</td><td>${escapeHtml(e.client)}</td>
180
+ <td>${escapeHtml(e.project)}</td><td title="${escapeHtml(e.task)}">${escapeHtml(e.task)}</td><td>${e.category}</td>
181
+ <td class="mono">${formatMins(e.duration_minutes)}</td><td class="mono">${e.tokens_total.toLocaleString()}</td>
182
+ <td class="mono">$${e.cost_usd.toFixed(4)}</td><td class="mono">${e.human_equiv_hours.toFixed(2)}h</td>
183
+ <td class="status-${e.status}">${e.status}</td><td>${e.approved ? 'Yes' : '-'}</td>
184
+ </tr>`).join('\n')}
185
+ </tbody>
186
+ </table>
187
+ </div>
188
+
189
+ <div id="tab-gantt" class="tab-content">
190
+ ${ganttHTML}
191
+ </div>
192
+
193
+ <div id="tab-csv" class="tab-content">
194
+ <div class="csv-container">
195
+ <button class="copy-btn" onclick="copyCSV()">Copy</button>
196
+ <pre class="csv-pre" id="csv-data">${escapeHtml([csvHeader, ...csvRows].join('\n'))}</pre>
197
+ </div>
198
+ </div>
199
+
200
+ <script>
201
+ // Tab switching
202
+ document.querySelectorAll('.tab').forEach(tab => {
203
+ tab.addEventListener('click', () => {
204
+ document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
205
+ document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
206
+ tab.classList.add('active');
207
+ document.getElementById('tab-' + tab.dataset.tab).classList.add('active');
208
+ });
209
+ });
210
+
211
+ // Table sorting
212
+ document.querySelectorAll('#entries-table th').forEach(th => {
213
+ let asc = true;
214
+ th.addEventListener('click', () => {
215
+ const col = parseInt(th.dataset.col);
216
+ const tbody = document.querySelector('#entries-table tbody');
217
+ const rows = Array.from(tbody.querySelectorAll('tr'));
218
+ rows.sort((a, b) => {
219
+ const av = a.children[col].textContent.trim();
220
+ const bv = b.children[col].textContent.trim();
221
+ const an = parseFloat(av.replace(/[^0-9.-]/g, ''));
222
+ const bn = parseFloat(bv.replace(/[^0-9.-]/g, ''));
223
+ if (!isNaN(an) && !isNaN(bn)) return asc ? an - bn : bn - an;
224
+ return asc ? av.localeCompare(bv) : bv.localeCompare(av);
225
+ });
226
+ rows.forEach(r => tbody.appendChild(r));
227
+ asc = !asc;
228
+ });
229
+ });
230
+
231
+ // Copy CSV
232
+ function copyCSV() {
233
+ const text = document.getElementById('csv-data').textContent;
234
+ navigator.clipboard.writeText(text).then(() => {
235
+ const btn = document.querySelector('.copy-btn');
236
+ btn.textContent = 'Copied!';
237
+ setTimeout(() => btn.textContent = 'Copy', 2000);
238
+ });
239
+ }
240
+ </script>
241
+ </body>
242
+ </html>`;
243
+ }
244
+ function escapeHtml(str) {
245
+ return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
246
+ }
247
+ function formatMins(mins) {
248
+ if (mins < 1)
249
+ return `${Math.round(mins * 60)}s`;
250
+ if (mins < 60)
251
+ return `${Math.round(mins)}m`;
252
+ const h = Math.floor(mins / 60);
253
+ const m = Math.round(mins % 60);
254
+ return m > 0 ? `${h}h ${m}m` : `${h}h`;
255
+ }
256
+ function buildCalendarDays(startStr, endStr, byDate, maxHours) {
257
+ const start = new Date(startStr + 'T00:00:00');
258
+ const end = new Date(endStr + 'T00:00:00');
259
+ const days = [];
260
+ // Pad to start of week (Sunday)
261
+ const firstDay = new Date(start);
262
+ firstDay.setDate(firstDay.getDate() - firstDay.getDay());
263
+ const current = new Date(firstDay);
264
+ while (current <= end || current.getDay() !== 0) {
265
+ const dateStr = current.toISOString().split('T')[0];
266
+ const inRange = current >= start && current <= end;
267
+ const data = byDate.get(dateStr);
268
+ if (!inRange && !data) {
269
+ days.push(`<div class="cal-day empty"></div>`);
270
+ }
271
+ else {
272
+ const hasEntries = data && data.count > 0;
273
+ const intensity = hasEntries ? Math.min(data.hours / maxHours, 1) : 0;
274
+ const bgStyle = hasEntries ? `background: rgba(108,99,255,${0.1 + intensity * 0.5})` : '';
275
+ days.push(`<div class="cal-day${hasEntries ? ' has-entries' : ''}" style="${bgStyle}">
276
+ <div class="day-num">${current.getDate()}</div>
277
+ ${hasEntries ? `<div class="day-info">${data.count} entries<br>${data.hours.toFixed(1)}h</div>` : ''}
278
+ </div>`);
279
+ }
280
+ current.setDate(current.getDate() + 1);
281
+ if (current > end && current.getDay() === 0)
282
+ break;
283
+ }
284
+ return days.join('\n');
285
+ }
286
+ function buildGanttChart(rawEntries) {
287
+ if (rawEntries.length === 0)
288
+ return '<p style="color:var(--text-dim)">No entries to display.</p>';
289
+ // Group by date
290
+ const byDate = new Map();
291
+ for (const e of rawEntries) {
292
+ const date = e.start.split('T')[0];
293
+ const arr = byDate.get(date) || [];
294
+ arr.push(e);
295
+ byDate.set(date, arr);
296
+ }
297
+ const categoryColors = {
298
+ research: 'cat-research', content: 'cat-content', code: 'cat-code',
299
+ data_entry: 'cat-data_entry', design: 'cat-design', communication: 'cat-communication',
300
+ analysis: 'cat-analysis', testing: 'cat-testing', planning: 'cat-planning', other: 'cat-other',
301
+ };
302
+ const sortedDates = [...byDate.keys()].sort();
303
+ const rows = [];
304
+ // Axis
305
+ rows.push(`<div class="gantt-axis">${Array.from({ length: 24 }, (_, i) => `<div class="gantt-tick">${String(i).padStart(2, '0')}</div>`).join('')}</div>`);
306
+ for (const date of sortedDates.slice(-14)) { // Limit to last 14 days
307
+ const dateEntries = byDate.get(date);
308
+ const bars = dateEntries.map(e => {
309
+ const startHour = new Date(e.start).getHours() + new Date(e.start).getMinutes() / 60;
310
+ const endTime = e.end ? new Date(e.end) : new Date();
311
+ const durHours = (endTime.getTime() - new Date(e.start).getTime()) / 3600000;
312
+ const left = (startHour / 24) * 100;
313
+ const width = Math.max((durHours / 24) * 100, 0.5);
314
+ const cls = categoryColors[e.category] || 'cat-other';
315
+ return `<div class="gantt-bar ${cls}" style="left:${left}%;width:${width}%" title="${escapeHtml(e.task)} (${e.category}, ${formatMins(durHours * 60)})"></div>`;
316
+ }).join('');
317
+ rows.push(`<div class="gantt-row"><div class="gantt-label">${date}</div><div class="gantt-bars">${bars}</div></div>`);
318
+ }
319
+ return `<div class="gantt-container">${rows.join('\n')}</div>`;
320
+ }
321
+ //# sourceMappingURL=html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/reports/html.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * ⏱️🦀 Clawck — PDF Report Generation
3
+ * Generates timesheet PDF reports using pdfkit.
4
+ */
5
+ import { TimesheetSummary } from '../core/types';
6
+ export interface PDFReportOptions {
7
+ title?: string;
8
+ clientName?: string;
9
+ dateRange: string;
10
+ outputPath: string;
11
+ }
12
+ export declare function generateTimesheetPDF(summary: TimesheetSummary, options: PDFReportOptions): Promise<void>;
13
+ //# sourceMappingURL=pdf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pdf.d.ts","sourceRoot":"","sources":["../../src/reports/pdf.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,gBAAgB,EACzB,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,IAAI,CAAC,CA8If"}