gh-tldr 1.0.1 → 1.0.2
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/dist/index.js +41 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,6 +6,23 @@ import { Command } from "commander";
|
|
|
6
6
|
|
|
7
7
|
// src/claude.ts
|
|
8
8
|
import { execa } from "execa";
|
|
9
|
+
import { existsSync } from "fs";
|
|
10
|
+
import { homedir } from "os";
|
|
11
|
+
import { join } from "path";
|
|
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
|
+
}
|
|
9
26
|
var wordLimits = {
|
|
10
27
|
brief: { en: "20-40 word", de: "20-40 W\xF6rter" },
|
|
11
28
|
normal: { en: "50-80 word", de: "50-80 W\xF6rter" },
|
|
@@ -30,10 +47,21 @@ ${JSON.stringify(activity, null, 2)}`;
|
|
|
30
47
|
if (model) {
|
|
31
48
|
args.push("--model", model);
|
|
32
49
|
}
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
50
|
+
const claudePath = findClaudeCli();
|
|
51
|
+
try {
|
|
52
|
+
const { stdout } = await execa(claudePath, args, {
|
|
53
|
+
input: fullPrompt
|
|
54
|
+
});
|
|
55
|
+
return stdout.trim();
|
|
56
|
+
} catch (error) {
|
|
57
|
+
if (error instanceof Error && "stderr" in error) {
|
|
58
|
+
const stderr = error.stderr;
|
|
59
|
+
if (stderr) {
|
|
60
|
+
throw new Error(`Claude CLI failed: ${stderr}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
37
65
|
}
|
|
38
66
|
|
|
39
67
|
// src/github.ts
|
|
@@ -549,6 +577,15 @@ async function run() {
|
|
|
549
577
|
} catch (error) {
|
|
550
578
|
if (error instanceof Error) {
|
|
551
579
|
console.error(chalk.red(`Error: ${error.message}`));
|
|
580
|
+
if (error.message.includes("claude")) {
|
|
581
|
+
console.error(
|
|
582
|
+
chalk.yellow(
|
|
583
|
+
"Make sure Claude CLI is installed and authenticated: https://docs.anthropic.com/en/docs/claude-code"
|
|
584
|
+
)
|
|
585
|
+
);
|
|
586
|
+
}
|
|
587
|
+
} else {
|
|
588
|
+
console.error(chalk.red("An unexpected error occurred:"), error);
|
|
552
589
|
}
|
|
553
590
|
process.exit(1);
|
|
554
591
|
}
|
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\tconsole.error(chalk.red(`Error: ${error.message}`));\n\t\t\t\t}\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t});\n\n\tawait program.parseAsync();\n}\n","import { execa } from \"execa\";\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\tconst args = [\"-p\", \"-\", \"--output-format\", \"text\"];\n\tif (model) {\n\t\targs.push(\"--model\", model);\n\t}\n\n\tconst { stdout } = await execa(\"claude\", args, {\n\t\tinput: fullPrompt,\n\t});\n\n\treturn stdout.trim();\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();\n"],"mappings":";;;AAAA,OAAO,WAAW;AAClB,SAAS,eAAe;;;ACDxB,SAAS,aAAa;AAGtB,IAAM,aAA0D;AAAA,EAC/D,OAAO,EAAE,IAAI,cAAc,IAAI,kBAAe;AAAA,EAC9C,QAAQ,EAAE,IAAI,cAAc,IAAI,kBAAe;AAAA,EAC/C,UAAU,EAAE,IAAI,gBAAgB,IAAI,oBAAiB;AACtD;AAEA,SAAS,YAAY,MAAgB,WAA8B;AAClE,QAAM,QAAQ,WAAW,SAAS,EAAE,IAAI;AAExC,MAAI,SAAS,MAAM;AAClB,WAAO,+FAA+F,KAAK;AAAA;AAAA;AAAA,EAG5G;AAEA,SAAO,oHAAiH,KAAK;AAAA;AAAA;AAG9H;AAEA,eAAsB,oBACrB,UACA,MACA,YAAuB,UACvB,OACkB;AAClB,QAAM,SAAS,YAAY,MAAM,SAAS;AAC1C,QAAM,aAAa,GAAG,MAAM;AAAA,EAAK,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAElE,QAAM,OAAO,CAAC,MAAM,KAAK,mBAAmB,MAAM;AAClD,MAAI,OAAO;AACV,SAAK,KAAK,WAAW,KAAK;AAAA,EAC3B;AAEA,QAAM,EAAE,OAAO,IAAI,MAAM,MAAM,UAAU,MAAM;AAAA,IAC9C,OAAO;AAAA,EACR,CAAC;AAED,SAAO,OAAO,KAAK;AACpB;;;AC1CA,SAAS,SAAAA,cAAa;AAStB,SAAS,aAAa,MAAsB;AAC3C,QAAM,OAAO,oBAAI,KAAK;AACtB,OAAK,QAAQ,KAAK,QAAQ,IAAI,IAAI;AAClC,SAAO,KAAK,YAAY;AACzB;AAEA,SAAS,WAAW,MAAoB;AACvC,QAAM,MAAM,KAAK,QAAQ,EAAE,SAAS,EAAE,SAAS,GAAG,GAAG;AACrD,QAAM,SAAS,KAAK,SAAS,IAAI,GAAG,SAAS,EAAE,SAAS,GAAG,GAAG;AAC9D,QAAM,OAAO,KAAK,YAAY;AAC9B,SAAO,GAAG,GAAG,IAAI,KAAK,IAAI,IAAI;AAC/B;AAEA,eAAe,MACd,UACA,QACa;AACb,QAAM,OAAO;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG,OAAO,QAAQ,MAAM,EAAE,QAAQ,CAAC,CAAC,KAAK,KAAK,MAAM;AAAA,MACnD;AAAA,MACA,GAAG,GAAG,IAAI,KAAK;AAAA,IAChB,CAAC;AAAA,EACF;AAEA,QAAM,EAAE,OAAO,IAAI,MAAMA,OAAM,MAAM,IAAI;AACzC,SAAO,KAAK,MAAM,MAAM;AACzB;AAEA,eAAe,eACd,UACA,QACA,WAAmB,IACJ;AACf,QAAM,WAAgB,CAAC;AACvB,MAAI,OAAO;AAEX,SAAO,QAAQ,UAAU;AACxB,UAAM,SAAS,MAAM,MAAuB,UAAU;AAAA,MACrD,GAAG;AAAA,MACH,MAAM,OAAO,IAAI;AAAA,MACjB,UAAU;AAAA,IACX,CAAC;AAED,aAAS,KAAK,GAAG,OAAO,KAAK;AAE7B,QAAI,OAAO,MAAM,SAAS,KAAK;AAC9B;AAAA,IACD;AACA;AAAA,EACD;AAEA,SAAO;AACR;AAkCA,SAAS,QAAQ,MAA0B;AAC1C,QAAM,WAAW,KAAK,eAAe,MAAM,GAAG;AAC9C,SAAO;AAAA,IACN,MAAM,SAAS,SAAS,SAAS,CAAC;AAAA,IAClC,KAAK,SAAS,SAAS,SAAS,CAAC;AAAA,IACjC,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,OAAO,KAAK;AAAA,IACZ,KAAK,KAAK;AAAA,EACX;AACD;AAEA,SAAS,WAAW,MAAoB;AACvC,QAAM,WAAW,KAAK,eAAe,MAAM,GAAG;AAC9C,SAAO;AAAA,IACN,MAAM,SAAS,SAAS,SAAS,CAAC;AAAA,IAClC,KAAK,SAAS,SAAS,SAAS,CAAC;AAAA,IACjC,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,KAAK,KAAK;AAAA,EACX;AACD;AAEA,SAAS,YAAY,MAAyB;AAC7C,SAAO;AAAA,IACN,MAAM,KAAK,WAAW;AAAA,IACtB,KAAK,KAAK,WAAW,MAAM;AAAA,IAC3B,SAAS,KAAK,OAAO,QAAQ,MAAM,IAAI,EAAE,CAAC;AAAA,IAC1C,KAAK,KAAK;AAAA,IACV,MAAM,KAAK,OAAO,OAAO;AAAA,EAC1B;AACD;AAEA,eAAsB,uBAAwC;AAC7D,QAAM,EAAE,OAAO,IAAI,MAAMA,OAAM,MAAM,CAAC,OAAO,QAAQ,QAAQ,QAAQ,CAAC;AACtE,SAAO,OAAO,KAAK;AACpB;AAEA,eAAe,cAAc,UAAqC;AAEjE,MAAI;AACH,UAAM,WAAW,MAAM,qBAAqB;AAC5C,QAAI,aAAa,UAAU;AAC1B,YAAM,EAAE,OAAO,IAAI,MAAMA,OAAM,MAAM;AAAA,QACpC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACD,CAAC;AACD,aAAO,OAAO,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AAAA,IAChD;AAAA,EACD,QAAQ;AAAA,EAER;AAGA,MAAI;AACH,UAAM,EAAE,OAAO,IAAI,MAAMA,OAAM,MAAM;AAAA,MACpC;AAAA,MACA,SAAS,QAAQ;AAAA,MACjB;AAAA,MACA;AAAA,IACD,CAAC;AACD,WAAO,OAAO,KAAK,EAAE,MAAM,IAAI,EAAE,OAAO,OAAO;AAAA,EAChD,QAAQ;AACP,WAAO,CAAC;AAAA,EACT;AACD;AAEA,eAAe,uBACd,UACA,OACA,YACsB;AACtB,QAAM,YAAY,IAAI,KAAK,KAAK;AAChC,QAAM,QAAoB,CAAC;AAG3B,MAAI;AACH,UAAM,aAAa,aAAa,WAAW;AAC3C,UAAM,EAAE,OAAO,IAAI,MAAMA,OAAM,MAAM;AAAA,MACpC;AAAA,MACA,SAAS,QAAQ,eAAe,UAAU;AAAA,IAC3C,CAAC;AACD,UAAM,YAAY,KAAK,MAAM,MAAM;AACnC,eAAW,QAAQ,WAAW;AAC7B,UAAI,IAAI,KAAK,KAAK,UAAU,KAAK,WAAW;AAC3C,cAAM,KAAK,EAAE,MAAM,KAAK,MAAM,KAAK,KAAK,MAAM,MAAM,CAAC;AAAA,MACtD;AAAA,IACD;AAAA,EACD,QAAQ;AAAA,EAER;AAGA,QAAM,OAAO,MAAM,cAAc,QAAQ;AACzC,aAAW,OAAO,MAAM;AACvB,QAAI;AACH,YAAM,EAAE,OAAO,IAAI,MAAMA,OAAM,MAAM;AAAA,QACpC;AAAA,QACA,QAAQ,GAAG;AAAA,MACZ,CAAC;AACD,YAAM,WAAW,KAAK,MAAM,MAAM;AAClC,iBAAW,QAAQ,UAAU;AAC5B,YAAI,IAAI,KAAK,KAAK,UAAU,KAAK,WAAW;AAC3C,gBAAM,KAAK,EAAE,MAAM,KAAK,MAAM,KAAK,KAAK,MAAM,MAAM,CAAC;AAAA,QACtD;AAAA,MACD;AAAA,IACD,QAAQ;AAAA,IAER;AAAA,EACD;AAGA,SAAO,MAAM;AAAA,IACZ,CAAC,MAAM,OAAO,SACb,KAAK,UAAU,CAAC,MAAM,EAAE,SAAS,KAAK,QAAQ,EAAE,QAAQ,KAAK,GAAG,MAChE;AAAA,EACF;AACD;AAEA,eAAsB,oBACrB,UACA,MACA,YAC0B;AAC1B,QAAM,QAAQ,aAAa,IAAI;AAC/B,QAAM,QAAQ,WAAW,oBAAI,KAAK,CAAC;AACnC,QAAM,mBAAmB,aAAa,eAAe;AAGrD,QAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,IAAI,MAAM,QAAQ,IAAI;AAAA,IACrB,eAAsB,iBAAiB;AAAA,MACtC,GAAG,UAAU,QAAQ,sBAAsB,KAAK,GAAG,gBAAgB;AAAA,IACpE,CAAC;AAAA,IACD,eAAsB,iBAAiB;AAAA,MACtC,GAAG,UAAU,QAAQ,qBAAqB,KAAK,GAAG,gBAAgB;AAAA,IACnE,CAAC;AAAA,IACD,eAAsB,iBAAiB;AAAA,MACtC,GAAG,eAAe,QAAQ,sBAAsB,KAAK,YAAY,QAAQ,GAAG,gBAAgB;AAAA,IAC7F,CAAC;AAAA,IACD,eAAsB,iBAAiB;AAAA,MACtC,GAAG,UAAU,QAAQ,yBAAyB,KAAK,GAAG,gBAAgB;AAAA,IACvE,CAAC;AAAA,IACD,eAAsB,iBAAiB;AAAA,MACtC,GAAG,UAAU,QAAQ,wBAAwB,KAAK,GAAG,gBAAgB;AAAA,IACtE,CAAC;AAAA,IACD,eAA0B,kBAAkB;AAAA,MAC3C,GAAG,UAAU,QAAQ,qBAAqB,KAAK;AAAA,IAChD,CAAC;AAAA,IACD,uBAAuB,UAAU,OAAO,UAAU;AAAA,EACnD,CAAC;AAED,QAAM,cAAc,gBAAgB,IAAI,OAAO;AAC/C,QAAM,aAAa,eAAe,IAAI,OAAO;AAC7C,QAAM,eAAe,iBAAiB,IAAI,OAAO;AACjD,QAAM,iBAAiB,mBAAmB,IAAI,UAAU;AACxD,QAAM,gBAAgB,kBAAkB,IAAI,UAAU;AACtD,QAAM,UAAU,aAAa,IAAI,WAAW;AAG5C,QAAM,WAAW;AAAA,IAChB,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,EACJ,EAAE,IAAI,CAAC,SAAS,GAAG,KAAK,GAAG,IAAI,KAAK,IAAI,EAAE;AAE1C,QAAM,gBAAgB,CAAC,GAAG,IAAI,IAAI,QAAQ,CAAC;AAE3C,QAAM,aACL,SAAS,IACN,kBACA,SAAS,IACR,gBACA,SAAS,KACR,iBACA,QAAQ,IAAI;AAElB,SAAO;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;;;AC7SA,SAAS,SAAS,OAAO,cAAc;AAavC,eAAsB,iBAA8C;AACnE,QAAM,WAAW,MAAM,MAAM;AAAA,IAC5B,SAAS;AAAA,IACT,SAAS;AAAA,EACV,CAAC;AAED,QAAM,OAAO,MAAM,OAAO;AAAA,IACzB,SAAS;AAAA,IACT,SAAS;AAAA,MACR,EAAE,MAAM,iBAAiB,OAAO,EAAE;AAAA,MAClC,EAAE,MAAM,eAAe,OAAO,EAAE;AAAA,MAChC,EAAE,MAAM,gBAAgB,OAAO,GAAG;AAAA,IACnC;AAAA,IACA,SAAS;AAAA,EACV,CAAC;AAED,QAAM,WAAW,MAAM,OAAO;AAAA,IAC7B,SAAS;AAAA,IACT,SAAS;AAAA,MACR,EAAE,MAAM,WAAW,OAAO,KAAiB;AAAA,MAC3C,EAAE,MAAM,UAAU,OAAO,KAAiB;AAAA,IAC3C;AAAA,IACA,SAAS;AAAA,EACV,CAAC;AAED,QAAM,YAAY,MAAM,OAAO;AAAA,IAC9B,SAAS;AAAA,IACT,SAAS;AAAA,MACR,EAAE,MAAM,qBAAqB,OAAO,QAAqB;AAAA,MACzD,EAAE,MAAM,sBAAsB,OAAO,SAAsB;AAAA,MAC3D,EAAE,MAAM,yBAAyB,OAAO,WAAwB;AAAA,IACjE;AAAA,IACA,SAAS;AAAA,EACV,CAAC;AAED,QAAM,SAAS,MAAM,OAAO;AAAA,IAC3B,SAAS;AAAA,IACT,SAAS;AAAA,MACR,EAAE,MAAM,cAAc,OAAO,QAAwB;AAAA,MACrD,EAAE,MAAM,YAAY,OAAO,WAA2B;AAAA,MACtD,EAAE,MAAM,SAAS,OAAO,QAAwB;AAAA,IACjD;AAAA,IACA,SAAS;AAAA,EACV,CAAC;AAED,QAAM,iBAAiB,MAAM,QAAQ;AAAA,IACpC,SAAS;AAAA,IACT,SAAS;AAAA,EACV,CAAC;AAED,QAAM,QAAQ,MAAM,MAAM;AAAA,IACzB,SAAS;AAAA,IACT,SAAS;AAAA,EACV,CAAC;AAED,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;;;ACrEA,IAAM,mBAAmB,IAAI,KAAK,KAAK;AAEvC,IAAM,sBAAsB;AAE5B,SAAS,qBACR,SACA,MACgB;AAChB,MAAI,QAAQ,SAAS,EAAG,QAAO;AAG/B,QAAM,aAAa,QACjB,IAAI,CAAC,MAAM,IAAI,KAAK,EAAE,IAAI,EAAE,QAAQ,CAAC,EACrC,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAGtB,QAAM,WAAuB,CAAC;AAC9B,MAAI,iBAAiB,CAAC,WAAW,CAAC,CAAC;AAEnC,WAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK;AAC3C,UAAM,MAAM,WAAW,CAAC,IAAI,WAAW,IAAI,CAAC;AAC5C,QAAI,MAAM,kBAAkB;AAC3B,eAAS,KAAK,cAAc;AAC5B,uBAAiB,CAAC,WAAW,CAAC,CAAC;AAAA,IAChC,OAAO;AACN,qBAAe,KAAK,WAAW,CAAC,CAAC;AAAA,IAClC;AAAA,EACD;AACA,WAAS,KAAK,cAAc;AAG5B,MAAI,aAAa;AACjB,aAAW,WAAW,UAAU;AAC/B,QAAI,QAAQ,WAAW,GAAG;AACzB,oBAAc;AAAA,IACf,OAAO;AACN,YAAM,WAAW,QAAQ,QAAQ,SAAS,CAAC,IAAI,QAAQ,CAAC;AACxD,oBAAc,YAAY,MAAO,KAAK;AAAA,IACvC;AAAA,EACD;AAGA,QAAM,UAAU,KAAK,MAAM,aAAa,CAAC,IAAI;AAE7C,MAAI,UAAU,IAAK,QAAO;AAE1B,QAAM,QAAQ,SAAS,OAAO,iBAAiB;AAC/C,QAAM,aACL,YAAY,IACT,SAAS,OACR,SACA,WACD,SAAS,OACR,UACA;AAEL,SAAO,GAAG,KAAK,MAAM,OAAO,IAAI,UAAU;AAC3C;AAEA,SAAS,aAAa,OAAmC;AACxD,QAAM,QAAQ,CAAC,GAAG,IAAI,IAAI,MAAM,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;AACnD,SAAO,MAAM,KAAK,IAAI;AACvB;AAEA,SAAS,mBACR,OACA,SACA,SACA,OACA,MACA,QACgB;AAChB,MAAI,UAAU,EAAG,QAAO;AAExB,QAAM,QAAQ,SAAS,OAAO,UAAU;AACxC,QAAM,aAAa,QAAQ,KAAK,KAAK,MAAM;AAE3C,MAAI,WAAW,YAAY;AAC1B,WAAO,OAAO,KAAK,MAAM,KAAK,GAAG,UAAU;AAAA,EAC5C;AACA,SAAO,UAAK,KAAK,IAAI,KAAK,GAAG,UAAU;AACxC;AAEO,SAAS,eACf,UACA,QACA,MACS;AACT,QAAM,QAAkB,CAAC;AAGzB,QAAM,eAAe,WAAW,aAAa,QAAQ;AACrD,QAAM,KAAK,GAAG,YAAY,SAAS,SAAS,IAAI,EAAE;AAClD,QAAM,KAAK,EAAE;AAEb,QAAM,gBAAgB;AAAA,IACrB;AAAA,MACC,SAAS,YAAY;AAAA,MACrB;AAAA,MACA;AAAA,MACA,aAAa,SAAS,WAAW;AAAA,MACjC;AAAA,MACA;AAAA,IACD;AAAA,IACA;AAAA,MACC,SAAS,aAAa;AAAA,MACtB;AAAA,MACA;AAAA,MACA,aAAa,SAAS,YAAY;AAAA,MAClC;AAAA,MACA;AAAA,IACD;AAAA,IACA;AAAA,MACC,SAAS,WAAW;AAAA,MACpB;AAAA,MACA;AAAA,MACA,aAAa,SAAS,UAAU;AAAA,MAChC;AAAA,MACA;AAAA,IACD;AAAA,IACA;AAAA,MACC,SAAS,eAAe;AAAA,MACxB;AAAA,MACA;AAAA,MACA,aAAa,SAAS,cAAc;AAAA,MACpC;AAAA,MACA;AAAA,IACD;AAAA,IACA;AAAA,MACC,SAAS,cAAc;AAAA,MACvB;AAAA,MACA;AAAA,MACA,aAAa,SAAS,aAAa;AAAA,MACnC;AAAA,MACA;AAAA,IACD;AAAA,IACA;AAAA,MACC,SAAS,QAAQ;AAAA,MACjB;AAAA,MACA;AAAA,MACA,aAAa,SAAS,OAAO;AAAA,MAC7B;AAAA,MACA;AAAA,IACD;AAAA,IACA;AAAA,MACC,SAAS,cAAc;AAAA,MACvB;AAAA,MACA;AAAA,MACA,SAAS,cAAc,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,IAAI;AAAA,MACnD;AAAA,MACA;AAAA,IACD;AAAA,EACD,EAAE,OAAO,OAAO;AAEhB,MAAI,cAAc,WAAW,GAAG;AAC/B,UAAM,aACL,SAAS,OACN,6BAA6B,SAAS,MAAM,MAC5C,oCAAiC,SAAS,MAAM;AACpD,UAAM,KAAK,UAAU;AACrB,WAAO,MAAM,KAAK,IAAI;AAAA,EACvB;AAEA,QAAM,KAAK,GAAG,aAAa;AAG3B,QAAM,cAAc,qBAAqB,SAAS,SAAS,IAAI;AAC/D,MAAI,aAAa;AAChB,UAAM,KAAK,WAAW,aAAa,KAAK,WAAW,KAAK,UAAK,WAAW,EAAE;AAAA,EAC3E;AAEA,QAAM,KAAK,EAAE;AAGb,MAAI,SAAS,cAAc,SAAS,GAAG;AACtC,UAAM,aAAa,SAAS,OAAO,UAAU;AAC7C,UAAM,KAAK,GAAG,UAAU,KAAK,SAAS,cAAc,KAAK,IAAI,CAAC,EAAE;AAAA,EACjE;AAEA,SAAO,MAAM,KAAK,IAAI;AACvB;AAEO,SAAS,YAAY,UAAmC;AAC9D,SACC,SAAS,YAAY,SACpB,SAAS,WAAW,SACpB,SAAS,aAAa,SACtB,SAAS,eAAe,SACxB,SAAS,cAAc,SACxB;AAEF;;;AJ/LA,eAAe,oBAAmC;AACjD,QAAM,EAAE,OAAAC,OAAM,IAAI,MAAM,OAAO,OAAO;AAEtC,QAAM,OAAO;AAAA,IACZ,EAAE,KAAK,MAAM,MAAM,cAAc,aAAa,kBAAkB;AAAA,IAChE;AAAA,MACC,KAAK;AAAA,MACL,MAAM;AAAA,MACN,aAAa;AAAA,IACd;AAAA,EACD;AAEA,QAAM,UAAoB,CAAC;AAE3B,aAAW,OAAO,MAAM;AACvB,QAAI;AACH,YAAMA,OAAM,SAAS,CAAC,IAAI,GAAG,CAAC;AAAA,IAC/B,QAAQ;AACP,cAAQ,KAAK,GAAG,IAAI,IAAI,KAAK,IAAI,WAAW,GAAG;AAAA,IAChD;AAAA,EACD;AAEA,MAAI,QAAQ,SAAS,GAAG;AACvB,YAAQ,MAAM,MAAM,IAAI,uBAAuB,CAAC;AAChD,eAAW,KAAK,SAAS;AACxB,cAAQ,MAAM,OAAO,CAAC,EAAE;AAAA,IACzB;AACA,YAAQ,KAAK,CAAC;AAAA,EACf;AAGA,MAAI;AACH,UAAMA,OAAM,MAAM,CAAC,QAAQ,QAAQ,CAAC;AAAA,EACrC,QAAQ;AACP,YAAQ;AAAA,MACP,MAAM,IAAI,oDAAoD;AAAA,IAC/D;AACA,YAAQ,KAAK,CAAC;AAAA,EACf;AACD;AAYA,SAAS,kBAAkB,OAA0B;AACpD,QAAM,QAAqB,CAAC,SAAS,UAAU,UAAU;AACzD,SAAO,MAAM,SAAS,KAAkB,IAAK,QAAsB;AACpE;AAEA,eAAe,QACd,UACA,MACA,MACA,QACA,YACA,WACA,OACgB;AAEhB,QAAM,mBAAmB,YAAa,MAAM,qBAAqB;AAEjE,UAAQ;AAAA,IACP,MAAM,OAAO,gCAAgC,gBAAgB,KAAK;AAAA,EACnE;AAEA,QAAM,WAAW,MAAM;AAAA,IACtB;AAAA,IACA;AAAA,IACA;AAAA,EACD;AAEA,MAAI,CAAC,YAAY,QAAQ,GAAG;AAC3B,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,SAAS,SAAS,IAAI,EAAE;AACpC,YAAQ,IAAI,EAAE;AACd,UAAM,aACL,SAAS,OACN,6BAA6B,SAAS,MAAM,MAC5C,oCAAiC,SAAS,MAAM;AACpD,YAAQ,IAAI,UAAU;AACtB;AAAA,EACD;AAGA,QAAM,QAAQ,eAAe,UAAU,QAAQ,IAAI;AAEnD,UAAQ,MAAM,MAAM,OAAO,mCAAmC,CAAC;AAG/D,QAAM,cAAc,MAAM;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AAEA,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,KAAK;AACjB,UAAQ,IAAI,EAAE;AACd,UAAQ,IAAI,KAAK;AACjB,UAAQ,IAAI,WAAW;AACxB;AAEA,eAAsB,MAAqB;AAC1C,QAAM,UAAU,IAAI,QAAQ;AAE5B,UACE,KAAK,SAAS,EACd,YAAY,kDAAkD,EAC9D,QAAQ,OAAO,EACf,SAAS,cAAc,kDAAkD,EACzE,OAAO,kBAAkB,uBAAuB,GAAG,EACnD,OAAO,iBAAiB,uCAAuC,KAAK,EACpE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,EACC,OAAO,qBAAqB,gCAAgC,KAAK,EACjE,OAAO,qBAAqB,0BAA0B,KAAK,EAC3D;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,EACC;AAAA,IACA;AAAA,IACA;AAAA,EACD,EACC,OAAO,OAAO,UAA8B,YAAwB;AACpE,QAAI;AACH,YAAM,kBAAkB;AAGxB,YAAM,UAAU,QAAQ,KAAK,SAAS;AACtC,YAAM,mBAAmB,QAAQ;AAEjC,UAAI,CAAC,WAAW,kBAAkB;AAEjC,cAAM,UAAU,MAAM,eAAe;AACrC,cAAM;AAAA,UACL,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,QAAQ;AAAA,UACR,CAAC,QAAQ;AAAA,UACT,QAAQ;AAAA,UACR,QAAQ,SAAS;AAAA,QAClB;AAAA,MACD,OAAO;AAEN,cAAM,OAAO,SAAS,QAAQ,MAAM,EAAE;AACtC,cAAM,OAAiB,QAAQ,UAAU,OAAO;AAChD,cAAM,SAAS,QAAQ;AAEvB,cAAM;AAAA,UACL,YAAY;AAAA,UACZ;AAAA,UACA;AAAA,UACA;AAAA,UACA,QAAQ;AAAA,UACR,kBAAkB,QAAQ,SAAS;AAAA,UACnC,QAAQ;AAAA,QACT;AAAA,MACD;AAAA,IACD,SAAS,OAAO;AACf,UAAI,iBAAiB,OAAO;AAC3B,gBAAQ,MAAM,MAAM,IAAI,UAAU,MAAM,OAAO,EAAE,CAAC;AAAA,MACnD;AACA,cAAQ,KAAK,CAAC;AAAA,IACf;AAAA,EACD,CAAC;AAEF,QAAM,QAAQ,WAAW;AAC1B;;;AKxLA,IAAI;","names":["execa","execa"]}
|
|
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\tconsole.error(chalk.red(`Error: ${error.message}`));\n\t\t\t\t\tif (error.message.includes(\"claude\")) {\n\t\t\t\t\t\tconsole.error(\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\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\tconsole.error(chalk.red(\"An unexpected error occurred:\"), error);\n\t\t\t\t}\n\t\t\t\tprocess.exit(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\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\n\ttry {\n\t\tconst { stdout } = await execa(claudePath, args, {\n\t\t\tinput: fullPrompt,\n\t\t});\n\t\treturn stdout.trim();\n\t} catch (error) {\n\t\tif (error instanceof Error && \"stderr\" in error) {\n\t\t\tconst stderr = (error as { stderr: string }).stderr;\n\t\t\tif (stderr) {\n\t\t\t\tthrow new Error(`Claude CLI failed: ${stderr}`);\n\t\t\t}\n\t\t}\n\t\tthrow error;\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();\n"],"mappings":"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","names":["execa","execa"]}
|