hackhours 0.1.0 → 0.1.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.
Files changed (3) hide show
  1. package/README.md +2 -1
  2. package/dist/cli.js +65 -0
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -28,6 +28,7 @@ hackhours init
28
28
  ```bash
29
29
  hackhours start
30
30
  hackhours stop
31
+ hackhours status
31
32
  ```
32
33
 
33
34
  ## Reports
@@ -70,4 +71,4 @@ npm test
70
71
 
71
72
  ## Notes
72
73
  - `hackhours start` spawns a detached background process.
73
- - Use `hackhours stop` to end tracking cleanly.
74
+ - Use `hackhours stop` to end tracking cleanly.
package/dist/cli.js CHANGED
@@ -58,6 +58,15 @@ const printBreakdown = (title, map, total) => {
58
58
  }
59
59
  console.log(table.toString());
60
60
  };
61
+ const topEntry = (map) => {
62
+ let best = null;
63
+ for (const entry of map.entries()) {
64
+ if (!best || entry[1] > best[1]) {
65
+ best = entry;
66
+ }
67
+ }
68
+ return best;
69
+ };
61
70
  const parseRange = (from, to) => {
62
71
  if (!from || !to) {
63
72
  throw new Error("Both --from and --to are required.");
@@ -122,6 +131,62 @@ program
122
131
  console.log(chalk.yellow("HackHours was not running."));
123
132
  }
124
133
  });
134
+ program
135
+ .command("status")
136
+ .description("Show tracker status and recent activity")
137
+ .action(async () => {
138
+ const state = readState();
139
+ let running = false;
140
+ if (state) {
141
+ try {
142
+ process.kill(state.pid, 0);
143
+ running = true;
144
+ }
145
+ catch {
146
+ clearState();
147
+ }
148
+ }
149
+ const config = loadConfig();
150
+ const { collections } = await openChrono(config.dataDir);
151
+ const now = new Date();
152
+ const todayFrom = startOfDay(now).getTime();
153
+ const todayTo = endOfDay(now).getTime();
154
+ const weekFromDate = new Date(now);
155
+ weekFromDate.setDate(weekFromDate.getDate() - 6);
156
+ const weekFrom = startOfDay(weekFromDate).getTime();
157
+ const weekTo = endOfDay(now).getTime();
158
+ const [todaySummary, weekSummary] = await Promise.all([
159
+ buildSummary(collections, todayFrom, todayTo, config.idleMinutes),
160
+ buildSummary(collections, weekFrom, weekTo, config.idleMinutes),
161
+ ]);
162
+ console.log(chalk.bold("\nHackHours Status"));
163
+ console.log(`${chalk.cyan("Running:")} ${running ? chalk.green("Yes") : chalk.red("No")}`);
164
+ if (running && state) {
165
+ const startedAt = new Date(state.startedAt);
166
+ const uptime = Math.max(0, Date.now() - state.startedAt);
167
+ console.log(`${chalk.cyan("PID:")} ${state.pid}`);
168
+ console.log(`${chalk.cyan("Started:")} ${startedAt.toLocaleString()}`);
169
+ console.log(`${chalk.cyan("Uptime:")} ${formatDuration(uptime)}`);
170
+ }
171
+ console.log(`\n${chalk.cyan("Today:")} ${formatDuration(todaySummary.totalTimeMs)}`);
172
+ const todayTopProject = topEntry(todaySummary.projects);
173
+ if (todayTopProject) {
174
+ console.log(`${chalk.cyan("Top project (today):")} ${todayTopProject[0]} (${formatDuration(todayTopProject[1])})`);
175
+ }
176
+ const todayTopLang = topEntry(todaySummary.languages);
177
+ if (todayTopLang) {
178
+ console.log(`${chalk.cyan("Top language (today):")} ${todayTopLang[0]} (${formatDuration(todayTopLang[1])})`);
179
+ }
180
+ console.log(`\n${chalk.cyan("Last 7 days:")} ${formatDuration(weekSummary.totalTimeMs)}`);
181
+ const weekTopProject = topEntry(weekSummary.projects);
182
+ if (weekTopProject) {
183
+ console.log(`${chalk.cyan("Top project (7 days):")} ${weekTopProject[0]} (${formatDuration(weekTopProject[1])})`);
184
+ }
185
+ const weekTopLang = topEntry(weekSummary.languages);
186
+ if (weekTopLang) {
187
+ console.log(`${chalk.cyan("Top language (7 days):")} ${weekTopLang[0]} (${formatDuration(weekTopLang[1])})`);
188
+ }
189
+ });
125
190
  program
126
191
  .command("daemon")
127
192
  .description("Run watcher in foreground (internal)")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hackhours",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Offline local-first coding activity tracker",
5
5
  "type": "module",
6
6
  "bin": {