@pkprosol/coach 1.0.2 → 1.0.4

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/bin/coach.js CHANGED
@@ -4,8 +4,8 @@ import ora from "ora";
4
4
  import chalk from "chalk";
5
5
  import { collectToday } from "../src/collector.js";
6
6
  import { analyze, runClaude, buildHandoffPrompt, buildFocusPrompt } from "../src/analyzer.js";
7
- import { renderInsight, renderStreak, renderHistory, renderNoData, renderError, renderHandoff, renderFocus, renderRecap, renderGoals, renderCompare, } from "../src/display.js";
8
- import { loadState, saveState, loadInsights, appendInsight, updateLastInsightRating, updateStreak, recordDimension, addGoal, completeGoal, clearCompletedGoals, recordDailyStat, } from "../src/storage.js";
7
+ import { renderInsight, renderStreak, renderHistory, renderNoData, renderError, renderHandoff, renderFocus, renderRecap, renderGoals, renderCompare, renderWelcome, } from "../src/display.js";
8
+ import { isFirstRun, loadState, saveState, loadInsights, appendInsight, updateLastInsightRating, updateStreak, recordDimension, addGoal, completeGoal, clearCompletedGoals, recordDailyStat, } from "../src/storage.js";
9
9
  function askQuestion(prompt) {
10
10
  const rl = createInterface({ input: process.stdin, output: process.stdout });
11
11
  return new Promise((resolve) => {
@@ -289,6 +289,13 @@ ${chalk.bold("Usage:")}
289
289
  // --- Main ---
290
290
  async function main() {
291
291
  const command = process.argv[2];
292
+ // Show welcome on first run (no command or default)
293
+ if (!command && isFirstRun()) {
294
+ console.log("");
295
+ console.log(renderWelcome());
296
+ console.log("");
297
+ return;
298
+ }
292
299
  switch (command) {
293
300
  case "handoff":
294
301
  await handleHandoff();
@@ -2,31 +2,46 @@ import { spawn } from "node:child_process";
2
2
  import { DIMENSIONS } from "./types.js";
3
3
  export function runClaude(prompt) {
4
4
  return new Promise((resolve, reject) => {
5
- const proc = spawn("claude", ["-p", "--output-format", "text", "--max-tokens", "1024"], {
5
+ const proc = spawn("claude", ["-p", "--output-format", "text"], {
6
6
  stdio: ["pipe", "pipe", "pipe"],
7
7
  });
8
8
  let stdout = "";
9
9
  let stderr = "";
10
+ let rejected = false;
11
+ function fail(err) {
12
+ if (!rejected) {
13
+ rejected = true;
14
+ reject(err);
15
+ }
16
+ }
10
17
  proc.stdout.on("data", (chunk) => {
11
18
  stdout += chunk.toString();
12
19
  });
13
20
  proc.stderr.on("data", (chunk) => {
14
21
  stderr += chunk.toString();
15
22
  });
23
+ proc.stdin.on("error", (err) => {
24
+ // EPIPE means claude exited before we finished writing — handled in 'close'
25
+ if (err.code !== "EPIPE") {
26
+ fail(err);
27
+ }
28
+ });
16
29
  proc.on("error", (err) => {
17
30
  if (err.code === "ENOENT") {
18
- reject(new Error("claude CLI not found. Install Claude Code first: https://docs.anthropic.com/en/docs/claude-code"));
31
+ fail(new Error("claude CLI not found. Install Claude Code first: https://docs.anthropic.com/en/docs/claude-code"));
19
32
  }
20
33
  else {
21
- reject(err);
34
+ fail(err);
22
35
  }
23
36
  });
24
37
  proc.on("close", (code) => {
38
+ if (rejected)
39
+ return;
25
40
  if (code === 0) {
26
41
  resolve(stdout.trim());
27
42
  }
28
43
  else {
29
- reject(new Error(stderr.trim() || `claude exited with code ${code}`));
44
+ fail(new Error(stderr.trim() || `claude exited with code ${code}`));
30
45
  }
31
46
  });
32
47
  proc.stdin.write(prompt);
@@ -2,6 +2,7 @@ import type { Insight, CoachState, StoredInsight, Goal, CollectedData, DailyStat
2
2
  export declare function renderInsight(insight: Insight, state: CoachState): string;
3
3
  export declare function renderStreak(state: CoachState): string;
4
4
  export declare function renderHistory(insights: StoredInsight[]): string;
5
+ export declare function renderWelcome(): string;
5
6
  export declare function renderNoData(): string;
6
7
  export declare function renderError(msg: string): string;
7
8
  export declare function renderHandoff(handoff: {
@@ -126,6 +126,38 @@ export function renderHistory(insights) {
126
126
  }
127
127
  return out.join("\n");
128
128
  }
129
+ export function renderWelcome() {
130
+ const out = [];
131
+ out.push(boxTop());
132
+ out.push(padLine(chalk.bold.white(" WELCOME TO COACH")));
133
+ out.push(boxMid());
134
+ out.push(padLine(""));
135
+ out.push(padLine(" Coach analyzes your Claude Code and Claude"));
136
+ out.push(padLine(" App sessions to give you a daily lesson and"));
137
+ out.push(padLine(" actionable tip — like a personal AI work coach."));
138
+ out.push(padLine(""));
139
+ out.push(padLine(chalk.bold(" How it works:")));
140
+ out.push(padLine(" 1. Use Claude Code / Claude App as usual"));
141
+ out.push(padLine(" 2. Run " + chalk.cyan("coach") + " at the end of your day"));
142
+ out.push(padLine(" 3. Get a personalized insight + tip"));
143
+ out.push(padLine(""));
144
+ out.push(padLine(chalk.bold(" Commands:")));
145
+ out.push(padLine(" " + chalk.cyan("coach") + " Today's lesson + tip"));
146
+ out.push(padLine(" " + chalk.cyan("coach handoff") + " Handoff note for your work"));
147
+ out.push(padLine(" " + chalk.cyan("coach focus") + " Focus & context-switching"));
148
+ out.push(padLine(" " + chalk.cyan("coach recap") + " Quick stats (no AI)"));
149
+ out.push(padLine(" " + chalk.cyan("coach goals") + " Track your goals"));
150
+ out.push(padLine(" " + chalk.cyan("coach compare") + " Today vs recent averages"));
151
+ out.push(padLine(" " + chalk.cyan("coach help") + " All commands"));
152
+ out.push(padLine(""));
153
+ out.push(padLine(chalk.bold(" Requirements:")));
154
+ out.push(padLine(" " + chalk.dim("Claude Code CLI must be installed and")));
155
+ out.push(padLine(" " + chalk.dim("authenticated. Get it at:")));
156
+ out.push(padLine(" " + chalk.dim("https://docs.anthropic.com/en/docs/claude-code")));
157
+ out.push(padLine(""));
158
+ out.push(boxBot());
159
+ return out.join("\n");
160
+ }
129
161
  export function renderNoData() {
130
162
  return chalk.yellow("No Claude Code sessions found for today.") +
131
163
  "\n" +
@@ -1,4 +1,5 @@
1
1
  import type { CoachState, StoredInsight, Goal, DailyStat } from "./types.js";
2
+ export declare function isFirstRun(): boolean;
2
3
  export declare function loadState(): CoachState;
3
4
  export declare function saveState(state: CoachState): void;
4
5
  export declare function updateStreak(state: CoachState, today: string): CoachState;
@@ -19,6 +19,9 @@ const DEFAULT_STATE = {
19
19
  goals: [],
20
20
  dailyStats: [],
21
21
  };
22
+ export function isFirstRun() {
23
+ return !existsSync(STATE_FILE);
24
+ }
22
25
  export function loadState() {
23
26
  ensureDir();
24
27
  if (!existsSync(STATE_FILE)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pkprosol/coach",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Daily AI work coach — analyzes your Claude Code & Claude App sessions to deliver one lesson + one tip daily",
5
5
  "type": "module",
6
6
  "bin": {