@keepgoingdev/mcp-server 0.7.1 → 0.7.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 CHANGED
@@ -78,7 +78,8 @@ function findGitRoot(startPath) {
78
78
  const toplevel = execFileSync("git", ["rev-parse", "--show-toplevel"], {
79
79
  cwd: startPath,
80
80
  encoding: "utf-8",
81
- timeout: 5e3
81
+ timeout: 5e3,
82
+ stdio: ["pipe", "pipe", "pipe"]
82
83
  }).trim();
83
84
  return toplevel || startPath;
84
85
  } catch {
@@ -95,12 +96,14 @@ function resolveStorageRoot(startPath) {
95
96
  const toplevel = execFileSync("git", ["rev-parse", "--show-toplevel"], {
96
97
  cwd: startPath,
97
98
  encoding: "utf-8",
98
- timeout: 5e3
99
+ timeout: 5e3,
100
+ stdio: ["pipe", "pipe", "pipe"]
99
101
  }).trim();
100
102
  const commonDir = execFileSync("git", ["rev-parse", "--git-common-dir"], {
101
103
  cwd: startPath,
102
104
  encoding: "utf-8",
103
- timeout: 5e3
105
+ timeout: 5e3,
106
+ stdio: ["pipe", "pipe", "pipe"]
104
107
  }).trim();
105
108
  const absoluteCommonDir = path.resolve(toplevel, commonDir);
106
109
  const mainRoot = path.dirname(absoluteCommonDir);
@@ -1842,12 +1845,14 @@ var SESSION_END_HOOK = {
1842
1845
  }
1843
1846
  ]
1844
1847
  };
1845
- var KEEPGOING_RULES_VERSION = 1;
1848
+ var KEEPGOING_RULES_VERSION = 2;
1846
1849
  var KEEPGOING_RULES_CONTENT = `<!-- @keepgoingdev/mcp-server v${KEEPGOING_RULES_VERSION} -->
1847
1850
  ## KeepGoing
1848
1851
 
1852
+ When you see KeepGoing momentum data in your session context (from a SessionStart hook), share a brief welcome with the user that includes: what was last worked on, the suggested next step, and any blockers.
1853
+
1849
1854
  After completing a task or meaningful piece of work, call the \`save_checkpoint\` MCP tool with:
1850
- - \`summary\`: 1-2 sentences. What changed and why \u2014 no file paths, no implementation details (those are captured from git).
1855
+ - \`summary\`: 1-2 sentences. What changed and why, no file paths, no implementation details (those are captured from git).
1851
1856
  - \`nextStep\`: What to do next
1852
1857
  - \`blocker\`: Any blocker (if applicable)
1853
1858
  `;
@@ -1973,7 +1978,7 @@ function setupProject(options) {
1973
1978
  messages.push(`Warning: ${conflict}`);
1974
1979
  }
1975
1980
  }
1976
- if (scope === "project") {
1981
+ {
1977
1982
  const needsUpdate = settings.statusLine?.command && statusline?.isLegacy?.(settings.statusLine.command);
1978
1983
  if (!settings.statusLine || needsUpdate) {
1979
1984
  settings.statusLine = {
@@ -1981,7 +1986,7 @@ function setupProject(options) {
1981
1986
  command: STATUSLINE_CMD
1982
1987
  };
1983
1988
  settingsChanged = true;
1984
- messages.push(needsUpdate ? "Statusline: Migrated to auto-updating npx command" : "Statusline: Added to .claude/settings.json");
1989
+ messages.push(needsUpdate ? "Statusline: Migrated to auto-updating npx command" : `Statusline: Added to ${scopeLabel}`);
1985
1990
  } else {
1986
1991
  messages.push("Statusline: Already configured in settings, skipped");
1987
1992
  }
@@ -3190,7 +3195,8 @@ async function handleSaveCheckpoint() {
3190
3195
 
3191
3196
  // src/cli/transcriptUtils.ts
3192
3197
  import fs8 from "fs";
3193
- var TAIL_READ_BYTES = 8192;
3198
+ var TAIL_READ_BYTES = 32768;
3199
+ var LATEST_LABEL_READ_BYTES = 65536;
3194
3200
  var TOOL_VERB_MAP = {
3195
3201
  Edit: "editing",
3196
3202
  MultiEdit: "editing",
@@ -3202,7 +3208,12 @@ var TOOL_VERB_MAP = {
3202
3208
  Agent: "delegating",
3203
3209
  WebFetch: "browsing",
3204
3210
  WebSearch: "browsing",
3205
- TodoWrite: "planning"
3211
+ TodoWrite: "planning",
3212
+ AskUserQuestion: "discussing",
3213
+ EnterPlanMode: "planning",
3214
+ ExitPlanMode: "planning",
3215
+ TaskCreate: "planning",
3216
+ TaskUpdate: "planning"
3206
3217
  };
3207
3218
  function truncateAtWord(text, max) {
3208
3219
  if (text.length <= max) return text;
@@ -3270,6 +3281,50 @@ function extractSessionLabel(transcriptPath) {
3270
3281
  }
3271
3282
  return null;
3272
3283
  }
3284
+ function extractLatestUserLabel(transcriptPath) {
3285
+ if (!transcriptPath || !fs8.existsSync(transcriptPath)) return null;
3286
+ try {
3287
+ const stat = fs8.statSync(transcriptPath);
3288
+ const fileSize = stat.size;
3289
+ if (fileSize === 0) return null;
3290
+ const readSize = Math.min(fileSize, LATEST_LABEL_READ_BYTES);
3291
+ const offset = fileSize - readSize;
3292
+ const buf = Buffer.alloc(readSize);
3293
+ const fd = fs8.openSync(transcriptPath, "r");
3294
+ try {
3295
+ fs8.readSync(fd, buf, 0, readSize, offset);
3296
+ } finally {
3297
+ fs8.closeSync(fd);
3298
+ }
3299
+ const tail = buf.toString("utf-8");
3300
+ const lines = tail.split("\n").reverse();
3301
+ for (const line of lines) {
3302
+ const trimmed = line.trim();
3303
+ if (!trimmed) continue;
3304
+ let entry;
3305
+ try {
3306
+ entry = JSON.parse(trimmed);
3307
+ } catch {
3308
+ continue;
3309
+ }
3310
+ if (!isUserEntry(entry)) continue;
3311
+ let text = extractTextFromContent(entry.message?.content);
3312
+ if (!text) continue;
3313
+ if (text.startsWith("[") || /^<[a-z][\w-]*>/.test(text)) continue;
3314
+ text = text.replace(/@[\w./\-]+/g, "").trim();
3315
+ text = text.replace(FILLER_PREFIX_RE, "").trim();
3316
+ text = text.replace(MARKDOWN_HEADING_RE, "").trim();
3317
+ text = text.replace(/\s+/g, " ").trim();
3318
+ if (text.length < 20) continue;
3319
+ if (text.length > 80) {
3320
+ text = text.slice(0, 80);
3321
+ }
3322
+ return text;
3323
+ }
3324
+ } catch {
3325
+ }
3326
+ return null;
3327
+ }
3273
3328
  function extractCurrentAction(transcriptPath) {
3274
3329
  if (!transcriptPath || !fs8.existsSync(transcriptPath)) return null;
3275
3330
  try {
@@ -3410,6 +3465,9 @@ async function handleStatusline() {
3410
3465
  if (input.agent?.name) {
3411
3466
  label = input.agent.name;
3412
3467
  }
3468
+ if (!label && transcriptPath) {
3469
+ label = extractLatestUserLabel(transcriptPath);
3470
+ }
3413
3471
  if (!label) {
3414
3472
  try {
3415
3473
  const gitRoot = findGitRoot(dir);
@@ -3428,7 +3486,28 @@ async function handleStatusline() {
3428
3486
  if (!label && transcriptPath) {
3429
3487
  label = extractSessionLabel(transcriptPath);
3430
3488
  }
3431
- if (!label) process.exit(0);
3489
+ if (!label) {
3490
+ try {
3491
+ const gitRoot = findGitRoot(dir);
3492
+ const reader = new KeepGoingReader(gitRoot);
3493
+ if (reader.exists()) {
3494
+ const recent = reader.getScopedRecentSessions(10);
3495
+ const last = recent.find((s) => s.source !== "auto") ?? recent[0];
3496
+ if (last) {
3497
+ const ago = formatRelativeTime(last.timestamp);
3498
+ const summary = last.summary ? truncateAtWord(last.summary, 40) : null;
3499
+ const next = last.nextStep ? truncateAtWord(last.nextStep, 30) : null;
3500
+ const parts = [`[KG] ${ago}`];
3501
+ if (summary) parts.push(summary);
3502
+ if (next) parts.push(`\u2192 ${next}`);
3503
+ process.stdout.write(`${parts.join(" \xB7 ")}
3504
+ `);
3505
+ }
3506
+ }
3507
+ } catch {
3508
+ }
3509
+ process.exit(0);
3510
+ }
3432
3511
  const action = transcriptPath ? extractCurrentAction(transcriptPath) : null;
3433
3512
  const budget = action ? 40 : 55;
3434
3513
  const displayLabel = truncateAtWord(label, budget);