gh-tldr 1.0.6 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -1
- package/dist/index.js +129 -146
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,11 +29,32 @@ pnpm build
|
|
|
29
29
|
pnpm link --global
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
Or via npx
|
|
32
|
+
Or via npx:
|
|
33
33
|
```bash
|
|
34
34
|
npx gh-tldr
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
+
### Note for Aikido Safe-Chain Users
|
|
38
|
+
|
|
39
|
+
If you use [Aikido Safe-Chain](https://github.com/AikidoSec/safe-chain), you may need to bypass it when running via npx:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Bash/Zsh
|
|
43
|
+
\npx gh-tldr
|
|
44
|
+
|
|
45
|
+
# Fish
|
|
46
|
+
command npx gh-tldr
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Or add an alias to your shell config:
|
|
50
|
+
```bash
|
|
51
|
+
# ~/.bashrc or ~/.zshrc
|
|
52
|
+
alias gh-tldr='\npx gh-tldr'
|
|
53
|
+
|
|
54
|
+
# ~/.config/fish/config.fish
|
|
55
|
+
alias gh-tldr='command npx gh-tldr'
|
|
56
|
+
```
|
|
57
|
+
|
|
37
58
|
## Usage
|
|
38
59
|
|
|
39
60
|
### Interactive Mode
|
package/dist/index.js
CHANGED
|
@@ -1,44 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
3
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
4
|
+
}) : x)(function(x) {
|
|
5
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
6
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
// src/index.ts
|
|
10
|
+
import * as fs2 from "fs";
|
|
2
11
|
|
|
3
12
|
// src/cli.ts
|
|
4
13
|
import chalk from "chalk";
|
|
5
14
|
import { Command } from "commander";
|
|
6
15
|
|
|
7
16
|
// src/claude.ts
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
import
|
|
12
|
-
function findClaudeCli() {
|
|
13
|
-
const candidates = [
|
|
14
|
-
join(homedir(), ".local", "bin", "claude"),
|
|
15
|
-
join(homedir(), ".claude", "bin", "claude"),
|
|
16
|
-
"/usr/local/bin/claude",
|
|
17
|
-
"/opt/homebrew/bin/claude"
|
|
18
|
-
];
|
|
19
|
-
for (const path of candidates) {
|
|
20
|
-
if (existsSync(path)) {
|
|
21
|
-
return path;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
return "claude";
|
|
25
|
-
}
|
|
26
|
-
function getShellEnv() {
|
|
27
|
-
const currentPath = process.env.PATH || "";
|
|
28
|
-
const home = homedir();
|
|
29
|
-
const additionalPaths = [
|
|
30
|
-
join(home, ".local", "bin"),
|
|
31
|
-
join(home, ".claude", "bin"),
|
|
32
|
-
"/usr/local/bin",
|
|
33
|
-
"/opt/homebrew/bin"
|
|
34
|
-
];
|
|
35
|
-
const newPath = [...additionalPaths, currentPath].join(":");
|
|
36
|
-
return {
|
|
37
|
-
...process.env,
|
|
38
|
-
PATH: newPath,
|
|
39
|
-
HOME: home
|
|
40
|
-
};
|
|
41
|
-
}
|
|
17
|
+
import { execSync } from "child_process";
|
|
18
|
+
import * as fs from "fs";
|
|
19
|
+
import * as os from "os";
|
|
20
|
+
import * as path from "path";
|
|
42
21
|
var wordLimits = {
|
|
43
22
|
brief: { en: "20-40 word", de: "20-40 W\xF6rter" },
|
|
44
23
|
normal: { en: "50-80 word", de: "50-80 W\xF6rter" },
|
|
@@ -59,39 +38,32 @@ async function generateSummaryText(activity, lang, verbosity = "normal", model)
|
|
|
59
38
|
const prompt = buildPrompt(lang, verbosity);
|
|
60
39
|
const fullPrompt = `${prompt}
|
|
61
40
|
${JSON.stringify(activity, null, 2)}`;
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
args.push("--model", model);
|
|
65
|
-
}
|
|
66
|
-
const claudePath = findClaudeCli();
|
|
67
|
-
console.error(`[DEBUG] Claude path: ${claudePath}`);
|
|
68
|
-
console.error(`[DEBUG] Claude exists: ${existsSync(claudePath)}`);
|
|
69
|
-
console.error(`[DEBUG] HOME: ${homedir()}`);
|
|
41
|
+
const tempFile = path.join(os.tmpdir(), `gh-tldr-prompt-${Date.now()}.txt`);
|
|
42
|
+
fs.writeFileSync(tempFile, fullPrompt);
|
|
70
43
|
try {
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
44
|
+
const modelArgs = model ? `--model ${model}` : "";
|
|
45
|
+
const outputFile = `${tempFile}.out`;
|
|
46
|
+
execSync(
|
|
47
|
+
`claude -p - --output-format text ${modelArgs} < "${tempFile}" > "${outputFile}" 2>&1`,
|
|
48
|
+
{
|
|
49
|
+
stdio: "inherit",
|
|
50
|
+
timeout: 12e4
|
|
51
|
+
// 2 minute timeout
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
const stdout = fs.readFileSync(outputFile, "utf8");
|
|
55
|
+
fs.unlinkSync(outputFile);
|
|
56
|
+
return stdout.trim();
|
|
57
|
+
} finally {
|
|
78
58
|
try {
|
|
79
|
-
|
|
80
|
-
JSON.stringify(error, Object.getOwnPropertyNames(error), 2)
|
|
81
|
-
);
|
|
59
|
+
fs.unlinkSync(tempFile);
|
|
82
60
|
} catch {
|
|
83
|
-
process.stderr.write(String(error));
|
|
84
61
|
}
|
|
85
|
-
process.stderr.write("\n=== END EXECA ERROR ===\n");
|
|
86
|
-
const execaError = error;
|
|
87
|
-
throw new Error(
|
|
88
|
-
`Claude CLI failed: ${execaError.shortMessage || execaError.message || "Unknown error"}`
|
|
89
|
-
);
|
|
90
62
|
}
|
|
91
63
|
}
|
|
92
64
|
|
|
93
65
|
// src/github.ts
|
|
94
|
-
import { execa
|
|
66
|
+
import { execa } from "execa";
|
|
95
67
|
function getSinceDate(days) {
|
|
96
68
|
const date = /* @__PURE__ */ new Date();
|
|
97
69
|
date.setDate(date.getDate() - days);
|
|
@@ -114,7 +86,7 @@ async function ghApi(endpoint, params) {
|
|
|
114
86
|
`${key}=${value}`
|
|
115
87
|
])
|
|
116
88
|
];
|
|
117
|
-
const { stdout } = await
|
|
89
|
+
const { stdout } = await execa("gh", args);
|
|
118
90
|
return JSON.parse(stdout);
|
|
119
91
|
}
|
|
120
92
|
async function ghApiPaginated(endpoint, params, maxPages = 10) {
|
|
@@ -165,14 +137,14 @@ function parseCommit(item) {
|
|
|
165
137
|
};
|
|
166
138
|
}
|
|
167
139
|
async function getAuthenticatedUser() {
|
|
168
|
-
const { stdout } = await
|
|
140
|
+
const { stdout } = await execa("gh", ["api", "user", "--jq", ".login"]);
|
|
169
141
|
return stdout.trim();
|
|
170
142
|
}
|
|
171
143
|
async function fetchUserOrgs(username) {
|
|
172
144
|
try {
|
|
173
145
|
const authUser = await getAuthenticatedUser();
|
|
174
146
|
if (authUser === username) {
|
|
175
|
-
const { stdout } = await
|
|
147
|
+
const { stdout } = await execa("gh", [
|
|
176
148
|
"api",
|
|
177
149
|
"user/orgs",
|
|
178
150
|
"--jq",
|
|
@@ -183,7 +155,7 @@ async function fetchUserOrgs(username) {
|
|
|
183
155
|
} catch {
|
|
184
156
|
}
|
|
185
157
|
try {
|
|
186
|
-
const { stdout } = await
|
|
158
|
+
const { stdout } = await execa("gh", [
|
|
187
159
|
"api",
|
|
188
160
|
`users/${username}/orgs`,
|
|
189
161
|
"--jq",
|
|
@@ -199,7 +171,7 @@ async function fetchReposCreatedSince(username, since, publicOnly) {
|
|
|
199
171
|
const repos = [];
|
|
200
172
|
try {
|
|
201
173
|
const visibility = publicOnly ? "public" : "all";
|
|
202
|
-
const { stdout } = await
|
|
174
|
+
const { stdout } = await execa("gh", [
|
|
203
175
|
"api",
|
|
204
176
|
`users/${username}/repos?type=${visibility}&sort=created&direction=desc&per_page=100`
|
|
205
177
|
]);
|
|
@@ -214,7 +186,7 @@ async function fetchReposCreatedSince(username, since, publicOnly) {
|
|
|
214
186
|
const orgs = await fetchUserOrgs(username);
|
|
215
187
|
for (const org of orgs) {
|
|
216
188
|
try {
|
|
217
|
-
const { stdout } = await
|
|
189
|
+
const { stdout } = await execa("gh", [
|
|
218
190
|
"api",
|
|
219
191
|
`orgs/${org}/repos?sort=created&direction=desc&per_page=100`
|
|
220
192
|
]);
|
|
@@ -488,7 +460,7 @@ function hasActivity(activity) {
|
|
|
488
460
|
|
|
489
461
|
// src/cli.ts
|
|
490
462
|
async function checkDependencies() {
|
|
491
|
-
const { execa:
|
|
463
|
+
const { execa: execa2 } = await import("execa");
|
|
492
464
|
const deps = [
|
|
493
465
|
{ cmd: "gh", name: "GitHub CLI", installHint: "brew install gh" },
|
|
494
466
|
{
|
|
@@ -500,25 +472,22 @@ async function checkDependencies() {
|
|
|
500
472
|
const missing = [];
|
|
501
473
|
for (const dep of deps) {
|
|
502
474
|
try {
|
|
503
|
-
await
|
|
475
|
+
await execa2("which", [dep.cmd]);
|
|
504
476
|
} catch {
|
|
505
477
|
missing.push(`${dep.name} (${dep.installHint})`);
|
|
506
478
|
}
|
|
507
479
|
}
|
|
508
480
|
if (missing.length > 0) {
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
481
|
+
const message = [
|
|
482
|
+
"Missing dependencies:",
|
|
483
|
+
...missing.map((m) => ` - ${m}`)
|
|
484
|
+
].join("\n");
|
|
485
|
+
throw new Error(message);
|
|
514
486
|
}
|
|
515
487
|
try {
|
|
516
|
-
await
|
|
488
|
+
await execa2("gh", ["auth", "status"]);
|
|
517
489
|
} catch {
|
|
518
|
-
|
|
519
|
-
chalk.red("GitHub CLI not authenticated. Run 'gh auth login'.")
|
|
520
|
-
);
|
|
521
|
-
process.exit(1);
|
|
490
|
+
throw new Error("GitHub CLI not authenticated. Run 'gh auth login'.");
|
|
522
491
|
}
|
|
523
492
|
}
|
|
524
493
|
function validateVerbosity(value) {
|
|
@@ -557,6 +526,41 @@ async function execute(username, days, lang, format, publicOnly, verbosity, mode
|
|
|
557
526
|
console.log("---");
|
|
558
527
|
console.log(summaryText);
|
|
559
528
|
}
|
|
529
|
+
function extractStderr(error) {
|
|
530
|
+
if (error && typeof error === "object" && "stderr" in error) {
|
|
531
|
+
const stderr = error.stderr;
|
|
532
|
+
if (typeof stderr === "string" && stderr.trim().length > 0) {
|
|
533
|
+
return stderr.trim();
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
return void 0;
|
|
537
|
+
}
|
|
538
|
+
function formatError(error) {
|
|
539
|
+
if (error instanceof Error) {
|
|
540
|
+
const stderr = extractStderr(error);
|
|
541
|
+
if (stderr) {
|
|
542
|
+
return `${error.message}
|
|
543
|
+
${stderr}`;
|
|
544
|
+
}
|
|
545
|
+
return error.message || "Unknown error";
|
|
546
|
+
}
|
|
547
|
+
if (typeof error === "string") {
|
|
548
|
+
return error;
|
|
549
|
+
}
|
|
550
|
+
try {
|
|
551
|
+
return JSON.stringify(error);
|
|
552
|
+
} catch {
|
|
553
|
+
return String(error);
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
function handleFatal(error) {
|
|
557
|
+
const message = formatError(error);
|
|
558
|
+
const prefixed = message.startsWith("Error:") ? message : `Error: ${message}`;
|
|
559
|
+
const fs3 = __require("fs");
|
|
560
|
+
fs3.writeSync(2, `${chalk.red(prefixed)}
|
|
561
|
+
`);
|
|
562
|
+
process.exitCode = 1;
|
|
563
|
+
}
|
|
560
564
|
async function run() {
|
|
561
565
|
const program = new Command();
|
|
562
566
|
program.name("gh-tldr").description("Generate a TL;DR summary of your GitHub activity").version("1.0.0").argument("[username]", "GitHub username (defaults to authenticated user)").option("-d, --days <n>", "Time period in days", "1").option("-e, --english", "Output in English (default: German)", false).option(
|
|
@@ -571,82 +575,61 @@ async function run() {
|
|
|
571
575
|
"-m, --model <model>",
|
|
572
576
|
"Claude model to use (e.g., sonnet, opus, haiku)"
|
|
573
577
|
).action(async (username, options) => {
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
);
|
|
602
|
-
}
|
|
603
|
-
} catch (error) {
|
|
604
|
-
if (error instanceof Error) {
|
|
605
|
-
process.stderr.write(chalk.red(`Error: ${error.message}
|
|
606
|
-
`));
|
|
607
|
-
if (error.message.includes("claude")) {
|
|
608
|
-
process.stderr.write(
|
|
609
|
-
chalk.yellow(
|
|
610
|
-
"Make sure Claude CLI is installed and authenticated: https://docs.anthropic.com/en/docs/claude-code\n"
|
|
611
|
-
)
|
|
612
|
-
);
|
|
613
|
-
}
|
|
614
|
-
} else {
|
|
615
|
-
process.stderr.write(
|
|
616
|
-
chalk.red(`An unexpected error occurred: ${error}
|
|
617
|
-
`)
|
|
618
|
-
);
|
|
619
|
-
}
|
|
620
|
-
process.exitCode = 1;
|
|
578
|
+
await checkDependencies();
|
|
579
|
+
const hasArgs = process.argv.length > 2;
|
|
580
|
+
const forceInteractive = options.interactive;
|
|
581
|
+
if (!hasArgs || forceInteractive) {
|
|
582
|
+
const answers = await runInteractive();
|
|
583
|
+
await execute(
|
|
584
|
+
answers.username,
|
|
585
|
+
answers.days,
|
|
586
|
+
answers.language,
|
|
587
|
+
answers.format,
|
|
588
|
+
!answers.includePrivate,
|
|
589
|
+
answers.verbosity,
|
|
590
|
+
answers.model || void 0
|
|
591
|
+
);
|
|
592
|
+
} else {
|
|
593
|
+
const days = parseInt(options.days, 10);
|
|
594
|
+
const lang = options.english ? "en" : "de";
|
|
595
|
+
const format = options.format;
|
|
596
|
+
await execute(
|
|
597
|
+
username || "",
|
|
598
|
+
days,
|
|
599
|
+
lang,
|
|
600
|
+
format,
|
|
601
|
+
options.publicOnly,
|
|
602
|
+
validateVerbosity(options.verbosity),
|
|
603
|
+
options.model
|
|
604
|
+
);
|
|
621
605
|
}
|
|
622
606
|
});
|
|
623
|
-
|
|
607
|
+
try {
|
|
608
|
+
program.exitOverride();
|
|
609
|
+
await program.parseAsync();
|
|
610
|
+
} catch (error) {
|
|
611
|
+
if (error && typeof error === "object" && "exitCode" in error && error.exitCode === 0) {
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
handleFatal(error);
|
|
615
|
+
}
|
|
624
616
|
}
|
|
625
617
|
|
|
626
618
|
// src/index.ts
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
stderr.write("\n=== UNHANDLED ERROR ===\n");
|
|
630
|
-
stderr.write(`Type: ${typeof error}
|
|
631
|
-
`);
|
|
632
|
-
stderr.write(`Is Error: ${error instanceof Error}
|
|
633
|
-
`);
|
|
634
|
-
if (error instanceof Error) {
|
|
635
|
-
stderr.write(`Message: ${error.message}
|
|
636
|
-
`);
|
|
637
|
-
stderr.write(`Stack: ${error.stack}
|
|
619
|
+
process.on("uncaughtException", (error) => {
|
|
620
|
+
fs2.writeSync(2, `Fatal: ${error.message}
|
|
638
621
|
`);
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
`
|
|
644
|
-
);
|
|
645
|
-
} catch {
|
|
646
|
-
stderr.write(`Raw: ${String(error)}
|
|
622
|
+
process.exitCode = 1;
|
|
623
|
+
});
|
|
624
|
+
process.on("unhandledRejection", (reason) => {
|
|
625
|
+
const msg = reason instanceof Error ? reason.message : String(reason);
|
|
626
|
+
fs2.writeSync(2, `Fatal: ${msg}
|
|
647
627
|
`);
|
|
648
|
-
}
|
|
649
|
-
stderr.write("=== END ERROR ===\n");
|
|
650
628
|
process.exitCode = 1;
|
|
651
629
|
});
|
|
630
|
+
run().catch(() => {
|
|
631
|
+
if (process.exitCode === void 0) {
|
|
632
|
+
process.exitCode = 1;
|
|
633
|
+
}
|
|
634
|
+
});
|
|
652
635
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/claude.ts","../src/github.ts","../src/interactive.ts","../src/output.ts","../src/index.ts"],"sourcesContent":["import chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport { generateSummaryText } from \"./claude.js\";\nimport { fetchGitHubActivity, getAuthenticatedUser } from \"./github.js\";\nimport { runInteractive } from \"./interactive.js\";\nimport { formatActivity, hasActivity } from \"./output.js\";\nimport type { Language, OutputFormat, Verbosity } from \"./types.js\";\n\nasync function checkDependencies(): Promise<void> {\n\tconst { execa } = await import(\"execa\");\n\n\tconst deps = [\n\t\t{ cmd: \"gh\", name: \"GitHub CLI\", installHint: \"brew install gh\" },\n\t\t{\n\t\t\tcmd: \"claude\",\n\t\t\tname: \"Claude Code CLI\",\n\t\t\tinstallHint: \"npm install -g @anthropic-ai/claude-code\",\n\t\t},\n\t];\n\n\tconst missing: string[] = [];\n\n\tfor (const dep of deps) {\n\t\ttry {\n\t\t\tawait execa(\"which\", [dep.cmd]);\n\t\t} catch {\n\t\t\tmissing.push(`${dep.name} (${dep.installHint})`);\n\t\t}\n\t}\n\n\tif (missing.length > 0) {\n\t\tconsole.error(chalk.red(\"Missing dependencies:\"));\n\t\tfor (const m of missing) {\n\t\t\tconsole.error(` - ${m}`);\n\t\t}\n\t\tprocess.exit(1);\n\t}\n\n\t// Check gh auth\n\ttry {\n\t\tawait execa(\"gh\", [\"auth\", \"status\"]);\n\t} catch {\n\t\tconsole.error(\n\t\t\tchalk.red(\"GitHub CLI not authenticated. Run 'gh auth login'.\"),\n\t\t);\n\t\tprocess.exit(1);\n\t}\n}\n\ninterface CliOptions {\n\tdays: string;\n\tenglish: boolean;\n\tformat: OutputFormat;\n\tpublicOnly: boolean;\n\tinteractive: boolean;\n\tverbosity: string;\n\tmodel?: string;\n}\n\nfunction validateVerbosity(value: string): Verbosity {\n\tconst valid: Verbosity[] = [\"brief\", \"normal\", \"detailed\"];\n\treturn valid.includes(value as Verbosity) ? (value as Verbosity) : \"normal\";\n}\n\nasync function execute(\n\tusername: string,\n\tdays: number,\n\tlang: Language,\n\tformat: OutputFormat,\n\tpublicOnly: boolean,\n\tverbosity: Verbosity,\n\tmodel?: string,\n): Promise<void> {\n\t// Resolve username\n\tconst resolvedUsername = username || (await getAuthenticatedUser());\n\n\tconsole.error(\n\t\tchalk.yellow(`Fetching GitHub activity for ${resolvedUsername}...`),\n\t);\n\n\tconst activity = await fetchGitHubActivity(\n\t\tresolvedUsername,\n\t\tdays,\n\t\tpublicOnly,\n\t);\n\n\tif (!hasActivity(activity)) {\n\t\tconsole.log(\"\");\n\t\tconsole.log(`tl;dr ${activity.date}`);\n\t\tconsole.log(\"\");\n\t\tconst noActivity =\n\t\t\tlang === \"en\"\n\t\t\t\t? `No GitHub activity in the ${activity.period}.`\n\t\t\t\t: `Keine GitHub-Aktivität in den ${activity.period}.`;\n\t\tconsole.log(noActivity);\n\t\treturn;\n\t}\n\n\t// Format stats locally\n\tconst stats = formatActivity(activity, format, lang);\n\n\tconsole.error(chalk.yellow(\"Generating summary with Claude...\"));\n\n\t// Only ask Claude for the summary paragraph\n\tconst summaryText = await generateSummaryText(\n\t\tactivity,\n\t\tlang,\n\t\tverbosity,\n\t\tmodel,\n\t);\n\n\tconsole.log(\"\");\n\tconsole.log(stats);\n\tconsole.log(\"\");\n\tconsole.log(\"---\");\n\tconsole.log(summaryText);\n}\n\nexport async function run(): Promise<void> {\n\tconst program = new Command();\n\n\tprogram\n\t\t.name(\"gh-tldr\")\n\t\t.description(\"Generate a TL;DR summary of your GitHub activity\")\n\t\t.version(\"1.0.0\")\n\t\t.argument(\"[username]\", \"GitHub username (defaults to authenticated user)\")\n\t\t.option(\"-d, --days <n>\", \"Time period in days\", \"1\")\n\t\t.option(\"-e, --english\", \"Output in English (default: German)\", false)\n\t\t.option(\n\t\t\t\"-f, --format <type>\",\n\t\t\t\"Output format: slack|markdown|plain\",\n\t\t\t\"slack\",\n\t\t)\n\t\t.option(\"-p, --public-only\", \"Exclude private repositories\", false)\n\t\t.option(\"-i, --interactive\", \"Force interactive mode\", false)\n\t\t.option(\n\t\t\t\"-v, --verbosity <level>\",\n\t\t\t\"Summary verbosity: brief|normal|detailed\",\n\t\t\t\"normal\",\n\t\t)\n\t\t.option(\n\t\t\t\"-m, --model <model>\",\n\t\t\t\"Claude model to use (e.g., sonnet, opus, haiku)\",\n\t\t)\n\t\t.action(async (username: string | undefined, options: CliOptions) => {\n\t\t\ttry {\n\t\t\t\tawait checkDependencies();\n\n\t\t\t\t// Determine if we should run interactive mode\n\t\t\t\tconst hasArgs = process.argv.length > 2;\n\t\t\t\tconst forceInteractive = options.interactive;\n\n\t\t\t\tif (!hasArgs || forceInteractive) {\n\t\t\t\t\t// Interactive mode\n\t\t\t\t\tconst answers = await runInteractive();\n\t\t\t\t\tawait execute(\n\t\t\t\t\t\tanswers.username,\n\t\t\t\t\t\tanswers.days,\n\t\t\t\t\t\tanswers.language,\n\t\t\t\t\t\tanswers.format,\n\t\t\t\t\t\t!answers.includePrivate,\n\t\t\t\t\t\tanswers.verbosity,\n\t\t\t\t\t\tanswers.model || undefined,\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\t// Direct mode\n\t\t\t\t\tconst days = parseInt(options.days, 10);\n\t\t\t\t\tconst lang: Language = options.english ? \"en\" : \"de\";\n\t\t\t\t\tconst format = options.format as OutputFormat;\n\n\t\t\t\t\tawait execute(\n\t\t\t\t\t\tusername || \"\",\n\t\t\t\t\t\tdays,\n\t\t\t\t\t\tlang,\n\t\t\t\t\t\tformat,\n\t\t\t\t\t\toptions.publicOnly,\n\t\t\t\t\t\tvalidateVerbosity(options.verbosity),\n\t\t\t\t\t\toptions.model,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof Error) {\n\t\t\t\t\tprocess.stderr.write(chalk.red(`Error: ${error.message}\\n`));\n\t\t\t\t\tif (error.message.includes(\"claude\")) {\n\t\t\t\t\t\tprocess.stderr.write(\n\t\t\t\t\t\t\tchalk.yellow(\n\t\t\t\t\t\t\t\t\"Make sure Claude CLI is installed and authenticated: https://docs.anthropic.com/en/docs/claude-code\\n\",\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tprocess.stderr.write(\n\t\t\t\t\t\tchalk.red(`An unexpected error occurred: ${error}\\n`),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\t// Use exitCode instead of exit() to allow stdio to flush\n\t\t\t\tprocess.exitCode = 1;\n\t\t\t}\n\t\t});\n\n\tawait program.parseAsync();\n}\n","import { execa } from \"execa\";\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { GitHubActivity, Language, Verbosity } from \"./types.js\";\n\nfunction findClaudeCli(): string {\n\t// Common installation paths for Claude CLI\n\tconst candidates = [\n\t\tjoin(homedir(), \".local\", \"bin\", \"claude\"),\n\t\tjoin(homedir(), \".claude\", \"bin\", \"claude\"),\n\t\t\"/usr/local/bin/claude\",\n\t\t\"/opt/homebrew/bin/claude\",\n\t];\n\n\tfor (const path of candidates) {\n\t\tif (existsSync(path)) {\n\t\t\treturn path;\n\t\t}\n\t}\n\n\t// Fall back to PATH lookup\n\treturn \"claude\";\n}\n\nfunction getShellEnv(): Record<string, string> {\n\t// Ensure we have a proper PATH that includes common bin directories\n\tconst currentPath = process.env.PATH || \"\";\n\tconst home = homedir();\n\tconst additionalPaths = [\n\t\tjoin(home, \".local\", \"bin\"),\n\t\tjoin(home, \".claude\", \"bin\"),\n\t\t\"/usr/local/bin\",\n\t\t\"/opt/homebrew/bin\",\n\t];\n\n\tconst newPath = [...additionalPaths, currentPath].join(\":\");\n\n\treturn {\n\t\t...process.env,\n\t\tPATH: newPath,\n\t\tHOME: home,\n\t};\n}\n\nconst wordLimits: Record<Verbosity, Record<Language, string>> = {\n\tbrief: { en: \"20-40 word\", de: \"20-40 Wörter\" },\n\tnormal: { en: \"50-80 word\", de: \"50-80 Wörter\" },\n\tdetailed: { en: \"150-200 word\", de: \"150-200 Wörter\" },\n};\n\nfunction buildPrompt(lang: Language, verbosity: Verbosity): string {\n\tconst limit = wordLimits[verbosity][lang];\n\n\tif (lang === \"en\") {\n\t\treturn `Based on this GitHub activity data, write a summary of what was accomplished. STRICT LIMIT: ${limit}. Mention specific PR/issue titles. Casual tone, no bullet points, no emojis.\n\nGitHub Activity Data:`;\n\t}\n\n\treturn `Basierend auf diesen GitHub-Aktivitätsdaten, schreibe eine Zusammenfassung was gemacht wurde. STRIKTES LIMIT: ${limit}. Erwähne konkret die PR/Issue-Titel. Lockerer Ton, keine Aufzählungen, keine Emojis.\n\nGitHub-Aktivitätsdaten:`;\n}\n\nexport async function generateSummaryText(\n\tactivity: GitHubActivity,\n\tlang: Language,\n\tverbosity: Verbosity = \"normal\",\n\tmodel?: string,\n): Promise<string> {\n\tconst prompt = buildPrompt(lang, verbosity);\n\tconst fullPrompt = `${prompt}\\n${JSON.stringify(activity, null, 2)}`;\n\n\tconst args = [\"-p\", \"-\", \"--output-format\", \"text\"];\n\tif (model) {\n\t\targs.push(\"--model\", model);\n\t}\n\n\tconst claudePath = findClaudeCli();\n\tconsole.error(`[DEBUG] Claude path: ${claudePath}`);\n\tconsole.error(`[DEBUG] Claude exists: ${existsSync(claudePath)}`);\n\tconsole.error(`[DEBUG] HOME: ${homedir()}`);\n\n\ttry {\n\t\tconst result = await execa(claudePath, args, {\n\t\t\tinput: fullPrompt,\n\t\t\tenv: getShellEnv(),\n\t\t});\n\t\treturn result.stdout.trim();\n\t} catch (error) {\n\t\t// Log the raw error immediately before any processing\n\t\tprocess.stderr.write(\"\\n=== EXECA ERROR (raw) ===\\n\");\n\t\ttry {\n\t\t\tprocess.stderr.write(\n\t\t\t\tJSON.stringify(error, Object.getOwnPropertyNames(error as object), 2),\n\t\t\t);\n\t\t} catch {\n\t\t\tprocess.stderr.write(String(error));\n\t\t}\n\t\tprocess.stderr.write(\"\\n=== END EXECA ERROR ===\\n\");\n\n\t\t// Re-throw with details\n\t\tconst execaError = error as {\n\t\t\tmessage?: string;\n\t\t\tstderr?: string;\n\t\t\tstdout?: string;\n\t\t\texitCode?: number;\n\t\t\tcommand?: string;\n\t\t\tshortMessage?: string;\n\t\t};\n\n\t\tthrow new Error(\n\t\t\t`Claude CLI failed: ${execaError.shortMessage || execaError.message || \"Unknown error\"}`,\n\t\t);\n\t}\n}\n","import { execa } from \"execa\";\nimport type {\n\tCommit,\n\tGitHubActivity,\n\tIssue,\n\tPullRequest,\n\tRepoInfo,\n} from \"./types.js\";\n\nfunction getSinceDate(days: number): string {\n\tconst date = new Date();\n\tdate.setDate(date.getDate() - days);\n\treturn date.toISOString();\n}\n\nfunction formatDate(date: Date): string {\n\tconst day = date.getDate().toString().padStart(2, \"0\");\n\tconst month = (date.getMonth() + 1).toString().padStart(2, \"0\");\n\tconst year = date.getFullYear();\n\treturn `${day}.${month}.${year}`;\n}\n\nasync function ghApi<T>(\n\tendpoint: string,\n\tparams: Record<string, string>,\n): Promise<T> {\n\tconst args = [\n\t\t\"api\",\n\t\t\"-X\",\n\t\t\"GET\",\n\t\tendpoint,\n\t\t...Object.entries(params).flatMap(([key, value]) => [\n\t\t\t\"-f\",\n\t\t\t`${key}=${value}`,\n\t\t]),\n\t];\n\n\tconst { stdout } = await execa(\"gh\", args);\n\treturn JSON.parse(stdout) as T;\n}\n\nasync function ghApiPaginated<T>(\n\tendpoint: string,\n\tparams: Record<string, string>,\n\tmaxPages: number = 10,\n): Promise<T[]> {\n\tconst allItems: T[] = [];\n\tlet page = 1;\n\n\twhile (page <= maxPages) {\n\t\tconst result = await ghApi<SearchResult<T>>(endpoint, {\n\t\t\t...params,\n\t\t\tpage: String(page),\n\t\t\tper_page: \"100\",\n\t\t});\n\n\t\tallItems.push(...result.items);\n\n\t\tif (result.items.length < 100) {\n\t\t\tbreak;\n\t\t}\n\t\tpage++;\n\t}\n\n\treturn allItems;\n}\n\ninterface SearchResult<T> {\n\ttotal_count?: number;\n\titems: T[];\n}\n\ninterface RawPR {\n\trepository_url: string;\n\ttitle: string;\n\tnumber: number;\n\tstate: string;\n\thtml_url: string;\n}\n\ninterface RawCommit {\n\trepository: {\n\t\tname: string;\n\t\towner: { login: string };\n\t};\n\tcommit: {\n\t\tmessage: string;\n\t\tauthor: { date: string };\n\t};\n\thtml_url: string;\n}\n\ninterface RawRepo {\n\tname: string;\n\towner: { login: string };\n\tcreated_at: string;\n\thtml_url: string;\n}\n\nfunction parsePR(item: RawPR): PullRequest {\n\tconst urlParts = item.repository_url.split(\"/\");\n\treturn {\n\t\trepo: urlParts[urlParts.length - 1],\n\t\torg: urlParts[urlParts.length - 2],\n\t\ttitle: item.title,\n\t\tnumber: item.number,\n\t\tstate: item.state,\n\t\turl: item.html_url,\n\t};\n}\n\nfunction parseIssue(item: RawPR): Issue {\n\tconst urlParts = item.repository_url.split(\"/\");\n\treturn {\n\t\trepo: urlParts[urlParts.length - 1],\n\t\torg: urlParts[urlParts.length - 2],\n\t\ttitle: item.title,\n\t\tnumber: item.number,\n\t\turl: item.html_url,\n\t};\n}\n\nfunction parseCommit(item: RawCommit): Commit {\n\treturn {\n\t\trepo: item.repository.name,\n\t\torg: item.repository.owner.login,\n\t\tmessage: item.commit.message.split(\"\\n\")[0],\n\t\turl: item.html_url,\n\t\tdate: item.commit.author.date,\n\t};\n}\n\nexport async function getAuthenticatedUser(): Promise<string> {\n\tconst { stdout } = await execa(\"gh\", [\"api\", \"user\", \"--jq\", \".login\"]);\n\treturn stdout.trim();\n}\n\nasync function fetchUserOrgs(username: string): Promise<string[]> {\n\t// First try authenticated user's orgs (includes private memberships)\n\ttry {\n\t\tconst authUser = await getAuthenticatedUser();\n\t\tif (authUser === username) {\n\t\t\tconst { stdout } = await execa(\"gh\", [\n\t\t\t\t\"api\",\n\t\t\t\t\"user/orgs\",\n\t\t\t\t\"--jq\",\n\t\t\t\t\".[].login\",\n\t\t\t]);\n\t\t\treturn stdout.trim().split(\"\\n\").filter(Boolean);\n\t\t}\n\t} catch {\n\t\t// Fall through to public orgs\n\t}\n\n\t// Fallback to public orgs for other users\n\ttry {\n\t\tconst { stdout } = await execa(\"gh\", [\n\t\t\t\"api\",\n\t\t\t`users/${username}/orgs`,\n\t\t\t\"--jq\",\n\t\t\t\".[].login\",\n\t\t]);\n\t\treturn stdout.trim().split(\"\\n\").filter(Boolean);\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nasync function fetchReposCreatedSince(\n\tusername: string,\n\tsince: string,\n\tpublicOnly: boolean,\n): Promise<RepoInfo[]> {\n\tconst sinceDate = new Date(since);\n\tconst repos: RepoInfo[] = [];\n\n\t// Fetch user's own repos\n\ttry {\n\t\tconst visibility = publicOnly ? \"public\" : \"all\";\n\t\tconst { stdout } = await execa(\"gh\", [\n\t\t\t\"api\",\n\t\t\t`users/${username}/repos?type=${visibility}&sort=created&direction=desc&per_page=100`,\n\t\t]);\n\t\tconst userRepos = JSON.parse(stdout) as RawRepo[];\n\t\tfor (const repo of userRepos) {\n\t\t\tif (new Date(repo.created_at) >= sinceDate) {\n\t\t\t\trepos.push({ name: repo.name, org: repo.owner.login });\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Ignore errors for user repos\n\t}\n\n\t// Fetch repos from user's orgs\n\tconst orgs = await fetchUserOrgs(username);\n\tfor (const org of orgs) {\n\t\ttry {\n\t\t\tconst { stdout } = await execa(\"gh\", [\n\t\t\t\t\"api\",\n\t\t\t\t`orgs/${org}/repos?sort=created&direction=desc&per_page=100`,\n\t\t\t]);\n\t\t\tconst orgRepos = JSON.parse(stdout) as RawRepo[];\n\t\t\tfor (const repo of orgRepos) {\n\t\t\t\tif (new Date(repo.created_at) >= sinceDate) {\n\t\t\t\t\trepos.push({ name: repo.name, org: repo.owner.login });\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore errors for individual orgs\n\t\t}\n\t}\n\n\t// Deduplicate\n\treturn repos.filter(\n\t\t(repo, index, self) =>\n\t\t\tself.findIndex((r) => r.name === repo.name && r.org === repo.org) ===\n\t\t\tindex,\n\t);\n}\n\nexport async function fetchGitHubActivity(\n\tusername: string,\n\tdays: number,\n\tpublicOnly: boolean,\n): Promise<GitHubActivity> {\n\tconst since = getSinceDate(days);\n\tconst today = formatDate(new Date());\n\tconst visibilityFilter = publicOnly ? \" is:public\" : \"\";\n\n\t// Fetch all data in parallel with pagination\n\tconst [\n\t\tprsCreatedItems,\n\t\tprsMergedItems,\n\t\tprsReviewedItems,\n\t\tissuesCreatedItems,\n\t\tissuesClosedItems,\n\t\tcommitsItems,\n\t\trepos_created,\n\t] = await Promise.all([\n\t\tghApiPaginated<RawPR>(\"search/issues\", {\n\t\t\tq: `author:${username} type:pr created:>=${since}${visibilityFilter}`,\n\t\t}),\n\t\tghApiPaginated<RawPR>(\"search/issues\", {\n\t\t\tq: `author:${username} type:pr merged:>=${since}${visibilityFilter}`,\n\t\t}),\n\t\tghApiPaginated<RawPR>(\"search/issues\", {\n\t\t\tq: `reviewed-by:${username} type:pr created:>=${since} -author:${username}${visibilityFilter}`,\n\t\t}),\n\t\tghApiPaginated<RawPR>(\"search/issues\", {\n\t\t\tq: `author:${username} type:issue created:>=${since}${visibilityFilter}`,\n\t\t}),\n\t\tghApiPaginated<RawPR>(\"search/issues\", {\n\t\t\tq: `author:${username} type:issue closed:>=${since}${visibilityFilter}`,\n\t\t}),\n\t\tghApiPaginated<RawCommit>(\"search/commits\", {\n\t\t\tq: `author:${username} committer-date:>=${since}`,\n\t\t}),\n\t\tfetchReposCreatedSince(username, since, publicOnly),\n\t]);\n\n\tconst prs_created = prsCreatedItems.map(parsePR);\n\tconst prs_merged = prsMergedItems.map(parsePR);\n\tconst prs_reviewed = prsReviewedItems.map(parsePR);\n\tconst issues_created = issuesCreatedItems.map(parseIssue);\n\tconst issues_closed = issuesClosedItems.map(parseIssue);\n\tconst commits = commitsItems.map(parseCommit);\n\n\t// Extract unique repos touched\n\tconst allRepos = [\n\t\t...prs_created,\n\t\t...prs_merged,\n\t\t...prs_reviewed,\n\t\t...issues_created,\n\t\t...issues_closed,\n\t\t...commits,\n\t].map((item) => `${item.org}/${item.repo}`);\n\n\tconst repos_touched = [...new Set(allRepos)];\n\n\tconst periodText =\n\t\tdays === 1\n\t\t\t? \"last 24 hours\"\n\t\t\t: days === 7\n\t\t\t\t? \"last 7 days\"\n\t\t\t\t: days === 30\n\t\t\t\t\t? \"last 30 days\"\n\t\t\t\t\t: `last ${days} days`;\n\n\treturn {\n\t\tuser: username,\n\t\tdate: today,\n\t\tperiod: periodText,\n\t\tprs_created,\n\t\tprs_merged,\n\t\tprs_reviewed,\n\t\tissues_created,\n\t\tissues_closed,\n\t\tcommits,\n\t\trepos_created,\n\t\trepos_touched,\n\t};\n}\n","import { confirm, input, select } from \"@inquirer/prompts\";\nimport type { Language, OutputFormat, Verbosity } from \"./types.js\";\n\ninterface InteractiveOptions {\n\tusername: string;\n\tdays: number;\n\tlanguage: Language;\n\tverbosity: Verbosity;\n\tformat: OutputFormat;\n\tincludePrivate: boolean;\n\tmodel: string;\n}\n\nexport async function runInteractive(): Promise<InteractiveOptions> {\n\tconst username = await input({\n\t\tmessage: \"GitHub username (leave empty for authenticated user)\",\n\t\tdefault: \"\",\n\t});\n\n\tconst days = await select({\n\t\tmessage: \"Time period\",\n\t\tchoices: [\n\t\t\t{ name: \"Last 24 hours\", value: 1 },\n\t\t\t{ name: \"Last 7 days\", value: 7 },\n\t\t\t{ name: \"Last 30 days\", value: 30 },\n\t\t],\n\t\tdefault: 1,\n\t});\n\n\tconst language = await select({\n\t\tmessage: \"Language\",\n\t\tchoices: [\n\t\t\t{ name: \"English\", value: \"en\" as Language },\n\t\t\t{ name: \"German\", value: \"de\" as Language },\n\t\t],\n\t\tdefault: \"en\" as Language,\n\t});\n\n\tconst verbosity = await select({\n\t\tmessage: \"Summary verbosity\",\n\t\tchoices: [\n\t\t\t{ name: \"Brief (~30 words)\", value: \"brief\" as Verbosity },\n\t\t\t{ name: \"Normal (~60 words)\", value: \"normal\" as Verbosity },\n\t\t\t{ name: \"Detailed (~175 words)\", value: \"detailed\" as Verbosity },\n\t\t],\n\t\tdefault: \"normal\" as Verbosity,\n\t});\n\n\tconst format = await select({\n\t\tmessage: \"Output format\",\n\t\tchoices: [\n\t\t\t{ name: \"Plain text\", value: \"plain\" as OutputFormat },\n\t\t\t{ name: \"Markdown\", value: \"markdown\" as OutputFormat },\n\t\t\t{ name: \"Slack\", value: \"slack\" as OutputFormat },\n\t\t],\n\t\tdefault: \"plain\" as OutputFormat,\n\t});\n\n\tconst includePrivate = await confirm({\n\t\tmessage: \"Include private repos?\",\n\t\tdefault: true,\n\t});\n\n\tconst model = await input({\n\t\tmessage: \"Claude model (leave empty for default)\",\n\t\tdefault: \"\",\n\t});\n\n\treturn {\n\t\tusername,\n\t\tdays,\n\t\tlanguage,\n\t\tverbosity,\n\t\tformat,\n\t\tincludePrivate,\n\t\tmodel,\n\t};\n}\n","import type {\n\tCommit,\n\tGitHubActivity,\n\tLanguage,\n\tOutputFormat,\n} from \"./types.js\";\n\n// Gap threshold: if gap between commits > 3 hours, treat as separate session\nconst GAP_THRESHOLD_MS = 3 * 60 * 60 * 1000;\n// Minimum time to count for a single-commit session (15 minutes)\nconst SINGLE_COMMIT_HOURS = 0.25;\n\nfunction calculateWorkSession(\n\tcommits: Commit[],\n\tlang: Language,\n): string | null {\n\tif (commits.length < 2) return null;\n\n\t// Sort timestamps chronologically\n\tconst timestamps = commits\n\t\t.map((c) => new Date(c.date).getTime())\n\t\t.sort((a, b) => a - b);\n\n\t// Group commits into sessions based on gap threshold\n\tconst sessions: number[][] = [];\n\tlet currentSession = [timestamps[0]];\n\n\tfor (let i = 1; i < timestamps.length; i++) {\n\t\tconst gap = timestamps[i] - timestamps[i - 1];\n\t\tif (gap > GAP_THRESHOLD_MS) {\n\t\t\tsessions.push(currentSession);\n\t\t\tcurrentSession = [timestamps[i]];\n\t\t} else {\n\t\t\tcurrentSession.push(timestamps[i]);\n\t\t}\n\t}\n\tsessions.push(currentSession);\n\n\t// Calculate total hours across all sessions\n\tlet totalHours = 0;\n\tfor (const session of sessions) {\n\t\tif (session.length === 1) {\n\t\t\ttotalHours += SINGLE_COMMIT_HOURS;\n\t\t} else {\n\t\t\tconst duration = session[session.length - 1] - session[0];\n\t\t\ttotalHours += duration / (1000 * 60 * 60);\n\t\t}\n\t}\n\n\t// Round to nearest 0.5 hours\n\tconst rounded = Math.round(totalHours * 2) / 2;\n\n\tif (rounded < 0.5) return null;\n\n\tconst label = lang === \"en\" ? \"Work session\" : \"Arbeitszeit\";\n\tconst hoursLabel =\n\t\trounded === 1\n\t\t\t? lang === \"en\"\n\t\t\t\t? \"hour\"\n\t\t\t\t: \"Stunde\"\n\t\t\t: lang === \"en\"\n\t\t\t\t? \"hours\"\n\t\t\t\t: \"Stunden\";\n\n\treturn `${label}: ~${rounded} ${hoursLabel}`;\n}\n\nfunction getRepoNames(items: { repo: string }[]): string {\n\tconst repos = [...new Set(items.map((i) => i.repo))];\n\treturn repos.join(\", \");\n}\n\nfunction formatActivityLine(\n\tcount: number,\n\tlabelEn: string,\n\tlabelDe: string,\n\trepos: string,\n\tlang: Language,\n\tformat: OutputFormat,\n): string | null {\n\tif (count === 0) return null;\n\n\tconst label = lang === \"en\" ? labelEn : labelDe;\n\tconst repoSuffix = repos ? ` (${repos})` : \"\";\n\n\tif (format === \"markdown\") {\n\t\treturn `- **${count}** ${label}${repoSuffix}`;\n\t}\n\treturn `• ${count} ${label}${repoSuffix}`;\n}\n\nexport function formatActivity(\n\tactivity: GitHubActivity,\n\tformat: OutputFormat,\n\tlang: Language,\n): string {\n\tconst lines: string[] = [];\n\n\t// Header\n\tconst headerPrefix = format === \"markdown\" ? \"## \" : \"\";\n\tlines.push(`${headerPrefix}tl;dr ${activity.date}`);\n\tlines.push(\"\");\n\n\tconst activityLines = [\n\t\tformatActivityLine(\n\t\t\tactivity.prs_created.length,\n\t\t\t\"PRs created\",\n\t\t\t\"PRs erstellt\",\n\t\t\tgetRepoNames(activity.prs_created),\n\t\t\tlang,\n\t\t\tformat,\n\t\t),\n\t\tformatActivityLine(\n\t\t\tactivity.prs_reviewed.length,\n\t\t\t\"PRs reviewed\",\n\t\t\t\"PRs reviewed/approved\",\n\t\t\tgetRepoNames(activity.prs_reviewed),\n\t\t\tlang,\n\t\t\tformat,\n\t\t),\n\t\tformatActivityLine(\n\t\t\tactivity.prs_merged.length,\n\t\t\t\"PRs merged\",\n\t\t\t\"PRs gemerged\",\n\t\t\tgetRepoNames(activity.prs_merged),\n\t\t\tlang,\n\t\t\tformat,\n\t\t),\n\t\tformatActivityLine(\n\t\t\tactivity.issues_created.length,\n\t\t\t\"issues created\",\n\t\t\t\"Issues erstellt\",\n\t\t\tgetRepoNames(activity.issues_created),\n\t\t\tlang,\n\t\t\tformat,\n\t\t),\n\t\tformatActivityLine(\n\t\t\tactivity.issues_closed.length,\n\t\t\t\"issues closed\",\n\t\t\t\"Issues geschlossen\",\n\t\t\tgetRepoNames(activity.issues_closed),\n\t\t\tlang,\n\t\t\tformat,\n\t\t),\n\t\tformatActivityLine(\n\t\t\tactivity.commits.length,\n\t\t\t\"commits\",\n\t\t\t\"Commits\",\n\t\t\tgetRepoNames(activity.commits),\n\t\t\tlang,\n\t\t\tformat,\n\t\t),\n\t\tformatActivityLine(\n\t\t\tactivity.repos_created.length,\n\t\t\t\"new repos created\",\n\t\t\t\"neue Repos erstellt\",\n\t\t\tactivity.repos_created.map((r) => r.name).join(\", \"),\n\t\t\tlang,\n\t\t\tformat,\n\t\t),\n\t].filter(Boolean) as string[];\n\n\tif (activityLines.length === 0) {\n\t\tconst noActivity =\n\t\t\tlang === \"en\"\n\t\t\t\t? `No GitHub activity in the ${activity.period}.`\n\t\t\t\t: `Keine GitHub-Aktivität in den ${activity.period}.`;\n\t\tlines.push(noActivity);\n\t\treturn lines.join(\"\\n\");\n\t}\n\n\tlines.push(...activityLines);\n\n\t// Work session duration\n\tconst workSession = calculateWorkSession(activity.commits, lang);\n\tif (workSession) {\n\t\tlines.push(format === \"markdown\" ? `- ${workSession}` : `• ${workSession}`);\n\t}\n\n\tlines.push(\"\");\n\n\t// Repos touched\n\tif (activity.repos_touched.length > 0) {\n\t\tconst reposLabel = lang === \"en\" ? \"Repos\" : \"Repos\";\n\t\tlines.push(`${reposLabel}: ${activity.repos_touched.join(\", \")}`);\n\t}\n\n\treturn lines.join(\"\\n\");\n}\n\nexport function hasActivity(activity: GitHubActivity): boolean {\n\treturn (\n\t\tactivity.prs_created.length +\n\t\t\tactivity.prs_merged.length +\n\t\t\tactivity.prs_reviewed.length +\n\t\t\tactivity.issues_created.length +\n\t\t\tactivity.issues_closed.length >\n\t\t0\n\t);\n}\n","// gh-tldr - Generate a TL;DR summary of your GitHub activity\n// Entry point: detects mode (interactive vs direct) and runs CLI\n\nimport { run } from \"./cli.js\";\n\nrun().catch((error: unknown) => {\n\t// Force output of any unhandled error\n\tconst stderr = process.stderr;\n\tstderr.write(\"\\n=== UNHANDLED ERROR ===\\n\");\n\tstderr.write(`Type: ${typeof error}\\n`);\n\tstderr.write(`Is Error: ${error instanceof Error}\\n`);\n\n\tif (error instanceof Error) {\n\t\tstderr.write(`Message: ${error.message}\\n`);\n\t\tstderr.write(`Stack: ${error.stack}\\n`);\n\t}\n\n\ttry {\n\t\tstderr.write(\n\t\t\t`JSON: ${JSON.stringify(error, Object.getOwnPropertyNames(error as object), 2)}\\n`,\n\t\t);\n\t} catch {\n\t\tstderr.write(`Raw: ${String(error)}\\n`);\n\t}\n\n\tstderr.write(\"=== END ERROR ===\\n\");\n\tprocess.exitCode = 1;\n});\n"],"mappings":"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","names":["execa","execa"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/cli.ts","../src/claude.ts","../src/github.ts","../src/interactive.ts","../src/output.ts"],"sourcesContent":["// gh-tldr - Generate a TL;DR summary of your GitHub activity\n// Entry point with proper error handling for npx/global install contexts\n\nimport * as fs from \"node:fs\";\n\n// Global handlers for truly unexpected errors (defense in depth)\n// Use fs.writeSync(2, ...) for synchronous stderr - ensures output before exit\nprocess.on(\"uncaughtException\", (error) => {\n\tfs.writeSync(2, `Fatal: ${error.message}\\n`);\n\tprocess.exitCode = 1;\n});\n\nprocess.on(\"unhandledRejection\", (reason) => {\n\tconst msg = reason instanceof Error ? reason.message : String(reason);\n\tfs.writeSync(2, `Fatal: ${msg}\\n`);\n\tprocess.exitCode = 1;\n});\n\nimport { run } from \"./cli.js\";\n\n// Await run() to ensure proper async handling\nrun().catch(() => {\n\t// Error already printed by run()'s handleFatal()\n\t// This prevents unhandled rejection and ensures exit code is set\n\tif (process.exitCode === undefined) {\n\t\tprocess.exitCode = 1;\n\t}\n});\n","import chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport { generateSummaryText } from \"./claude.js\";\nimport { fetchGitHubActivity, getAuthenticatedUser } from \"./github.js\";\nimport { runInteractive } from \"./interactive.js\";\nimport { formatActivity, hasActivity } from \"./output.js\";\nimport type { Language, OutputFormat, Verbosity } from \"./types.js\";\n\nasync function checkDependencies(): Promise<void> {\n\tconst { execa } = await import(\"execa\");\n\n\tconst deps = [\n\t\t{ cmd: \"gh\", name: \"GitHub CLI\", installHint: \"brew install gh\" },\n\t\t{\n\t\t\tcmd: \"claude\",\n\t\t\tname: \"Claude Code CLI\",\n\t\t\tinstallHint: \"npm install -g @anthropic-ai/claude-code\",\n\t\t},\n\t];\n\n\tconst missing: string[] = [];\n\n\tfor (const dep of deps) {\n\t\ttry {\n\t\t\tawait execa(\"which\", [dep.cmd]);\n\t\t} catch {\n\t\t\tmissing.push(`${dep.name} (${dep.installHint})`);\n\t\t}\n\t}\n\n\tif (missing.length > 0) {\n\t\tconst message = [\n\t\t\t\"Missing dependencies:\",\n\t\t\t...missing.map((m) => ` - ${m}`),\n\t\t].join(\"\\n\");\n\t\tthrow new Error(message);\n\t}\n\n\t// Check gh auth\n\ttry {\n\t\tawait execa(\"gh\", [\"auth\", \"status\"]);\n\t} catch {\n\t\tthrow new Error(\"GitHub CLI not authenticated. Run 'gh auth login'.\");\n\t}\n}\n\ninterface CliOptions {\n\tdays: string;\n\tenglish: boolean;\n\tformat: OutputFormat;\n\tpublicOnly: boolean;\n\tinteractive: boolean;\n\tverbosity: string;\n\tmodel?: string;\n}\n\nfunction validateVerbosity(value: string): Verbosity {\n\tconst valid: Verbosity[] = [\"brief\", \"normal\", \"detailed\"];\n\treturn valid.includes(value as Verbosity) ? (value as Verbosity) : \"normal\";\n}\n\nasync function execute(\n\tusername: string,\n\tdays: number,\n\tlang: Language,\n\tformat: OutputFormat,\n\tpublicOnly: boolean,\n\tverbosity: Verbosity,\n\tmodel?: string,\n): Promise<void> {\n\t// Resolve username\n\tconst resolvedUsername = username || (await getAuthenticatedUser());\n\n\tconsole.error(\n\t\tchalk.yellow(`Fetching GitHub activity for ${resolvedUsername}...`),\n\t);\n\n\tconst activity = await fetchGitHubActivity(\n\t\tresolvedUsername,\n\t\tdays,\n\t\tpublicOnly,\n\t);\n\n\tif (!hasActivity(activity)) {\n\t\tconsole.log(\"\");\n\t\tconsole.log(`tl;dr ${activity.date}`);\n\t\tconsole.log(\"\");\n\t\tconst noActivity =\n\t\t\tlang === \"en\"\n\t\t\t\t? `No GitHub activity in the ${activity.period}.`\n\t\t\t\t: `Keine GitHub-Aktivität in den ${activity.period}.`;\n\t\tconsole.log(noActivity);\n\t\treturn;\n\t}\n\n\t// Format stats locally\n\tconst stats = formatActivity(activity, format, lang);\n\n\tconsole.error(chalk.yellow(\"Generating summary with Claude...\"));\n\n\t// Only ask Claude for the summary paragraph\n\tconst summaryText = await generateSummaryText(\n\t\tactivity,\n\t\tlang,\n\t\tverbosity,\n\t\tmodel,\n\t);\n\n\tconsole.log(\"\");\n\tconsole.log(stats);\n\tconsole.log(\"\");\n\tconsole.log(\"---\");\n\tconsole.log(summaryText);\n}\n\nfunction extractStderr(error: unknown): string | undefined {\n\tif (error && typeof error === \"object\" && \"stderr\" in error) {\n\t\tconst stderr = (error as { stderr?: unknown }).stderr;\n\t\tif (typeof stderr === \"string\" && stderr.trim().length > 0) {\n\t\t\treturn stderr.trim();\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction formatError(error: unknown): string {\n\tif (error instanceof Error) {\n\t\tconst stderr = extractStderr(error);\n\t\tif (stderr) {\n\t\t\treturn `${error.message}\\n${stderr}`;\n\t\t}\n\t\treturn error.message || \"Unknown error\";\n\t}\n\tif (typeof error === \"string\") {\n\t\treturn error;\n\t}\n\ttry {\n\t\treturn JSON.stringify(error);\n\t} catch {\n\t\treturn String(error);\n\t}\n}\n\nfunction handleFatal(error: unknown): void {\n\tconst message = formatError(error);\n\tconst prefixed = message.startsWith(\"Error:\") ? message : `Error: ${message}`;\n\t// Use fs.writeSync for synchronous output - ensures error is visible\n\t// before process exits, even when stderr is piped (npm exec/npx)\n\tconst fs = require(\"node:fs\") as typeof import(\"node:fs\");\n\tfs.writeSync(2, `${chalk.red(prefixed)}\\n`);\n\tprocess.exitCode = 1;\n}\n\nexport async function run(): Promise<void> {\n\tconst program = new Command();\n\n\tprogram\n\t\t.name(\"gh-tldr\")\n\t\t.description(\"Generate a TL;DR summary of your GitHub activity\")\n\t\t.version(\"1.0.0\")\n\t\t.argument(\"[username]\", \"GitHub username (defaults to authenticated user)\")\n\t\t.option(\"-d, --days <n>\", \"Time period in days\", \"1\")\n\t\t.option(\"-e, --english\", \"Output in English (default: German)\", false)\n\t\t.option(\n\t\t\t\"-f, --format <type>\",\n\t\t\t\"Output format: slack|markdown|plain\",\n\t\t\t\"slack\",\n\t\t)\n\t\t.option(\"-p, --public-only\", \"Exclude private repositories\", false)\n\t\t.option(\"-i, --interactive\", \"Force interactive mode\", false)\n\t\t.option(\n\t\t\t\"-v, --verbosity <level>\",\n\t\t\t\"Summary verbosity: brief|normal|detailed\",\n\t\t\t\"normal\",\n\t\t)\n\t\t.option(\n\t\t\t\"-m, --model <model>\",\n\t\t\t\"Claude model to use (e.g., sonnet, opus, haiku)\",\n\t\t)\n\t\t.action(async (username: string | undefined, options: CliOptions) => {\n\t\t\tawait checkDependencies();\n\n\t\t\t// Determine if we should run interactive mode\n\t\t\tconst hasArgs = process.argv.length > 2;\n\t\t\tconst forceInteractive = options.interactive;\n\n\t\t\tif (!hasArgs || forceInteractive) {\n\t\t\t\t// Interactive mode\n\t\t\t\tconst answers = await runInteractive();\n\t\t\t\tawait execute(\n\t\t\t\t\tanswers.username,\n\t\t\t\t\tanswers.days,\n\t\t\t\t\tanswers.language,\n\t\t\t\t\tanswers.format,\n\t\t\t\t\t!answers.includePrivate,\n\t\t\t\t\tanswers.verbosity,\n\t\t\t\t\tanswers.model || undefined,\n\t\t\t\t);\n\t\t\t} else {\n\t\t\t\t// Direct mode\n\t\t\t\tconst days = parseInt(options.days, 10);\n\t\t\t\tconst lang: Language = options.english ? \"en\" : \"de\";\n\t\t\t\tconst format = options.format as OutputFormat;\n\n\t\t\t\tawait execute(\n\t\t\t\t\tusername || \"\",\n\t\t\t\t\tdays,\n\t\t\t\t\tlang,\n\t\t\t\t\tformat,\n\t\t\t\t\toptions.publicOnly,\n\t\t\t\t\tvalidateVerbosity(options.verbosity),\n\t\t\t\t\toptions.model,\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\n\ttry {\n\t\tprogram.exitOverride();\n\t\tawait program.parseAsync();\n\t} catch (error) {\n\t\tif (\n\t\t\terror &&\n\t\t\ttypeof error === \"object\" &&\n\t\t\t\"exitCode\" in error &&\n\t\t\t(error as { exitCode?: number }).exitCode === 0\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\thandleFatal(error);\n\t}\n}\n","import { execSync } from \"node:child_process\";\nimport * as fs from \"node:fs\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport type { GitHubActivity, Language, Verbosity } from \"./types.js\";\n\nconst wordLimits: Record<Verbosity, Record<Language, string>> = {\n\tbrief: { en: \"20-40 word\", de: \"20-40 Wörter\" },\n\tnormal: { en: \"50-80 word\", de: \"50-80 Wörter\" },\n\tdetailed: { en: \"150-200 word\", de: \"150-200 Wörter\" },\n};\n\nfunction buildPrompt(lang: Language, verbosity: Verbosity): string {\n\tconst limit = wordLimits[verbosity][lang];\n\n\tif (lang === \"en\") {\n\t\treturn `Based on this GitHub activity data, write a summary of what was accomplished. STRICT LIMIT: ${limit}. Mention specific PR/issue titles. Casual tone, no bullet points, no emojis.\n\nGitHub Activity Data:`;\n\t}\n\n\treturn `Basierend auf diesen GitHub-Aktivitätsdaten, schreibe eine Zusammenfassung was gemacht wurde. STRIKTES LIMIT: ${limit}. Erwähne konkret die PR/Issue-Titel. Lockerer Ton, keine Aufzählungen, keine Emojis.\n\nGitHub-Aktivitätsdaten:`;\n}\n\nexport async function generateSummaryText(\n\tactivity: GitHubActivity,\n\tlang: Language,\n\tverbosity: Verbosity = \"normal\",\n\tmodel?: string,\n): Promise<string> {\n\tconst prompt = buildPrompt(lang, verbosity);\n\tconst fullPrompt = `${prompt}\\n${JSON.stringify(activity, null, 2)}`;\n\n\t// Write prompt to temp file to avoid both E2BIG (arg too long) and\n\t// stdin pipe issues in npm exec/npx contexts\n\tconst tempFile = path.join(os.tmpdir(), `gh-tldr-prompt-${Date.now()}.txt`);\n\tfs.writeFileSync(tempFile, fullPrompt);\n\n\ttry {\n\t\tconst modelArgs = model ? `--model ${model}` : \"\";\n\t\t// Write output to another temp file to capture it\n\t\tconst outputFile = `${tempFile}.out`;\n\t\t// Use execSync with inherited stdio but redirect output to file\n\t\t// This avoids all pipe buffering issues\n\t\texecSync(\n\t\t\t`claude -p - --output-format text ${modelArgs} < \"${tempFile}\" > \"${outputFile}\" 2>&1`,\n\t\t\t{\n\t\t\t\tstdio: \"inherit\",\n\t\t\t\ttimeout: 120000, // 2 minute timeout\n\t\t\t},\n\t\t);\n\t\tconst stdout = fs.readFileSync(outputFile, \"utf8\");\n\t\tfs.unlinkSync(outputFile);\n\t\treturn stdout.trim();\n\t} finally {\n\t\ttry {\n\t\t\tfs.unlinkSync(tempFile);\n\t\t} catch {}\n\t}\n}\n","import { execa } from \"execa\";\nimport type {\n\tCommit,\n\tGitHubActivity,\n\tIssue,\n\tPullRequest,\n\tRepoInfo,\n} from \"./types.js\";\n\nfunction getSinceDate(days: number): string {\n\tconst date = new Date();\n\tdate.setDate(date.getDate() - days);\n\treturn date.toISOString();\n}\n\nfunction formatDate(date: Date): string {\n\tconst day = date.getDate().toString().padStart(2, \"0\");\n\tconst month = (date.getMonth() + 1).toString().padStart(2, \"0\");\n\tconst year = date.getFullYear();\n\treturn `${day}.${month}.${year}`;\n}\n\nasync function ghApi<T>(\n\tendpoint: string,\n\tparams: Record<string, string>,\n): Promise<T> {\n\tconst args = [\n\t\t\"api\",\n\t\t\"-X\",\n\t\t\"GET\",\n\t\tendpoint,\n\t\t...Object.entries(params).flatMap(([key, value]) => [\n\t\t\t\"-f\",\n\t\t\t`${key}=${value}`,\n\t\t]),\n\t];\n\n\tconst { stdout } = await execa(\"gh\", args);\n\treturn JSON.parse(stdout) as T;\n}\n\nasync function ghApiPaginated<T>(\n\tendpoint: string,\n\tparams: Record<string, string>,\n\tmaxPages: number = 10,\n): Promise<T[]> {\n\tconst allItems: T[] = [];\n\tlet page = 1;\n\n\twhile (page <= maxPages) {\n\t\tconst result = await ghApi<SearchResult<T>>(endpoint, {\n\t\t\t...params,\n\t\t\tpage: String(page),\n\t\t\tper_page: \"100\",\n\t\t});\n\n\t\tallItems.push(...result.items);\n\n\t\tif (result.items.length < 100) {\n\t\t\tbreak;\n\t\t}\n\t\tpage++;\n\t}\n\n\treturn allItems;\n}\n\ninterface SearchResult<T> {\n\ttotal_count?: number;\n\titems: T[];\n}\n\ninterface RawPR {\n\trepository_url: string;\n\ttitle: string;\n\tnumber: number;\n\tstate: string;\n\thtml_url: string;\n}\n\ninterface RawCommit {\n\trepository: {\n\t\tname: string;\n\t\towner: { login: string };\n\t};\n\tcommit: {\n\t\tmessage: string;\n\t\tauthor: { date: string };\n\t};\n\thtml_url: string;\n}\n\ninterface RawRepo {\n\tname: string;\n\towner: { login: string };\n\tcreated_at: string;\n\thtml_url: string;\n}\n\nfunction parsePR(item: RawPR): PullRequest {\n\tconst urlParts = item.repository_url.split(\"/\");\n\treturn {\n\t\trepo: urlParts[urlParts.length - 1],\n\t\torg: urlParts[urlParts.length - 2],\n\t\ttitle: item.title,\n\t\tnumber: item.number,\n\t\tstate: item.state,\n\t\turl: item.html_url,\n\t};\n}\n\nfunction parseIssue(item: RawPR): Issue {\n\tconst urlParts = item.repository_url.split(\"/\");\n\treturn {\n\t\trepo: urlParts[urlParts.length - 1],\n\t\torg: urlParts[urlParts.length - 2],\n\t\ttitle: item.title,\n\t\tnumber: item.number,\n\t\turl: item.html_url,\n\t};\n}\n\nfunction parseCommit(item: RawCommit): Commit {\n\treturn {\n\t\trepo: item.repository.name,\n\t\torg: item.repository.owner.login,\n\t\tmessage: item.commit.message.split(\"\\n\")[0],\n\t\turl: item.html_url,\n\t\tdate: item.commit.author.date,\n\t};\n}\n\nexport async function getAuthenticatedUser(): Promise<string> {\n\tconst { stdout } = await execa(\"gh\", [\"api\", \"user\", \"--jq\", \".login\"]);\n\treturn stdout.trim();\n}\n\nasync function fetchUserOrgs(username: string): Promise<string[]> {\n\t// First try authenticated user's orgs (includes private memberships)\n\ttry {\n\t\tconst authUser = await getAuthenticatedUser();\n\t\tif (authUser === username) {\n\t\t\tconst { stdout } = await execa(\"gh\", [\n\t\t\t\t\"api\",\n\t\t\t\t\"user/orgs\",\n\t\t\t\t\"--jq\",\n\t\t\t\t\".[].login\",\n\t\t\t]);\n\t\t\treturn stdout.trim().split(\"\\n\").filter(Boolean);\n\t\t}\n\t} catch {\n\t\t// Fall through to public orgs\n\t}\n\n\t// Fallback to public orgs for other users\n\ttry {\n\t\tconst { stdout } = await execa(\"gh\", [\n\t\t\t\"api\",\n\t\t\t`users/${username}/orgs`,\n\t\t\t\"--jq\",\n\t\t\t\".[].login\",\n\t\t]);\n\t\treturn stdout.trim().split(\"\\n\").filter(Boolean);\n\t} catch {\n\t\treturn [];\n\t}\n}\n\nasync function fetchReposCreatedSince(\n\tusername: string,\n\tsince: string,\n\tpublicOnly: boolean,\n): Promise<RepoInfo[]> {\n\tconst sinceDate = new Date(since);\n\tconst repos: RepoInfo[] = [];\n\n\t// Fetch user's own repos\n\ttry {\n\t\tconst visibility = publicOnly ? \"public\" : \"all\";\n\t\tconst { stdout } = await execa(\"gh\", [\n\t\t\t\"api\",\n\t\t\t`users/${username}/repos?type=${visibility}&sort=created&direction=desc&per_page=100`,\n\t\t]);\n\t\tconst userRepos = JSON.parse(stdout) as RawRepo[];\n\t\tfor (const repo of userRepos) {\n\t\t\tif (new Date(repo.created_at) >= sinceDate) {\n\t\t\t\trepos.push({ name: repo.name, org: repo.owner.login });\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Ignore errors for user repos\n\t}\n\n\t// Fetch repos from user's orgs\n\tconst orgs = await fetchUserOrgs(username);\n\tfor (const org of orgs) {\n\t\ttry {\n\t\t\tconst { stdout } = await execa(\"gh\", [\n\t\t\t\t\"api\",\n\t\t\t\t`orgs/${org}/repos?sort=created&direction=desc&per_page=100`,\n\t\t\t]);\n\t\t\tconst orgRepos = JSON.parse(stdout) as RawRepo[];\n\t\t\tfor (const repo of orgRepos) {\n\t\t\t\tif (new Date(repo.created_at) >= sinceDate) {\n\t\t\t\t\trepos.push({ name: repo.name, org: repo.owner.login });\n\t\t\t\t}\n\t\t\t}\n\t\t} catch {\n\t\t\t// Ignore errors for individual orgs\n\t\t}\n\t}\n\n\t// Deduplicate\n\treturn repos.filter(\n\t\t(repo, index, self) =>\n\t\t\tself.findIndex((r) => r.name === repo.name && r.org === repo.org) ===\n\t\t\tindex,\n\t);\n}\n\nexport async function fetchGitHubActivity(\n\tusername: string,\n\tdays: number,\n\tpublicOnly: boolean,\n): Promise<GitHubActivity> {\n\tconst since = getSinceDate(days);\n\tconst today = formatDate(new Date());\n\tconst visibilityFilter = publicOnly ? \" is:public\" : \"\";\n\n\t// Fetch all data in parallel with pagination\n\tconst [\n\t\tprsCreatedItems,\n\t\tprsMergedItems,\n\t\tprsReviewedItems,\n\t\tissuesCreatedItems,\n\t\tissuesClosedItems,\n\t\tcommitsItems,\n\t\trepos_created,\n\t] = await Promise.all([\n\t\tghApiPaginated<RawPR>(\"search/issues\", {\n\t\t\tq: `author:${username} type:pr created:>=${since}${visibilityFilter}`,\n\t\t}),\n\t\tghApiPaginated<RawPR>(\"search/issues\", {\n\t\t\tq: `author:${username} type:pr merged:>=${since}${visibilityFilter}`,\n\t\t}),\n\t\tghApiPaginated<RawPR>(\"search/issues\", {\n\t\t\tq: `reviewed-by:${username} type:pr created:>=${since} -author:${username}${visibilityFilter}`,\n\t\t}),\n\t\tghApiPaginated<RawPR>(\"search/issues\", {\n\t\t\tq: `author:${username} type:issue created:>=${since}${visibilityFilter}`,\n\t\t}),\n\t\tghApiPaginated<RawPR>(\"search/issues\", {\n\t\t\tq: `author:${username} type:issue closed:>=${since}${visibilityFilter}`,\n\t\t}),\n\t\tghApiPaginated<RawCommit>(\"search/commits\", {\n\t\t\tq: `author:${username} committer-date:>=${since}`,\n\t\t}),\n\t\tfetchReposCreatedSince(username, since, publicOnly),\n\t]);\n\n\tconst prs_created = prsCreatedItems.map(parsePR);\n\tconst prs_merged = prsMergedItems.map(parsePR);\n\tconst prs_reviewed = prsReviewedItems.map(parsePR);\n\tconst issues_created = issuesCreatedItems.map(parseIssue);\n\tconst issues_closed = issuesClosedItems.map(parseIssue);\n\tconst commits = commitsItems.map(parseCommit);\n\n\t// Extract unique repos touched\n\tconst allRepos = [\n\t\t...prs_created,\n\t\t...prs_merged,\n\t\t...prs_reviewed,\n\t\t...issues_created,\n\t\t...issues_closed,\n\t\t...commits,\n\t].map((item) => `${item.org}/${item.repo}`);\n\n\tconst repos_touched = [...new Set(allRepos)];\n\n\tconst periodText =\n\t\tdays === 1\n\t\t\t? \"last 24 hours\"\n\t\t\t: days === 7\n\t\t\t\t? \"last 7 days\"\n\t\t\t\t: days === 30\n\t\t\t\t\t? \"last 30 days\"\n\t\t\t\t\t: `last ${days} days`;\n\n\treturn {\n\t\tuser: username,\n\t\tdate: today,\n\t\tperiod: periodText,\n\t\tprs_created,\n\t\tprs_merged,\n\t\tprs_reviewed,\n\t\tissues_created,\n\t\tissues_closed,\n\t\tcommits,\n\t\trepos_created,\n\t\trepos_touched,\n\t};\n}\n","import { confirm, input, select } from \"@inquirer/prompts\";\nimport type { Language, OutputFormat, Verbosity } from \"./types.js\";\n\ninterface InteractiveOptions {\n\tusername: string;\n\tdays: number;\n\tlanguage: Language;\n\tverbosity: Verbosity;\n\tformat: OutputFormat;\n\tincludePrivate: boolean;\n\tmodel: string;\n}\n\nexport async function runInteractive(): Promise<InteractiveOptions> {\n\tconst username = await input({\n\t\tmessage: \"GitHub username (leave empty for authenticated user)\",\n\t\tdefault: \"\",\n\t});\n\n\tconst days = await select({\n\t\tmessage: \"Time period\",\n\t\tchoices: [\n\t\t\t{ name: \"Last 24 hours\", value: 1 },\n\t\t\t{ name: \"Last 7 days\", value: 7 },\n\t\t\t{ name: \"Last 30 days\", value: 30 },\n\t\t],\n\t\tdefault: 1,\n\t});\n\n\tconst language = await select({\n\t\tmessage: \"Language\",\n\t\tchoices: [\n\t\t\t{ name: \"English\", value: \"en\" as Language },\n\t\t\t{ name: \"German\", value: \"de\" as Language },\n\t\t],\n\t\tdefault: \"en\" as Language,\n\t});\n\n\tconst verbosity = await select({\n\t\tmessage: \"Summary verbosity\",\n\t\tchoices: [\n\t\t\t{ name: \"Brief (~30 words)\", value: \"brief\" as Verbosity },\n\t\t\t{ name: \"Normal (~60 words)\", value: \"normal\" as Verbosity },\n\t\t\t{ name: \"Detailed (~175 words)\", value: \"detailed\" as Verbosity },\n\t\t],\n\t\tdefault: \"normal\" as Verbosity,\n\t});\n\n\tconst format = await select({\n\t\tmessage: \"Output format\",\n\t\tchoices: [\n\t\t\t{ name: \"Plain text\", value: \"plain\" as OutputFormat },\n\t\t\t{ name: \"Markdown\", value: \"markdown\" as OutputFormat },\n\t\t\t{ name: \"Slack\", value: \"slack\" as OutputFormat },\n\t\t],\n\t\tdefault: \"plain\" as OutputFormat,\n\t});\n\n\tconst includePrivate = await confirm({\n\t\tmessage: \"Include private repos?\",\n\t\tdefault: true,\n\t});\n\n\tconst model = await input({\n\t\tmessage: \"Claude model (leave empty for default)\",\n\t\tdefault: \"\",\n\t});\n\n\treturn {\n\t\tusername,\n\t\tdays,\n\t\tlanguage,\n\t\tverbosity,\n\t\tformat,\n\t\tincludePrivate,\n\t\tmodel,\n\t};\n}\n","import type {\n\tCommit,\n\tGitHubActivity,\n\tLanguage,\n\tOutputFormat,\n} from \"./types.js\";\n\n// Gap threshold: if gap between commits > 3 hours, treat as separate session\nconst GAP_THRESHOLD_MS = 3 * 60 * 60 * 1000;\n// Minimum time to count for a single-commit session (15 minutes)\nconst SINGLE_COMMIT_HOURS = 0.25;\n\nfunction calculateWorkSession(\n\tcommits: Commit[],\n\tlang: Language,\n): string | null {\n\tif (commits.length < 2) return null;\n\n\t// Sort timestamps chronologically\n\tconst timestamps = commits\n\t\t.map((c) => new Date(c.date).getTime())\n\t\t.sort((a, b) => a - b);\n\n\t// Group commits into sessions based on gap threshold\n\tconst sessions: number[][] = [];\n\tlet currentSession = [timestamps[0]];\n\n\tfor (let i = 1; i < timestamps.length; i++) {\n\t\tconst gap = timestamps[i] - timestamps[i - 1];\n\t\tif (gap > GAP_THRESHOLD_MS) {\n\t\t\tsessions.push(currentSession);\n\t\t\tcurrentSession = [timestamps[i]];\n\t\t} else {\n\t\t\tcurrentSession.push(timestamps[i]);\n\t\t}\n\t}\n\tsessions.push(currentSession);\n\n\t// Calculate total hours across all sessions\n\tlet totalHours = 0;\n\tfor (const session of sessions) {\n\t\tif (session.length === 1) {\n\t\t\ttotalHours += SINGLE_COMMIT_HOURS;\n\t\t} else {\n\t\t\tconst duration = session[session.length - 1] - session[0];\n\t\t\ttotalHours += duration / (1000 * 60 * 60);\n\t\t}\n\t}\n\n\t// Round to nearest 0.5 hours\n\tconst rounded = Math.round(totalHours * 2) / 2;\n\n\tif (rounded < 0.5) return null;\n\n\tconst label = lang === \"en\" ? \"Work session\" : \"Arbeitszeit\";\n\tconst hoursLabel =\n\t\trounded === 1\n\t\t\t? lang === \"en\"\n\t\t\t\t? \"hour\"\n\t\t\t\t: \"Stunde\"\n\t\t\t: lang === \"en\"\n\t\t\t\t? \"hours\"\n\t\t\t\t: \"Stunden\";\n\n\treturn `${label}: ~${rounded} ${hoursLabel}`;\n}\n\nfunction getRepoNames(items: { repo: string }[]): string {\n\tconst repos = [...new Set(items.map((i) => i.repo))];\n\treturn repos.join(\", \");\n}\n\nfunction formatActivityLine(\n\tcount: number,\n\tlabelEn: string,\n\tlabelDe: string,\n\trepos: string,\n\tlang: Language,\n\tformat: OutputFormat,\n): string | null {\n\tif (count === 0) return null;\n\n\tconst label = lang === \"en\" ? labelEn : labelDe;\n\tconst repoSuffix = repos ? ` (${repos})` : \"\";\n\n\tif (format === \"markdown\") {\n\t\treturn `- **${count}** ${label}${repoSuffix}`;\n\t}\n\treturn `• ${count} ${label}${repoSuffix}`;\n}\n\nexport function formatActivity(\n\tactivity: GitHubActivity,\n\tformat: OutputFormat,\n\tlang: Language,\n): string {\n\tconst lines: string[] = [];\n\n\t// Header\n\tconst headerPrefix = format === \"markdown\" ? \"## \" : \"\";\n\tlines.push(`${headerPrefix}tl;dr ${activity.date}`);\n\tlines.push(\"\");\n\n\tconst activityLines = [\n\t\tformatActivityLine(\n\t\t\tactivity.prs_created.length,\n\t\t\t\"PRs created\",\n\t\t\t\"PRs erstellt\",\n\t\t\tgetRepoNames(activity.prs_created),\n\t\t\tlang,\n\t\t\tformat,\n\t\t),\n\t\tformatActivityLine(\n\t\t\tactivity.prs_reviewed.length,\n\t\t\t\"PRs reviewed\",\n\t\t\t\"PRs reviewed/approved\",\n\t\t\tgetRepoNames(activity.prs_reviewed),\n\t\t\tlang,\n\t\t\tformat,\n\t\t),\n\t\tformatActivityLine(\n\t\t\tactivity.prs_merged.length,\n\t\t\t\"PRs merged\",\n\t\t\t\"PRs gemerged\",\n\t\t\tgetRepoNames(activity.prs_merged),\n\t\t\tlang,\n\t\t\tformat,\n\t\t),\n\t\tformatActivityLine(\n\t\t\tactivity.issues_created.length,\n\t\t\t\"issues created\",\n\t\t\t\"Issues erstellt\",\n\t\t\tgetRepoNames(activity.issues_created),\n\t\t\tlang,\n\t\t\tformat,\n\t\t),\n\t\tformatActivityLine(\n\t\t\tactivity.issues_closed.length,\n\t\t\t\"issues closed\",\n\t\t\t\"Issues geschlossen\",\n\t\t\tgetRepoNames(activity.issues_closed),\n\t\t\tlang,\n\t\t\tformat,\n\t\t),\n\t\tformatActivityLine(\n\t\t\tactivity.commits.length,\n\t\t\t\"commits\",\n\t\t\t\"Commits\",\n\t\t\tgetRepoNames(activity.commits),\n\t\t\tlang,\n\t\t\tformat,\n\t\t),\n\t\tformatActivityLine(\n\t\t\tactivity.repos_created.length,\n\t\t\t\"new repos created\",\n\t\t\t\"neue Repos erstellt\",\n\t\t\tactivity.repos_created.map((r) => r.name).join(\", \"),\n\t\t\tlang,\n\t\t\tformat,\n\t\t),\n\t].filter(Boolean) as string[];\n\n\tif (activityLines.length === 0) {\n\t\tconst noActivity =\n\t\t\tlang === \"en\"\n\t\t\t\t? `No GitHub activity in the ${activity.period}.`\n\t\t\t\t: `Keine GitHub-Aktivität in den ${activity.period}.`;\n\t\tlines.push(noActivity);\n\t\treturn lines.join(\"\\n\");\n\t}\n\n\tlines.push(...activityLines);\n\n\t// Work session duration\n\tconst workSession = calculateWorkSession(activity.commits, lang);\n\tif (workSession) {\n\t\tlines.push(format === \"markdown\" ? `- ${workSession}` : `• ${workSession}`);\n\t}\n\n\tlines.push(\"\");\n\n\t// Repos touched\n\tif (activity.repos_touched.length > 0) {\n\t\tconst reposLabel = lang === \"en\" ? \"Repos\" : \"Repos\";\n\t\tlines.push(`${reposLabel}: ${activity.repos_touched.join(\", \")}`);\n\t}\n\n\treturn lines.join(\"\\n\");\n}\n\nexport function hasActivity(activity: GitHubActivity): boolean {\n\treturn (\n\t\tactivity.prs_created.length +\n\t\t\tactivity.prs_merged.length +\n\t\t\tactivity.prs_reviewed.length +\n\t\t\tactivity.issues_created.length +\n\t\t\tactivity.issues_closed.length >\n\t\t0\n\t);\n}\n"],"mappings":"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","names":["fs","execa","fs"]}
|