@rama_nigg/open-cursor 2.3.3 → 2.3.4
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/index.js +307 -210
- package/dist/plugin-entry.js +301 -204
- package/package.json +1 -1
- package/src/plugin.ts +33 -0
- package/src/provider/boundary.ts +3 -3
- package/src/provider/passthrough-tracker.ts +38 -0
- package/src/provider/runtime-interception.ts +175 -123
- package/src/provider/tool-loop-guard.ts +0 -63
- package/src/proxy/tool-loop.ts +42 -28
- package/src/services/toast-service.ts +81 -0
package/dist/index.js
CHANGED
|
@@ -13614,41 +13614,46 @@ function extractAllowedToolNames(tools) {
|
|
|
13614
13614
|
}
|
|
13615
13615
|
function extractOpenAiToolCall(event, allowedToolNames) {
|
|
13616
13616
|
if (allowedToolNames.size === 0) {
|
|
13617
|
-
return
|
|
13617
|
+
return { action: "skip", skipReason: "no_allowed_tools" };
|
|
13618
13618
|
}
|
|
13619
13619
|
const { name, args, skipped } = extractToolNameAndArgs(event);
|
|
13620
13620
|
if (skipped) {
|
|
13621
|
-
return
|
|
13621
|
+
return { action: "skip", skipReason: "event_skipped" };
|
|
13622
13622
|
}
|
|
13623
13623
|
if (!name) {
|
|
13624
|
-
return
|
|
13624
|
+
return { action: "skip", skipReason: "no_name" };
|
|
13625
13625
|
}
|
|
13626
13626
|
const resolvedName = resolveAllowedToolName(name, allowedToolNames);
|
|
13627
|
-
if (
|
|
13628
|
-
|
|
13629
|
-
|
|
13630
|
-
|
|
13631
|
-
|
|
13632
|
-
|
|
13633
|
-
|
|
13634
|
-
|
|
13635
|
-
|
|
13636
|
-
|
|
13637
|
-
|
|
13638
|
-
|
|
13639
|
-
|
|
13640
|
-
|
|
13641
|
-
|
|
13642
|
-
|
|
13627
|
+
if (resolvedName) {
|
|
13628
|
+
if (args === undefined && event.subtype === "started") {
|
|
13629
|
+
log5.debug("Tool call args extraction returned undefined", {
|
|
13630
|
+
toolName: name,
|
|
13631
|
+
subtype: event.subtype ?? "none",
|
|
13632
|
+
payloadKeys: Object.entries(event.tool_call || {}).map(([k, v]) => `${k}:[${isRecord(v) ? Object.keys(v).join(",") : typeof v}]`),
|
|
13633
|
+
hasCallId: Boolean(event.call_id)
|
|
13634
|
+
});
|
|
13635
|
+
}
|
|
13636
|
+
const callId = event.call_id || event.tool_call_id || "call_unknown";
|
|
13637
|
+
return {
|
|
13638
|
+
action: "intercept",
|
|
13639
|
+
toolCall: {
|
|
13640
|
+
id: callId,
|
|
13641
|
+
type: "function",
|
|
13642
|
+
function: {
|
|
13643
|
+
name: resolvedName,
|
|
13644
|
+
arguments: toOpenAiArguments(args)
|
|
13645
|
+
}
|
|
13646
|
+
}
|
|
13647
|
+
};
|
|
13643
13648
|
}
|
|
13644
|
-
|
|
13649
|
+
log5.debug("Tool call not in allowlist; passing through to cursor-agent", {
|
|
13650
|
+
name,
|
|
13651
|
+
normalized: normalizeAliasKey(name),
|
|
13652
|
+
allowedToolCount: allowedToolNames.size
|
|
13653
|
+
});
|
|
13645
13654
|
return {
|
|
13646
|
-
|
|
13647
|
-
|
|
13648
|
-
function: {
|
|
13649
|
-
name: resolvedName,
|
|
13650
|
-
arguments: toOpenAiArguments(args)
|
|
13651
|
-
}
|
|
13655
|
+
action: "passthrough",
|
|
13656
|
+
passthroughName: name
|
|
13652
13657
|
};
|
|
13653
13658
|
}
|
|
13654
13659
|
function createToolCallCompletionResponse(meta, toolCall) {
|
|
@@ -16388,7 +16393,7 @@ function createSharedBoundary(providerId) {
|
|
|
16388
16393
|
},
|
|
16389
16394
|
maybeExtractToolCall(event, allowedToolNames, toolLoopMode) {
|
|
16390
16395
|
if (toolLoopMode !== "opencode") {
|
|
16391
|
-
return
|
|
16396
|
+
return { action: "skip", skipReason: "tool_loop_mode_not_opencode" };
|
|
16392
16397
|
}
|
|
16393
16398
|
return extractOpenAiToolCall(event, allowedToolNames);
|
|
16394
16399
|
},
|
|
@@ -16815,9 +16820,33 @@ async function handleToolLoopEventLegacy(options) {
|
|
|
16815
16820
|
responseMeta,
|
|
16816
16821
|
onToolUpdate,
|
|
16817
16822
|
onToolResult,
|
|
16818
|
-
onInterceptedToolCall
|
|
16823
|
+
onInterceptedToolCall,
|
|
16824
|
+
passThroughTracker
|
|
16819
16825
|
} = options;
|
|
16820
|
-
const
|
|
16826
|
+
const extraction = toolLoopMode === "opencode" ? extractOpenAiToolCall(event, allowedToolNames) : { action: "skip", skipReason: "tool_loop_mode_not_opencode" };
|
|
16827
|
+
if (extraction.action === "passthrough") {
|
|
16828
|
+
passThroughTracker?.trackTool(extraction.passthroughName);
|
|
16829
|
+
log13.debug("MCP tool passed through to cursor-agent (legacy)", {
|
|
16830
|
+
tool: extraction.passthroughName
|
|
16831
|
+
});
|
|
16832
|
+
return { intercepted: false, skipConverter: false };
|
|
16833
|
+
}
|
|
16834
|
+
if (extraction.action === "skip" || !extraction.toolCall) {
|
|
16835
|
+
const updates2 = await toolMapper.mapCursorEventToAcp(event, event.session_id ?? toolSessionId);
|
|
16836
|
+
if (shouldEmitToolUpdates) {
|
|
16837
|
+
for (const update of updates2) {
|
|
16838
|
+
await onToolUpdate(update);
|
|
16839
|
+
}
|
|
16840
|
+
}
|
|
16841
|
+
if (toolRouter && proxyExecuteToolCalls) {
|
|
16842
|
+
const toolResult = await toolRouter.handleToolCall(event, responseMeta);
|
|
16843
|
+
if (toolResult) {
|
|
16844
|
+
await onToolResult(toolResult);
|
|
16845
|
+
}
|
|
16846
|
+
}
|
|
16847
|
+
return { intercepted: false, skipConverter: suppressConverterToolEvents };
|
|
16848
|
+
}
|
|
16849
|
+
const interceptedToolCall = extraction.toolCall;
|
|
16821
16850
|
if (interceptedToolCall) {
|
|
16822
16851
|
const compat2 = applyToolSchemaCompat(interceptedToolCall, toolSchemaMap);
|
|
16823
16852
|
let normalizedToolCall = compat2.toolCall;
|
|
@@ -16894,118 +16923,125 @@ async function handleToolLoopEventV1(options) {
|
|
|
16894
16923
|
responseMeta,
|
|
16895
16924
|
onToolUpdate,
|
|
16896
16925
|
onToolResult,
|
|
16897
|
-
onInterceptedToolCall
|
|
16926
|
+
onInterceptedToolCall,
|
|
16927
|
+
passThroughTracker
|
|
16898
16928
|
} = options;
|
|
16899
|
-
let
|
|
16929
|
+
let extraction;
|
|
16900
16930
|
try {
|
|
16901
|
-
|
|
16931
|
+
extraction = boundary.maybeExtractToolCall(event, allowedToolNames, toolLoopMode);
|
|
16902
16932
|
} catch (error45) {
|
|
16903
16933
|
throw new ToolBoundaryExtractionError("Boundary tool extraction failed", error45);
|
|
16904
16934
|
}
|
|
16905
|
-
if (
|
|
16906
|
-
|
|
16907
|
-
|
|
16908
|
-
|
|
16909
|
-
rawArgs: safeArgTypeSummary(event),
|
|
16910
|
-
normalizedArgs: compat2.normalizedArgs
|
|
16911
|
-
} : undefined;
|
|
16912
|
-
log13.debug("Applied tool schema compatibility", {
|
|
16913
|
-
tool: interceptedToolCall.function.name,
|
|
16914
|
-
originalArgKeys: compat2.originalArgKeys,
|
|
16915
|
-
normalizedArgKeys: compat2.normalizedArgKeys,
|
|
16916
|
-
collisionKeys: compat2.collisionKeys,
|
|
16917
|
-
validationOk: compat2.validation.ok,
|
|
16918
|
-
...editDiag ? { editDiag } : {}
|
|
16935
|
+
if (extraction.action === "passthrough") {
|
|
16936
|
+
passThroughTracker?.trackTool(extraction.passthroughName);
|
|
16937
|
+
log13.debug("MCP tool passed through to cursor-agent (v1)", {
|
|
16938
|
+
tool: extraction.passthroughName
|
|
16919
16939
|
});
|
|
16920
|
-
|
|
16921
|
-
|
|
16922
|
-
|
|
16940
|
+
return { intercepted: false, skipConverter: false };
|
|
16941
|
+
}
|
|
16942
|
+
if (extraction.action === "skip" || !extraction.toolCall) {
|
|
16943
|
+
const updates = await toolMapper.mapCursorEventToAcp(event, event.session_id ?? toolSessionId);
|
|
16944
|
+
if (shouldEmitToolUpdates) {
|
|
16945
|
+
for (const update of updates) {
|
|
16946
|
+
await onToolUpdate(update);
|
|
16947
|
+
}
|
|
16948
|
+
}
|
|
16949
|
+
if (toolRouter && proxyExecuteToolCalls) {
|
|
16950
|
+
const toolResult = await toolRouter.handleToolCall(event, responseMeta);
|
|
16951
|
+
if (toolResult) {
|
|
16952
|
+
await onToolResult(toolResult);
|
|
16953
|
+
}
|
|
16954
|
+
}
|
|
16955
|
+
return { intercepted: false, skipConverter: suppressConverterToolEvents };
|
|
16956
|
+
}
|
|
16957
|
+
const interceptedToolCall = extraction.toolCall;
|
|
16958
|
+
const compat2 = applyToolSchemaCompat(interceptedToolCall, toolSchemaMap);
|
|
16959
|
+
let normalizedToolCall = compat2.toolCall;
|
|
16960
|
+
const editDiag = normalizedToolCall.function.name.toLowerCase() === "edit" ? {
|
|
16961
|
+
rawArgs: safeArgTypeSummary(event),
|
|
16962
|
+
normalizedArgs: compat2.normalizedArgs
|
|
16963
|
+
} : undefined;
|
|
16964
|
+
log13.debug("Applied tool schema compatibility", {
|
|
16965
|
+
tool: normalizedToolCall.function.name,
|
|
16966
|
+
originalArgKeys: compat2.originalArgKeys,
|
|
16967
|
+
normalizedArgKeys: compat2.normalizedArgKeys,
|
|
16968
|
+
collisionKeys: compat2.collisionKeys,
|
|
16969
|
+
validationOk: compat2.validation.ok,
|
|
16970
|
+
...editDiag ? { editDiag } : {}
|
|
16971
|
+
});
|
|
16972
|
+
if (compat2.validation.hasSchema && !compat2.validation.ok) {
|
|
16973
|
+
log13.debug("Tool schema compatibility validation failed", {
|
|
16974
|
+
tool: normalizedToolCall.function.name,
|
|
16975
|
+
missing: compat2.validation.missing,
|
|
16976
|
+
unexpected: compat2.validation.unexpected,
|
|
16977
|
+
typeErrors: compat2.validation.typeErrors,
|
|
16978
|
+
repairHint: compat2.validation.repairHint
|
|
16979
|
+
});
|
|
16980
|
+
const validationTermination = evaluateSchemaValidationLoopGuard(toolLoopGuard, normalizedToolCall, compat2.validation);
|
|
16981
|
+
if (validationTermination) {
|
|
16982
|
+
return { intercepted: false, skipConverter: true, terminate: validationTermination };
|
|
16983
|
+
}
|
|
16984
|
+
const termination2 = evaluateToolLoopGuard(toolLoopGuard, normalizedToolCall);
|
|
16985
|
+
if (termination2) {
|
|
16986
|
+
return { intercepted: false, skipConverter: true, terminate: termination2 };
|
|
16987
|
+
}
|
|
16988
|
+
const reroutedWrite = tryRerouteEditToWrite(normalizedToolCall, compat2.normalizedArgs, allowedToolNames, toolSchemaMap);
|
|
16989
|
+
if (reroutedWrite) {
|
|
16990
|
+
log13.debug("Rerouting malformed edit call to write", {
|
|
16991
|
+
path: reroutedWrite.path,
|
|
16923
16992
|
missing: compat2.validation.missing,
|
|
16924
|
-
|
|
16925
|
-
typeErrors: compat2.validation.typeErrors,
|
|
16926
|
-
repairHint: compat2.validation.repairHint
|
|
16993
|
+
typeErrors: compat2.validation.typeErrors
|
|
16927
16994
|
});
|
|
16928
|
-
|
|
16929
|
-
if (validationTermination) {
|
|
16930
|
-
return { intercepted: false, skipConverter: true, terminate: validationTermination };
|
|
16931
|
-
}
|
|
16932
|
-
const termination2 = evaluateToolLoopGuard(toolLoopGuard, interceptedToolCall);
|
|
16933
|
-
if (termination2) {
|
|
16934
|
-
return { intercepted: false, skipConverter: true, terminate: termination2 };
|
|
16935
|
-
}
|
|
16936
|
-
const reroutedWrite = tryRerouteEditToWrite(interceptedToolCall, compat2.normalizedArgs, allowedToolNames, toolSchemaMap);
|
|
16937
|
-
if (reroutedWrite) {
|
|
16938
|
-
log13.debug("Rerouting malformed edit call to write", {
|
|
16939
|
-
path: reroutedWrite.path,
|
|
16940
|
-
missing: compat2.validation.missing,
|
|
16941
|
-
typeErrors: compat2.validation.typeErrors
|
|
16942
|
-
});
|
|
16943
|
-
await onInterceptedToolCall(reroutedWrite.toolCall);
|
|
16944
|
-
return {
|
|
16945
|
-
intercepted: true,
|
|
16946
|
-
skipConverter: true
|
|
16947
|
-
};
|
|
16948
|
-
}
|
|
16949
|
-
if (schemaValidationFailureMode === "pass_through" && shouldTerminateOnSchemaValidation(interceptedToolCall, compat2.validation)) {
|
|
16950
|
-
return {
|
|
16951
|
-
intercepted: false,
|
|
16952
|
-
skipConverter: true,
|
|
16953
|
-
terminate: createSchemaValidationTermination(interceptedToolCall, compat2.validation)
|
|
16954
|
-
};
|
|
16955
|
-
}
|
|
16956
|
-
if (schemaValidationFailureMode === "pass_through" && shouldEmitNonFatalSchemaValidationHint(interceptedToolCall, compat2.validation)) {
|
|
16957
|
-
const hintChunk = createNonFatalSchemaValidationHintChunk(responseMeta, interceptedToolCall, compat2.validation);
|
|
16958
|
-
log13.debug("Emitting non-fatal schema validation hint and skipping malformed tool execution", {
|
|
16959
|
-
tool: interceptedToolCall.function.name,
|
|
16960
|
-
missing: compat2.validation.missing,
|
|
16961
|
-
typeErrors: compat2.validation.typeErrors
|
|
16962
|
-
});
|
|
16963
|
-
await onToolResult(hintChunk);
|
|
16964
|
-
return {
|
|
16965
|
-
intercepted: false,
|
|
16966
|
-
skipConverter: true
|
|
16967
|
-
};
|
|
16968
|
-
}
|
|
16969
|
-
if (schemaValidationFailureMode === "terminate") {
|
|
16970
|
-
return {
|
|
16971
|
-
intercepted: false,
|
|
16972
|
-
skipConverter: true,
|
|
16973
|
-
terminate: createSchemaValidationTermination(interceptedToolCall, compat2.validation)
|
|
16974
|
-
};
|
|
16975
|
-
}
|
|
16976
|
-
log13.debug("Forwarding schema-invalid tool call to OpenCode loop", {
|
|
16977
|
-
tool: interceptedToolCall.function.name,
|
|
16978
|
-
repairHint: compat2.validation.repairHint
|
|
16979
|
-
});
|
|
16980
|
-
await onInterceptedToolCall(interceptedToolCall);
|
|
16995
|
+
await onInterceptedToolCall(reroutedWrite.toolCall);
|
|
16981
16996
|
return {
|
|
16982
16997
|
intercepted: true,
|
|
16983
16998
|
skipConverter: true
|
|
16984
16999
|
};
|
|
16985
17000
|
}
|
|
16986
|
-
|
|
16987
|
-
|
|
16988
|
-
|
|
17001
|
+
if (schemaValidationFailureMode === "pass_through" && shouldTerminateOnSchemaValidation(normalizedToolCall, compat2.validation)) {
|
|
17002
|
+
return {
|
|
17003
|
+
intercepted: false,
|
|
17004
|
+
skipConverter: true,
|
|
17005
|
+
terminate: createSchemaValidationTermination(normalizedToolCall, compat2.validation)
|
|
17006
|
+
};
|
|
16989
17007
|
}
|
|
16990
|
-
|
|
16991
|
-
|
|
16992
|
-
|
|
16993
|
-
|
|
16994
|
-
|
|
16995
|
-
|
|
16996
|
-
|
|
17008
|
+
if (schemaValidationFailureMode === "pass_through" && shouldEmitNonFatalSchemaValidationHint(normalizedToolCall, compat2.validation)) {
|
|
17009
|
+
const hintChunk = createNonFatalSchemaValidationHintChunk(responseMeta, normalizedToolCall, compat2.validation);
|
|
17010
|
+
log13.debug("Emitting non-fatal schema validation hint and skipping malformed tool execution", {
|
|
17011
|
+
tool: normalizedToolCall.function.name,
|
|
17012
|
+
missing: compat2.validation.missing,
|
|
17013
|
+
typeErrors: compat2.validation.typeErrors
|
|
17014
|
+
});
|
|
17015
|
+
await onToolResult(hintChunk);
|
|
17016
|
+
return {
|
|
17017
|
+
intercepted: false,
|
|
17018
|
+
skipConverter: true
|
|
17019
|
+
};
|
|
16997
17020
|
}
|
|
16998
|
-
|
|
16999
|
-
|
|
17000
|
-
|
|
17001
|
-
|
|
17002
|
-
|
|
17021
|
+
if (schemaValidationFailureMode === "terminate") {
|
|
17022
|
+
return {
|
|
17023
|
+
intercepted: false,
|
|
17024
|
+
skipConverter: true,
|
|
17025
|
+
terminate: createSchemaValidationTermination(normalizedToolCall, compat2.validation)
|
|
17026
|
+
};
|
|
17003
17027
|
}
|
|
17028
|
+
log13.debug("Forwarding schema-invalid tool call to OpenCode loop", {
|
|
17029
|
+
tool: normalizedToolCall.function.name,
|
|
17030
|
+
repairHint: compat2.validation.repairHint
|
|
17031
|
+
});
|
|
17032
|
+
await onInterceptedToolCall(normalizedToolCall);
|
|
17033
|
+
return {
|
|
17034
|
+
intercepted: true,
|
|
17035
|
+
skipConverter: true
|
|
17036
|
+
};
|
|
17004
17037
|
}
|
|
17005
|
-
|
|
17006
|
-
|
|
17007
|
-
skipConverter:
|
|
17008
|
-
}
|
|
17038
|
+
const termination = evaluateToolLoopGuard(toolLoopGuard, normalizedToolCall);
|
|
17039
|
+
if (termination) {
|
|
17040
|
+
return { intercepted: false, skipConverter: true, terminate: termination };
|
|
17041
|
+
}
|
|
17042
|
+
await onInterceptedToolCall(normalizedToolCall);
|
|
17043
|
+
return { intercepted: true, skipConverter: true };
|
|
17044
|
+
return { intercepted: false, skipConverter: suppressConverterToolEvents };
|
|
17009
17045
|
}
|
|
17010
17046
|
async function handleToolLoopEventWithFallback(options) {
|
|
17011
17047
|
const {
|
|
@@ -17286,6 +17322,80 @@ var init_runtime_interception = __esm(() => {
|
|
|
17286
17322
|
};
|
|
17287
17323
|
});
|
|
17288
17324
|
|
|
17325
|
+
// src/provider/passthrough-tracker.ts
|
|
17326
|
+
class PassThroughTracker {
|
|
17327
|
+
tools = new Set;
|
|
17328
|
+
errors = [];
|
|
17329
|
+
trackTool(name) {
|
|
17330
|
+
this.tools.add(name);
|
|
17331
|
+
}
|
|
17332
|
+
trackError(toolName, message) {
|
|
17333
|
+
this.errors.push(`${toolName}: ${message}`);
|
|
17334
|
+
}
|
|
17335
|
+
getSummary() {
|
|
17336
|
+
return {
|
|
17337
|
+
tools: Array.from(this.tools),
|
|
17338
|
+
errors: [...this.errors],
|
|
17339
|
+
hasActivity: this.tools.size > 0
|
|
17340
|
+
};
|
|
17341
|
+
}
|
|
17342
|
+
reset() {
|
|
17343
|
+
this.tools.clear();
|
|
17344
|
+
this.errors.length = 0;
|
|
17345
|
+
}
|
|
17346
|
+
}
|
|
17347
|
+
|
|
17348
|
+
// src/services/toast-service.ts
|
|
17349
|
+
class ToastService {
|
|
17350
|
+
client = null;
|
|
17351
|
+
setClient(client3) {
|
|
17352
|
+
this.client = client3;
|
|
17353
|
+
}
|
|
17354
|
+
async show(options) {
|
|
17355
|
+
if (!this.client?.tui?.showToast) {
|
|
17356
|
+
log14.debug("Toast not available; client.tui.showToast missing", { message: options.message });
|
|
17357
|
+
return;
|
|
17358
|
+
}
|
|
17359
|
+
try {
|
|
17360
|
+
await this.client.tui.showToast({
|
|
17361
|
+
body: {
|
|
17362
|
+
title: options.title,
|
|
17363
|
+
message: options.message,
|
|
17364
|
+
variant: options.variant
|
|
17365
|
+
}
|
|
17366
|
+
});
|
|
17367
|
+
} catch (error45) {
|
|
17368
|
+
log14.debug("Toast failed", { error: error45, message: options.message });
|
|
17369
|
+
}
|
|
17370
|
+
}
|
|
17371
|
+
async showPassThroughSummary(tools) {
|
|
17372
|
+
if (tools.length === 0)
|
|
17373
|
+
return;
|
|
17374
|
+
const toolList = tools.length <= 3 ? tools.join(", ") : `${tools.slice(0, 3).join(", ")} +${tools.length - 3} more`;
|
|
17375
|
+
await this.show({
|
|
17376
|
+
title: "MCP Tools",
|
|
17377
|
+
message: `\uD83C\uDFAD ${tools.length} tool${tools.length > 1 ? "s" : ""} handled by cursor-agent: ${toolList}`,
|
|
17378
|
+
variant: "info"
|
|
17379
|
+
});
|
|
17380
|
+
}
|
|
17381
|
+
async showErrorSummary(errors3) {
|
|
17382
|
+
if (errors3.length === 0)
|
|
17383
|
+
return;
|
|
17384
|
+
const errorList = errors3.length <= 2 ? errors3.join("; ") : `${errors3.slice(0, 2).join("; ")} +${errors3.length - 2} more`;
|
|
17385
|
+
await this.show({
|
|
17386
|
+
title: "MCP Errors",
|
|
17387
|
+
message: `⚠️ ${errors3.length} MCP tool${errors3.length > 1 ? "s" : ""} failed: ${errorList}`,
|
|
17388
|
+
variant: "warning"
|
|
17389
|
+
});
|
|
17390
|
+
}
|
|
17391
|
+
}
|
|
17392
|
+
var log14, toastService;
|
|
17393
|
+
var init_toast_service = __esm(() => {
|
|
17394
|
+
init_logger();
|
|
17395
|
+
log14 = createLogger("services:toast");
|
|
17396
|
+
toastService = new ToastService;
|
|
17397
|
+
});
|
|
17398
|
+
|
|
17289
17399
|
// src/provider/tool-loop-guard.ts
|
|
17290
17400
|
function parseToolLoopMaxRepeat(value) {
|
|
17291
17401
|
if (value === undefined) {
|
|
@@ -17428,25 +17538,6 @@ function indexToolLoopHistory(messages) {
|
|
|
17428
17538
|
incrementCount(initialValidationCounts, `${call.name}|schema:${schemaSignature}|validation`);
|
|
17429
17539
|
incrementCount(initialValidationCoarseCounts, `${call.name}|validation`);
|
|
17430
17540
|
}
|
|
17431
|
-
const strippedRounds = countStrippedAssistantRounds(messages);
|
|
17432
|
-
if (strippedRounds > 0 && assistantCalls.length > 0) {
|
|
17433
|
-
for (const call of assistantCalls) {
|
|
17434
|
-
const errorClass = normalizeErrorClassForTool(call.name, byCallId.get(call.id) ?? latestByToolName.get(call.name) ?? latest ?? "unknown");
|
|
17435
|
-
if (errorClass !== "success") {
|
|
17436
|
-
continue;
|
|
17437
|
-
}
|
|
17438
|
-
const coarseSuccessFP = deriveSuccessCoarseFingerprint(call.name, call.rawArguments);
|
|
17439
|
-
if (coarseSuccessFP) {
|
|
17440
|
-
for (let i = 0;i < strippedRounds; i++) {
|
|
17441
|
-
incrementCount(initialCoarseCounts, coarseSuccessFP);
|
|
17442
|
-
}
|
|
17443
|
-
}
|
|
17444
|
-
const successFP = `${call.name}|values:${call.argValueSignature}|success`;
|
|
17445
|
-
for (let i = 0;i < strippedRounds; i++) {
|
|
17446
|
-
incrementCount(initialCounts, successFP);
|
|
17447
|
-
}
|
|
17448
|
-
}
|
|
17449
|
-
}
|
|
17450
17541
|
return {
|
|
17451
17542
|
byCallId,
|
|
17452
17543
|
latest,
|
|
@@ -17669,23 +17760,6 @@ function normalizeErrorClassForTool(toolName, errorClass) {
|
|
|
17669
17760
|
}
|
|
17670
17761
|
return errorClass;
|
|
17671
17762
|
}
|
|
17672
|
-
function countStrippedAssistantRounds(messages) {
|
|
17673
|
-
let count = 0;
|
|
17674
|
-
for (const message of messages) {
|
|
17675
|
-
if (!isRecord4(message) || message.role !== "assistant") {
|
|
17676
|
-
continue;
|
|
17677
|
-
}
|
|
17678
|
-
if (Array.isArray(message.tool_calls) && message.tool_calls.length > 0) {
|
|
17679
|
-
continue;
|
|
17680
|
-
}
|
|
17681
|
-
const content = message.content;
|
|
17682
|
-
const hasContent = typeof content === "string" && content.trim().length > 0 || Array.isArray(content) && content.length > 0;
|
|
17683
|
-
if (!hasContent) {
|
|
17684
|
-
count++;
|
|
17685
|
-
}
|
|
17686
|
-
}
|
|
17687
|
-
return count;
|
|
17688
|
-
}
|
|
17689
17763
|
function toLowerText(content) {
|
|
17690
17764
|
const rendered = renderContent(content);
|
|
17691
17765
|
return rendered.trim().toLowerCase();
|
|
@@ -17770,9 +17844,9 @@ async function ensurePluginDirectory() {
|
|
|
17770
17844
|
const pluginDir = join4(configHome, "opencode", "plugin");
|
|
17771
17845
|
try {
|
|
17772
17846
|
await mkdir(pluginDir, { recursive: true });
|
|
17773
|
-
|
|
17847
|
+
log15.debug("Plugin directory ensured", { path: pluginDir });
|
|
17774
17848
|
} catch (error45) {
|
|
17775
|
-
|
|
17849
|
+
log15.warn("Failed to create plugin directory", { error: String(error45) });
|
|
17776
17850
|
}
|
|
17777
17851
|
}
|
|
17778
17852
|
function shouldProcessModel(model) {
|
|
@@ -17960,9 +18034,9 @@ function createBoundaryRuntimeContext(scope) {
|
|
|
17960
18034
|
error: toErrorMessage(error45)
|
|
17961
18035
|
};
|
|
17962
18036
|
if (!fallbackActive) {
|
|
17963
|
-
|
|
18037
|
+
log15.warn("Provider boundary v1 failed; switching to legacy for this request", details);
|
|
17964
18038
|
} else {
|
|
17965
|
-
|
|
18039
|
+
log15.debug("Provider boundary fallback already active", details);
|
|
17966
18040
|
}
|
|
17967
18041
|
fallbackActive = true;
|
|
17968
18042
|
return true;
|
|
@@ -18100,7 +18174,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18100
18174
|
headers: { "Content-Type": "application/json" }
|
|
18101
18175
|
});
|
|
18102
18176
|
} catch (err) {
|
|
18103
|
-
|
|
18177
|
+
log15.error("Failed to list models", { error: String(err) });
|
|
18104
18178
|
return new Response(JSON.stringify({ error: "Failed to fetch models from cursor-agent" }), {
|
|
18105
18179
|
status: 500,
|
|
18106
18180
|
headers: { "Content-Type": "application/json" }
|
|
@@ -18113,7 +18187,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18113
18187
|
headers: { "Content-Type": "application/json" }
|
|
18114
18188
|
});
|
|
18115
18189
|
}
|
|
18116
|
-
|
|
18190
|
+
log15.debug("Proxy request (bun)", { method: req.method, path: url2.pathname });
|
|
18117
18191
|
const body = await req.json().catch(() => ({}));
|
|
18118
18192
|
const messages = Array.isArray(body?.messages) ? body.messages : [];
|
|
18119
18193
|
const stream = body?.stream === true;
|
|
@@ -18140,7 +18214,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18140
18214
|
const clen = typeof m?.content === "string" ? m.content.length : Array.isArray(m?.content) ? `arr${m.content.length}` : typeof m?.content;
|
|
18141
18215
|
return `${i}:${role}${hasTc ? `(tc:${hasTc})` : ""}(clen:${clen})`;
|
|
18142
18216
|
});
|
|
18143
|
-
|
|
18217
|
+
log15.debug("Proxy chat request (bun)", {
|
|
18144
18218
|
stream,
|
|
18145
18219
|
model,
|
|
18146
18220
|
messages: messages.length,
|
|
@@ -18186,7 +18260,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18186
18260
|
const stdout = (stdoutText || "").trim();
|
|
18187
18261
|
const stderr = (stderrText || "").trim();
|
|
18188
18262
|
const exitCode = await child.exited;
|
|
18189
|
-
|
|
18263
|
+
log15.debug("cursor-agent completed (bun non-stream)", {
|
|
18190
18264
|
exitCode,
|
|
18191
18265
|
stdoutChars: stdout.length,
|
|
18192
18266
|
stderrChars: stderr.length
|
|
@@ -18212,7 +18286,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18212
18286
|
});
|
|
18213
18287
|
}
|
|
18214
18288
|
if (intercepted.toolCall) {
|
|
18215
|
-
|
|
18289
|
+
log15.debug("Intercepted OpenCode tool call (non-stream)", {
|
|
18216
18290
|
name: intercepted.toolCall.function.name,
|
|
18217
18291
|
callId: intercepted.toolCall.id
|
|
18218
18292
|
});
|
|
@@ -18226,7 +18300,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18226
18300
|
const errSource = stderr || stdout || `cursor-agent exited with code ${String(exitCode ?? "unknown")} and no output`;
|
|
18227
18301
|
const parsed = parseAgentError(errSource);
|
|
18228
18302
|
const userError = formatErrorForUser(parsed);
|
|
18229
|
-
|
|
18303
|
+
log15.error("cursor-cli failed", {
|
|
18230
18304
|
type: parsed.type,
|
|
18231
18305
|
message: parsed.message,
|
|
18232
18306
|
code: exitCode
|
|
@@ -18250,6 +18324,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18250
18324
|
const perf = new RequestPerf(id);
|
|
18251
18325
|
const toolMapper = new ToolMapper;
|
|
18252
18326
|
const toolSessionId = id;
|
|
18327
|
+
const passThroughTracker = new PassThroughTracker;
|
|
18253
18328
|
perf.mark("spawn");
|
|
18254
18329
|
const sse = new ReadableStream({
|
|
18255
18330
|
async start(controller) {
|
|
@@ -18260,7 +18335,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18260
18335
|
const converter = new StreamToSseConverter(model, { id, created });
|
|
18261
18336
|
const lineBuffer = new LineBuffer;
|
|
18262
18337
|
const emitToolCallAndTerminate = (toolCall) => {
|
|
18263
|
-
|
|
18338
|
+
log15.debug("Intercepted OpenCode tool call (stream)", {
|
|
18264
18339
|
name: toolCall.function.name,
|
|
18265
18340
|
callId: toolCall.id
|
|
18266
18341
|
});
|
|
@@ -18327,6 +18402,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18327
18402
|
suppressConverterToolEvents: SUPPRESS_CONVERTER_TOOL_EVENTS,
|
|
18328
18403
|
toolRouter,
|
|
18329
18404
|
responseMeta: { id, created, model },
|
|
18405
|
+
passThroughTracker,
|
|
18330
18406
|
onToolUpdate: (update) => {
|
|
18331
18407
|
controller.enqueue(encoder.encode(formatToolUpdateEvent(update)));
|
|
18332
18408
|
},
|
|
@@ -18393,6 +18469,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18393
18469
|
suppressConverterToolEvents: SUPPRESS_CONVERTER_TOOL_EVENTS,
|
|
18394
18470
|
toolRouter,
|
|
18395
18471
|
responseMeta: { id, created, model },
|
|
18472
|
+
passThroughTracker,
|
|
18396
18473
|
onToolUpdate: (update) => {
|
|
18397
18474
|
controller.enqueue(encoder.encode(formatToolUpdateEvent(update)));
|
|
18398
18475
|
},
|
|
@@ -18440,7 +18517,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18440
18517
|
const errSource = (stderrText || "").trim() || `cursor-agent exited with code ${String(exitCode ?? "unknown")} and no output`;
|
|
18441
18518
|
const parsed = parseAgentError(errSource);
|
|
18442
18519
|
const msg = formatErrorForUser(parsed);
|
|
18443
|
-
|
|
18520
|
+
log15.error("cursor-cli streaming failed", {
|
|
18444
18521
|
type: parsed.type,
|
|
18445
18522
|
code: exitCode
|
|
18446
18523
|
});
|
|
@@ -18451,9 +18528,16 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18451
18528
|
controller.enqueue(encoder.encode(formatSseDone()));
|
|
18452
18529
|
return;
|
|
18453
18530
|
}
|
|
18454
|
-
|
|
18531
|
+
log15.debug("cursor-agent completed (bun stream)", {
|
|
18455
18532
|
exitCode
|
|
18456
18533
|
});
|
|
18534
|
+
const passThroughSummary = passThroughTracker.getSummary();
|
|
18535
|
+
if (passThroughSummary.hasActivity) {
|
|
18536
|
+
await toastService.showPassThroughSummary(passThroughSummary.tools);
|
|
18537
|
+
}
|
|
18538
|
+
if (passThroughSummary.errors.length > 0) {
|
|
18539
|
+
await toastService.showErrorSummary(passThroughSummary.errors);
|
|
18540
|
+
}
|
|
18457
18541
|
const doneChunk = createChatCompletionChunk(id, created, model, "", true);
|
|
18458
18542
|
controller.enqueue(encoder.encode(`data: ${JSON.stringify(doneChunk)}
|
|
18459
18543
|
|
|
@@ -18526,7 +18610,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18526
18610
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
18527
18611
|
res.end(JSON.stringify({ object: "list", data: models }));
|
|
18528
18612
|
} catch (err) {
|
|
18529
|
-
|
|
18613
|
+
log15.error("Failed to list models", { error: String(err) });
|
|
18530
18614
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
18531
18615
|
res.end(JSON.stringify({ error: "Failed to fetch models" }));
|
|
18532
18616
|
}
|
|
@@ -18537,7 +18621,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18537
18621
|
res.end(JSON.stringify({ error: `Unsupported path: ${url2.pathname}` }));
|
|
18538
18622
|
return;
|
|
18539
18623
|
}
|
|
18540
|
-
|
|
18624
|
+
log15.debug("Proxy request (node)", { method: req.method, path: url2.pathname });
|
|
18541
18625
|
let body = "";
|
|
18542
18626
|
for await (const chunk of req) {
|
|
18543
18627
|
body += chunk;
|
|
@@ -18560,7 +18644,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18560
18644
|
const contentLen = typeof m?.content === "string" ? m.content.length : Array.isArray(m?.content) ? `arr${m.content.length}` : typeof m?.content;
|
|
18561
18645
|
return `${i}:${role}${hasTc ? `(tc:${hasTc})` : ""}${role === "tool" ? `(tcid:${tcId},name:${tcName},clen:${contentLen})` : `(clen:${contentLen})`}`;
|
|
18562
18646
|
});
|
|
18563
|
-
|
|
18647
|
+
log15.debug("Proxy chat request (node)", {
|
|
18564
18648
|
stream,
|
|
18565
18649
|
model,
|
|
18566
18650
|
messages: messages.length,
|
|
@@ -18591,14 +18675,14 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18591
18675
|
let spawnErrorText = null;
|
|
18592
18676
|
child.on("error", (error45) => {
|
|
18593
18677
|
spawnErrorText = String(error45?.message || error45);
|
|
18594
|
-
|
|
18678
|
+
log15.error("Failed to spawn cursor-agent", { error: spawnErrorText, model });
|
|
18595
18679
|
});
|
|
18596
18680
|
child.stdout.on("data", (chunk) => stdoutChunks.push(chunk));
|
|
18597
18681
|
child.stderr.on("data", (chunk) => stderrChunks.push(chunk));
|
|
18598
18682
|
child.on("close", async (code) => {
|
|
18599
18683
|
const stdout = Buffer.concat(stdoutChunks).toString().trim();
|
|
18600
18684
|
const stderr = Buffer.concat(stderrChunks).toString().trim();
|
|
18601
|
-
|
|
18685
|
+
log15.debug("cursor-agent completed (node non-stream)", {
|
|
18602
18686
|
code,
|
|
18603
18687
|
stdoutChars: stdout.length,
|
|
18604
18688
|
stderrChars: stderr.length,
|
|
@@ -18624,7 +18708,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18624
18708
|
return;
|
|
18625
18709
|
}
|
|
18626
18710
|
if (intercepted.toolCall) {
|
|
18627
|
-
|
|
18711
|
+
log15.debug("Intercepted OpenCode tool call (non-stream)", {
|
|
18628
18712
|
name: intercepted.toolCall.function.name,
|
|
18629
18713
|
callId: intercepted.toolCall.id
|
|
18630
18714
|
});
|
|
@@ -18638,7 +18722,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18638
18722
|
const errSource = stderr || stdout || spawnErrorText || `cursor-agent exited with code ${String(code ?? "unknown")} and no output`;
|
|
18639
18723
|
const parsed = parseAgentError(errSource);
|
|
18640
18724
|
const userError = formatErrorForUser(parsed);
|
|
18641
|
-
|
|
18725
|
+
log15.error("cursor-cli failed", {
|
|
18642
18726
|
type: parsed.type,
|
|
18643
18727
|
message: parsed.message,
|
|
18644
18728
|
code
|
|
@@ -18666,6 +18750,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18666
18750
|
const lineBuffer = new LineBuffer;
|
|
18667
18751
|
const toolMapper = new ToolMapper;
|
|
18668
18752
|
const toolSessionId = id;
|
|
18753
|
+
const passThroughTracker = new PassThroughTracker;
|
|
18669
18754
|
const stderrChunks = [];
|
|
18670
18755
|
let streamTerminated = false;
|
|
18671
18756
|
let firstTokenReceived = false;
|
|
@@ -18677,7 +18762,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18677
18762
|
return;
|
|
18678
18763
|
}
|
|
18679
18764
|
const errSource = String(error45?.message || error45);
|
|
18680
|
-
|
|
18765
|
+
log15.error("Failed to spawn cursor-agent (stream)", { error: errSource, model });
|
|
18681
18766
|
const parsed = parseAgentError(errSource);
|
|
18682
18767
|
const msg = formatErrorForUser(parsed);
|
|
18683
18768
|
const errChunk = createChatCompletionChunk(id, created, model, msg, true);
|
|
@@ -18692,7 +18777,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18692
18777
|
if (streamTerminated || res.writableEnded) {
|
|
18693
18778
|
return;
|
|
18694
18779
|
}
|
|
18695
|
-
|
|
18780
|
+
log15.debug("Intercepted OpenCode tool call (stream)", {
|
|
18696
18781
|
name: toolCall.function.name,
|
|
18697
18782
|
callId: toolCall.id
|
|
18698
18783
|
});
|
|
@@ -18758,6 +18843,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18758
18843
|
suppressConverterToolEvents: SUPPRESS_CONVERTER_TOOL_EVENTS,
|
|
18759
18844
|
toolRouter,
|
|
18760
18845
|
responseMeta: { id, created, model },
|
|
18846
|
+
passThroughTracker,
|
|
18761
18847
|
onToolUpdate: (update) => {
|
|
18762
18848
|
res.write(formatToolUpdateEvent(update));
|
|
18763
18849
|
},
|
|
@@ -18828,6 +18914,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18828
18914
|
suppressConverterToolEvents: SUPPRESS_CONVERTER_TOOL_EVENTS,
|
|
18829
18915
|
toolRouter,
|
|
18830
18916
|
responseMeta: { id, created, model },
|
|
18917
|
+
passThroughTracker,
|
|
18831
18918
|
onToolUpdate: (update) => {
|
|
18832
18919
|
res.write(formatToolUpdateEvent(update));
|
|
18833
18920
|
},
|
|
@@ -18874,7 +18961,7 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18874
18961
|
perf.mark("request:done");
|
|
18875
18962
|
perf.summarize();
|
|
18876
18963
|
const stderrText = Buffer.concat(stderrChunks).toString().trim();
|
|
18877
|
-
|
|
18964
|
+
log15.debug("cursor-agent completed (node stream)", {
|
|
18878
18965
|
code,
|
|
18879
18966
|
stderrChars: stderrText.length
|
|
18880
18967
|
});
|
|
@@ -18891,6 +18978,13 @@ async function ensureCursorProxyServer(workspaceDirectory, toolRouter) {
|
|
|
18891
18978
|
res.end();
|
|
18892
18979
|
return;
|
|
18893
18980
|
}
|
|
18981
|
+
const passThroughSummary = passThroughTracker.getSummary();
|
|
18982
|
+
if (passThroughSummary.hasActivity) {
|
|
18983
|
+
await toastService.showPassThroughSummary(passThroughSummary.tools);
|
|
18984
|
+
}
|
|
18985
|
+
if (passThroughSummary.errors.length > 0) {
|
|
18986
|
+
await toastService.showErrorSummary(passThroughSummary.errors);
|
|
18987
|
+
}
|
|
18894
18988
|
const doneChunk = {
|
|
18895
18989
|
id,
|
|
18896
18990
|
object: "chat.completion.chunk",
|
|
@@ -19095,7 +19189,7 @@ function buildToolHookEntries(registry2, fallbackBaseDir) {
|
|
|
19095
19189
|
const normalizedArgs = applyToolContextDefaults(toolName, args, context, fallbackBaseDir, sessionWorkspaceBySession);
|
|
19096
19190
|
return await handler(normalizedArgs);
|
|
19097
19191
|
} catch (error45) {
|
|
19098
|
-
|
|
19192
|
+
log15.debug("Tool hook execution failed", { tool: toolName, error: String(error45?.message || error45) });
|
|
19099
19193
|
throw error45;
|
|
19100
19194
|
}
|
|
19101
19195
|
}
|
|
@@ -19107,9 +19201,9 @@ function buildToolHookEntries(registry2, fallbackBaseDir) {
|
|
|
19107
19201
|
}
|
|
19108
19202
|
return entries;
|
|
19109
19203
|
}
|
|
19110
|
-
var
|
|
19204
|
+
var log15, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID = "cursor-acp", CURSOR_PROVIDER_PREFIX, CURSOR_PROXY_HOST = "127.0.0.1", CURSOR_PROXY_DEFAULT_PORT = 32124, CURSOR_PROXY_DEFAULT_BASE_URL, REUSE_EXISTING_PROXY, SESSION_WORKSPACE_CACHE_LIMIT = 200, FORCE_TOOL_MODE, EMIT_TOOL_UPDATES, FORWARD_TOOL_CALLS, TOOL_LOOP_MODE_RAW, TOOL_LOOP_MODE, TOOL_LOOP_MODE_VALID, PROVIDER_BOUNDARY_MODE_RAW, PROVIDER_BOUNDARY_MODE, PROVIDER_BOUNDARY_MODE_VALID, LEGACY_PROVIDER_BOUNDARY, PROVIDER_BOUNDARY, ENABLE_PROVIDER_BOUNDARY_AUTOFALLBACK, TOOL_LOOP_MAX_REPEAT_RAW, TOOL_LOOP_MAX_REPEAT, TOOL_LOOP_MAX_REPEAT_VALID, PROXY_EXECUTE_TOOL_CALLS, SUPPRESS_CONVERTER_TOOL_EVENTS, SHOULD_EMIT_TOOL_UPDATES, CursorPlugin = async ({ $, directory, worktree, client: client3, serverUrl }) => {
|
|
19111
19205
|
const workspaceDirectory = resolveWorkspaceDirectory(worktree, directory);
|
|
19112
|
-
|
|
19206
|
+
log15.debug("Plugin initializing", {
|
|
19113
19207
|
directory,
|
|
19114
19208
|
worktree,
|
|
19115
19209
|
workspaceDirectory,
|
|
@@ -19117,22 +19211,22 @@ var log14, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID = "cursor-acp", C
|
|
|
19117
19211
|
serverUrl: serverUrl?.toString()
|
|
19118
19212
|
});
|
|
19119
19213
|
if (!TOOL_LOOP_MODE_VALID) {
|
|
19120
|
-
|
|
19214
|
+
log15.warn("Invalid CURSOR_ACP_TOOL_LOOP_MODE; defaulting to opencode", { value: TOOL_LOOP_MODE_RAW });
|
|
19121
19215
|
}
|
|
19122
19216
|
if (!PROVIDER_BOUNDARY_MODE_VALID) {
|
|
19123
|
-
|
|
19217
|
+
log15.warn("Invalid CURSOR_ACP_PROVIDER_BOUNDARY; defaulting to v1", {
|
|
19124
19218
|
value: PROVIDER_BOUNDARY_MODE_RAW
|
|
19125
19219
|
});
|
|
19126
19220
|
}
|
|
19127
19221
|
if (!TOOL_LOOP_MAX_REPEAT_VALID) {
|
|
19128
|
-
|
|
19222
|
+
log15.warn("Invalid CURSOR_ACP_TOOL_LOOP_MAX_REPEAT; defaulting to 3", {
|
|
19129
19223
|
value: TOOL_LOOP_MAX_REPEAT_RAW
|
|
19130
19224
|
});
|
|
19131
19225
|
}
|
|
19132
19226
|
if (ENABLE_PROVIDER_BOUNDARY_AUTOFALLBACK && PROVIDER_BOUNDARY.mode !== "v1") {
|
|
19133
|
-
|
|
19227
|
+
log15.debug("Provider boundary auto-fallback is enabled but inactive unless mode=v1");
|
|
19134
19228
|
}
|
|
19135
|
-
|
|
19229
|
+
log15.info("Tool loop mode configured", {
|
|
19136
19230
|
mode: TOOL_LOOP_MODE,
|
|
19137
19231
|
providerBoundary: PROVIDER_BOUNDARY.mode,
|
|
19138
19232
|
proxyExecToolCalls: PROXY_EXECUTE_TOOL_CALLS,
|
|
@@ -19140,12 +19234,14 @@ var log14, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID = "cursor-acp", C
|
|
|
19140
19234
|
toolLoopMaxRepeat: TOOL_LOOP_MAX_REPEAT
|
|
19141
19235
|
});
|
|
19142
19236
|
await ensurePluginDirectory();
|
|
19237
|
+
toastService.setClient(client3);
|
|
19238
|
+
toastService.setClient(client3);
|
|
19143
19239
|
const toolsEnabled = process.env.CURSOR_ACP_ENABLE_OPENCODE_TOOLS !== "false";
|
|
19144
19240
|
const legacyProxyToolPathsEnabled = toolsEnabled && TOOL_LOOP_MODE === "proxy-exec";
|
|
19145
19241
|
if (toolsEnabled && TOOL_LOOP_MODE === "opencode") {
|
|
19146
|
-
|
|
19242
|
+
log15.debug("OpenCode mode active; skipping legacy SDK/MCP discovery and proxy-side tool execution");
|
|
19147
19243
|
} else if (toolsEnabled && TOOL_LOOP_MODE === "off") {
|
|
19148
|
-
|
|
19244
|
+
log15.debug("Tool loop mode off; proxy-side tool execution disabled");
|
|
19149
19245
|
}
|
|
19150
19246
|
const serverClient = legacyProxyToolPathsEnabled ? createOpencodeClient({ baseUrl: serverUrl.toString(), directory: workspaceDirectory }) : null;
|
|
19151
19247
|
const discovery = legacyProxyToolPathsEnabled ? new OpenCodeToolDiscovery(serverClient ?? client3) : null;
|
|
@@ -19197,7 +19293,7 @@ var log14, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID = "cursor-acp", C
|
|
|
19197
19293
|
discoveredList = await discovery.listTools();
|
|
19198
19294
|
discoveredList.forEach((t) => toolsByName.set(t.name, t));
|
|
19199
19295
|
} catch (err) {
|
|
19200
|
-
|
|
19296
|
+
log15.debug("Tool discovery failed, using local tools only", { error: String(err) });
|
|
19201
19297
|
}
|
|
19202
19298
|
}
|
|
19203
19299
|
const allTools = [...localTools, ...discoveredList];
|
|
@@ -19227,11 +19323,11 @@ var log14, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID = "cursor-acp", C
|
|
|
19227
19323
|
}
|
|
19228
19324
|
lastToolNames = toolEntries.map((e) => e.function.name);
|
|
19229
19325
|
lastToolMap = allTools.map((t) => ({ id: t.id, name: t.name }));
|
|
19230
|
-
|
|
19326
|
+
log15.debug("Tools refreshed", { local: localTools.length, discovered: discoveredList.length, total: toolEntries.length });
|
|
19231
19327
|
return toolEntries;
|
|
19232
19328
|
}
|
|
19233
19329
|
const proxyBaseURL = await ensureCursorProxyServer(workspaceDirectory, router);
|
|
19234
|
-
|
|
19330
|
+
log15.debug("Proxy server started", { baseURL: proxyBaseURL });
|
|
19235
19331
|
const toolHookEntries = buildToolHookEntries(localRegistry, workspaceDirectory);
|
|
19236
19332
|
return {
|
|
19237
19333
|
tool: toolHookEntries,
|
|
@@ -19246,9 +19342,9 @@ var log14, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID = "cursor-acp", C
|
|
|
19246
19342
|
type: "oauth",
|
|
19247
19343
|
async authorize() {
|
|
19248
19344
|
try {
|
|
19249
|
-
|
|
19345
|
+
log15.info("Starting OAuth flow");
|
|
19250
19346
|
const { url: url2, instructions, callback } = await startCursorOAuth();
|
|
19251
|
-
|
|
19347
|
+
log15.debug("Got OAuth URL", { url: url2.substring(0, 50) + "..." });
|
|
19252
19348
|
return {
|
|
19253
19349
|
url: url2,
|
|
19254
19350
|
instructions,
|
|
@@ -19256,7 +19352,7 @@ var log14, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID = "cursor-acp", C
|
|
|
19256
19352
|
callback
|
|
19257
19353
|
};
|
|
19258
19354
|
} catch (error45) {
|
|
19259
|
-
|
|
19355
|
+
log15.error("OAuth error", { error: error45 });
|
|
19260
19356
|
throw error45;
|
|
19261
19357
|
}
|
|
19262
19358
|
}
|
|
@@ -19280,10 +19376,10 @@ var log14, DEBUG_LOG_DIR2, DEBUG_LOG_FILE2, CURSOR_PROVIDER_ID = "cursor-acp", C
|
|
|
19280
19376
|
output.options.tools = resolved.tools;
|
|
19281
19377
|
} else if (resolved.action === "preserve") {
|
|
19282
19378
|
const count = Array.isArray(existingTools) ? existingTools.length : 0;
|
|
19283
|
-
|
|
19379
|
+
log15.debug("Using OpenCode-provided tools from chat.params", { count });
|
|
19284
19380
|
}
|
|
19285
19381
|
} catch (err) {
|
|
19286
|
-
|
|
19382
|
+
log15.debug("Failed to refresh tools", { error: String(err) });
|
|
19287
19383
|
}
|
|
19288
19384
|
}
|
|
19289
19385
|
},
|
|
@@ -19316,9 +19412,10 @@ var init_plugin = __esm(() => {
|
|
|
19316
19412
|
init_executor();
|
|
19317
19413
|
init_boundary();
|
|
19318
19414
|
init_runtime_interception();
|
|
19415
|
+
init_toast_service();
|
|
19319
19416
|
init_tool_schema_compat();
|
|
19320
19417
|
init_tool_loop_guard();
|
|
19321
|
-
|
|
19418
|
+
log15 = createLogger("plugin");
|
|
19322
19419
|
DEBUG_LOG_DIR2 = join4(homedir4(), ".config", "opencode", "logs");
|
|
19323
19420
|
DEBUG_LOG_FILE2 = join4(DEBUG_LOG_DIR2, "tool-loop-debug.log");
|
|
19324
19421
|
CURSOR_PROVIDER_PREFIX = `${CURSOR_PROVIDER_ID}/`;
|
|
@@ -19562,7 +19659,7 @@ init_logger();
|
|
|
19562
19659
|
import { execSync } from "node:child_process";
|
|
19563
19660
|
import { createServer } from "node:net";
|
|
19564
19661
|
import { platform as platform2 } from "node:os";
|
|
19565
|
-
var
|
|
19662
|
+
var log16 = createLogger("proxy-server");
|
|
19566
19663
|
var DEFAULT_PORT = 32124;
|
|
19567
19664
|
var PORT_RANGE_SIZE = 256;
|
|
19568
19665
|
async function isPortAvailable(port, host) {
|
|
@@ -19609,11 +19706,11 @@ function getUsedPortsInRange(minPort, maxPort) {
|
|
|
19609
19706
|
}
|
|
19610
19707
|
}
|
|
19611
19708
|
} else {
|
|
19612
|
-
|
|
19709
|
+
log16.debug(`Port detection not supported on ${os2}. Using probe-based discovery.`);
|
|
19613
19710
|
}
|
|
19614
19711
|
} catch (error45) {
|
|
19615
19712
|
const msg = error45 instanceof Error ? error45.message : String(error45);
|
|
19616
|
-
|
|
19713
|
+
log16.debug(`Port detection failed: ${msg}. Using probe-based discovery.`);
|
|
19617
19714
|
}
|
|
19618
19715
|
return used;
|
|
19619
19716
|
}
|
|
@@ -19664,7 +19761,7 @@ function createProxyServer(config2) {
|
|
|
19664
19761
|
const err = error45 instanceof Error ? error45 : new Error(String(error45));
|
|
19665
19762
|
const isPortInUse = err.message.includes("EADDRINUSE") || err.message.includes("address already in use") || err.message.includes("port is already in use");
|
|
19666
19763
|
if (!isPortInUse) {
|
|
19667
|
-
|
|
19764
|
+
log16.debug(`Unexpected error starting on port ${port}: ${err.message}`);
|
|
19668
19765
|
}
|
|
19669
19766
|
return { success: false, error: err };
|
|
19670
19767
|
}
|
|
@@ -19680,13 +19777,13 @@ function createProxyServer(config2) {
|
|
|
19680
19777
|
if (result.success) {
|
|
19681
19778
|
port = requestedPort;
|
|
19682
19779
|
} else {
|
|
19683
|
-
|
|
19780
|
+
log16.debug(`Requested port ${requestedPort} unavailable: ${result.error?.message ?? "unknown"}. Falling back to automatic port selection.`);
|
|
19684
19781
|
port = await findAvailablePort(host);
|
|
19685
19782
|
const fallbackResult = tryStart(port);
|
|
19686
19783
|
if (!fallbackResult.success) {
|
|
19687
19784
|
throw new Error(`Failed to start server on port ${requestedPort} (${result.error?.message ?? "unknown"}) ` + `and fallback port ${port} (${fallbackResult.error?.message ?? "unknown"})`);
|
|
19688
19785
|
}
|
|
19689
|
-
|
|
19786
|
+
log16.debug(`Server started on fallback port ${port} instead of requested port ${requestedPort}`);
|
|
19690
19787
|
}
|
|
19691
19788
|
} else {
|
|
19692
19789
|
port = await findAvailablePort(host);
|
|
@@ -20032,11 +20129,11 @@ init_auth();
|
|
|
20032
20129
|
init_auth();
|
|
20033
20130
|
init_logger();
|
|
20034
20131
|
import { existsSync as existsSync5 } from "fs";
|
|
20035
|
-
var
|
|
20132
|
+
var log17 = createLogger("status");
|
|
20036
20133
|
function checkAuthStatus() {
|
|
20037
20134
|
const authFilePath = getAuthFilePath();
|
|
20038
20135
|
const exists = existsSync5(authFilePath);
|
|
20039
|
-
|
|
20136
|
+
log17.debug("Checking auth status", { path: authFilePath });
|
|
20040
20137
|
if (exists) {
|
|
20041
20138
|
return {
|
|
20042
20139
|
authenticated: true,
|