opencode-gitlab-duo-agentic 0.2.18 → 0.2.21
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 +115 -7
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -793,11 +793,16 @@ var WorkflowSession = class {
|
|
|
793
793
|
#queue;
|
|
794
794
|
#startRequestSent = false;
|
|
795
795
|
#pendingApproval = false;
|
|
796
|
-
|
|
796
|
+
#onWorkflowCreated;
|
|
797
|
+
constructor(client, modelId, cwd, options) {
|
|
797
798
|
this.#client = client;
|
|
798
799
|
this.#tokenService = new WorkflowTokenService(client);
|
|
799
800
|
this.#modelId = modelId;
|
|
800
801
|
this.#cwd = cwd;
|
|
802
|
+
if (options?.existingWorkflowId) {
|
|
803
|
+
this.#workflowId = options.existingWorkflowId;
|
|
804
|
+
}
|
|
805
|
+
this.#onWorkflowCreated = options?.onWorkflowCreated;
|
|
801
806
|
}
|
|
802
807
|
/**
|
|
803
808
|
* Opt-in: override the server-side system prompt and/or register MCP tools.
|
|
@@ -905,6 +910,25 @@ var WorkflowSession = class {
|
|
|
905
910
|
}
|
|
906
911
|
});
|
|
907
912
|
}
|
|
913
|
+
/**
|
|
914
|
+
* Send an HTTP response back to DWS on the existing connection.
|
|
915
|
+
* Used for gitlab_api_request which requires httpResponse (not plainTextResponse).
|
|
916
|
+
*/
|
|
917
|
+
sendHttpResult(requestId, statusCode, headers, body, error) {
|
|
918
|
+
dlog(`sendHttpResult: reqId=${requestId} status=${statusCode} body=${body.length}b error=${error ?? "none"} socket=${!!this.#socket}`);
|
|
919
|
+
if (!this.#socket) throw new Error("Not connected");
|
|
920
|
+
this.#socket.send({
|
|
921
|
+
actionResponse: {
|
|
922
|
+
requestID: requestId,
|
|
923
|
+
httpResponse: {
|
|
924
|
+
statusCode,
|
|
925
|
+
headers,
|
|
926
|
+
body,
|
|
927
|
+
error: error ?? ""
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
});
|
|
931
|
+
}
|
|
908
932
|
/**
|
|
909
933
|
* Wait for the next event from the session.
|
|
910
934
|
* Returns null when the stream is closed (turn complete or connection lost).
|
|
@@ -948,6 +972,12 @@ var WorkflowSession = class {
|
|
|
948
972
|
return;
|
|
949
973
|
}
|
|
950
974
|
const toolAction = action;
|
|
975
|
+
if (toolAction.runHTTPRequest && toolAction.requestID) {
|
|
976
|
+
dlog(`standalone: httpRequest ${toolAction.runHTTPRequest.method} ${toolAction.runHTTPRequest.path} reqId=${toolAction.requestID}`);
|
|
977
|
+
this.#executeHttpRequest(toolAction.requestID, toolAction.runHTTPRequest).catch(() => {
|
|
978
|
+
});
|
|
979
|
+
return;
|
|
980
|
+
}
|
|
951
981
|
const mapped = mapActionToToolRequest(toolAction);
|
|
952
982
|
if (mapped) {
|
|
953
983
|
dlog(`standalone: ${mapped.toolName} reqId=${mapped.requestId} args=${JSON.stringify(mapped.args).slice(0, 200)}`);
|
|
@@ -962,6 +992,42 @@ var WorkflowSession = class {
|
|
|
962
992
|
}
|
|
963
993
|
}
|
|
964
994
|
// ---------------------------------------------------------------------------
|
|
995
|
+
// Private: HTTP request handling (gitlab_api_request)
|
|
996
|
+
// ---------------------------------------------------------------------------
|
|
997
|
+
/**
|
|
998
|
+
* Execute a GitLab API request directly and send the response as httpResponse.
|
|
999
|
+
* DWS is the only action that expects httpResponse instead of plainTextResponse.
|
|
1000
|
+
* Runs async in the background (fire-and-forget from #handleAction).
|
|
1001
|
+
*/
|
|
1002
|
+
async #executeHttpRequest(requestId, request2) {
|
|
1003
|
+
try {
|
|
1004
|
+
const url = `${this.#client.instanceUrl}/api/v4/${request2.path}`;
|
|
1005
|
+
dlog(`httpRequest: ${request2.method} ${request2.path} reqId=${requestId}`);
|
|
1006
|
+
const init = {
|
|
1007
|
+
method: request2.method,
|
|
1008
|
+
headers: {
|
|
1009
|
+
"authorization": `Bearer ${this.#client.token}`,
|
|
1010
|
+
"content-type": "application/json"
|
|
1011
|
+
}
|
|
1012
|
+
};
|
|
1013
|
+
if (request2.body) {
|
|
1014
|
+
init.body = request2.body;
|
|
1015
|
+
}
|
|
1016
|
+
const response = await fetch(url, init);
|
|
1017
|
+
const body = await response.text();
|
|
1018
|
+
const headers = {};
|
|
1019
|
+
response.headers.forEach((value, key) => {
|
|
1020
|
+
headers[key] = value;
|
|
1021
|
+
});
|
|
1022
|
+
dlog(`httpRequest: ${request2.method} ${request2.path} \u2192 ${response.status} body=${body.length}b`);
|
|
1023
|
+
this.sendHttpResult(requestId, response.status, headers, body);
|
|
1024
|
+
} catch (error) {
|
|
1025
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1026
|
+
dlog(`httpRequest: ERROR ${request2.method} ${request2.path} \u2192 ${message}`);
|
|
1027
|
+
this.sendHttpResult(requestId, 0, {}, "", message);
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
// ---------------------------------------------------------------------------
|
|
965
1031
|
// Private: connection management
|
|
966
1032
|
// ---------------------------------------------------------------------------
|
|
967
1033
|
/**
|
|
@@ -1027,7 +1093,9 @@ var WorkflowSession = class {
|
|
|
1027
1093
|
const details = [created.message, created.error].filter(Boolean).join("; ");
|
|
1028
1094
|
throw new Error(`failed to create workflow${details ? `: ${details}` : ""}`);
|
|
1029
1095
|
}
|
|
1030
|
-
|
|
1096
|
+
const workflowId = String(created.id);
|
|
1097
|
+
this.#onWorkflowCreated?.(workflowId);
|
|
1098
|
+
return workflowId;
|
|
1031
1099
|
}
|
|
1032
1100
|
async #loadProjectContext() {
|
|
1033
1101
|
if (this.#projectPath !== void 0) return;
|
|
@@ -1193,10 +1261,7 @@ function mapDuoToolRequest(toolName, args) {
|
|
|
1193
1261
|
switch (toolName) {
|
|
1194
1262
|
case "list_dir": {
|
|
1195
1263
|
const directory = asString2(args.directory) ?? ".";
|
|
1196
|
-
return {
|
|
1197
|
-
toolName: "bash",
|
|
1198
|
-
args: { command: `ls -la ${shellQuote(directory)}`, description: "List directory contents", workdir: "." }
|
|
1199
|
-
};
|
|
1264
|
+
return { toolName: "read", args: { filePath: directory } };
|
|
1200
1265
|
}
|
|
1201
1266
|
case "read_file": {
|
|
1202
1267
|
const filePath = asString2(args.file_path) ?? asString2(args.filepath) ?? asString2(args.filePath) ?? asString2(args.path);
|
|
@@ -1408,6 +1473,39 @@ CODE QUALITY:
|
|
|
1408
1473
|
</communication>
|
|
1409
1474
|
</system-reminder>`;
|
|
1410
1475
|
|
|
1476
|
+
// src/workflow/session-store.ts
|
|
1477
|
+
import { readFileSync, writeFileSync, mkdirSync } from "fs";
|
|
1478
|
+
import { join } from "path";
|
|
1479
|
+
import { homedir } from "os";
|
|
1480
|
+
function getStorePath() {
|
|
1481
|
+
const dir = process.env.XDG_CACHE_HOME?.trim() ? join(process.env.XDG_CACHE_HOME, "opencode") : join(homedir(), ".cache", "opencode");
|
|
1482
|
+
return join(dir, "duo-workflow-sessions.json");
|
|
1483
|
+
}
|
|
1484
|
+
function readStore() {
|
|
1485
|
+
try {
|
|
1486
|
+
return JSON.parse(readFileSync(getStorePath(), "utf8"));
|
|
1487
|
+
} catch {
|
|
1488
|
+
return {};
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
function writeStore(store) {
|
|
1492
|
+
try {
|
|
1493
|
+
const storePath = getStorePath();
|
|
1494
|
+
mkdirSync(join(storePath, ".."), { recursive: true });
|
|
1495
|
+
writeFileSync(storePath, JSON.stringify(store, null, 2), "utf8");
|
|
1496
|
+
} catch {
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
function saveWorkflowId(key, workflowId) {
|
|
1500
|
+
const store = readStore();
|
|
1501
|
+
store[key] = workflowId;
|
|
1502
|
+
writeStore(store);
|
|
1503
|
+
}
|
|
1504
|
+
function loadWorkflowId(key) {
|
|
1505
|
+
const store = readStore();
|
|
1506
|
+
return store[key];
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1411
1509
|
// src/provider/duo-workflow-model.ts
|
|
1412
1510
|
var sessions = /* @__PURE__ */ new Map();
|
|
1413
1511
|
var UNKNOWN_USAGE = {
|
|
@@ -1685,7 +1783,17 @@ var DuoWorkflowModel = class {
|
|
|
1685
1783
|
const key = sessionKey(this.#client.instanceUrl, this.modelId, sessionID);
|
|
1686
1784
|
const existing = sessions.get(key);
|
|
1687
1785
|
if (existing) return existing;
|
|
1688
|
-
const
|
|
1786
|
+
const existingWorkflowId = loadWorkflowId(key);
|
|
1787
|
+
if (existingWorkflowId) {
|
|
1788
|
+
dlog(`resolveSession: restored workflowId=${existingWorkflowId} from disk for ${sessionID}`);
|
|
1789
|
+
}
|
|
1790
|
+
const created = new WorkflowSession(this.#client, this.modelId, this.#cwd, {
|
|
1791
|
+
existingWorkflowId,
|
|
1792
|
+
onWorkflowCreated: (workflowId) => {
|
|
1793
|
+
dlog(`resolveSession: saving workflowId=${workflowId} for ${sessionID}`);
|
|
1794
|
+
saveWorkflowId(key, workflowId);
|
|
1795
|
+
}
|
|
1796
|
+
});
|
|
1689
1797
|
if (this.#toolsConfig) created.setToolsConfig(this.#toolsConfig);
|
|
1690
1798
|
sessions.set(key, created);
|
|
1691
1799
|
return created;
|