codeloop-mcp-server 0.1.41 → 0.1.43
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/cli_cache_warmer.d.ts.map +1 -1
- package/dist/auth/cli_cache_warmer.js +61 -11
- package/dist/auth/cli_cache_warmer.js.map +1 -1
- package/dist/auth/update_check.d.ts +7 -0
- package/dist/auth/update_check.d.ts.map +1 -1
- package/dist/auth/update_check.js +9 -0
- package/dist/auth/update_check.js.map +1 -1
- package/dist/evidence/interaction_coverage.d.ts.map +1 -1
- package/dist/evidence/interaction_coverage.js +34 -2
- package/dist/evidence/interaction_coverage.js.map +1 -1
- package/dist/evidence/screenshot_diff.d.ts +26 -0
- package/dist/evidence/screenshot_diff.d.ts.map +1 -1
- package/dist/evidence/screenshot_diff.js +64 -1
- package/dist/evidence/screenshot_diff.js.map +1 -1
- package/dist/index.js +132 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -20,7 +20,7 @@ import { loadConfig } from "./config.js";
|
|
|
20
20
|
import { validateApiKey, isActivationRequired } from "./auth/api_key.js";
|
|
21
21
|
import { identifyKeySource, buildRevokedKeyDiagnostic } from "./auth/key_source.js";
|
|
22
22
|
import { warmCliCache } from "./auth/cli_cache_warmer.js";
|
|
23
|
-
import { startUpdateCheck, getUpdateInfo, formatUpdateNotice, } from "./auth/update_check.js";
|
|
23
|
+
import { startUpdateCheck, getUpdateInfo, formatUpdateNotice, getRunningVersion, } from "./auth/update_check.js";
|
|
24
24
|
import { applyUpdate, applyUpdateInputSchema, } from "./tools/apply_update.js";
|
|
25
25
|
import { trackUsage } from "./auth/usage_tracker.js";
|
|
26
26
|
import { isLocalMode } from "./auth/local_mode.js";
|
|
@@ -264,18 +264,45 @@ function withUpdateNotice(content) {
|
|
|
264
264
|
...content,
|
|
265
265
|
];
|
|
266
266
|
}
|
|
267
|
+
/**
|
|
268
|
+
* Tiny footer appended to every tool response so the agent (and the
|
|
269
|
+
* user reading the chat) always know which MCP server version is
|
|
270
|
+
* actually serving the call. Without this, a stale long-lived child
|
|
271
|
+
* process from a pre-fix version can keep producing failing tool
|
|
272
|
+
* calls indefinitely with no visible signal of "you're running an
|
|
273
|
+
* old version". The startup banner only goes to stderr, which is
|
|
274
|
+
* hidden from the chat.
|
|
275
|
+
*
|
|
276
|
+
* Format is deliberately one short line so it doesn't drown the
|
|
277
|
+
* tool's actual JSON payload, and prefixed `[CodeLoop]` so an agent
|
|
278
|
+
* scanning the response can match on it without ambiguity.
|
|
279
|
+
*/
|
|
280
|
+
function buildVersionBanner() {
|
|
281
|
+
const v = getRunningVersion();
|
|
282
|
+
if (!v)
|
|
283
|
+
return null;
|
|
284
|
+
return {
|
|
285
|
+
type: "text",
|
|
286
|
+
text: `[CodeLoop server v${v}]`,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
267
289
|
function withInitHint(content, dir) {
|
|
268
|
-
// Order matters:
|
|
269
|
-
//
|
|
270
|
-
//
|
|
271
|
-
//
|
|
290
|
+
// Order matters:
|
|
291
|
+
// 1. Update notice (most actionable signal — CRITICAL stays at top).
|
|
292
|
+
// 2. Init hint (only when project is not initialized).
|
|
293
|
+
// 3. The original content.
|
|
294
|
+
// 4. Version banner footer (so the agent can always see what
|
|
295
|
+
// version it's talking to — survives across all responses).
|
|
296
|
+
const banner = buildVersionBanner();
|
|
272
297
|
const withUpdate = withUpdateNotice(content);
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
298
|
+
const head = [];
|
|
299
|
+
if (!isProjectInitialized(dir || projectDir)) {
|
|
300
|
+
head.push({ type: "text", text: INIT_HINT });
|
|
301
|
+
}
|
|
302
|
+
const result = [...head, ...withUpdate];
|
|
303
|
+
if (banner)
|
|
304
|
+
result.push(banner);
|
|
305
|
+
return result;
|
|
279
306
|
}
|
|
280
307
|
const TOOL_BOOTSTRAP = "[CodeLoop] You MUST call codeloop_verify after every code change. If .codeloop/config.json is missing, call codeloop_init_project FIRST.\n\n";
|
|
281
308
|
// ── Implemented Tools ────────────────────────────────────────────
|
|
@@ -1929,6 +1956,10 @@ Wait 1-2 seconds between interactions so video frames capture state changes.`, {
|
|
|
1929
1956
|
.describe("For win_ui_automate"),
|
|
1930
1957
|
app_name: z.string().optional().describe("App name to bring to front before interaction. Auto-detected from active recording if omitted. Also used for launch_app, win_ui_inspect, win_ui_automate."),
|
|
1931
1958
|
package_id: z.string().optional().describe("Package/bundle ID for mobile actions"),
|
|
1959
|
+
intent: z.string().optional().describe("Semantic label for what this interaction is doing — short verb-phrase like 'edit product row', 'confirm delete dialog', 'save form', 'create new range'. STRONGLY RECOMMENDED for desktop coordinate-based clicks (target_type='desktop' with only x/y) because the CRUD classifier in user_journey_evidence can't infer the meaning of a raw (x, y) pair the way it can from a Playwright selector or DOM aria_label. Without `intent`, a sequence of coordinate clicks that delete a record will score `delete_actions: 0` and fail the gate. The classifier reads `intent` (plus `description` / `purpose` / `step` as aliases) into the same target-text bucket as selectors and aria labels, so the SAME keywords that work for browsers (edit / delete / save / submit / create / new) also work here. Example: when clicking the 'Yes' button of a Windows MessageBox at (2640, 820), pass intent='confirm delete'."),
|
|
1960
|
+
description: z.string().optional().describe("[Alias for intent] Same semantics."),
|
|
1961
|
+
purpose: z.string().optional().describe("[Alias for intent] Same semantics."),
|
|
1962
|
+
step: z.string().optional().describe("Plan-step name when this interaction is driving a codeloop_plan_user_journey arc (e.g. 'edit', 'delete', 'create', 'save', 'verify'). Logged alongside `intent` and read by the CRUD classifier."),
|
|
1932
1963
|
project_dir: z.string().optional().describe("Absolute path to project root."),
|
|
1933
1964
|
workspace_root: z.string().optional().describe("[Alias for project_dir] Pass either; they're equivalent."),
|
|
1934
1965
|
}, async (params) => {
|
|
@@ -2537,6 +2568,24 @@ Wait 1-2 seconds between interactions so video frames capture state changes.`, {
|
|
|
2537
2568
|
inputArgs.automation_action = params.automation_action;
|
|
2538
2569
|
if (params.app_name)
|
|
2539
2570
|
inputArgs.app_name = params.app_name;
|
|
2571
|
+
// Semantic-intent fields. These are the ONLY hook coordinate-based
|
|
2572
|
+
// desktop clicks (target_type='desktop' with only x/y) have to
|
|
2573
|
+
// tell the CRUD classifier what they MEAN. Without one of these,
|
|
2574
|
+
// a sequence of (x, y) clicks that deletes a record scores
|
|
2575
|
+
// delete_actions: 0 because the classifier has nothing to match
|
|
2576
|
+
// DELETE_HINT against. Persisted under the same keys we accepted
|
|
2577
|
+
// them under (no normalisation) so users can grep the log for
|
|
2578
|
+
// their original tags. The classifier in interaction_coverage.ts
|
|
2579
|
+
// reads each of these fields into targetText() alongside
|
|
2580
|
+
// selector / aria_label / etc.
|
|
2581
|
+
if (params.intent)
|
|
2582
|
+
inputArgs.intent = params.intent;
|
|
2583
|
+
if (params.description)
|
|
2584
|
+
inputArgs.description = params.description;
|
|
2585
|
+
if (params.purpose)
|
|
2586
|
+
inputArgs.purpose = params.purpose;
|
|
2587
|
+
if (params.step)
|
|
2588
|
+
inputArgs.step = params.step;
|
|
2540
2589
|
// Post-action verification readback. Persisted alongside the
|
|
2541
2590
|
// interaction so a downstream consumer (depth gate, dev report,
|
|
2542
2591
|
// the agent on the next turn) can confirm the action actually
|
|
@@ -2660,6 +2709,78 @@ Returns: counts for attempted / succeeded / requeued events and the queue locati
|
|
|
2660
2709
|
]),
|
|
2661
2710
|
};
|
|
2662
2711
|
});
|
|
2712
|
+
server.tool("codeloop_version", `Return the running MCP server version, the latest published version, and whether an update is pending.
|
|
2713
|
+
|
|
2714
|
+
Use this tool when:
|
|
2715
|
+
- The agent or the user is unsure whether the CodeLoop MCP server has picked up a recent fix.
|
|
2716
|
+
- A previous CodeLoop tool call returned an error that looks like it should have been fixed (e.g., a Zod schema rejection that you know was made optional in a later release).
|
|
2717
|
+
- The user explicitly asks "what CodeLoop version am I running?".
|
|
2718
|
+
|
|
2719
|
+
Use this tool FIRST in any new chat session if you have reason to suspect the MCP child process is stale — Cursor / Claude Code keep one long-lived MCP server per workspace, so a session opened days ago may still be serving from an old version even though npm has shipped fixes since.
|
|
2720
|
+
|
|
2721
|
+
Returns:
|
|
2722
|
+
- \`running_version\`: the version of THIS process. This is the source of truth — the agent should compare its expectations against this value, not against the npm package metadata.
|
|
2723
|
+
- \`latest_published_version\`: from the background update poller (may be null if the poll has not completed yet).
|
|
2724
|
+
- \`is_outdated\`: whether running < latest.
|
|
2725
|
+
- \`is_critical\`: whether the running version falls below any entry in the critical-fix floor list.
|
|
2726
|
+
- \`recommended_action\`: a one-line instruction for what to do next (call codeloop_apply_update, restart IDE, or no action).
|
|
2727
|
+
- \`how_to_update\`: human-readable steps to get to the latest version, tailored to the situation.
|
|
2728
|
+
|
|
2729
|
+
No project_dir / workspace_root required — this tool is workspace-independent.`, {}, async () => {
|
|
2730
|
+
const running = getRunningVersion();
|
|
2731
|
+
const info = getUpdateInfo();
|
|
2732
|
+
const isOutdated = info?.is_outdated ?? false;
|
|
2733
|
+
const isCritical = info?.is_critical ?? false;
|
|
2734
|
+
let recommendedAction;
|
|
2735
|
+
let howToUpdate;
|
|
2736
|
+
if (!running) {
|
|
2737
|
+
recommendedAction = "diagnose_only";
|
|
2738
|
+
howToUpdate = [
|
|
2739
|
+
"Could not read the running MCP server's package.json — this is unusual. Check that the codeloop-mcp-server package files are intact.",
|
|
2740
|
+
];
|
|
2741
|
+
}
|
|
2742
|
+
else if (!info) {
|
|
2743
|
+
recommendedAction = "no_action";
|
|
2744
|
+
howToUpdate = [
|
|
2745
|
+
`Currently running v${running}.`,
|
|
2746
|
+
"The background update check has not completed yet (or has been disabled via CODELOOP_SKIP_UPDATE_CHECK=1). Try this tool again in a few seconds, or run `npm view codeloop-mcp-server version` in the user's terminal to compare manually.",
|
|
2747
|
+
];
|
|
2748
|
+
}
|
|
2749
|
+
else if (!isOutdated) {
|
|
2750
|
+
recommendedAction = "no_action";
|
|
2751
|
+
howToUpdate = [`Already on the latest version (v${running}). No action needed.`];
|
|
2752
|
+
}
|
|
2753
|
+
else if (isCritical) {
|
|
2754
|
+
recommendedAction = "call_codeloop_apply_update_now";
|
|
2755
|
+
howToUpdate = [
|
|
2756
|
+
`Running v${running} is below a critical-fix floor. Latest is v${info.latest}.`,
|
|
2757
|
+
`Reasons: ${info.critical_reasons.join("; ")}.`,
|
|
2758
|
+
"Call `codeloop_apply_update` NOW. It returns the terminal commands to pre-warm the npx cache, schedules the MCP server to exit gracefully, and the IDE respawns it with the latest version automatically. Your next CodeLoop tool call will be served by the new version — no IDE restart required.",
|
|
2759
|
+
];
|
|
2760
|
+
}
|
|
2761
|
+
else {
|
|
2762
|
+
recommendedAction = "call_codeloop_apply_update_when_convenient";
|
|
2763
|
+
howToUpdate = [
|
|
2764
|
+
`Running v${running}, latest is v${info.latest}.`,
|
|
2765
|
+
"Not critical, but recommended. Call `codeloop_apply_update` to pick up the new version in-session, OR let the next IDE restart pick it up via `npx -y codeloop-mcp-server@latest`.",
|
|
2766
|
+
];
|
|
2767
|
+
}
|
|
2768
|
+
const result = {
|
|
2769
|
+
running_version: running,
|
|
2770
|
+
latest_published_version: info?.latest ?? null,
|
|
2771
|
+
is_outdated: isOutdated,
|
|
2772
|
+
is_critical: isCritical,
|
|
2773
|
+
critical_reasons: info?.critical_reasons ?? [],
|
|
2774
|
+
last_checked_at: info?.checked_at ?? null,
|
|
2775
|
+
recommended_action: recommendedAction,
|
|
2776
|
+
how_to_update: howToUpdate,
|
|
2777
|
+
};
|
|
2778
|
+
return {
|
|
2779
|
+
content: withInitHint([
|
|
2780
|
+
{ type: "text", text: JSON.stringify(result, null, 2) },
|
|
2781
|
+
]),
|
|
2782
|
+
};
|
|
2783
|
+
});
|
|
2663
2784
|
server.tool("codeloop_apply_update", TOOL_BOOTSTRAP + `Apply a pending CodeLoop MCP server update to the current chat session — without asking the user to restart their IDE.
|
|
2664
2785
|
|
|
2665
2786
|
Use this tool when:
|