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.
- package/README.md +223 -151
- package/dist/cli/index.js +926 -30
- package/dist/cli/index.js.map +1 -1
- package/dist/core/clawck.d.ts +16 -3
- package/dist/core/clawck.d.ts.map +1 -1
- package/dist/core/clawck.js +48 -14
- package/dist/core/clawck.js.map +1 -1
- package/dist/core/database.d.ts +4 -4
- package/dist/core/database.d.ts.map +1 -1
- package/dist/core/database.js +85 -104
- package/dist/core/database.js.map +1 -1
- package/dist/core/patterns.d.ts +7 -0
- package/dist/core/patterns.d.ts.map +1 -0
- package/dist/core/patterns.js +36 -0
- package/dist/core/patterns.js.map +1 -0
- package/dist/core/types.d.ts +31 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/core/webhooks.d.ts +22 -0
- package/dist/core/webhooks.d.ts.map +1 -0
- package/dist/core/webhooks.js +70 -0
- package/dist/core/webhooks.js.map +1 -0
- package/dist/dashboard/index.d.ts.map +1 -1
- package/dist/dashboard/index.js +7 -1
- package/dist/dashboard/index.js.map +1 -1
- package/dist/hooks/adapters.d.ts +8 -0
- package/dist/hooks/adapters.d.ts.map +1 -0
- package/dist/hooks/adapters.js +138 -0
- package/dist/hooks/adapters.js.map +1 -0
- package/dist/hooks/handler.d.ts +9 -0
- package/dist/hooks/handler.d.ts.map +1 -0
- package/dist/hooks/handler.js +90 -0
- package/dist/hooks/handler.js.map +1 -0
- package/dist/hooks/index.d.ts +10 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +23 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/install.d.ts +16 -0
- package/dist/hooks/install.d.ts.map +1 -0
- package/dist/hooks/install.js +239 -0
- package/dist/hooks/install.js.map +1 -0
- package/dist/hooks/session.d.ts +10 -0
- package/dist/hooks/session.d.ts.map +1 -0
- package/dist/hooks/session.js +72 -0
- package/dist/hooks/session.js.map +1 -0
- package/dist/hooks/stdin.d.ts +6 -0
- package/dist/hooks/stdin.d.ts.map +1 -0
- package/dist/hooks/stdin.js +38 -0
- package/dist/hooks/stdin.js.map +1 -0
- package/dist/hooks/types.d.ts +23 -0
- package/dist/hooks/types.d.ts.map +1 -0
- package/dist/hooks/types.js +7 -0
- package/dist/hooks/types.js.map +1 -0
- package/dist/reports/html.d.ts +13 -0
- package/dist/reports/html.d.ts.map +1 -0
- package/dist/reports/html.js +321 -0
- package/dist/reports/html.js.map +1 -0
- package/dist/reports/pdf.d.ts +13 -0
- package/dist/reports/pdf.d.ts.map +1 -0
- package/dist/reports/pdf.js +169 -0
- package/dist/reports/pdf.js.map +1 -0
- package/dist/server/api.d.ts.map +1 -1
- package/dist/server/api.js +18 -2
- package/dist/server/api.js.map +1 -1
- package/dist/server/mcp.d.ts.map +1 -1
- package/dist/server/mcp.js +140 -32
- package/dist/server/mcp.js.map +1 -1
- package/docs/skills/clawck-setup.md +131 -0
- package/docs/skills/clawck-usage.md +148 -0
- package/docs/snippets/claude-md.txt +24 -0
- package/docs/snippets/hooks-claude.json +16 -0
- package/docs/snippets/hooks-cline.txt +10 -0
- package/docs/snippets/hooks-codex.json +16 -0
- package/docs/snippets/hooks-cursor.json +16 -0
- package/docs/snippets/hooks-gemini.json +16 -0
- package/docs/snippets/hooks-windsurf.json +16 -0
- package/docs/snippets/mcp-config.json +7 -0
- package/docs/snippets/openclaw-agent-md.txt +18 -0
- package/docs/snippets/openclaw-heartbeat-md.txt +17 -0
- 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 @@
|
|
|
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 @@
|
|
|
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, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
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"}
|