@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 +89 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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 =
|
|
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
|
|
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
|
-
|
|
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" :
|
|
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 =
|
|
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)
|
|
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);
|