gdharness 1.1.43 → 1.1.45
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/build/cli.js
CHANGED
|
@@ -18407,7 +18407,7 @@ var init_tool_definitions = __esm(() => {
|
|
|
18407
18407
|
requires: [],
|
|
18408
18408
|
operations: {
|
|
18409
18409
|
click: {
|
|
18410
|
-
summary:
|
|
18410
|
+
summary: `press and release on a Control, a frame apart, and answer with what was under the pointer and what became of the control: in_tree, removed or freed. The control is named by nodePath, or by says with the words on it, found under nodePath when both are given, and the answer then says under found which match it was. Words that are part of a RichTextLabel are pressed where they are drawn rather than at the label's middle, so a link among them is the one pressed: found.pressedOn says "the words", or "the middle of the label" with a note saying why they could not be placed, and link_pressed names the meta the label reports clicked. A control out of sight inside a ScrollContainer is scrolled to first, each container out from it a frame after the one inside, and scrolled_into_view says whether a scroll value changed. A disabled button, and a control that does not process (the game paused, say), are refused: the pointer reaches them and the press does nothing. A 3D node is clicked where it is drawn, and landed then says the interface did not swallow the press: no control under the pointer stopped it, a control letting the pointer pass included, and every viewport on the way out from the room had the pointer over what shows the room`,
|
|
18411
18411
|
requires: []
|
|
18412
18412
|
},
|
|
18413
18413
|
choose: {
|
|
@@ -24160,6 +24160,9 @@ class Protocol {
|
|
|
24160
24160
|
this.setRequestHandler(GetTaskPayloadRequestSchema, async (request, extra) => {
|
|
24161
24161
|
const handleTaskResult = async () => {
|
|
24162
24162
|
const taskId = request.params.taskId;
|
|
24163
|
+
if (!await this._taskStore.getTask(taskId, extra.sessionId)) {
|
|
24164
|
+
throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
|
|
24165
|
+
}
|
|
24163
24166
|
if (this._taskMessageQueue) {
|
|
24164
24167
|
let queuedMessage;
|
|
24165
24168
|
while (queuedMessage = await this._taskMessageQueue.dequeue(taskId, extra.sessionId)) {
|
|
@@ -24190,12 +24193,12 @@ class Protocol {
|
|
|
24190
24193
|
throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
|
|
24191
24194
|
}
|
|
24192
24195
|
if (!isTerminal(task.status)) {
|
|
24193
|
-
await this._waitForTaskUpdate(taskId, extra.signal);
|
|
24196
|
+
await this._waitForTaskUpdate(taskId, extra.signal, extra.sessionId);
|
|
24194
24197
|
return await handleTaskResult();
|
|
24195
24198
|
}
|
|
24196
24199
|
if (isTerminal(task.status)) {
|
|
24197
24200
|
const result = await this._taskStore.getTaskResult(taskId, extra.sessionId);
|
|
24198
|
-
this._clearTaskQueue(taskId);
|
|
24201
|
+
this._clearTaskQueue(taskId, extra.sessionId);
|
|
24199
24202
|
return {
|
|
24200
24203
|
...result,
|
|
24201
24204
|
_meta: {
|
|
@@ -24232,7 +24235,7 @@ class Protocol {
|
|
|
24232
24235
|
throw new McpError(ErrorCode.InvalidParams, `Cannot cancel task in terminal status: ${task.status}`);
|
|
24233
24236
|
}
|
|
24234
24237
|
await this._taskStore.updateTaskStatus(request.params.taskId, "cancelled", "Client cancelled task execution.", extra.sessionId);
|
|
24235
|
-
this._clearTaskQueue(request.params.taskId);
|
|
24238
|
+
this._clearTaskQueue(request.params.taskId, extra.sessionId);
|
|
24236
24239
|
const cancelledTask = await this._taskStore.getTask(request.params.taskId, extra.sessionId);
|
|
24237
24240
|
if (!cancelledTask) {
|
|
24238
24241
|
throw new McpError(ErrorCode.InvalidParams, `Task not found after cancellation: ${request.params.taskId}`);
|
|
@@ -24355,6 +24358,19 @@ class Protocol {
|
|
|
24355
24358
|
const handler = this._requestHandlers.get(request.method) ?? this.fallbackRequestHandler;
|
|
24356
24359
|
const capturedTransport = this._transport;
|
|
24357
24360
|
const relatedTaskId = request.params?._meta?.[RELATED_TASK_META_KEY]?.taskId;
|
|
24361
|
+
const sessionId = capturedTransport?.sessionId;
|
|
24362
|
+
const store = this._taskStore;
|
|
24363
|
+
let relatedTaskFound = true;
|
|
24364
|
+
let relatedTaskLookup;
|
|
24365
|
+
if (relatedTaskId && store && this._taskMessageQueue && sessionId !== undefined) {
|
|
24366
|
+
relatedTaskFound = false;
|
|
24367
|
+
relatedTaskLookup = (async () => {
|
|
24368
|
+
if (!await store.getTask(relatedTaskId, sessionId)) {
|
|
24369
|
+
throw new McpError(ErrorCode.InvalidParams, `Task not found: ${relatedTaskId}`);
|
|
24370
|
+
}
|
|
24371
|
+
relatedTaskFound = true;
|
|
24372
|
+
})();
|
|
24373
|
+
}
|
|
24358
24374
|
if (handler === undefined) {
|
|
24359
24375
|
const errorResponse = {
|
|
24360
24376
|
jsonrpc: "2.0",
|
|
@@ -24364,7 +24380,10 @@ class Protocol {
|
|
|
24364
24380
|
message: "Method not found"
|
|
24365
24381
|
}
|
|
24366
24382
|
};
|
|
24367
|
-
if (relatedTaskId &&
|
|
24383
|
+
if (relatedTaskId && relatedTaskLookup) {
|
|
24384
|
+
const queuedError = { type: "error", message: errorResponse, timestamp: Date.now() };
|
|
24385
|
+
relatedTaskLookup.then(() => this._enqueueTaskMessage(relatedTaskId, queuedError, sessionId), () => capturedTransport?.send(errorResponse)).catch((error) => this._onerror(new Error(`Failed to send an error response: ${error}`)));
|
|
24386
|
+
} else if (relatedTaskId && this._taskMessageQueue) {
|
|
24368
24387
|
this._enqueueTaskMessage(relatedTaskId, {
|
|
24369
24388
|
type: "error",
|
|
24370
24389
|
message: errorResponse,
|
|
@@ -24415,7 +24434,10 @@ class Protocol {
|
|
|
24415
24434
|
closeSSEStream: extra?.closeSSEStream,
|
|
24416
24435
|
closeStandaloneSSEStream: extra?.closeStandaloneSSEStream
|
|
24417
24436
|
};
|
|
24418
|
-
Promise.resolve().then(() => {
|
|
24437
|
+
(relatedTaskLookup ?? Promise.resolve()).then(() => {
|
|
24438
|
+
if (relatedTaskLookup && abortController.signal.aborted) {
|
|
24439
|
+
throw new McpError(ErrorCode.ConnectionClosed, "Request was cancelled");
|
|
24440
|
+
}
|
|
24419
24441
|
if (taskCreationParams) {
|
|
24420
24442
|
this.assertTaskHandlerCapability(request.method);
|
|
24421
24443
|
}
|
|
@@ -24450,7 +24472,7 @@ class Protocol {
|
|
|
24450
24472
|
...error["data"] !== undefined && { data: error["data"] }
|
|
24451
24473
|
}
|
|
24452
24474
|
};
|
|
24453
|
-
if (relatedTaskId && this._taskMessageQueue) {
|
|
24475
|
+
if (relatedTaskId && this._taskMessageQueue && relatedTaskFound) {
|
|
24454
24476
|
await this._enqueueTaskMessage(relatedTaskId, {
|
|
24455
24477
|
type: "error",
|
|
24456
24478
|
message: errorResponse,
|
|
@@ -24838,7 +24860,7 @@ class Protocol {
|
|
|
24838
24860
|
throw new Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured");
|
|
24839
24861
|
}
|
|
24840
24862
|
const maxQueueSize = this._options?.maxTaskQueueSize;
|
|
24841
|
-
await this._taskMessageQueue.enqueue(taskId, message, sessionId, maxQueueSize);
|
|
24863
|
+
await this._taskMessageQueue.enqueue(taskId, message, sessionId ?? this._transport?.sessionId, maxQueueSize);
|
|
24842
24864
|
}
|
|
24843
24865
|
async _clearTaskQueue(taskId, sessionId) {
|
|
24844
24866
|
if (this._taskMessageQueue) {
|
|
@@ -24857,10 +24879,10 @@ class Protocol {
|
|
|
24857
24879
|
}
|
|
24858
24880
|
}
|
|
24859
24881
|
}
|
|
24860
|
-
async _waitForTaskUpdate(taskId, signal) {
|
|
24882
|
+
async _waitForTaskUpdate(taskId, signal, sessionId) {
|
|
24861
24883
|
let interval = this._options?.defaultTaskPollInterval ?? 1000;
|
|
24862
24884
|
try {
|
|
24863
|
-
const task = await this._taskStore?.getTask(taskId);
|
|
24885
|
+
const task = await this._taskStore?.getTask(taskId, sessionId);
|
|
24864
24886
|
if (task?.pollInterval) {
|
|
24865
24887
|
interval = task.pollInterval;
|
|
24866
24888
|
}
|
|
@@ -32444,6 +32466,43 @@ var init_zod = __esm(() => {
|
|
|
32444
32466
|
});
|
|
32445
32467
|
|
|
32446
32468
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js
|
|
32469
|
+
function toolInputElementCount(value, max) {
|
|
32470
|
+
let count = 0;
|
|
32471
|
+
const stack = [value];
|
|
32472
|
+
while (stack.length > 0) {
|
|
32473
|
+
const node = stack.pop();
|
|
32474
|
+
if (node === null || typeof node !== "object")
|
|
32475
|
+
continue;
|
|
32476
|
+
if (Array.isArray(node)) {
|
|
32477
|
+
for (const child of node) {
|
|
32478
|
+
if (++count > max)
|
|
32479
|
+
return count;
|
|
32480
|
+
if (child !== null && typeof child === "object")
|
|
32481
|
+
stack.push(child);
|
|
32482
|
+
}
|
|
32483
|
+
} else {
|
|
32484
|
+
for (const key in node) {
|
|
32485
|
+
if (!Object.prototype.hasOwnProperty.call(node, key))
|
|
32486
|
+
continue;
|
|
32487
|
+
if (++count > max)
|
|
32488
|
+
return count;
|
|
32489
|
+
const child = node[key];
|
|
32490
|
+
if (child !== null && typeof child === "object")
|
|
32491
|
+
stack.push(child);
|
|
32492
|
+
}
|
|
32493
|
+
}
|
|
32494
|
+
}
|
|
32495
|
+
return count;
|
|
32496
|
+
}
|
|
32497
|
+
function resolveMaxToolInputElements(value) {
|
|
32498
|
+
if (value === undefined || value === Infinity)
|
|
32499
|
+
return;
|
|
32500
|
+
if (typeof value !== "number" || Number.isNaN(value) || value < 1) {
|
|
32501
|
+
throw new RangeError(`maxToolInputElements must be a number of at least 1, or Infinity, got ${String(value)}`);
|
|
32502
|
+
}
|
|
32503
|
+
return value;
|
|
32504
|
+
}
|
|
32505
|
+
|
|
32447
32506
|
class McpServer {
|
|
32448
32507
|
constructor(serverInfo, options) {
|
|
32449
32508
|
this._registeredResources = {};
|
|
@@ -32455,6 +32514,7 @@ class McpServer {
|
|
|
32455
32514
|
this._resourceHandlersInitialized = false;
|
|
32456
32515
|
this._promptHandlersInitialized = false;
|
|
32457
32516
|
this.server = new Server(serverInfo, options);
|
|
32517
|
+
this._maxToolInputElements = resolveMaxToolInputElements(options?.maxToolInputElements);
|
|
32458
32518
|
}
|
|
32459
32519
|
get experimental() {
|
|
32460
32520
|
if (!this._experimental) {
|
|
@@ -32561,12 +32621,15 @@ class McpServer {
|
|
|
32561
32621
|
};
|
|
32562
32622
|
}
|
|
32563
32623
|
async validateToolInput(tool, args, toolName) {
|
|
32624
|
+
if (this._maxToolInputElements !== undefined && toolInputElementCount(args, this._maxToolInputElements) > this._maxToolInputElements) {
|
|
32625
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid arguments for tool ${toolName}: arguments contain more than the maximum of ${this._maxToolInputElements} elements`);
|
|
32626
|
+
}
|
|
32564
32627
|
if (!tool.inputSchema) {
|
|
32565
32628
|
return;
|
|
32566
32629
|
}
|
|
32567
32630
|
const inputObj = normalizeObjectSchema(tool.inputSchema);
|
|
32568
32631
|
const schemaToParse = inputObj ?? tool.inputSchema;
|
|
32569
|
-
const parseResult = await safeParseAsync3(schemaToParse, args);
|
|
32632
|
+
const parseResult = await safeParseAsync3(schemaToParse, args ?? {});
|
|
32570
32633
|
if (!parseResult.success) {
|
|
32571
32634
|
const error = "error" in parseResult ? parseResult.error : "Unknown error";
|
|
32572
32635
|
const errorMessage = getParseErrorMessage(error);
|
|
@@ -32791,7 +32854,7 @@ class McpServer {
|
|
|
32791
32854
|
}
|
|
32792
32855
|
if (prompt.argsSchema) {
|
|
32793
32856
|
const argsObj = normalizeObjectSchema(prompt.argsSchema);
|
|
32794
|
-
const parseResult = await safeParseAsync3(argsObj, request.params.arguments);
|
|
32857
|
+
const parseResult = await safeParseAsync3(argsObj, request.params.arguments ?? {});
|
|
32795
32858
|
if (!parseResult.success) {
|
|
32796
32859
|
const error = "error" in parseResult ? parseResult.error : "Unknown error";
|
|
32797
32860
|
const errorMessage = getParseErrorMessage(error);
|
|
@@ -36690,11 +36753,23 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
36690
36753
|
this._isServer = false;
|
|
36691
36754
|
this._redirects = 0;
|
|
36692
36755
|
if (protocols === undefined) {
|
|
36693
|
-
protocols
|
|
36756
|
+
if (!options || options.protocols === undefined) {
|
|
36757
|
+
protocols = [];
|
|
36758
|
+
} else if (Array.isArray(options.protocols)) {
|
|
36759
|
+
protocols = options.protocols;
|
|
36760
|
+
} else {
|
|
36761
|
+
protocols = [options.protocols];
|
|
36762
|
+
}
|
|
36694
36763
|
} else if (!Array.isArray(protocols)) {
|
|
36695
36764
|
if (typeof protocols === "object" && protocols !== null) {
|
|
36696
36765
|
options = protocols;
|
|
36697
|
-
protocols
|
|
36766
|
+
if (options.protocols === undefined) {
|
|
36767
|
+
protocols = [];
|
|
36768
|
+
} else if (Array.isArray(options.protocols)) {
|
|
36769
|
+
protocols = options.protocols;
|
|
36770
|
+
} else {
|
|
36771
|
+
protocols = [options.protocols];
|
|
36772
|
+
}
|
|
36698
36773
|
} else {
|
|
36699
36774
|
protocols = [protocols];
|
|
36700
36775
|
}
|
|
@@ -36813,7 +36888,6 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
36813
36888
|
}
|
|
36814
36889
|
return;
|
|
36815
36890
|
}
|
|
36816
|
-
this._readyState = WebSocket.CLOSING;
|
|
36817
36891
|
this._sender.close(code, data, !this._isServer, (err) => {
|
|
36818
36892
|
if (err)
|
|
36819
36893
|
return;
|
|
@@ -36822,6 +36896,7 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
36822
36896
|
this._socket.end();
|
|
36823
36897
|
}
|
|
36824
36898
|
});
|
|
36899
|
+
this._readyState = WebSocket.CLOSING;
|
|
36825
36900
|
setCloseTimer(this);
|
|
36826
36901
|
}
|
|
36827
36902
|
pause() {
|
|
@@ -37009,6 +37084,7 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
37009
37084
|
socketPath: undefined,
|
|
37010
37085
|
hostname: undefined,
|
|
37011
37086
|
protocol: undefined,
|
|
37087
|
+
protocols: undefined,
|
|
37012
37088
|
timeout: undefined,
|
|
37013
37089
|
method: "GET",
|
|
37014
37090
|
host: undefined,
|
|
@@ -408,9 +408,27 @@ func click(params: Dictionary) -> Dictionary:
|
|
|
408
408
|
if not unmoved.is_empty():
|
|
409
409
|
return {"type": "error", "message": unmoved}
|
|
410
410
|
|
|
411
|
+
# Words that are part of a rich label are pressed where they are drawn, since its middle can be on
|
|
412
|
+
# other words, a link among them. Said either way, so a press on the middle is never read as one
|
|
413
|
+
# on the words.
|
|
414
|
+
var aim: Vector2 = control.size * 0.5
|
|
415
|
+
var rich: RichTextLabel = control as RichTextLabel
|
|
416
|
+
if found != null and rich != null:
|
|
417
|
+
var placed: Dictionary = Targets.point_on_words(rich, wanted)
|
|
418
|
+
var found_here: Dictionary = found
|
|
419
|
+
if placed.has("point"):
|
|
420
|
+
aim = placed["point"]
|
|
421
|
+
found_here["pressedOn"] = "the words"
|
|
422
|
+
elif placed.has("unplaced"):
|
|
423
|
+
found_here["pressedOn"] = "the middle of the label"
|
|
424
|
+
found_here["note"] = (
|
|
425
|
+
"the words are part of a longer label and %s, so the press went to its middle"
|
|
426
|
+
% placed["unplaced"]
|
|
427
|
+
)
|
|
428
|
+
|
|
411
429
|
# In the control's own viewport first, which is the space its scrolling happens in.
|
|
412
430
|
var own: Viewport = control.get_viewport()
|
|
413
|
-
var local: Vector2 = control.get_global_transform_with_canvas() *
|
|
431
|
+
var local: Vector2 = control.get_global_transform_with_canvas() * aim
|
|
414
432
|
|
|
415
433
|
# A control out of sight inside a ScrollContainer is not out of reach, it is one scroll away,
|
|
416
434
|
# which is what a person does without thinking about it before they click. Refusing it
|
|
@@ -434,7 +452,7 @@ func click(params: Dictionary) -> Dictionary:
|
|
|
434
452
|
% [node_path, "freed" if left == "freed" else "taken out of the tree"]
|
|
435
453
|
)
|
|
436
454
|
}
|
|
437
|
-
local = control.get_global_transform_with_canvas() *
|
|
455
|
+
local = control.get_global_transform_with_canvas() * aim
|
|
438
456
|
|
|
439
457
|
var reached: Dictionary = Screen.reach(own, local)
|
|
440
458
|
var viewport: Viewport = reached["viewport"]
|
|
@@ -472,12 +490,19 @@ func click(params: Dictionary) -> Dictionary:
|
|
|
472
490
|
hovered_path = str(hovered.get_path())
|
|
473
491
|
var landed: bool = hovered == control or (hovered != null and control.is_ancestor_of(hovered))
|
|
474
492
|
|
|
493
|
+
# The link a rich label says was pressed, which is its own word for what the press reached.
|
|
494
|
+
var links: Array[String] = []
|
|
495
|
+
var heard: Callable = func(meta: Variant) -> void: links.append(str(meta))
|
|
496
|
+
if rich != null:
|
|
497
|
+
var _listening: int = rich.meta_clicked.connect(heard)
|
|
475
498
|
_press_button(viewport, _button(position, button, true, double))
|
|
476
499
|
await _host.get_tree().process_frame
|
|
477
500
|
_press_button(viewport, _button(position, button, false, false))
|
|
478
501
|
# The release is what a button acts on, and a queue_free it causes lands at the end of
|
|
479
502
|
# this frame; the frame passes so the answer describes the control as the click left it.
|
|
480
503
|
await _host.get_tree().process_frame
|
|
504
|
+
if rich != null and is_instance_valid(rich) and rich.meta_clicked.is_connected(heard):
|
|
505
|
+
rich.meta_clicked.disconnect(heard)
|
|
481
506
|
|
|
482
507
|
# What became of the control: still in the tree, taken out of it, or freed. A button that
|
|
483
508
|
# opened another screen is the second or the third, and the caller wants to hear that
|
|
@@ -497,6 +522,8 @@ func click(params: Dictionary) -> Dictionary:
|
|
|
497
522
|
}
|
|
498
523
|
if found != null:
|
|
499
524
|
answer["found"] = found
|
|
525
|
+
if not links.is_empty():
|
|
526
|
+
answer["link_pressed"] = links.back()
|
|
500
527
|
return _pointer_noted(answer)
|
|
501
528
|
|
|
502
529
|
|
|
@@ -450,6 +450,60 @@ static func _clipped_away(
|
|
|
450
450
|
return false
|
|
451
451
|
|
|
452
452
|
|
|
453
|
+
## Where [param label] draws the words [param wanted] matched in it, in the label's own space, when
|
|
454
|
+
## they are part of its text: {"point"} on their middle, {"unplaced"} saying why there is none, or
|
|
455
|
+
## {} when the words are the whole text, whose middle is the label's.
|
|
456
|
+
##
|
|
457
|
+
## A line of a dispatch names two people, each a link to their page, and a press on the label's
|
|
458
|
+
## middle landed on the second name when the first was asked for, so the game opened the wrong page.
|
|
459
|
+
## Godot answers which line a character is on, where that line is and how wide it is drawn, and
|
|
460
|
+
## nothing narrower, so the place along the line is the font's measure of the text before the
|
|
461
|
+
## words. A line in another font or holding an image measures off from what is drawn, which a wide
|
|
462
|
+
## line with nothing between the words and its start hardly does.
|
|
463
|
+
static func point_on_words(label: RichTextLabel, wanted: String) -> Dictionary:
|
|
464
|
+
var text: String = Words.said_by(label)
|
|
465
|
+
var start: int = -1
|
|
466
|
+
var length: int = 0
|
|
467
|
+
for words: String in Says.alternatives(wanted):
|
|
468
|
+
if not Says.is_plain(words):
|
|
469
|
+
continue
|
|
470
|
+
var at: int = text.findn(words)
|
|
471
|
+
if at >= 0 and (start < 0 or at < start):
|
|
472
|
+
start = at
|
|
473
|
+
length = words.length()
|
|
474
|
+
if start < 0:
|
|
475
|
+
return {"unplaced": "the words were matched as a pattern, which names no one place in the text"}
|
|
476
|
+
if text.strip_edges().length() == length:
|
|
477
|
+
return {}
|
|
478
|
+
var line: int = label.get_character_line(start)
|
|
479
|
+
var shown: Vector2i = label.get_line_range(line)
|
|
480
|
+
if line < 0 or shown.x > start:
|
|
481
|
+
return {"unplaced": "the label could not say which line the words are on"}
|
|
482
|
+
var on_line: int = mini(length, shown.y - start) if shown.y > start else length
|
|
483
|
+
var font: Font = label.get_theme_font("normal_font")
|
|
484
|
+
var font_size: int = label.get_theme_font_size("normal_font_size")
|
|
485
|
+
var before: float = _width(font, font_size, text.substr(shown.x, start - shown.x))
|
|
486
|
+
var across: float = _width(font, font_size, text.substr(start, on_line))
|
|
487
|
+
var frame: StyleBox = label.get_theme_stylebox("normal")
|
|
488
|
+
var left: float = frame.get_margin(SIDE_LEFT)
|
|
489
|
+
var room: float = label.size.x - left - frame.get_margin(SIDE_RIGHT)
|
|
490
|
+
var spare: float = maxf(room - label.get_line_width(line), 0.0)
|
|
491
|
+
var aligned: float = 0.0
|
|
492
|
+
if label.horizontal_alignment == HORIZONTAL_ALIGNMENT_CENTER:
|
|
493
|
+
aligned = spare * 0.5
|
|
494
|
+
elif label.horizontal_alignment == HORIZONTAL_ALIGNMENT_RIGHT:
|
|
495
|
+
aligned = spare
|
|
496
|
+
var scrolled: float = label.get_v_scroll_bar().value if label.scroll_active else 0.0
|
|
497
|
+
var x: float = clampf(left + aligned + before + across * 0.5, left, left + room)
|
|
498
|
+
var top: float = frame.get_margin(SIDE_TOP) + label.get_line_offset(line) - scrolled
|
|
499
|
+
return {"point": Vector2(x, top + label.get_line_height(line) * 0.5)}
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
## How wide [param font] at [param font_size] draws [param words] on one line.
|
|
503
|
+
static func _width(font: Font, font_size: int, words: String) -> float:
|
|
504
|
+
return font.get_string_size(words, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x
|
|
505
|
+
|
|
506
|
+
|
|
453
507
|
## The canvas layer [param control] is drawn on, 0 for the viewport's own canvas.
|
|
454
508
|
static func _layer_of(control: Control) -> int:
|
|
455
509
|
var layer: CanvasLayer = control.get_canvas_layer_node()
|
package/build/index.js
CHANGED
|
@@ -8629,11 +8629,23 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
8629
8629
|
this._isServer = false;
|
|
8630
8630
|
this._redirects = 0;
|
|
8631
8631
|
if (protocols === undefined) {
|
|
8632
|
-
protocols
|
|
8632
|
+
if (!options || options.protocols === undefined) {
|
|
8633
|
+
protocols = [];
|
|
8634
|
+
} else if (Array.isArray(options.protocols)) {
|
|
8635
|
+
protocols = options.protocols;
|
|
8636
|
+
} else {
|
|
8637
|
+
protocols = [options.protocols];
|
|
8638
|
+
}
|
|
8633
8639
|
} else if (!Array.isArray(protocols)) {
|
|
8634
8640
|
if (typeof protocols === "object" && protocols !== null) {
|
|
8635
8641
|
options = protocols;
|
|
8636
|
-
protocols
|
|
8642
|
+
if (options.protocols === undefined) {
|
|
8643
|
+
protocols = [];
|
|
8644
|
+
} else if (Array.isArray(options.protocols)) {
|
|
8645
|
+
protocols = options.protocols;
|
|
8646
|
+
} else {
|
|
8647
|
+
protocols = [options.protocols];
|
|
8648
|
+
}
|
|
8637
8649
|
} else {
|
|
8638
8650
|
protocols = [protocols];
|
|
8639
8651
|
}
|
|
@@ -8752,7 +8764,6 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
8752
8764
|
}
|
|
8753
8765
|
return;
|
|
8754
8766
|
}
|
|
8755
|
-
this._readyState = WebSocket.CLOSING;
|
|
8756
8767
|
this._sender.close(code, data, !this._isServer, (err) => {
|
|
8757
8768
|
if (err)
|
|
8758
8769
|
return;
|
|
@@ -8761,6 +8772,7 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
8761
8772
|
this._socket.end();
|
|
8762
8773
|
}
|
|
8763
8774
|
});
|
|
8775
|
+
this._readyState = WebSocket.CLOSING;
|
|
8764
8776
|
setCloseTimer(this);
|
|
8765
8777
|
}
|
|
8766
8778
|
pause() {
|
|
@@ -8948,6 +8960,7 @@ var require_websocket = __commonJS(function(exports, module) {
|
|
|
8948
8960
|
socketPath: undefined,
|
|
8949
8961
|
hostname: undefined,
|
|
8950
8962
|
protocol: undefined,
|
|
8963
|
+
protocols: undefined,
|
|
8951
8964
|
timeout: undefined,
|
|
8952
8965
|
method: "GET",
|
|
8953
8966
|
host: undefined,
|
|
@@ -22615,6 +22628,9 @@ class Protocol {
|
|
|
22615
22628
|
this.setRequestHandler(GetTaskPayloadRequestSchema, async (request, extra) => {
|
|
22616
22629
|
const handleTaskResult = async () => {
|
|
22617
22630
|
const taskId = request.params.taskId;
|
|
22631
|
+
if (!await this._taskStore.getTask(taskId, extra.sessionId)) {
|
|
22632
|
+
throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
|
|
22633
|
+
}
|
|
22618
22634
|
if (this._taskMessageQueue) {
|
|
22619
22635
|
let queuedMessage;
|
|
22620
22636
|
while (queuedMessage = await this._taskMessageQueue.dequeue(taskId, extra.sessionId)) {
|
|
@@ -22645,12 +22661,12 @@ class Protocol {
|
|
|
22645
22661
|
throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
|
|
22646
22662
|
}
|
|
22647
22663
|
if (!isTerminal(task.status)) {
|
|
22648
|
-
await this._waitForTaskUpdate(taskId, extra.signal);
|
|
22664
|
+
await this._waitForTaskUpdate(taskId, extra.signal, extra.sessionId);
|
|
22649
22665
|
return await handleTaskResult();
|
|
22650
22666
|
}
|
|
22651
22667
|
if (isTerminal(task.status)) {
|
|
22652
22668
|
const result = await this._taskStore.getTaskResult(taskId, extra.sessionId);
|
|
22653
|
-
this._clearTaskQueue(taskId);
|
|
22669
|
+
this._clearTaskQueue(taskId, extra.sessionId);
|
|
22654
22670
|
return {
|
|
22655
22671
|
...result,
|
|
22656
22672
|
_meta: {
|
|
@@ -22687,7 +22703,7 @@ class Protocol {
|
|
|
22687
22703
|
throw new McpError(ErrorCode.InvalidParams, `Cannot cancel task in terminal status: ${task.status}`);
|
|
22688
22704
|
}
|
|
22689
22705
|
await this._taskStore.updateTaskStatus(request.params.taskId, "cancelled", "Client cancelled task execution.", extra.sessionId);
|
|
22690
|
-
this._clearTaskQueue(request.params.taskId);
|
|
22706
|
+
this._clearTaskQueue(request.params.taskId, extra.sessionId);
|
|
22691
22707
|
const cancelledTask = await this._taskStore.getTask(request.params.taskId, extra.sessionId);
|
|
22692
22708
|
if (!cancelledTask) {
|
|
22693
22709
|
throw new McpError(ErrorCode.InvalidParams, `Task not found after cancellation: ${request.params.taskId}`);
|
|
@@ -22810,6 +22826,19 @@ class Protocol {
|
|
|
22810
22826
|
const handler = this._requestHandlers.get(request.method) ?? this.fallbackRequestHandler;
|
|
22811
22827
|
const capturedTransport = this._transport;
|
|
22812
22828
|
const relatedTaskId = request.params?._meta?.[RELATED_TASK_META_KEY]?.taskId;
|
|
22829
|
+
const sessionId = capturedTransport?.sessionId;
|
|
22830
|
+
const store = this._taskStore;
|
|
22831
|
+
let relatedTaskFound = true;
|
|
22832
|
+
let relatedTaskLookup;
|
|
22833
|
+
if (relatedTaskId && store && this._taskMessageQueue && sessionId !== undefined) {
|
|
22834
|
+
relatedTaskFound = false;
|
|
22835
|
+
relatedTaskLookup = (async () => {
|
|
22836
|
+
if (!await store.getTask(relatedTaskId, sessionId)) {
|
|
22837
|
+
throw new McpError(ErrorCode.InvalidParams, `Task not found: ${relatedTaskId}`);
|
|
22838
|
+
}
|
|
22839
|
+
relatedTaskFound = true;
|
|
22840
|
+
})();
|
|
22841
|
+
}
|
|
22813
22842
|
if (handler === undefined) {
|
|
22814
22843
|
const errorResponse = {
|
|
22815
22844
|
jsonrpc: "2.0",
|
|
@@ -22819,7 +22848,10 @@ class Protocol {
|
|
|
22819
22848
|
message: "Method not found"
|
|
22820
22849
|
}
|
|
22821
22850
|
};
|
|
22822
|
-
if (relatedTaskId &&
|
|
22851
|
+
if (relatedTaskId && relatedTaskLookup) {
|
|
22852
|
+
const queuedError = { type: "error", message: errorResponse, timestamp: Date.now() };
|
|
22853
|
+
relatedTaskLookup.then(() => this._enqueueTaskMessage(relatedTaskId, queuedError, sessionId), () => capturedTransport?.send(errorResponse)).catch((error) => this._onerror(new Error(`Failed to send an error response: ${error}`)));
|
|
22854
|
+
} else if (relatedTaskId && this._taskMessageQueue) {
|
|
22823
22855
|
this._enqueueTaskMessage(relatedTaskId, {
|
|
22824
22856
|
type: "error",
|
|
22825
22857
|
message: errorResponse,
|
|
@@ -22870,7 +22902,10 @@ class Protocol {
|
|
|
22870
22902
|
closeSSEStream: extra?.closeSSEStream,
|
|
22871
22903
|
closeStandaloneSSEStream: extra?.closeStandaloneSSEStream
|
|
22872
22904
|
};
|
|
22873
|
-
Promise.resolve().then(() => {
|
|
22905
|
+
(relatedTaskLookup ?? Promise.resolve()).then(() => {
|
|
22906
|
+
if (relatedTaskLookup && abortController.signal.aborted) {
|
|
22907
|
+
throw new McpError(ErrorCode.ConnectionClosed, "Request was cancelled");
|
|
22908
|
+
}
|
|
22874
22909
|
if (taskCreationParams) {
|
|
22875
22910
|
this.assertTaskHandlerCapability(request.method);
|
|
22876
22911
|
}
|
|
@@ -22905,7 +22940,7 @@ class Protocol {
|
|
|
22905
22940
|
...error["data"] !== undefined && { data: error["data"] }
|
|
22906
22941
|
}
|
|
22907
22942
|
};
|
|
22908
|
-
if (relatedTaskId && this._taskMessageQueue) {
|
|
22943
|
+
if (relatedTaskId && this._taskMessageQueue && relatedTaskFound) {
|
|
22909
22944
|
await this._enqueueTaskMessage(relatedTaskId, {
|
|
22910
22945
|
type: "error",
|
|
22911
22946
|
message: errorResponse,
|
|
@@ -23293,7 +23328,7 @@ class Protocol {
|
|
|
23293
23328
|
throw new Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured");
|
|
23294
23329
|
}
|
|
23295
23330
|
const maxQueueSize = this._options?.maxTaskQueueSize;
|
|
23296
|
-
await this._taskMessageQueue.enqueue(taskId, message, sessionId, maxQueueSize);
|
|
23331
|
+
await this._taskMessageQueue.enqueue(taskId, message, sessionId ?? this._transport?.sessionId, maxQueueSize);
|
|
23297
23332
|
}
|
|
23298
23333
|
async _clearTaskQueue(taskId, sessionId) {
|
|
23299
23334
|
if (this._taskMessageQueue) {
|
|
@@ -23312,10 +23347,10 @@ class Protocol {
|
|
|
23312
23347
|
}
|
|
23313
23348
|
}
|
|
23314
23349
|
}
|
|
23315
|
-
async _waitForTaskUpdate(taskId, signal) {
|
|
23350
|
+
async _waitForTaskUpdate(taskId, signal, sessionId) {
|
|
23316
23351
|
let interval = this._options?.defaultTaskPollInterval ?? 1000;
|
|
23317
23352
|
try {
|
|
23318
|
-
const task = await this._taskStore?.getTask(taskId);
|
|
23353
|
+
const task = await this._taskStore?.getTask(taskId, sessionId);
|
|
23319
23354
|
if (task?.pollInterval) {
|
|
23320
23355
|
interval = task.pollInterval;
|
|
23321
23356
|
}
|
|
@@ -23983,6 +24018,43 @@ class ExperimentalMcpServerTasks {
|
|
|
23983
24018
|
}
|
|
23984
24019
|
|
|
23985
24020
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js
|
|
24021
|
+
function toolInputElementCount(value, max) {
|
|
24022
|
+
let count = 0;
|
|
24023
|
+
const stack = [value];
|
|
24024
|
+
while (stack.length > 0) {
|
|
24025
|
+
const node = stack.pop();
|
|
24026
|
+
if (node === null || typeof node !== "object")
|
|
24027
|
+
continue;
|
|
24028
|
+
if (Array.isArray(node)) {
|
|
24029
|
+
for (const child of node) {
|
|
24030
|
+
if (++count > max)
|
|
24031
|
+
return count;
|
|
24032
|
+
if (child !== null && typeof child === "object")
|
|
24033
|
+
stack.push(child);
|
|
24034
|
+
}
|
|
24035
|
+
} else {
|
|
24036
|
+
for (const key in node) {
|
|
24037
|
+
if (!Object.prototype.hasOwnProperty.call(node, key))
|
|
24038
|
+
continue;
|
|
24039
|
+
if (++count > max)
|
|
24040
|
+
return count;
|
|
24041
|
+
const child = node[key];
|
|
24042
|
+
if (child !== null && typeof child === "object")
|
|
24043
|
+
stack.push(child);
|
|
24044
|
+
}
|
|
24045
|
+
}
|
|
24046
|
+
}
|
|
24047
|
+
return count;
|
|
24048
|
+
}
|
|
24049
|
+
function resolveMaxToolInputElements(value) {
|
|
24050
|
+
if (value === undefined || value === Infinity)
|
|
24051
|
+
return;
|
|
24052
|
+
if (typeof value !== "number" || Number.isNaN(value) || value < 1) {
|
|
24053
|
+
throw new RangeError(`maxToolInputElements must be a number of at least 1, or Infinity, got ${String(value)}`);
|
|
24054
|
+
}
|
|
24055
|
+
return value;
|
|
24056
|
+
}
|
|
24057
|
+
|
|
23986
24058
|
class McpServer {
|
|
23987
24059
|
constructor(serverInfo, options) {
|
|
23988
24060
|
this._registeredResources = {};
|
|
@@ -23994,6 +24066,7 @@ class McpServer {
|
|
|
23994
24066
|
this._resourceHandlersInitialized = false;
|
|
23995
24067
|
this._promptHandlersInitialized = false;
|
|
23996
24068
|
this.server = new Server(serverInfo, options);
|
|
24069
|
+
this._maxToolInputElements = resolveMaxToolInputElements(options?.maxToolInputElements);
|
|
23997
24070
|
}
|
|
23998
24071
|
get experimental() {
|
|
23999
24072
|
if (!this._experimental) {
|
|
@@ -24100,12 +24173,15 @@ class McpServer {
|
|
|
24100
24173
|
};
|
|
24101
24174
|
}
|
|
24102
24175
|
async validateToolInput(tool, args, toolName) {
|
|
24176
|
+
if (this._maxToolInputElements !== undefined && toolInputElementCount(args, this._maxToolInputElements) > this._maxToolInputElements) {
|
|
24177
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid arguments for tool ${toolName}: arguments contain more than the maximum of ${this._maxToolInputElements} elements`);
|
|
24178
|
+
}
|
|
24103
24179
|
if (!tool.inputSchema) {
|
|
24104
24180
|
return;
|
|
24105
24181
|
}
|
|
24106
24182
|
const inputObj = normalizeObjectSchema(tool.inputSchema);
|
|
24107
24183
|
const schemaToParse = inputObj ?? tool.inputSchema;
|
|
24108
|
-
const parseResult = await safeParseAsync2(schemaToParse, args);
|
|
24184
|
+
const parseResult = await safeParseAsync2(schemaToParse, args ?? {});
|
|
24109
24185
|
if (!parseResult.success) {
|
|
24110
24186
|
const error = "error" in parseResult ? parseResult.error : "Unknown error";
|
|
24111
24187
|
const errorMessage = getParseErrorMessage(error);
|
|
@@ -24330,7 +24406,7 @@ class McpServer {
|
|
|
24330
24406
|
}
|
|
24331
24407
|
if (prompt.argsSchema) {
|
|
24332
24408
|
const argsObj = normalizeObjectSchema(prompt.argsSchema);
|
|
24333
|
-
const parseResult = await safeParseAsync2(argsObj, request.params.arguments);
|
|
24409
|
+
const parseResult = await safeParseAsync2(argsObj, request.params.arguments ?? {});
|
|
24334
24410
|
if (!parseResult.success) {
|
|
24335
24411
|
const error = "error" in parseResult ? parseResult.error : "Unknown error";
|
|
24336
24412
|
const errorMessage = getParseErrorMessage(error);
|
|
@@ -33828,7 +33904,7 @@ var TOOL_SPECS = [
|
|
|
33828
33904
|
requires: [],
|
|
33829
33905
|
operations: {
|
|
33830
33906
|
click: {
|
|
33831
|
-
summary:
|
|
33907
|
+
summary: `press and release on a Control, a frame apart, and answer with what was under the pointer and what became of the control: in_tree, removed or freed. The control is named by nodePath, or by says with the words on it, found under nodePath when both are given, and the answer then says under found which match it was. Words that are part of a RichTextLabel are pressed where they are drawn rather than at the label's middle, so a link among them is the one pressed: found.pressedOn says "the words", or "the middle of the label" with a note saying why they could not be placed, and link_pressed names the meta the label reports clicked. A control out of sight inside a ScrollContainer is scrolled to first, each container out from it a frame after the one inside, and scrolled_into_view says whether a scroll value changed. A disabled button, and a control that does not process (the game paused, say), are refused: the pointer reaches them and the press does nothing. A 3D node is clicked where it is drawn, and landed then says the interface did not swallow the press: no control under the pointer stopped it, a control letting the pointer pass included, and every viewport on the way out from the room had the pointer over what shows the room`,
|
|
33832
33908
|
requires: []
|
|
33833
33909
|
},
|
|
33834
33910
|
choose: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gdharness",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.45",
|
|
4
4
|
"mcpName": "io.github.Aureliolo/gdharness",
|
|
5
5
|
"description": "A harness for driving a Godot 4 project from an agent: editor addons, a runtime bridge into the running game, an MCP server in front of them, and a CLI that installs and diagnoses the Godot side.",
|
|
6
6
|
"type": "module",
|