@keepgoingdev/mcp-server 0.5.4 → 0.5.6
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/LICENSE +21 -0
- package/README.md +12 -2
- package/dist/index.js +207 -69
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/statusline.sh +0 -51
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 KeepGoing.dev
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -8,13 +8,23 @@ KeepGoing auto-captures checkpoints (what you were doing, what's next, which fil
|
|
|
8
8
|
|
|
9
9
|
### Claude Code
|
|
10
10
|
|
|
11
|
+
**Global (recommended)** — works across all your projects:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
claude mcp add keepgoing --scope user -- npx -y @keepgoingdev/mcp-server
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
**Per-project** — scoped to a single project:
|
|
18
|
+
|
|
11
19
|
```bash
|
|
12
|
-
claude mcp add keepgoing -- npx -y @keepgoingdev/mcp-server
|
|
20
|
+
claude mcp add keepgoing --scope project -- npx -y @keepgoingdev/mcp-server
|
|
13
21
|
```
|
|
14
22
|
|
|
23
|
+
Then ask Claude Code to run `setup_project` (with `scope: "user"` for global, or default for per-project) to add session hooks and CLAUDE.md instructions.
|
|
24
|
+
|
|
15
25
|
### Manual config
|
|
16
26
|
|
|
17
|
-
Add to your MCP config (e.g., `~/.claude
|
|
27
|
+
Add to your MCP config (e.g., `~/.claude.json` for global, or `.mcp.json` for per-project):
|
|
18
28
|
|
|
19
29
|
```json
|
|
20
30
|
{
|
package/dist/index.js
CHANGED
|
@@ -1960,10 +1960,48 @@ function registerGetCurrentTask(server, reader) {
|
|
|
1960
1960
|
}
|
|
1961
1961
|
|
|
1962
1962
|
// src/tools/setupProject.ts
|
|
1963
|
+
import fs6 from "fs";
|
|
1964
|
+
import os3 from "os";
|
|
1965
|
+
import path8 from "path";
|
|
1966
|
+
import { z as z4 } from "zod";
|
|
1967
|
+
|
|
1968
|
+
// src/cli/migrate.ts
|
|
1963
1969
|
import fs5 from "fs";
|
|
1964
1970
|
import os2 from "os";
|
|
1965
1971
|
import path7 from "path";
|
|
1966
|
-
|
|
1972
|
+
var STATUSLINE_CMD = "npx -y @keepgoingdev/mcp-server --statusline";
|
|
1973
|
+
function isLegacyStatusline(command) {
|
|
1974
|
+
return !command.includes("--statusline") && command.includes("keepgoing-statusline");
|
|
1975
|
+
}
|
|
1976
|
+
function migrateStatusline(wsPath) {
|
|
1977
|
+
const settingsPath = path7.join(wsPath, ".claude", "settings.json");
|
|
1978
|
+
if (!fs5.existsSync(settingsPath)) return void 0;
|
|
1979
|
+
try {
|
|
1980
|
+
const settings = JSON.parse(fs5.readFileSync(settingsPath, "utf-8"));
|
|
1981
|
+
const cmd = settings.statusLine?.command;
|
|
1982
|
+
if (!cmd || !isLegacyStatusline(cmd)) return void 0;
|
|
1983
|
+
settings.statusLine = {
|
|
1984
|
+
type: "command",
|
|
1985
|
+
command: STATUSLINE_CMD
|
|
1986
|
+
};
|
|
1987
|
+
fs5.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
1988
|
+
cleanupLegacyScript();
|
|
1989
|
+
return "[KeepGoing] Migrated statusline to auto-updating command (restart Claude Code to apply)";
|
|
1990
|
+
} catch {
|
|
1991
|
+
return void 0;
|
|
1992
|
+
}
|
|
1993
|
+
}
|
|
1994
|
+
function cleanupLegacyScript() {
|
|
1995
|
+
const legacyScript = path7.join(os2.homedir(), ".claude", "keepgoing-statusline.sh");
|
|
1996
|
+
if (fs5.existsSync(legacyScript)) {
|
|
1997
|
+
try {
|
|
1998
|
+
fs5.unlinkSync(legacyScript);
|
|
1999
|
+
} catch {
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
// src/tools/setupProject.ts
|
|
1967
2005
|
var KEEPGOING_MARKER = "@keepgoingdev/mcp-server";
|
|
1968
2006
|
var SESSION_START_HOOK = {
|
|
1969
2007
|
matcher: "",
|
|
@@ -2005,101 +2043,140 @@ function hasKeepGoingHook(hookEntries) {
|
|
|
2005
2043
|
(entry) => entry?.hooks?.some((h) => typeof h?.command === "string" && h.command.includes(KEEPGOING_MARKER))
|
|
2006
2044
|
);
|
|
2007
2045
|
}
|
|
2046
|
+
function resolveScopePaths(scope, workspacePath) {
|
|
2047
|
+
if (scope === "user") {
|
|
2048
|
+
const claudeDir2 = path8.join(os3.homedir(), ".claude");
|
|
2049
|
+
return {
|
|
2050
|
+
claudeDir: claudeDir2,
|
|
2051
|
+
settingsPath: path8.join(claudeDir2, "settings.json"),
|
|
2052
|
+
claudeMdPath: path8.join(claudeDir2, "CLAUDE.md")
|
|
2053
|
+
};
|
|
2054
|
+
}
|
|
2055
|
+
const claudeDir = path8.join(workspacePath, ".claude");
|
|
2056
|
+
const dotClaudeMdPath = path8.join(workspacePath, ".claude", "CLAUDE.md");
|
|
2057
|
+
const rootClaudeMdPath = path8.join(workspacePath, "CLAUDE.md");
|
|
2058
|
+
return {
|
|
2059
|
+
claudeDir,
|
|
2060
|
+
settingsPath: path8.join(claudeDir, "settings.json"),
|
|
2061
|
+
claudeMdPath: fs6.existsSync(dotClaudeMdPath) ? dotClaudeMdPath : rootClaudeMdPath
|
|
2062
|
+
};
|
|
2063
|
+
}
|
|
2064
|
+
function writeHooksToSettings(settings) {
|
|
2065
|
+
let changed = false;
|
|
2066
|
+
if (!settings.hooks) {
|
|
2067
|
+
settings.hooks = {};
|
|
2068
|
+
}
|
|
2069
|
+
if (!Array.isArray(settings.hooks.SessionStart)) {
|
|
2070
|
+
settings.hooks.SessionStart = [];
|
|
2071
|
+
}
|
|
2072
|
+
if (!hasKeepGoingHook(settings.hooks.SessionStart)) {
|
|
2073
|
+
settings.hooks.SessionStart.push(SESSION_START_HOOK);
|
|
2074
|
+
changed = true;
|
|
2075
|
+
}
|
|
2076
|
+
if (!Array.isArray(settings.hooks.Stop)) {
|
|
2077
|
+
settings.hooks.Stop = [];
|
|
2078
|
+
}
|
|
2079
|
+
if (!hasKeepGoingHook(settings.hooks.Stop)) {
|
|
2080
|
+
settings.hooks.Stop.push(STOP_HOOK);
|
|
2081
|
+
changed = true;
|
|
2082
|
+
}
|
|
2083
|
+
if (!Array.isArray(settings.hooks.PostToolUse)) {
|
|
2084
|
+
settings.hooks.PostToolUse = [];
|
|
2085
|
+
}
|
|
2086
|
+
if (!hasKeepGoingHook(settings.hooks.PostToolUse)) {
|
|
2087
|
+
settings.hooks.PostToolUse.push(POST_TOOL_USE_HOOK);
|
|
2088
|
+
changed = true;
|
|
2089
|
+
}
|
|
2090
|
+
return changed;
|
|
2091
|
+
}
|
|
2092
|
+
function checkHookConflict(scope, workspacePath) {
|
|
2093
|
+
const otherPaths = resolveScopePaths(scope === "user" ? "project" : "user", workspacePath);
|
|
2094
|
+
if (!fs6.existsSync(otherPaths.settingsPath)) {
|
|
2095
|
+
return null;
|
|
2096
|
+
}
|
|
2097
|
+
try {
|
|
2098
|
+
const otherSettings = JSON.parse(fs6.readFileSync(otherPaths.settingsPath, "utf-8"));
|
|
2099
|
+
const hooks = otherSettings?.hooks;
|
|
2100
|
+
if (!hooks) return null;
|
|
2101
|
+
const hasConflict = Array.isArray(hooks.SessionStart) && hasKeepGoingHook(hooks.SessionStart) || Array.isArray(hooks.Stop) && hasKeepGoingHook(hooks.Stop);
|
|
2102
|
+
if (hasConflict) {
|
|
2103
|
+
const otherScope = scope === "user" ? "project" : "user";
|
|
2104
|
+
const otherFile = otherPaths.settingsPath;
|
|
2105
|
+
return `**Warning:** KeepGoing hooks are also configured at ${otherScope} scope (\`${otherFile}\`). Having hooks at both scopes may cause them to fire twice. Consider removing the ${otherScope}-level hooks if you want to use ${scope}-level only.`;
|
|
2106
|
+
}
|
|
2107
|
+
} catch {
|
|
2108
|
+
}
|
|
2109
|
+
return null;
|
|
2110
|
+
}
|
|
2008
2111
|
function registerSetupProject(server, workspacePath) {
|
|
2009
2112
|
server.tool(
|
|
2010
2113
|
"setup_project",
|
|
2011
|
-
|
|
2114
|
+
'Set up KeepGoing hooks and instructions. Use scope "user" for global setup (all projects) or "project" for per-project setup.',
|
|
2012
2115
|
{
|
|
2013
|
-
sessionHooks: z4.boolean().optional().default(true).describe("Add session hooks to
|
|
2014
|
-
claudeMd: z4.boolean().optional().default(true).describe("Add KeepGoing instructions to CLAUDE.md")
|
|
2116
|
+
sessionHooks: z4.boolean().optional().default(true).describe("Add session hooks to settings.json"),
|
|
2117
|
+
claudeMd: z4.boolean().optional().default(true).describe("Add KeepGoing instructions to CLAUDE.md"),
|
|
2118
|
+
scope: z4.enum(["project", "user"]).optional().default("project").describe('Where to write config: "user" for global (~/.claude/), "project" for per-project (.claude/)')
|
|
2015
2119
|
},
|
|
2016
|
-
async ({ sessionHooks, claudeMd }) => {
|
|
2120
|
+
async ({ sessionHooks, claudeMd, scope }) => {
|
|
2017
2121
|
const results = [];
|
|
2018
|
-
const claudeDir =
|
|
2019
|
-
const
|
|
2122
|
+
const { claudeDir, settingsPath, claudeMdPath } = resolveScopePaths(scope, workspacePath);
|
|
2123
|
+
const scopeLabel = scope === "user" ? "`~/.claude/settings.json`" : "`.claude/settings.json`";
|
|
2020
2124
|
let settings = {};
|
|
2021
|
-
if (
|
|
2022
|
-
settings = JSON.parse(
|
|
2125
|
+
if (fs6.existsSync(settingsPath)) {
|
|
2126
|
+
settings = JSON.parse(fs6.readFileSync(settingsPath, "utf-8"));
|
|
2023
2127
|
}
|
|
2024
2128
|
let settingsChanged = false;
|
|
2025
2129
|
if (sessionHooks) {
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
settings.hooks.SessionStart = [];
|
|
2031
|
-
}
|
|
2032
|
-
if (!hasKeepGoingHook(settings.hooks.SessionStart)) {
|
|
2033
|
-
settings.hooks.SessionStart.push(SESSION_START_HOOK);
|
|
2034
|
-
settingsChanged = true;
|
|
2035
|
-
}
|
|
2036
|
-
if (!Array.isArray(settings.hooks.Stop)) {
|
|
2037
|
-
settings.hooks.Stop = [];
|
|
2038
|
-
}
|
|
2039
|
-
if (!hasKeepGoingHook(settings.hooks.Stop)) {
|
|
2040
|
-
settings.hooks.Stop.push(STOP_HOOK);
|
|
2041
|
-
settingsChanged = true;
|
|
2042
|
-
}
|
|
2043
|
-
if (!Array.isArray(settings.hooks.PostToolUse)) {
|
|
2044
|
-
settings.hooks.PostToolUse = [];
|
|
2045
|
-
}
|
|
2046
|
-
if (!hasKeepGoingHook(settings.hooks.PostToolUse)) {
|
|
2047
|
-
settings.hooks.PostToolUse.push(POST_TOOL_USE_HOOK);
|
|
2048
|
-
settingsChanged = true;
|
|
2049
|
-
}
|
|
2050
|
-
if (settingsChanged) {
|
|
2051
|
-
results.push("**Session hooks:** Added to `.claude/settings.json`");
|
|
2130
|
+
const hooksChanged = writeHooksToSettings(settings);
|
|
2131
|
+
settingsChanged = hooksChanged;
|
|
2132
|
+
if (hooksChanged) {
|
|
2133
|
+
results.push(`**Session hooks:** Added to ${scopeLabel}`);
|
|
2052
2134
|
} else {
|
|
2053
2135
|
results.push("**Session hooks:** Already present, skipped");
|
|
2054
2136
|
}
|
|
2137
|
+
const conflict = checkHookConflict(scope, workspacePath);
|
|
2138
|
+
if (conflict) {
|
|
2139
|
+
results.push(conflict);
|
|
2140
|
+
}
|
|
2055
2141
|
}
|
|
2056
|
-
if (
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
);
|
|
2061
|
-
const claudeHome = path7.join(os2.homedir(), ".claude");
|
|
2062
|
-
const statuslineDest = path7.join(claudeHome, "keepgoing-statusline.sh");
|
|
2063
|
-
if (fs5.existsSync(statuslineSrc)) {
|
|
2064
|
-
if (!fs5.existsSync(claudeHome)) {
|
|
2065
|
-
fs5.mkdirSync(claudeHome, { recursive: true });
|
|
2066
|
-
}
|
|
2067
|
-
fs5.copyFileSync(statuslineSrc, statuslineDest);
|
|
2068
|
-
fs5.chmodSync(statuslineDest, 493);
|
|
2069
|
-
if (!settings.statusLine) {
|
|
2142
|
+
if (scope === "project") {
|
|
2143
|
+
if (process.env.KEEPGOING_PRO_BYPASS === "1" || getLicenseForFeature("session-awareness")) {
|
|
2144
|
+
const needsUpdate = settings.statusLine?.command && isLegacyStatusline(settings.statusLine.command);
|
|
2145
|
+
if (!settings.statusLine || needsUpdate) {
|
|
2070
2146
|
settings.statusLine = {
|
|
2071
2147
|
type: "command",
|
|
2072
|
-
command:
|
|
2148
|
+
command: STATUSLINE_CMD
|
|
2073
2149
|
};
|
|
2074
2150
|
settingsChanged = true;
|
|
2075
|
-
results.push("**Statusline:**
|
|
2151
|
+
results.push(needsUpdate ? "**Statusline:** Migrated to auto-updating `npx` command" : "**Statusline:** Added to `.claude/settings.json`");
|
|
2076
2152
|
} else {
|
|
2077
2153
|
results.push("**Statusline:** `statusLine` already configured in settings, skipped");
|
|
2078
2154
|
}
|
|
2079
|
-
|
|
2080
|
-
results.push("**Statusline:** Script not found in package, skipped");
|
|
2155
|
+
cleanupLegacyScript();
|
|
2081
2156
|
}
|
|
2082
2157
|
}
|
|
2083
2158
|
if (settingsChanged) {
|
|
2084
|
-
if (!
|
|
2085
|
-
|
|
2159
|
+
if (!fs6.existsSync(claudeDir)) {
|
|
2160
|
+
fs6.mkdirSync(claudeDir, { recursive: true });
|
|
2086
2161
|
}
|
|
2087
|
-
|
|
2162
|
+
fs6.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
2088
2163
|
}
|
|
2089
2164
|
if (claudeMd) {
|
|
2090
|
-
const dotClaudeMdPath = path7.join(workspacePath, ".claude", "CLAUDE.md");
|
|
2091
|
-
const rootClaudeMdPath = path7.join(workspacePath, "CLAUDE.md");
|
|
2092
|
-
const claudeMdPath = fs5.existsSync(dotClaudeMdPath) ? dotClaudeMdPath : rootClaudeMdPath;
|
|
2093
2165
|
let existing = "";
|
|
2094
|
-
if (
|
|
2095
|
-
existing =
|
|
2166
|
+
if (fs6.existsSync(claudeMdPath)) {
|
|
2167
|
+
existing = fs6.readFileSync(claudeMdPath, "utf-8");
|
|
2096
2168
|
}
|
|
2169
|
+
const mdLabel = scope === "user" ? "`~/.claude/CLAUDE.md`" : "`CLAUDE.md`";
|
|
2097
2170
|
if (existing.includes("## KeepGoing")) {
|
|
2098
|
-
results.push(
|
|
2171
|
+
results.push(`**CLAUDE.md:** KeepGoing section already present in ${mdLabel}, skipped`);
|
|
2099
2172
|
} else {
|
|
2100
2173
|
const updated = existing + CLAUDE_MD_SECTION;
|
|
2101
|
-
|
|
2102
|
-
|
|
2174
|
+
const mdDir = path8.dirname(claudeMdPath);
|
|
2175
|
+
if (!fs6.existsSync(mdDir)) {
|
|
2176
|
+
fs6.mkdirSync(mdDir, { recursive: true });
|
|
2177
|
+
}
|
|
2178
|
+
fs6.writeFileSync(claudeMdPath, updated);
|
|
2179
|
+
results.push(`**CLAUDE.md:** Added KeepGoing section to ${mdLabel}`);
|
|
2103
2180
|
}
|
|
2104
2181
|
}
|
|
2105
2182
|
return {
|
|
@@ -2381,6 +2458,10 @@ async function handlePrintMomentum() {
|
|
|
2381
2458
|
lines.push(` Worked on ${touchedCount} files on ${lastSession.gitBranch ?? "unknown branch"}`);
|
|
2382
2459
|
}
|
|
2383
2460
|
lines.push(" Tip: Use the get_reentry_briefing tool for a full briefing");
|
|
2461
|
+
const migrationMsg = migrateStatusline(wsPath);
|
|
2462
|
+
if (migrationMsg) {
|
|
2463
|
+
lines.push(migrationMsg);
|
|
2464
|
+
}
|
|
2384
2465
|
console.log(lines.join("\n"));
|
|
2385
2466
|
process.exit(0);
|
|
2386
2467
|
}
|
|
@@ -2422,7 +2503,7 @@ async function handlePrintCurrent() {
|
|
|
2422
2503
|
}
|
|
2423
2504
|
|
|
2424
2505
|
// src/cli/saveCheckpoint.ts
|
|
2425
|
-
import
|
|
2506
|
+
import path9 from "path";
|
|
2426
2507
|
async function handleSaveCheckpoint() {
|
|
2427
2508
|
const wsPath = resolveWsPath();
|
|
2428
2509
|
const reader = new KeepGoingReader(wsPath);
|
|
@@ -2450,9 +2531,9 @@ async function handleSaveCheckpoint() {
|
|
|
2450
2531
|
sessionStartTime: lastSession?.timestamp ?? now,
|
|
2451
2532
|
lastActivityTime: now
|
|
2452
2533
|
});
|
|
2453
|
-
const summary = buildSmartSummary(events) ?? `Worked on ${touchedFiles.slice(0, 5).map((f) =>
|
|
2534
|
+
const summary = buildSmartSummary(events) ?? `Worked on ${touchedFiles.slice(0, 5).map((f) => path9.basename(f)).join(", ")}`;
|
|
2454
2535
|
const nextStep = buildSmartNextStep(events);
|
|
2455
|
-
const projectName =
|
|
2536
|
+
const projectName = path9.basename(resolveStorageRoot(wsPath));
|
|
2456
2537
|
const sessionId = generateSessionId({ workspaceRoot: wsPath, branch: gitBranch ?? void 0, worktreePath: wsPath });
|
|
2457
2538
|
const checkpoint = createCheckpoint({
|
|
2458
2539
|
summary,
|
|
@@ -2543,7 +2624,8 @@ async function handleUpdateTaskFromHook() {
|
|
|
2543
2624
|
const fileName = filePath ? filePath.split("/").pop() ?? filePath : "";
|
|
2544
2625
|
const writer = new KeepGoingWriter(wsPath);
|
|
2545
2626
|
const existing = writer.readCurrentTasks();
|
|
2546
|
-
const
|
|
2627
|
+
const sessionIdFromHook = hookData.session_id;
|
|
2628
|
+
const cachedBranch = sessionIdFromHook ? existing.find((t) => t.sessionId === sessionIdFromHook)?.branch : void 0;
|
|
2547
2629
|
const branch = cachedBranch ?? getCurrentBranch(wsPath) ?? void 0;
|
|
2548
2630
|
const task = {
|
|
2549
2631
|
taskSummary: fileName ? `${toolName} ${fileName}` : `Used ${toolName}`,
|
|
@@ -2563,13 +2645,69 @@ async function handleUpdateTaskFromHook() {
|
|
|
2563
2645
|
process.stdin.resume();
|
|
2564
2646
|
}
|
|
2565
2647
|
|
|
2648
|
+
// src/cli/statusline.ts
|
|
2649
|
+
import fs7 from "fs";
|
|
2650
|
+
import path10 from "path";
|
|
2651
|
+
var STDIN_TIMEOUT_MS2 = 3e3;
|
|
2652
|
+
async function handleStatusline() {
|
|
2653
|
+
const chunks = [];
|
|
2654
|
+
const timeout = setTimeout(() => process.exit(0), STDIN_TIMEOUT_MS2);
|
|
2655
|
+
process.stdin.on("error", () => {
|
|
2656
|
+
clearTimeout(timeout);
|
|
2657
|
+
process.exit(0);
|
|
2658
|
+
});
|
|
2659
|
+
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
2660
|
+
process.stdin.on("end", () => {
|
|
2661
|
+
clearTimeout(timeout);
|
|
2662
|
+
try {
|
|
2663
|
+
const raw = Buffer.concat(chunks).toString("utf-8").trim();
|
|
2664
|
+
if (!raw) {
|
|
2665
|
+
process.exit(0);
|
|
2666
|
+
}
|
|
2667
|
+
const input = JSON.parse(raw);
|
|
2668
|
+
const dir = input.workspace?.current_dir ?? input.cwd;
|
|
2669
|
+
if (!dir) {
|
|
2670
|
+
process.exit(0);
|
|
2671
|
+
}
|
|
2672
|
+
const gitRoot = findGitRoot(dir);
|
|
2673
|
+
const tasksFile = path10.join(gitRoot, ".keepgoing", "current-tasks.json");
|
|
2674
|
+
if (!fs7.existsSync(tasksFile)) {
|
|
2675
|
+
process.exit(0);
|
|
2676
|
+
}
|
|
2677
|
+
const data = JSON.parse(fs7.readFileSync(tasksFile, "utf-8"));
|
|
2678
|
+
const branch = getCurrentBranch(gitRoot) ?? "";
|
|
2679
|
+
const active = pruneStaleTasks(data.tasks ?? []).filter((t) => t.sessionActive && t.branch === branch);
|
|
2680
|
+
if (active.length === 0) {
|
|
2681
|
+
process.exit(0);
|
|
2682
|
+
}
|
|
2683
|
+
active.sort((a, b) => a.updatedAt.localeCompare(b.updatedAt));
|
|
2684
|
+
const task = active[active.length - 1];
|
|
2685
|
+
const summary = task.taskSummary;
|
|
2686
|
+
if (!summary) {
|
|
2687
|
+
process.exit(0);
|
|
2688
|
+
}
|
|
2689
|
+
if (branch) {
|
|
2690
|
+
process.stdout.write(`[KG] ${branch}: ${summary}
|
|
2691
|
+
`);
|
|
2692
|
+
} else {
|
|
2693
|
+
process.stdout.write(`[KG] ${summary}
|
|
2694
|
+
`);
|
|
2695
|
+
}
|
|
2696
|
+
} catch {
|
|
2697
|
+
}
|
|
2698
|
+
process.exit(0);
|
|
2699
|
+
});
|
|
2700
|
+
process.stdin.resume();
|
|
2701
|
+
}
|
|
2702
|
+
|
|
2566
2703
|
// src/index.ts
|
|
2567
2704
|
var CLI_HANDLERS = {
|
|
2568
2705
|
"--print-momentum": handlePrintMomentum,
|
|
2569
2706
|
"--save-checkpoint": handleSaveCheckpoint,
|
|
2570
2707
|
"--update-task": handleUpdateTask,
|
|
2571
2708
|
"--update-task-from-hook": handleUpdateTaskFromHook,
|
|
2572
|
-
"--print-current": handlePrintCurrent
|
|
2709
|
+
"--print-current": handlePrintCurrent,
|
|
2710
|
+
"--statusline": handleStatusline
|
|
2573
2711
|
};
|
|
2574
2712
|
var flag = process.argv.slice(2).find((a) => a in CLI_HANDLERS);
|
|
2575
2713
|
if (flag) {
|