codeloop-mcp-server 0.1.39 → 0.1.41
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/auth/critical_floors.d.ts +45 -0
- package/dist/auth/critical_floors.d.ts.map +1 -0
- package/dist/auth/critical_floors.js +48 -0
- package/dist/auth/critical_floors.js.map +1 -0
- package/dist/auth/update_check.d.ts +65 -0
- package/dist/auth/update_check.d.ts.map +1 -0
- package/dist/auth/update_check.js +251 -0
- package/dist/auth/update_check.js.map +1 -0
- package/dist/auth/usage_tracker.d.ts +1 -1
- package/dist/auth/usage_tracker.d.ts.map +1 -1
- package/dist/auth/usage_tracker.js.map +1 -1
- package/dist/index.js +111 -26
- package/dist/index.js.map +1 -1
- package/dist/tools/apply_update.d.ts +72 -0
- package/dist/tools/apply_update.d.ts.map +1 -0
- package/dist/tools/apply_update.js +146 -0
- package/dist/tools/apply_update.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* codeloop_apply_update — let the agent apply an in-session CodeLoop
|
|
3
|
+
* update without the user having to manually restart their IDE.
|
|
4
|
+
*
|
|
5
|
+
* How it actually works
|
|
6
|
+
* ---------------------
|
|
7
|
+
* The MCP server is spawned by Cursor / Claude Code via the
|
|
8
|
+
* `npx -y codeloop-mcp-server@latest` line in `mcp.json`. That npx
|
|
9
|
+
* spec re-resolves the `@latest` dist-tag every time the server
|
|
10
|
+
* starts, so a fresh spawn always pulls the latest published version.
|
|
11
|
+
*
|
|
12
|
+
* If we cleanly `process.exit(0)` the running server, the IDE's MCP
|
|
13
|
+
* client treats it as a normal disconnect and respawns the server on
|
|
14
|
+
* the next tool call. That respawn fetches the new version from npm
|
|
15
|
+
* automatically. End result: the running chat picks up the new
|
|
16
|
+
* CodeLoop version on its next tool call — no IDE restart required.
|
|
17
|
+
*
|
|
18
|
+
* This tool packages that flow into one deterministic call:
|
|
19
|
+
* 1. Returns a short, agent-runnable list of terminal commands the
|
|
20
|
+
* agent should run in the user's terminal (so the user sees the
|
|
21
|
+
* version bump happen with full transparency, and so the npx
|
|
22
|
+
* tarball is warm for the next spawn).
|
|
23
|
+
* 2. Schedules a graceful `process.exit(0)` ~2 seconds after the
|
|
24
|
+
* response is flushed. The delay gives the JSON-RPC channel
|
|
25
|
+
* time to deliver the response cleanly before the disconnect.
|
|
26
|
+
* 3. Tells the agent exactly what to say to the user.
|
|
27
|
+
*
|
|
28
|
+
* Safety / fallbacks
|
|
29
|
+
* ------------------
|
|
30
|
+
* - `auto_respawn=false` (or `CODELOOP_DISABLE_AUTO_RESPAWN=1`)
|
|
31
|
+
* suppresses the self-exit. The tool still returns the command
|
|
32
|
+
* list and tells the agent to ask the user to restart manually.
|
|
33
|
+
* Useful for environments where the MCP client does NOT respawn
|
|
34
|
+
* exited servers (we have not seen this in the wild for Cursor /
|
|
35
|
+
* Claude Code, but we keep the escape hatch).
|
|
36
|
+
* - The actual `process.exit` call is injected so tests can spy on
|
|
37
|
+
* it without killing the test runner.
|
|
38
|
+
*/
|
|
39
|
+
import { z } from "zod";
|
|
40
|
+
import { getUpdateInfo, } from "../auth/update_check.js";
|
|
41
|
+
/** Injected so tests can stub it out instead of killing vitest. */
|
|
42
|
+
let exitFn = (code) => process.exit(code);
|
|
43
|
+
/** Test hook — production code does not call this. */
|
|
44
|
+
export function _setExitForTests(fn) {
|
|
45
|
+
exitFn = fn;
|
|
46
|
+
}
|
|
47
|
+
/** Test hook — restore the real `process.exit`. */
|
|
48
|
+
export function _resetExitForTests() {
|
|
49
|
+
exitFn = (code) => process.exit(code);
|
|
50
|
+
}
|
|
51
|
+
export const applyUpdateInputSchema = {
|
|
52
|
+
project_dir: z
|
|
53
|
+
.string()
|
|
54
|
+
.optional()
|
|
55
|
+
.describe("Workspace root. Optional; falls back to the MCP server's auto-discovered project root if omitted."),
|
|
56
|
+
workspace_root: z
|
|
57
|
+
.string()
|
|
58
|
+
.optional()
|
|
59
|
+
.describe("[Alias for project_dir] Same semantics; accepted because many agents reach for this conventional name."),
|
|
60
|
+
auto_respawn: z
|
|
61
|
+
.boolean()
|
|
62
|
+
.optional()
|
|
63
|
+
.default(true)
|
|
64
|
+
.describe("When true (default), schedules the MCP server to exit gracefully ~2s after returning so Cursor / Claude Code respawns it with the latest version. Set to false to ONLY return the commands without triggering a respawn — useful when you want the user to confirm before the update lands."),
|
|
65
|
+
};
|
|
66
|
+
function buildPreWarmCommands() {
|
|
67
|
+
return [
|
|
68
|
+
{
|
|
69
|
+
cmd: "npx -y codeloop-mcp-server@latest --version",
|
|
70
|
+
purpose: "Pre-fetch the latest MCP server tarball into the npx cache so the upcoming respawn is instant.",
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
cmd: "npx -y codeloop@latest --version",
|
|
74
|
+
purpose: "Pre-fetch the latest CLI tarball so the user's next `npx codeloop ...` command runs without a 'need to install' prompt.",
|
|
75
|
+
},
|
|
76
|
+
];
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Pure implementation. Exported for tests to call without going
|
|
80
|
+
* through MCP. Production registration in index.ts wires this up via
|
|
81
|
+
* server.tool().
|
|
82
|
+
*/
|
|
83
|
+
export function applyUpdate(params) {
|
|
84
|
+
const info = getUpdateInfo();
|
|
85
|
+
const wantsRespawn = params.auto_respawn !== false;
|
|
86
|
+
const respawnDisabledByEnv = process.env.CODELOOP_DISABLE_AUTO_RESPAWN === "1";
|
|
87
|
+
if (!info || !info.is_outdated) {
|
|
88
|
+
return {
|
|
89
|
+
status: "up_to_date",
|
|
90
|
+
current: info?.current ?? null,
|
|
91
|
+
latest: info?.latest ?? null,
|
|
92
|
+
is_critical: false,
|
|
93
|
+
critical_reasons: [],
|
|
94
|
+
commands_to_run: [],
|
|
95
|
+
auto_respawn_scheduled: false,
|
|
96
|
+
respawn_eta_ms: null,
|
|
97
|
+
instructions: [
|
|
98
|
+
"No action needed — CodeLoop is already running the latest published version.",
|
|
99
|
+
],
|
|
100
|
+
user_message: info && info.current
|
|
101
|
+
? `CodeLoop is already on the latest version (${info.current}). Nothing to update.`
|
|
102
|
+
: "CodeLoop appears to be up to date. (Background update check has not completed yet — try again in a few seconds if you expected an update.)",
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
const commands = buildPreWarmCommands();
|
|
106
|
+
let respawnScheduled = false;
|
|
107
|
+
if (wantsRespawn && !respawnDisabledByEnv) {
|
|
108
|
+
respawnScheduled = true;
|
|
109
|
+
// Delay the exit so the JSON-RPC response is flushed to the
|
|
110
|
+
// MCP client BEFORE the stdio channel drops. 2s is comfortable
|
|
111
|
+
// for slow disks / busy event loops. We unref so the timer
|
|
112
|
+
// doesn't itself keep the process alive past the exit.
|
|
113
|
+
const timer = setTimeout(() => {
|
|
114
|
+
// stderr is safe (MCP uses stdout for JSON-RPC).
|
|
115
|
+
console.error(`[CodeLoop] Exiting to allow IDE to respawn with codeloop-mcp-server@${info.latest} (was ${info.current}).`);
|
|
116
|
+
exitFn(0);
|
|
117
|
+
}, 2_000);
|
|
118
|
+
if (typeof timer.unref === "function")
|
|
119
|
+
timer.unref();
|
|
120
|
+
}
|
|
121
|
+
const instructions = [
|
|
122
|
+
"Run each entry in `commands_to_run` in the user's terminal — in order — so the user sees the version bump happen with full transparency. The agent's Shell tool is the correct channel for this.",
|
|
123
|
+
];
|
|
124
|
+
if (respawnScheduled) {
|
|
125
|
+
instructions.push("In ~2 seconds the MCP server will exit cleanly. Cursor / Claude Code will respawn it automatically on the next CodeLoop tool call, and the respawn pulls the latest version via `npx -y codeloop-mcp-server@latest`.", "The respawn is silent — you do NOT need to ask the user to restart Cursor / Claude Code. Just continue with the next CodeLoop tool call when ready; it will be served by the new version.", `Tell the user: "CodeLoop is updating in the background — your next CodeLoop call will run on v${info.latest}." Do not ask for permission to continue.`);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
instructions.push("Auto-respawn is disabled (either via the auto_respawn=false parameter or the CODELOOP_DISABLE_AUTO_RESPAWN=1 env var).", "After the commands finish, ask the user to restart Cursor / Claude Code to pick up the new MCP server version.");
|
|
129
|
+
}
|
|
130
|
+
const userMessageBody = info.is_critical
|
|
131
|
+
? `CodeLoop has a CRITICAL update available (current ${info.current} → latest ${info.latest}). Reasons: ${info.critical_reasons.join("; ")}.`
|
|
132
|
+
: `CodeLoop has an update available (current ${info.current} → latest ${info.latest}).`;
|
|
133
|
+
return {
|
|
134
|
+
status: respawnScheduled ? "update_applying" : "update_skipped",
|
|
135
|
+
current: info.current,
|
|
136
|
+
latest: info.latest,
|
|
137
|
+
is_critical: info.is_critical,
|
|
138
|
+
critical_reasons: info.critical_reasons,
|
|
139
|
+
commands_to_run: commands,
|
|
140
|
+
auto_respawn_scheduled: respawnScheduled,
|
|
141
|
+
respawn_eta_ms: respawnScheduled ? 2_000 : null,
|
|
142
|
+
instructions,
|
|
143
|
+
user_message: userMessageBody,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=apply_update.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apply_update.js","sourceRoot":"","sources":["../../src/tools/apply_update.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED