@richhaase/c2 0.1.1 → 0.2.1

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 CHANGED
@@ -12,7 +12,7 @@ bun install -g @richhaase/c2
12
12
 
13
13
  # Or install from source
14
14
  git clone https://github.com/richhaase/c2.git
15
- cd c2cli
15
+ cd c2
16
16
  bun install
17
17
  bun link
18
18
  ```
@@ -118,7 +118,7 @@ c2 export -f jsonl > workouts.jsonl
118
118
 
119
119
  ## Configuration
120
120
 
121
- Config lives at `~/.config/c2cli/config.json`. Created automatically on `c2 setup`.
121
+ Config lives at `~/.config/c2/config.json`. Created automatically on `c2 setup`.
122
122
 
123
123
  ```json
124
124
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@richhaase/c2",
3
- "version": "0.1.1",
3
+ "version": "0.2.1",
4
4
  "description": "CLI tool for syncing and analyzing Concept2 rowing data",
5
5
  "keywords": [
6
6
  "concept2",
@@ -1,5 +1,6 @@
1
- import { writeFile } from "node:fs/promises";
2
- import { resolve } from "node:path";
1
+ import { mkdtemp, writeFile } from "node:fs/promises";
2
+ import { tmpdir } from "node:os";
3
+ import { join, resolve } from "node:path";
3
4
  import type { Command } from "commander";
4
5
  import { loadConfig } from "../config.ts";
5
6
  import { formatMeters } from "../display.ts";
@@ -651,7 +652,7 @@ ${buildRecentWorkouts(allWorkouts, recentCount)}
651
652
  ${buildProjection(goal, allWorkouts)}
652
653
 
653
654
  <div style="text-align: center; color: #484f58; font-size: 12px; margin-top: 32px; padding-bottom: 16px;">
654
- Generated by c2cli &middot; Data from Concept2 Logbook &middot; ${fullDate(today)}
655
+ Generated by c2 &middot; Data from Concept2 Logbook &middot; ${fullDate(today)}
655
656
  </div>
656
657
 
657
658
  </body>
@@ -661,11 +662,11 @@ ${buildProjection(goal, allWorkouts)}
661
662
  export function registerReport(program: Command): void {
662
663
  program
663
664
  .command("report")
664
- .description("Generate HTML progress report")
665
- .option("-o, --output <file>", "output file path", "report.html")
665
+ .description("Generate HTML progress report and open in browser")
666
+ .option("-o, --output <file>", "save to a specific file instead of a temp file")
666
667
  .option("-w, --weeks <n>", "weeks of history to show", "12")
667
- .option("--open", "open report in default browser")
668
- .action(async (opts: { output: string; weeks: string; open?: boolean }) => {
668
+ .option("--no-open", "don't open in browser")
669
+ .action(async (opts: { output?: string; weeks: string; open: boolean }) => {
669
670
  const cfg = await loadConfig();
670
671
  if (!cfg.goal.start_date || !cfg.goal.end_date) {
671
672
  console.error("Goal dates not configured. Run `c2 setup` to set start and end dates.");
@@ -687,9 +688,14 @@ export function registerReport(program: Command): void {
687
688
  const summaries = buildWeekSummaries(workouts, new Date(), weeks);
688
689
  const html = buildHTML(goal, summaries, workouts, 10);
689
690
 
690
- const outPath = resolve(opts.output);
691
+ let outPath: string;
692
+ if (opts.output) {
693
+ outPath = resolve(opts.output);
694
+ } else {
695
+ const dir = await mkdtemp(join(tmpdir(), "c2-report-"));
696
+ outPath = join(dir, "report.html");
697
+ }
691
698
  await writeFile(outPath, html, "utf-8");
692
- console.log(`Report written to: ${outPath}`);
693
699
 
694
700
  if (opts.open) {
695
701
  const { spawn } = await import("node:child_process");
@@ -704,6 +710,8 @@ export function registerReport(program: Command): void {
704
710
  console.error(`Could not open report: ${err.message}`);
705
711
  });
706
712
  child.unref();
713
+ } else {
714
+ console.log(`Report written to: ${outPath}`);
707
715
  }
708
716
  });
709
717
  }
package/src/config.ts CHANGED
@@ -19,7 +19,7 @@ export function defaultConfig(): Config {
19
19
  }
20
20
 
21
21
  export function configDir(): string {
22
- return join(homedir(), ".config", "c2cli");
22
+ return join(homedir(), ".config", "c2");
23
23
  }
24
24
 
25
25
  export function dataDir(): string {
package/src/index.ts CHANGED
@@ -23,6 +23,15 @@ registerTrend(program);
23
23
  registerExport(program);
24
24
  registerReport(program);
25
25
 
26
+ // Default to `report` when run with no subcommand
27
+ const args = process.argv.slice(2);
28
+ const knownCommands = program.commands.map((c) => c.name());
29
+ const hasSubcommand = args.some((a) => knownCommands.includes(a));
30
+ const hasHelpOrVersion = args.some((a) => ["-h", "--help", "-v", "--version"].includes(a));
31
+ if (args.length === 0 || (!hasSubcommand && !hasHelpOrVersion)) {
32
+ process.argv.splice(2, 0, "report");
33
+ }
34
+
26
35
  program.parseAsync(process.argv).catch((err: Error) => {
27
36
  console.error(`Error: ${err.message}`);
28
37
  process.exit(1);
package/src/stats.ts CHANGED
@@ -71,7 +71,8 @@ export function buildWeekSummaries(workouts: Workout[], now: Date, weeks: number
71
71
  if (t < cutoff || t > now) continue;
72
72
 
73
73
  const monday = mondayOf(t);
74
- const idx = Math.floor((monday.getTime() - cutoff.getTime()) / (1000 * 60 * 60 * 24 * 7));
74
+ const diffDays = Math.round((monday.getTime() - cutoff.getTime()) / (1000 * 60 * 60 * 24));
75
+ const idx = Math.floor(diffDays / 7);
75
76
  if (idx < 0 || idx >= weeks) continue;
76
77
 
77
78
  const ws = summaries[idx]!;