devday 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.
Files changed (47) hide show
  1. package/README.md +58 -0
  2. package/bin/devday.js +2 -0
  3. package/dist/config.d.ts +14 -0
  4. package/dist/config.d.ts.map +1 -0
  5. package/dist/config.js +89 -0
  6. package/dist/config.js.map +1 -0
  7. package/dist/cost.d.ts +12 -0
  8. package/dist/cost.d.ts.map +1 -0
  9. package/dist/cost.js +47 -0
  10. package/dist/cost.js.map +1 -0
  11. package/dist/git.d.ts +6 -0
  12. package/dist/git.d.ts.map +1 -0
  13. package/dist/git.js +95 -0
  14. package/dist/git.js.map +1 -0
  15. package/dist/index.d.ts +2 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +231 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/merge.d.ts +6 -0
  20. package/dist/merge.d.ts.map +1 -0
  21. package/dist/merge.js +80 -0
  22. package/dist/merge.js.map +1 -0
  23. package/dist/parsers/claude-code.d.ts +18 -0
  24. package/dist/parsers/claude-code.d.ts.map +1 -0
  25. package/dist/parsers/claude-code.js +385 -0
  26. package/dist/parsers/claude-code.js.map +1 -0
  27. package/dist/parsers/cursor.d.ts +15 -0
  28. package/dist/parsers/cursor.d.ts.map +1 -0
  29. package/dist/parsers/cursor.js +302 -0
  30. package/dist/parsers/cursor.js.map +1 -0
  31. package/dist/parsers/opencode.d.ts +21 -0
  32. package/dist/parsers/opencode.d.ts.map +1 -0
  33. package/dist/parsers/opencode.js +301 -0
  34. package/dist/parsers/opencode.js.map +1 -0
  35. package/dist/render.d.ts +6 -0
  36. package/dist/render.d.ts.map +1 -0
  37. package/dist/render.js +161 -0
  38. package/dist/render.js.map +1 -0
  39. package/dist/summarize.d.ts +8 -0
  40. package/dist/summarize.d.ts.map +1 -0
  41. package/dist/summarize.js +157 -0
  42. package/dist/summarize.js.map +1 -0
  43. package/dist/types.d.ts +100 -0
  44. package/dist/types.d.ts.map +1 -0
  45. package/dist/types.js +23 -0
  46. package/dist/types.js.map +1 -0
  47. package/package.json +54 -0
package/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # devday
2
+
3
+ End-of-day recap for AI-assisted coding sessions. Reads your local conversations from OpenCode, Claude Code, and Cursor, cross-references with git, and generates standup-ready summaries.
4
+
5
+ ## What it does
6
+
7
+ - Scans completed AI coding sessions from your local machine (nothing leaves your machine unless you enable LLM summaries)
8
+ - Shows tokens used, estimated cost, duration, and models per session
9
+ - Groups sessions by project and shows git commits alongside
10
+ - Optionally generates first-person standup messages via OpenAI or Anthropic
11
+
12
+ ## Supported tools
13
+
14
+ | Tool | Data source |
15
+ |------|------------|
16
+ | OpenCode | `~/.local/share/opencode/storage/` |
17
+ | Claude Code | `~/.claude/` (SQLite + JSONL) |
18
+ | Cursor | `~/Library/Application Support/Cursor/User/globalStorage/state.vscdb` |
19
+
20
+ ## Install
21
+
22
+ ```bash
23
+ git clone https://github.com/ujjwaljainnn/devday.git
24
+ cd devday
25
+ npm install
26
+ npm run build
27
+ npm link
28
+ ```
29
+
30
+ ## Usage
31
+
32
+ ```bash
33
+ devday # today's recap
34
+ devday -d yesterday # yesterday
35
+ devday -d 2026-02-11 # specific date
36
+ devday --standup # short standup format
37
+ devday --json # machine-readable output
38
+ devday --no-git # skip git integration
39
+ devday --no-summarize # skip LLM summaries
40
+ devday -v # debug output
41
+ ```
42
+
43
+ ## AI summaries
44
+
45
+ Summaries are optional. Without an API key, devday shows stats and git only.
46
+
47
+ ```bash
48
+ export OPENAI_API_KEY=sk-... # or
49
+ export ANTHROPIC_API_KEY=sk-...
50
+ ```
51
+
52
+ ## How it works
53
+
54
+ devday reads completed sessions from each tool's local storage. Active sessions (still running) may not appear until they're closed. Sessions are grouped by project directory, and git commits are matched by date.
55
+
56
+ Duration is calculated from actual message processing times (not wall-clock), capped at 5 minutes per message to handle tools that write bogus completion timestamps.
57
+
58
+ Cost is estimated from token counts and model pricing tables when the tool doesn't provide it directly.
package/bin/devday.js ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import '../dist/index.js';
@@ -0,0 +1,14 @@
1
+ import type { DevDayConfig } from './types.js';
2
+ /**
3
+ * Load config purely from environment variables + auto-detection.
4
+ * API keys come from env vars only (OPENAI_API_KEY, ANTHROPIC_API_KEY).
5
+ * Tool paths are auto-detected. Non-sensitive preferences can be saved to config file.
6
+ */
7
+ export declare function loadConfig(): DevDayConfig;
8
+ /**
9
+ * Save non-sensitive preferences to config file.
10
+ * API keys are NEVER written to disk.
11
+ */
12
+ export declare function saveConfig(config: DevDayConfig): void;
13
+ export declare function getConfigPath(): string;
14
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAY,MAAM,YAAY,CAAC;AA+BzD;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,YAAY,CAuCzC;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAOrD;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC"}
package/dist/config.js ADDED
@@ -0,0 +1,89 @@
1
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ const CONFIG_DIR = join(homedir(), '.config', 'devday');
5
+ const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
6
+ function getDefaultPaths() {
7
+ const home = homedir();
8
+ const platform = process.platform;
9
+ return {
10
+ opencodeStorage: join(home, '.local', 'share', 'opencode', 'storage'),
11
+ claudeCodeHome: join(home, '.claude'),
12
+ cursorStateDb: platform === 'darwin'
13
+ ? join(home, 'Library', 'Application Support', 'Cursor', 'User', 'globalStorage', 'state.vscdb')
14
+ : platform === 'win32'
15
+ ? join(home, 'AppData', 'Roaming', 'Cursor', 'User', 'globalStorage', 'state.vscdb')
16
+ : join(home, '.config', 'Cursor', 'User', 'globalStorage', 'state.vscdb'),
17
+ };
18
+ }
19
+ function detectAvailableTools() {
20
+ const paths = getDefaultPaths();
21
+ const tools = [];
22
+ if (existsSync(paths.opencodeStorage))
23
+ tools.push('opencode');
24
+ if (existsSync(paths.claudeCodeHome))
25
+ tools.push('claude-code');
26
+ if (existsSync(paths.cursorStateDb))
27
+ tools.push('cursor');
28
+ return tools;
29
+ }
30
+ /**
31
+ * Load config purely from environment variables + auto-detection.
32
+ * API keys come from env vars only (OPENAI_API_KEY, ANTHROPIC_API_KEY).
33
+ * Tool paths are auto-detected. Non-sensitive preferences can be saved to config file.
34
+ */
35
+ export function loadConfig() {
36
+ const paths = getDefaultPaths();
37
+ const anthropicKey = process.env.ANTHROPIC_API_KEY ?? null;
38
+ const openaiKey = process.env.OPENAI_API_KEY ?? null;
39
+ // Prefer OpenAI (cheaper for summarization), fall back to Anthropic
40
+ let preferredSummarizer = 'none';
41
+ if (openaiKey)
42
+ preferredSummarizer = 'openai';
43
+ else if (anthropicKey)
44
+ preferredSummarizer = 'anthropic';
45
+ const defaults = {
46
+ anthropicApiKey: anthropicKey,
47
+ openaiApiKey: openaiKey,
48
+ preferredSummarizer,
49
+ paths: {
50
+ opencodeStorage: existsSync(paths.opencodeStorage) ? paths.opencodeStorage : null,
51
+ claudeCodeHome: existsSync(paths.claudeCodeHome) ? paths.claudeCodeHome : null,
52
+ cursorStateDb: existsSync(paths.cursorStateDb) ? paths.cursorStateDb : null,
53
+ },
54
+ enabledTools: detectAvailableTools(),
55
+ gitAuthorFilter: null,
56
+ };
57
+ // Merge non-sensitive preferences from config file (gitAuthorFilter, etc.)
58
+ if (existsSync(CONFIG_FILE)) {
59
+ try {
60
+ const raw = readFileSync(CONFIG_FILE, 'utf-8');
61
+ const saved = JSON.parse(raw);
62
+ // Only merge non-sensitive fields — never read keys from file
63
+ if (saved.gitAuthorFilter)
64
+ defaults.gitAuthorFilter = saved.gitAuthorFilter;
65
+ if (saved.enabledTools)
66
+ defaults.enabledTools = saved.enabledTools;
67
+ }
68
+ catch {
69
+ // Ignore corrupt config
70
+ }
71
+ }
72
+ return defaults;
73
+ }
74
+ /**
75
+ * Save non-sensitive preferences to config file.
76
+ * API keys are NEVER written to disk.
77
+ */
78
+ export function saveConfig(config) {
79
+ mkdirSync(CONFIG_DIR, { recursive: true });
80
+ const safe = {
81
+ gitAuthorFilter: config.gitAuthorFilter,
82
+ enabledTools: config.enabledTools,
83
+ };
84
+ writeFileSync(CONFIG_FILE, JSON.stringify(safe, null, 2), 'utf-8');
85
+ }
86
+ export function getConfigPath() {
87
+ return CONFIG_FILE;
88
+ }
89
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
package/dist/cost.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ import { type TokenUsage } from './types.js';
2
+ /**
3
+ * Estimate cost in USD from token usage and model name.
4
+ * Falls back to a generic mid-tier pricing if model is unknown.
5
+ */
6
+ export declare function estimateCost(model: string, tokens: TokenUsage): number;
7
+ /**
8
+ * Sum multiple TokenUsage objects.
9
+ */
10
+ export declare function sumTokens(...usages: TokenUsage[]): TokenUsage;
11
+ export declare function emptyTokenUsage(): TokenUsage;
12
+ //# sourceMappingURL=cost.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost.d.ts","sourceRoot":"","sources":["../src/cost.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,UAAU,EAAqB,MAAM,YAAY,CAAC;AAE/E;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAStE;AAsBD;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,GAAG,UAAU,CAY7D;AAED,wBAAgB,eAAe,IAAI,UAAU,CAE5C"}
package/dist/cost.js ADDED
@@ -0,0 +1,47 @@
1
+ import { MODEL_PRICING } from './types.js';
2
+ /**
3
+ * Estimate cost in USD from token usage and model name.
4
+ * Falls back to a generic mid-tier pricing if model is unknown.
5
+ */
6
+ export function estimateCost(model, tokens) {
7
+ const pricing = findPricing(model);
8
+ const inputCost = (tokens.input / 1_000_000) * pricing.inputPerMillion;
9
+ const outputCost = (tokens.output / 1_000_000) * pricing.outputPerMillion;
10
+ const cacheReadCost = (tokens.cacheRead / 1_000_000) * (pricing.cacheReadPerMillion ?? pricing.inputPerMillion * 0.1);
11
+ const cacheWriteCost = (tokens.cacheWrite / 1_000_000) * (pricing.cacheWritePerMillion ?? pricing.inputPerMillion * 1.25);
12
+ return inputCost + outputCost + cacheReadCost + cacheWriteCost;
13
+ }
14
+ /**
15
+ * Find pricing for a model, trying exact match first, then prefix/substring match.
16
+ */
17
+ function findPricing(model) {
18
+ const normalized = model.toLowerCase();
19
+ // Exact match
20
+ if (MODEL_PRICING[normalized])
21
+ return MODEL_PRICING[normalized];
22
+ // Prefix / substring match
23
+ for (const [key, pricing] of Object.entries(MODEL_PRICING)) {
24
+ if (normalized.includes(key) || key.includes(normalized)) {
25
+ return pricing;
26
+ }
27
+ }
28
+ // Heuristic fallback: mid-tier pricing
29
+ return { inputPerMillion: 3, outputPerMillion: 15 };
30
+ }
31
+ /**
32
+ * Sum multiple TokenUsage objects.
33
+ */
34
+ export function sumTokens(...usages) {
35
+ return usages.reduce((acc, t) => ({
36
+ input: acc.input + t.input,
37
+ output: acc.output + t.output,
38
+ reasoning: acc.reasoning + t.reasoning,
39
+ cacheRead: acc.cacheRead + t.cacheRead,
40
+ cacheWrite: acc.cacheWrite + t.cacheWrite,
41
+ total: acc.total + t.total,
42
+ }), emptyTokenUsage());
43
+ }
44
+ export function emptyTokenUsage() {
45
+ return { input: 0, output: 0, reasoning: 0, cacheRead: 0, cacheWrite: 0, total: 0 };
46
+ }
47
+ //# sourceMappingURL=cost.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost.js","sourceRoot":"","sources":["../src/cost.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAsC,MAAM,YAAY,CAAC;AAE/E;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,KAAa,EAAE,MAAkB;IAC5D,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;IAEnC,MAAM,SAAS,GAAG,CAAC,MAAM,CAAC,KAAK,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,eAAe,CAAC;IACvE,MAAM,UAAU,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAC1E,MAAM,aAAa,GAAG,CAAC,MAAM,CAAC,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,mBAAmB,IAAI,OAAO,CAAC,eAAe,GAAG,GAAG,CAAC,CAAC;IACtH,MAAM,cAAc,GAAG,CAAC,MAAM,CAAC,UAAU,GAAG,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,oBAAoB,IAAI,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IAE1H,OAAO,SAAS,GAAG,UAAU,GAAG,aAAa,GAAG,cAAc,CAAC;AACjE,CAAC;AAED;;GAEG;AACH,SAAS,WAAW,CAAC,KAAa;IAChC,MAAM,UAAU,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IAEvC,cAAc;IACd,IAAI,aAAa,CAAC,UAAU,CAAC;QAAE,OAAO,aAAa,CAAC,UAAU,CAAC,CAAC;IAEhE,2BAA2B;IAC3B,KAAK,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;QAC3D,IAAI,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YACzD,OAAO,OAAO,CAAC;QACjB,CAAC;IACH,CAAC;IAED,uCAAuC;IACvC,OAAO,EAAE,eAAe,EAAE,CAAC,EAAE,gBAAgB,EAAE,EAAE,EAAE,CAAC;AACtD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,GAAG,MAAoB;IAC/C,OAAO,MAAM,CAAC,MAAM,CAClB,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QACX,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK;QAC1B,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM;QAC7B,SAAS,EAAE,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS;QACtC,SAAS,EAAE,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC,SAAS;QACtC,UAAU,EAAE,GAAG,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU;QACzC,KAAK,EAAE,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK;KAC3B,CAAC,EACF,eAAe,EAAE,CAClB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;AACtF,CAAC"}
package/dist/git.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ import type { GitActivity } from './types.js';
2
+ /**
3
+ * Get git activity for a project directory on a specific date.
4
+ */
5
+ export declare function getGitActivity(projectPath: string, date: string, authorFilter?: string | null): GitActivity | null;
6
+ //# sourceMappingURL=git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAa,MAAM,YAAY,CAAC;AAEzD;;GAEG;AACH,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EACZ,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAC3B,WAAW,GAAG,IAAI,CAuEpB"}
package/dist/git.js ADDED
@@ -0,0 +1,95 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import { existsSync } from 'node:fs';
3
+ import { join, basename } from 'node:path';
4
+ /**
5
+ * Get git activity for a project directory on a specific date.
6
+ */
7
+ export function getGitActivity(projectPath, date, authorFilter) {
8
+ // Verify it's a git repo
9
+ if (!existsSync(join(projectPath, '.git')))
10
+ return null;
11
+ try {
12
+ const args = [
13
+ 'log',
14
+ `--after=${date}T00:00:00`,
15
+ `--before=${date}T23:59:59`,
16
+ '--format=%H|%h|%an|%aI|%s',
17
+ '--no-merges',
18
+ ];
19
+ if (authorFilter) {
20
+ args.push(`--author=${authorFilter}`);
21
+ }
22
+ const raw = execFileSync('git', args, {
23
+ cwd: projectPath,
24
+ encoding: 'utf-8',
25
+ timeout: 10_000,
26
+ }).trim();
27
+ if (!raw) {
28
+ return {
29
+ projectPath,
30
+ projectName: basename(projectPath),
31
+ commits: [],
32
+ totalFilesChanged: 0,
33
+ totalInsertions: 0,
34
+ totalDeletions: 0,
35
+ };
36
+ }
37
+ const commitLines = raw.split('\n').filter(Boolean);
38
+ const commits = [];
39
+ for (const line of commitLines) {
40
+ const [hash, shortHash, author, timestamp, ...messageParts] = line.split('|');
41
+ const message = messageParts.join('|'); // message might contain |
42
+ const stats = getCommitStats(projectPath, hash);
43
+ commits.push({
44
+ hash,
45
+ shortHash,
46
+ message,
47
+ author,
48
+ timestamp: new Date(timestamp),
49
+ filesChanged: stats.filesChanged,
50
+ insertions: stats.insertions,
51
+ deletions: stats.deletions,
52
+ files: stats.files,
53
+ });
54
+ }
55
+ const totalFilesChanged = new Set(commits.flatMap((c) => c.files)).size;
56
+ const totalInsertions = commits.reduce((sum, c) => sum + c.insertions, 0);
57
+ const totalDeletions = commits.reduce((sum, c) => sum + c.deletions, 0);
58
+ return {
59
+ projectPath,
60
+ projectName: basename(projectPath),
61
+ commits,
62
+ totalFilesChanged,
63
+ totalInsertions,
64
+ totalDeletions,
65
+ };
66
+ }
67
+ catch {
68
+ return null;
69
+ }
70
+ }
71
+ function getCommitStats(projectPath, hash) {
72
+ try {
73
+ const raw = execFileSync('git', ['diff-tree', '--no-commit-id', '--numstat', '-r', hash], { cwd: projectPath, encoding: 'utf-8', timeout: 10_000 }).trim();
74
+ if (!raw)
75
+ return { filesChanged: 0, insertions: 0, deletions: 0, files: [] };
76
+ const lines = raw.split('\n').filter(Boolean);
77
+ let insertions = 0;
78
+ let deletions = 0;
79
+ const files = [];
80
+ for (const line of lines) {
81
+ const [ins, del, file] = line.split('\t');
82
+ if (ins !== '-')
83
+ insertions += parseInt(ins, 10) || 0;
84
+ if (del !== '-')
85
+ deletions += parseInt(del, 10) || 0;
86
+ if (file)
87
+ files.push(file);
88
+ }
89
+ return { filesChanged: files.length, insertions, deletions, files };
90
+ }
91
+ catch {
92
+ return { filesChanged: 0, insertions: 0, deletions: 0, files: [] };
93
+ }
94
+ }
95
+ //# sourceMappingURL=git.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.js","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,231 @@
1
+ import { Command } from 'commander';
2
+ import ora from 'ora';
3
+ import chalk from 'chalk';
4
+ import { format, subDays } from 'date-fns';
5
+ import { homedir } from 'node:os';
6
+ import { loadConfig } from './config.js';
7
+ import { OpenCodeParser } from './parsers/opencode.js';
8
+ import { ClaudeCodeParser } from './parsers/claude-code.js';
9
+ import { CursorParser } from './parsers/cursor.js';
10
+ import { getGitActivity } from './git.js';
11
+ import { buildDayRecap } from './merge.js';
12
+ import { summarizeRecap } from './summarize.js';
13
+ import { renderRecap } from './render.js';
14
+ let verbose = false;
15
+ function debug(msg) {
16
+ if (verbose)
17
+ console.error(chalk.dim(` [debug] ${msg}`));
18
+ }
19
+ /**
20
+ * Resolve date string: supports YYYY-MM-DD, "today", "yesterday"
21
+ */
22
+ function resolveDate(input) {
23
+ if (!input)
24
+ return format(new Date(), 'yyyy-MM-dd');
25
+ const lower = input.toLowerCase();
26
+ if (lower === 'today')
27
+ return format(new Date(), 'yyyy-MM-dd');
28
+ if (lower === 'yesterday')
29
+ return format(subDays(new Date(), 1), 'yyyy-MM-dd');
30
+ return input;
31
+ }
32
+ const program = new Command();
33
+ program
34
+ .name('devday')
35
+ .description('End-of-day recap for AI-assisted coding sessions')
36
+ .version('0.1.0')
37
+ .option('-d, --date <date>', 'date: YYYY-MM-DD, "today", or "yesterday" (default: today)')
38
+ .option('-s, --standup', 'output a short standup-ready summary')
39
+ .option('-j, --json', 'output raw JSON')
40
+ .option('-v, --verbose', 'show debug output')
41
+ .option('--no-git', 'skip git log integration')
42
+ .option('--no-summarize', 'skip LLM summarization')
43
+ .addHelpText('after', `
44
+ Examples:
45
+ $ devday today's recap
46
+ $ devday -d yesterday yesterday's recap
47
+ $ devday -d 2026-02-10 specific date
48
+ $ devday --standup short standup format
49
+ $ devday --json machine-readable output
50
+ $ devday -d yesterday -s yesterday's standup
51
+
52
+ Environment variables:
53
+ OPENAI_API_KEY enables AI-powered summaries via OpenAI (recommended)
54
+ ANTHROPIC_API_KEY enables AI-powered summaries via Anthropic
55
+
56
+ Supported tools:
57
+ opencode ~/.local/share/opencode/storage/
58
+ claude code ~/.claude/
59
+ cursor ~/Library/.../state.vscdb
60
+ `)
61
+ .action(async (opts) => {
62
+ verbose = opts.verbose ?? false;
63
+ const date = resolveDate(opts.date);
64
+ const config = loadConfig();
65
+ // Validate date format
66
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
67
+ console.error(chalk.red(`Invalid date format: "${opts.date}". Use YYYY-MM-DD, "today", or "yesterday".`));
68
+ process.exit(1);
69
+ }
70
+ const isJson = opts.json ?? false;
71
+ // ── First-run banner (skip for JSON output) ───────────────
72
+ if (!isJson) {
73
+ printBanner(config, date);
74
+ }
75
+ const spinner = ora({ text: 'Scanning sessions...', color: 'cyan' });
76
+ if (!verbose && !isJson)
77
+ spinner.start();
78
+ try {
79
+ // ── Initialize parsers ──────────────────────────────────
80
+ const parsers = [];
81
+ if (config.enabledTools.includes('opencode') && config.paths.opencodeStorage) {
82
+ parsers.push(new OpenCodeParser(config.paths.opencodeStorage));
83
+ debug(`opencode storage: ${config.paths.opencodeStorage}`);
84
+ }
85
+ if (config.enabledTools.includes('claude-code') && config.paths.claudeCodeHome) {
86
+ parsers.push(new ClaudeCodeParser(config.paths.claudeCodeHome));
87
+ debug(`claude code home: ${config.paths.claudeCodeHome}`);
88
+ }
89
+ if (config.enabledTools.includes('cursor') && config.paths.cursorStateDb) {
90
+ parsers.push(new CursorParser(config.paths.cursorStateDb));
91
+ debug(`cursor db: ${config.paths.cursorStateDb}`);
92
+ }
93
+ if (parsers.length === 0) {
94
+ spinner.stop();
95
+ printNoToolsMessage();
96
+ return;
97
+ }
98
+ // ── Collect sessions ────────────────────────────────────
99
+ const allSessions = [];
100
+ for (const parser of parsers) {
101
+ if (await parser.isAvailable()) {
102
+ spinner.text = `Reading ${parser.name} sessions...`;
103
+ debug(`scanning ${parser.name}...`);
104
+ const sessions = await parser.getSessions(date);
105
+ debug(` found ${sessions.length} session(s) from ${parser.name}`);
106
+ allSessions.push(...sessions);
107
+ }
108
+ else {
109
+ debug(`${parser.name} not available, skipping`);
110
+ }
111
+ }
112
+ // ── Early exit if nothing found ─────────────────────────
113
+ if (allSessions.length === 0) {
114
+ spinner.stop();
115
+ if (!isJson) {
116
+ console.log(chalk.dim(` No sessions found for ${date}.`));
117
+ if (date === format(new Date(), 'yyyy-MM-dd')) {
118
+ console.log(chalk.dim(' Try: devday -d yesterday'));
119
+ }
120
+ console.log('');
121
+ }
122
+ else {
123
+ console.log(JSON.stringify({ date, projects: [], totalSessions: 0 }, null, 2));
124
+ }
125
+ return;
126
+ }
127
+ spinner.text = `Found ${allSessions.length} session(s). Checking git...`;
128
+ // ── Collect git activity ────────────────────────────────
129
+ const gitActivities = [];
130
+ if (opts.git !== false) {
131
+ const projectPaths = [...new Set(allSessions.map((s) => s.projectPath).filter(Boolean))];
132
+ for (const projectPath of projectPaths) {
133
+ debug(`checking git in ${projectPath}`);
134
+ const git = getGitActivity(projectPath, date, config.gitAuthorFilter);
135
+ if (git) {
136
+ debug(` ${git.commits.length} commit(s)`);
137
+ gitActivities.push(git);
138
+ }
139
+ }
140
+ }
141
+ // ── Merge ───────────────────────────────────────────────
142
+ let recap = buildDayRecap(date, allSessions, gitActivities);
143
+ // ── Summarize (only if API key is available) ──────────
144
+ const hasApiKey = config.preferredSummarizer !== 'none';
145
+ if (hasApiKey && opts.summarize !== false) {
146
+ debug(`using ${config.preferredSummarizer} for summarization`);
147
+ spinner.text = 'Generating summary...';
148
+ recap = await summarizeRecap(recap, config);
149
+ }
150
+ else if (!hasApiKey) {
151
+ debug('no API key set, skipping summarization');
152
+ }
153
+ spinner.stop();
154
+ // ── Standup without API key → exit early ────────────────
155
+ if (opts.standup && !hasApiKey) {
156
+ console.log('');
157
+ console.log(chalk.yellow(' Standup requires an API key to generate summaries.'));
158
+ console.log('');
159
+ console.log(' Run:');
160
+ console.log(chalk.cyan(' export OPENAI_API_KEY=sk-...'));
161
+ console.log('');
162
+ console.log(' Then try again:');
163
+ console.log(chalk.cyan(' devday --standup'));
164
+ console.log('');
165
+ return;
166
+ }
167
+ // ── Render ──────────────────────────────────────────────
168
+ renderRecap(recap, { standup: opts.standup, json: isJson });
169
+ // Prompt to set API key if not configured
170
+ if (!hasApiKey && !isJson) {
171
+ console.log('');
172
+ console.log(' To generate AI-powered summaries and standup messages:');
173
+ console.log(chalk.cyan(' export OPENAI_API_KEY=sk-...'));
174
+ console.log('');
175
+ }
176
+ }
177
+ catch (error) {
178
+ spinner.stop();
179
+ console.error(chalk.red('Error:'), error instanceof Error ? error.message : error);
180
+ if (verbose && error instanceof Error && error.stack) {
181
+ console.error(chalk.dim(error.stack));
182
+ }
183
+ process.exit(1);
184
+ }
185
+ });
186
+ program.parse();
187
+ // ── Helper functions ──────────────────────────────────────────────
188
+ function printBanner(config, date) {
189
+ console.log('');
190
+ console.log(chalk.bold.cyan(' devday') + chalk.dim(' v0.1.0'));
191
+ console.log('');
192
+ // Tools detected
193
+ const tools = [];
194
+ if (config.paths.opencodeStorage)
195
+ tools.push(chalk.green('opencode'));
196
+ if (config.paths.claudeCodeHome)
197
+ tools.push(chalk.green('claude code'));
198
+ if (config.paths.cursorStateDb)
199
+ tools.push(chalk.green('cursor'));
200
+ if (tools.length > 0) {
201
+ console.log(chalk.dim(' Tools: ') + tools.join(', '));
202
+ }
203
+ else {
204
+ console.log(chalk.dim(' Tools: ') + chalk.yellow('none detected'));
205
+ }
206
+ // Summarizer status
207
+ if (config.preferredSummarizer !== 'none') {
208
+ console.log(chalk.dim(' Summaries: ') + chalk.green(config.preferredSummarizer));
209
+ }
210
+ else {
211
+ console.log(chalk.dim(' Summaries: ') + chalk.yellow('not configured'));
212
+ }
213
+ console.log(chalk.dim(` Date: ${date}`));
214
+ console.log('');
215
+ }
216
+ function printNoToolsMessage() {
217
+ const home = homedir();
218
+ console.log('');
219
+ console.log(chalk.yellow(' No AI coding tools detected.'));
220
+ console.log('');
221
+ console.log(' devday scans local conversations from these tools:');
222
+ console.log('');
223
+ console.log(` ${chalk.cyan('opencode')} ${chalk.dim(home + '/.local/share/opencode/storage/')}`);
224
+ console.log(` ${chalk.cyan('claude code')} ${chalk.dim(home + '/.claude/')}`);
225
+ console.log(` ${chalk.cyan('cursor')} ${chalk.dim('~/Library/.../state.vscdb')}`);
226
+ console.log('');
227
+ console.log(' Install a supported tool and start a coding session,');
228
+ console.log(' then run ' + chalk.cyan('devday') + ' again.');
229
+ console.log('');
230
+ }
231
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { Session, GitActivity, DayRecap } from './types.js';
2
+ /**
3
+ * Merge sessions and git activity into a DayRecap.
4
+ */
5
+ export declare function buildDayRecap(date: string, sessions: Session[], gitActivities: GitActivity[]): DayRecap;
6
+ //# sourceMappingURL=merge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.d.ts","sourceRoot":"","sources":["../src/merge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAkB,QAAQ,EAAY,MAAM,YAAY,CAAC;AAG3F;;GAEG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,OAAO,EAAE,EACnB,aAAa,EAAE,WAAW,EAAE,GAC3B,QAAQ,CAsFV"}