@hyperfixi/mcp-server 2.7.2 → 2.9.0
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/CHANGELOG.md +156 -0
- package/README.md +71 -16
- package/dist/{esm-YPGJSQ36.js → esm-7SV6EOOG.js} +312 -289
- package/dist/index.js +151 -18
- package/package.json +40 -39
package/dist/index.js
CHANGED
|
@@ -5,8 +5,109 @@ import {
|
|
|
5
5
|
} from "./chunk-P76KH42G.js";
|
|
6
6
|
|
|
7
7
|
// src/index.ts
|
|
8
|
+
import { createRequire as createRequire2 } from "module";
|
|
8
9
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
9
10
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
11
|
+
|
|
12
|
+
// src/freshness.ts
|
|
13
|
+
import { createRequire } from "module";
|
|
14
|
+
import { statSync, existsSync, readdirSync } from "fs";
|
|
15
|
+
import { dirname, join } from "path";
|
|
16
|
+
import { fileURLToPath } from "url";
|
|
17
|
+
var require_ = createRequire(import.meta.url);
|
|
18
|
+
var WORKSPACE_SCOPES = ["@lokascript/", "@hyperfixi/"];
|
|
19
|
+
var PROBE_TTL_MS = 1e3;
|
|
20
|
+
var watched = [];
|
|
21
|
+
var lastProbeAt = 0;
|
|
22
|
+
var lastResult = [];
|
|
23
|
+
function watchedPackages() {
|
|
24
|
+
const pkg = require_("../package.json");
|
|
25
|
+
const names = /* @__PURE__ */ new Set([
|
|
26
|
+
...Object.keys(pkg.dependencies ?? {}),
|
|
27
|
+
...Object.keys(pkg.peerDependencies ?? {})
|
|
28
|
+
]);
|
|
29
|
+
return [...names].filter((n) => WORKSPACE_SCOPES.some((s) => n.startsWith(s))).sort();
|
|
30
|
+
}
|
|
31
|
+
function resolveMarker(name) {
|
|
32
|
+
try {
|
|
33
|
+
const url = import.meta.resolve(name);
|
|
34
|
+
const path = fileURLToPath(url);
|
|
35
|
+
return existsSync(path) ? path : null;
|
|
36
|
+
} catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function captureFreshnessBaseline() {
|
|
41
|
+
watched = watchedPackages().flatMap((pkg) => {
|
|
42
|
+
const marker = resolveMarker(pkg);
|
|
43
|
+
if (!marker) return [];
|
|
44
|
+
return [{ pkg, marker, loadedMtimeMs: statSync(marker).mtimeMs }];
|
|
45
|
+
});
|
|
46
|
+
lastProbeAt = 0;
|
|
47
|
+
lastResult = [];
|
|
48
|
+
}
|
|
49
|
+
function staleSinceStartup(now = Date.now()) {
|
|
50
|
+
if (now - lastProbeAt < PROBE_TTL_MS) return lastResult;
|
|
51
|
+
lastProbeAt = now;
|
|
52
|
+
lastResult = watched.filter((w) => {
|
|
53
|
+
try {
|
|
54
|
+
return statSync(w.marker).mtimeMs !== w.loadedMtimeMs;
|
|
55
|
+
} catch {
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
}).map((w) => w.pkg);
|
|
59
|
+
return lastResult;
|
|
60
|
+
}
|
|
61
|
+
function hasNewerTs(dir, builtAt) {
|
|
62
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
63
|
+
const p = join(dir, entry.name);
|
|
64
|
+
if (entry.isDirectory()) {
|
|
65
|
+
if (hasNewerTs(p, builtAt)) return true;
|
|
66
|
+
} else if (entry.name.endsWith(".ts") && statSync(p).mtimeMs > builtAt) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
function staleAtStartup() {
|
|
73
|
+
return watched.filter((w) => {
|
|
74
|
+
const srcDir = join(dirname(dirname(w.marker)), "src");
|
|
75
|
+
if (!existsSync(srcDir)) return false;
|
|
76
|
+
try {
|
|
77
|
+
return hasNewerTs(srcDir, statSync(w.marker).mtimeMs);
|
|
78
|
+
} catch {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
}).map((w) => ({ pkg: w.pkg, dir: dirname(dirname(w.marker)) }));
|
|
82
|
+
}
|
|
83
|
+
function staleToolError(stale) {
|
|
84
|
+
return {
|
|
85
|
+
content: [
|
|
86
|
+
{
|
|
87
|
+
type: "text",
|
|
88
|
+
text: `\u2717 This MCP server is serving STALE code and refused the call.
|
|
89
|
+
|
|
90
|
+
Rebuilt since the server started: ${stale.join(", ")}
|
|
91
|
+
|
|
92
|
+
The server resolves these packages' dist/ at startup and Node caches the module
|
|
93
|
+
graph, so it cannot pick up a rebuild without restarting. Any answer it gave now
|
|
94
|
+
would reflect the code as it was BEFORE the rebuild \u2014 silently.
|
|
95
|
+
|
|
96
|
+
Fix: restart the MCP server (in Claude Code: /mcp, then reconnect "lokascript").
|
|
97
|
+
|
|
98
|
+
If you are mid-arc and only need to probe the parser, prefer a direct tsx probe
|
|
99
|
+
(which imports fresh each run) over this server \u2014 see the probe recipe in
|
|
100
|
+
docs-internal/HANDOFF_foreign-validity-burndown.md.`
|
|
101
|
+
}
|
|
102
|
+
],
|
|
103
|
+
isError: true
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function freshnessSummary() {
|
|
107
|
+
return `watching ${watched.length} workspace dist entries`;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// src/index.ts
|
|
10
111
|
import {
|
|
11
112
|
CallToolRequestSchema,
|
|
12
113
|
GetPromptRequestSchema,
|
|
@@ -5877,7 +5978,7 @@ async function handleBDDMultiStep(name, args) {
|
|
|
5877
5978
|
let rendered = null;
|
|
5878
5979
|
if (renderer) {
|
|
5879
5980
|
const renderedSteps = result.steps.map((step) => renderer(step, to));
|
|
5880
|
-
rendered = renderedSteps.join("\n");
|
|
5981
|
+
rendered = renderedSteps.every((step) => step != null) ? renderedSteps.join("\n") : null;
|
|
5881
5982
|
}
|
|
5882
5983
|
return jsonResponse({
|
|
5883
5984
|
input: { scenario, language: from },
|
|
@@ -5976,23 +6077,32 @@ async function handleBehaviorSpecMultiLine(name, args) {
|
|
|
5976
6077
|
if (!from || !to) return errorResponse("Missing required parameter: from, to");
|
|
5977
6078
|
const result = parseSpec(scenario, from);
|
|
5978
6079
|
const renderedTests = [];
|
|
6080
|
+
let complete = true;
|
|
6081
|
+
const renderLine = (node, indent) => {
|
|
6082
|
+
const line = render(node, to);
|
|
6083
|
+
if (line == null) {
|
|
6084
|
+
complete = false;
|
|
6085
|
+
return;
|
|
6086
|
+
}
|
|
6087
|
+
lines.push(`${indent}${line}`);
|
|
6088
|
+
};
|
|
6089
|
+
let lines = [];
|
|
5979
6090
|
for (const test of result.tests) {
|
|
5980
|
-
|
|
5981
|
-
lines.push(`test "${test.name}"`);
|
|
6091
|
+
lines = [`test "${test.name}"`];
|
|
5982
6092
|
for (const given of test.givens) {
|
|
5983
|
-
|
|
6093
|
+
renderLine(given, " ");
|
|
5984
6094
|
}
|
|
5985
6095
|
for (const interaction of test.interactions) {
|
|
5986
|
-
|
|
6096
|
+
renderLine(interaction.when, " ");
|
|
5987
6097
|
for (const exp of interaction.expectations) {
|
|
5988
|
-
|
|
6098
|
+
renderLine(exp.node, " ");
|
|
5989
6099
|
}
|
|
5990
6100
|
}
|
|
5991
6101
|
renderedTests.push(lines.join("\n"));
|
|
5992
6102
|
}
|
|
5993
6103
|
return jsonResponse({
|
|
5994
6104
|
input: { scenario, language: from },
|
|
5995
|
-
translated: renderedTests.join("\n\n"),
|
|
6105
|
+
translated: complete ? renderedTests.join("\n\n") : null,
|
|
5996
6106
|
playwright: compile(scenario, from),
|
|
5997
6107
|
errors: result.errors
|
|
5998
6108
|
});
|
|
@@ -7977,7 +8087,7 @@ function createInlineExtractor() {
|
|
|
7977
8087
|
const fs = await import("fs");
|
|
7978
8088
|
const path = await import("path");
|
|
7979
8089
|
const crypto = await import("crypto");
|
|
7980
|
-
const { glob } = await import("./esm-
|
|
8090
|
+
const { glob } = await import("./esm-7SV6EOOG.js");
|
|
7981
8091
|
const globs = [
|
|
7982
8092
|
"**/*.html",
|
|
7983
8093
|
"**/*.htm",
|
|
@@ -10134,6 +10244,7 @@ function getLSEProtocolSpec() {
|
|
|
10134
10244
|
| Disabled flag | \`~name\` | \`~nullable\` |
|
|
10135
10245
|
| String literal | \`"..."\` or \`'...'\` | \`patient:"hello world"\` |
|
|
10136
10246
|
| Selector | \`#id\` \`.class\` \`[attr]\` \`@aria\` \`*wild\` | \`destination:#button\` |
|
|
10247
|
+
| Selector literal | \`<...selector.../>\` | \`patient:<ul > li/>\`, \`patient:<.a, .b/>\` |
|
|
10137
10248
|
| Boolean | \`true\` / \`false\` | \`goal:true\` |
|
|
10138
10249
|
| Number | digits with optional decimal | \`quantity:5\` |
|
|
10139
10250
|
| Duration | number + suffix | \`delay:500ms\`, \`timeout:2s\` |
|
|
@@ -10141,15 +10252,22 @@ function getLSEProtocolSpec() {
|
|
|
10141
10252
|
| Nested body | bracket command in value | \`body:[toggle patient:.active]\` |
|
|
10142
10253
|
| Compound | chain operator between commands | \`[add ...] then [fetch ...]\` |
|
|
10143
10254
|
|
|
10255
|
+
A selector containing a space, a combinator (\`>\` \`+\` \`~\`), or a comma must use a
|
|
10256
|
+
selector literal \u2014 the tokenizer would otherwise split it. Inside a structural role
|
|
10257
|
+
(\`body\`, \`then\`, \`else\`, \`condition\`, \`loop-body\`, \`variable\`, \`catch\`, \`finally\`)
|
|
10258
|
+
a \`[...]\` value is always a nested command, so an attribute selector there must also
|
|
10259
|
+
use the literal form: \`condition:<[data-active]/>\`.
|
|
10260
|
+
|
|
10144
10261
|
## Value Classification Priority (first match wins)
|
|
10145
10262
|
|
|
10146
|
-
1. **Selector** \u2014 starts with
|
|
10147
|
-
2. **
|
|
10148
|
-
3. **
|
|
10149
|
-
4. **
|
|
10150
|
-
5. **
|
|
10151
|
-
6. **
|
|
10152
|
-
7. **
|
|
10263
|
+
1. **Selector literal** \u2014 starts with \`<\` and ends with \`/>\`; delimiters stripped
|
|
10264
|
+
2. **Selector** \u2014 starts with \`#\`, \`.\`, \`[\`, \`@\`, \`*\`
|
|
10265
|
+
3. **String** \u2014 starts with \`"\` or \`'\`
|
|
10266
|
+
4. **Boolean** \u2014 exact: \`true\` or \`false\`
|
|
10267
|
+
5. **Reference** \u2014 \`me\`, \`you\`, \`it\`, \`result\`, \`event\`, \`target\`, \`body\`
|
|
10268
|
+
6. **Duration** \u2014 number + \`ms\`/\`s\`/\`m\`/\`h\`
|
|
10269
|
+
7. **Number** \u2014 integer or decimal
|
|
10270
|
+
8. **Plain** \u2014 fallback (any non-whitespace)
|
|
10153
10271
|
|
|
10154
10272
|
## Node Kinds
|
|
10155
10273
|
|
|
@@ -10388,10 +10506,11 @@ function readResource(uri) {
|
|
|
10388
10506
|
|
|
10389
10507
|
// src/index.ts
|
|
10390
10508
|
var registry = createDomainRegistry();
|
|
10509
|
+
var { version: pkgVersion } = createRequire2(import.meta.url)("../package.json");
|
|
10391
10510
|
var server = new Server(
|
|
10392
10511
|
{
|
|
10393
10512
|
name: "@hyperfixi/mcp-server",
|
|
10394
|
-
version:
|
|
10513
|
+
version: pkgVersion
|
|
10395
10514
|
},
|
|
10396
10515
|
{
|
|
10397
10516
|
capabilities: {
|
|
@@ -10428,6 +10547,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
10428
10547
|
});
|
|
10429
10548
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
10430
10549
|
const { name, arguments: args } = request.params;
|
|
10550
|
+
const stale = staleSinceStartup();
|
|
10551
|
+
if (stale.length > 0) {
|
|
10552
|
+
return staleToolError(stale);
|
|
10553
|
+
}
|
|
10431
10554
|
if (name.startsWith("analyze_") || name === "explain_code" || name === "recognize_intent") {
|
|
10432
10555
|
return handleAnalysisTool(name, args);
|
|
10433
10556
|
}
|
|
@@ -10484,7 +10607,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
10484
10607
|
if (name === "lse_validate_and_feedback" || name === "lse_pattern_stats") {
|
|
10485
10608
|
return handleFeedbackTool(name, args);
|
|
10486
10609
|
}
|
|
10487
|
-
if (name === "lse_from_hyperscript" || name === "lse_to_hyperscript") {
|
|
10610
|
+
if (name === "lse_from_hyperscript" || name === "lse_to_hyperscript" || name === "execute_lse" || name === "validate_lse" || name === "translate_lse") {
|
|
10488
10611
|
return handleLsePipelineTool(name, args);
|
|
10489
10612
|
}
|
|
10490
10613
|
if (name.startsWith("grail_")) {
|
|
@@ -10529,9 +10652,19 @@ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
|
10529
10652
|
return readResource(uri);
|
|
10530
10653
|
});
|
|
10531
10654
|
async function main() {
|
|
10655
|
+
captureFreshnessBaseline();
|
|
10656
|
+
const bornStale = staleAtStartup();
|
|
10657
|
+
if (bornStale.length > 0) {
|
|
10658
|
+
console.error(
|
|
10659
|
+
`\u26A0 MCP server started against a STALE dist/ in: ${bornStale.map((s) => s.pkg).join(", ")} \u2014
|
|
10660
|
+
src/ is newer than the built output, so answers will reflect the last build, not the
|
|
10661
|
+
checkout. Rebuild, then restart this server:
|
|
10662
|
+
` + bornStale.map((s) => ` npm run build --prefix ${s.dir}`).join("\n")
|
|
10663
|
+
);
|
|
10664
|
+
}
|
|
10532
10665
|
const transport = new StdioServerTransport();
|
|
10533
10666
|
await server.connect(transport);
|
|
10534
|
-
console.error(
|
|
10667
|
+
console.error(`HyperFixi MCP server started (${freshnessSummary()})`);
|
|
10535
10668
|
}
|
|
10536
10669
|
main().catch((error) => {
|
|
10537
10670
|
console.error("Failed to start MCP server:", error);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperfixi/mcp-server",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.0",
|
|
4
4
|
"description": "Model Context Protocol server for HyperFixi hyperscript development",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -37,31 +37,31 @@
|
|
|
37
37
|
"author": "LokaScript Contributors",
|
|
38
38
|
"license": "MIT",
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@hyperfixi/patterns-reference": "^2.
|
|
41
|
-
"@lokascript/compilation-service": "^2.
|
|
42
|
-
"@lokascript/domain-config": "^2.
|
|
43
|
-
"@lokascript/framework": "^2.
|
|
44
|
-
"@lokascript/planner": "^2.
|
|
45
|
-
"@lokascript/semantic": "^2.
|
|
40
|
+
"@hyperfixi/patterns-reference": "^2.9.0",
|
|
41
|
+
"@lokascript/compilation-service": "^2.9.0",
|
|
42
|
+
"@lokascript/domain-config": "^2.9.0",
|
|
43
|
+
"@lokascript/framework": "^2.9.0",
|
|
44
|
+
"@lokascript/planner": "^2.9.0",
|
|
45
|
+
"@lokascript/semantic": "^2.9.0",
|
|
46
46
|
"@modelcontextprotocol/sdk": "^1.25.0",
|
|
47
47
|
"yaml": "^2.8.3"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@hyperfixi/core": "^2.
|
|
51
|
-
"@hyperfixi/patterns-reference": "^2.
|
|
52
|
-
"@hyperfixi/server-bridge": "^2.
|
|
53
|
-
"@lokascript/compilation-service": "^2.
|
|
54
|
-
"@lokascript/domain-bdd": "^2.
|
|
55
|
-
"@lokascript/domain-behaviorspec": "^2.
|
|
56
|
-
"@lokascript/domain-flow": "^2.
|
|
57
|
-
"@lokascript/domain-jsx": "^2.
|
|
58
|
-
"@lokascript/domain-learn": "^2.
|
|
59
|
-
"@lokascript/domain-llm": "^2.
|
|
60
|
-
"@lokascript/domain-sql": "^2.
|
|
61
|
-
"@lokascript/domain-todo": "^2.
|
|
62
|
-
"@lokascript/domain-voice": "^2.
|
|
63
|
-
"@lokascript/framework": "^2.
|
|
64
|
-
"@lokascript/semantic": "^2.
|
|
50
|
+
"@hyperfixi/core": "^2.9.0",
|
|
51
|
+
"@hyperfixi/patterns-reference": "^2.9.0",
|
|
52
|
+
"@hyperfixi/server-bridge": "^2.9.0",
|
|
53
|
+
"@lokascript/compilation-service": "^2.9.0",
|
|
54
|
+
"@lokascript/domain-bdd": "^2.9.0",
|
|
55
|
+
"@lokascript/domain-behaviorspec": "^2.9.0",
|
|
56
|
+
"@lokascript/domain-flow": "^2.9.0",
|
|
57
|
+
"@lokascript/domain-jsx": "^2.9.0",
|
|
58
|
+
"@lokascript/domain-learn": "^2.9.0",
|
|
59
|
+
"@lokascript/domain-llm": "^2.9.0",
|
|
60
|
+
"@lokascript/domain-sql": "^2.9.0",
|
|
61
|
+
"@lokascript/domain-todo": "^2.9.0",
|
|
62
|
+
"@lokascript/domain-voice": "^2.9.0",
|
|
63
|
+
"@lokascript/framework": "^2.9.0",
|
|
64
|
+
"@lokascript/semantic": "^2.9.0"
|
|
65
65
|
},
|
|
66
66
|
"peerDependenciesMeta": {
|
|
67
67
|
"@lokascript/compilation-service": {
|
|
@@ -111,29 +111,30 @@
|
|
|
111
111
|
}
|
|
112
112
|
},
|
|
113
113
|
"devDependencies": {
|
|
114
|
-
"@hyperfixi/core": "^2.
|
|
115
|
-
"@hyperfixi/patterns-reference": "^2.
|
|
116
|
-
"@hyperfixi/server-bridge": "^2.
|
|
117
|
-
"@lokascript/compilation-service": "^2.
|
|
118
|
-
"@lokascript/domain-bdd": "^2.
|
|
119
|
-
"@lokascript/domain-behaviorspec": "^2.
|
|
120
|
-
"@lokascript/domain-flow": "^2.
|
|
121
|
-
"@lokascript/domain-jsx": "^2.
|
|
122
|
-
"@lokascript/domain-learn": "^2.
|
|
123
|
-
"@lokascript/domain-llm": "^2.
|
|
124
|
-
"@lokascript/domain-sql": "^2.
|
|
125
|
-
"@lokascript/domain-todo": "^2.
|
|
126
|
-
"@lokascript/domain-voice": "^2.
|
|
127
|
-
"@lokascript/framework": "^2.
|
|
128
|
-
"@lokascript/semantic": "^2.
|
|
114
|
+
"@hyperfixi/core": "^2.9.0",
|
|
115
|
+
"@hyperfixi/patterns-reference": "^2.9.0",
|
|
116
|
+
"@hyperfixi/server-bridge": "^2.9.0",
|
|
117
|
+
"@lokascript/compilation-service": "^2.9.0",
|
|
118
|
+
"@lokascript/domain-bdd": "^2.9.0",
|
|
119
|
+
"@lokascript/domain-behaviorspec": "^2.9.0",
|
|
120
|
+
"@lokascript/domain-flow": "^2.9.0",
|
|
121
|
+
"@lokascript/domain-jsx": "^2.9.0",
|
|
122
|
+
"@lokascript/domain-learn": "^2.9.0",
|
|
123
|
+
"@lokascript/domain-llm": "^2.9.0",
|
|
124
|
+
"@lokascript/domain-sql": "^2.9.0",
|
|
125
|
+
"@lokascript/domain-todo": "^2.9.0",
|
|
126
|
+
"@lokascript/domain-voice": "^2.9.0",
|
|
127
|
+
"@lokascript/framework": "^2.9.0",
|
|
128
|
+
"@lokascript/semantic": "^2.9.0",
|
|
129
129
|
"@types/node": "^20.0.0",
|
|
130
130
|
"tsup": "^8.0.0",
|
|
131
|
-
"tsx": "^4.
|
|
131
|
+
"tsx": "^4.23.1",
|
|
132
132
|
"typescript": "^5.0.0",
|
|
133
133
|
"vitest": "^4.1.5"
|
|
134
134
|
},
|
|
135
135
|
"files": [
|
|
136
|
-
"dist"
|
|
136
|
+
"dist",
|
|
137
|
+
"CHANGELOG.md"
|
|
137
138
|
],
|
|
138
139
|
"publishConfig": {
|
|
139
140
|
"access": "public"
|