@geometra/mcp 1.63.0 → 1.63.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/session-state.js +72 -9
- package/package.json +2 -2
package/dist/session-state.js
CHANGED
|
@@ -18,16 +18,59 @@ function resolveSessionStateFile() {
|
|
|
18
18
|
mkdirSync(dir, { recursive: true });
|
|
19
19
|
return path.join(dir, `parallel-mcp-${process.pid}-${threadId}.sqlite`);
|
|
20
20
|
}
|
|
21
|
-
|
|
22
|
-
const
|
|
21
|
+
function isSessionLifecycleDisabled() {
|
|
22
|
+
const raw = process.env.GEOMETRA_MCP_DISABLE_SESSION_LIFECYCLE?.trim().toLowerCase();
|
|
23
|
+
return raw === '1' || raw === 'true' || raw === 'yes' || raw === 'on';
|
|
24
|
+
}
|
|
25
|
+
function formatSessionLifecycleInitError(error) {
|
|
26
|
+
if (error instanceof Error) {
|
|
27
|
+
if (error.code === 'ERR_DLOPEN_FAILED' &&
|
|
28
|
+
error.message.includes('better_sqlite3.node')) {
|
|
29
|
+
return `${error.message}. Rebuild the native module with \`npm rebuild better-sqlite3\` in the MCP package directory, or reinstall dependencies for the current Node.js version.`;
|
|
30
|
+
}
|
|
31
|
+
return error.message;
|
|
32
|
+
}
|
|
33
|
+
return String(error);
|
|
34
|
+
}
|
|
35
|
+
function createSessionLifecycleRegistry() {
|
|
36
|
+
if (isSessionLifecycleDisabled()) {
|
|
37
|
+
process.stderr.write('[geometra-mcp] durable session lifecycle disabled via GEOMETRA_MCP_DISABLE_SESSION_LIFECYCLE\n');
|
|
38
|
+
return {
|
|
39
|
+
available: false,
|
|
40
|
+
orchestrator: null,
|
|
41
|
+
close: () => { },
|
|
42
|
+
};
|
|
43
|
+
}
|
|
23
44
|
try {
|
|
24
|
-
orchestrator
|
|
45
|
+
const orchestrator = new ParallelMcpOrchestrator(new SqliteParallelMcpStore({ filename: resolveSessionStateFile() }), { defaultLeaseMs: SESSION_LEASE_MS });
|
|
46
|
+
const leaseSweep = setInterval(() => {
|
|
47
|
+
try {
|
|
48
|
+
orchestrator.expireLeases();
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
/* ignore background lease sweep failures */
|
|
52
|
+
}
|
|
53
|
+
}, SESSION_SWEEP_MS);
|
|
54
|
+
leaseSweep.unref();
|
|
55
|
+
return {
|
|
56
|
+
available: true,
|
|
57
|
+
orchestrator,
|
|
58
|
+
close: () => {
|
|
59
|
+
clearInterval(leaseSweep);
|
|
60
|
+
orchestrator.close();
|
|
61
|
+
},
|
|
62
|
+
};
|
|
25
63
|
}
|
|
26
|
-
catch {
|
|
27
|
-
|
|
64
|
+
catch (error) {
|
|
65
|
+
process.stderr.write(`[geometra-mcp] durable session lifecycle disabled: ${formatSessionLifecycleInitError(error)}\n`);
|
|
66
|
+
return {
|
|
67
|
+
available: false,
|
|
68
|
+
orchestrator: null,
|
|
69
|
+
close: () => { },
|
|
70
|
+
};
|
|
28
71
|
}
|
|
29
|
-
}
|
|
30
|
-
|
|
72
|
+
}
|
|
73
|
+
const lifecycleRegistry = createSessionLifecycleRegistry();
|
|
31
74
|
function extractPageUrl(target) {
|
|
32
75
|
const cached = target.cachedA11y?.meta?.pageUrl;
|
|
33
76
|
if (typeof cached === 'string' && cached.length > 0)
|
|
@@ -86,6 +129,15 @@ function workerIdFor(sessionId) {
|
|
|
86
129
|
return `${SESSION_WORKER_PREFIX}:${sessionId}`;
|
|
87
130
|
}
|
|
88
131
|
export function initializeSessionLifecycle(target, options) {
|
|
132
|
+
if (!lifecycleRegistry.available || !lifecycleRegistry.orchestrator) {
|
|
133
|
+
target.lifecycleFinalized = true;
|
|
134
|
+
target.lifecycleTaskId = undefined;
|
|
135
|
+
target.lifecycleTaskKind = undefined;
|
|
136
|
+
target.lifecycleLeaseId = undefined;
|
|
137
|
+
target.lifecycleWorkerId = undefined;
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const orchestrator = lifecycleRegistry.orchestrator;
|
|
89
141
|
const sessionId = target.id;
|
|
90
142
|
const taskId = liveTaskIdFor(sessionId);
|
|
91
143
|
const taskKind = liveTaskKindFor(sessionId);
|
|
@@ -131,6 +183,9 @@ export function initializeSessionLifecycle(target, options) {
|
|
|
131
183
|
target.lifecycleFinalized = false;
|
|
132
184
|
}
|
|
133
185
|
export function heartbeatSessionLifecycle(target) {
|
|
186
|
+
if (!lifecycleRegistry.orchestrator)
|
|
187
|
+
return;
|
|
188
|
+
const orchestrator = lifecycleRegistry.orchestrator;
|
|
134
189
|
if (target.lifecycleFinalized || !target.lifecycleTaskId || !target.lifecycleLeaseId || !target.lifecycleWorkerId)
|
|
135
190
|
return;
|
|
136
191
|
orchestrator.heartbeatLease({
|
|
@@ -141,6 +196,9 @@ export function heartbeatSessionLifecycle(target) {
|
|
|
141
196
|
});
|
|
142
197
|
}
|
|
143
198
|
export function recordSessionSnapshot(target, label, extra) {
|
|
199
|
+
if (!lifecycleRegistry.orchestrator)
|
|
200
|
+
return;
|
|
201
|
+
const orchestrator = lifecycleRegistry.orchestrator;
|
|
144
202
|
if (!target.lifecycleTaskId)
|
|
145
203
|
return;
|
|
146
204
|
orchestrator.appendContextSnapshot({
|
|
@@ -152,6 +210,9 @@ export function recordSessionSnapshot(target, label, extra) {
|
|
|
152
210
|
});
|
|
153
211
|
}
|
|
154
212
|
export function completeSessionLifecycle(target, reason, extra) {
|
|
213
|
+
if (!lifecycleRegistry.orchestrator)
|
|
214
|
+
return;
|
|
215
|
+
const orchestrator = lifecycleRegistry.orchestrator;
|
|
155
216
|
if (target.lifecycleFinalized || !target.lifecycleTaskId || !target.lifecycleLeaseId || !target.lifecycleWorkerId)
|
|
156
217
|
return;
|
|
157
218
|
orchestrator.completeTask({
|
|
@@ -171,6 +232,9 @@ export function completeSessionLifecycle(target, reason, extra) {
|
|
|
171
232
|
target.lifecycleFinalized = true;
|
|
172
233
|
}
|
|
173
234
|
export function failSessionLifecycle(target, error, extra) {
|
|
235
|
+
if (!lifecycleRegistry.orchestrator)
|
|
236
|
+
return;
|
|
237
|
+
const orchestrator = lifecycleRegistry.orchestrator;
|
|
174
238
|
if (target.lifecycleFinalized || !target.lifecycleTaskId || !target.lifecycleLeaseId || !target.lifecycleWorkerId)
|
|
175
239
|
return;
|
|
176
240
|
recordSessionSnapshot(target, 'session.failed', {
|
|
@@ -187,6 +251,5 @@ export function failSessionLifecycle(target, error, extra) {
|
|
|
187
251
|
target.lifecycleFinalized = true;
|
|
188
252
|
}
|
|
189
253
|
export function shutdownSessionLifecycleRegistry() {
|
|
190
|
-
|
|
191
|
-
orchestrator.close();
|
|
254
|
+
lifecycleRegistry.close();
|
|
192
255
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geometra/mcp",
|
|
3
|
-
"version": "1.63.
|
|
3
|
+
"version": "1.63.2",
|
|
4
4
|
"description": "MCP server for Geometra — interact with running Geometra apps via the geometry protocol, no browser needed",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"ui-testing"
|
|
33
33
|
],
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@geometra/proxy": "^1.63.
|
|
35
|
+
"@geometra/proxy": "^1.63.2",
|
|
36
36
|
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
37
37
|
"@razroo/parallel-mcp": "^0.1.0",
|
|
38
38
|
"ws": "^8.18.0",
|