opencode-gitlab-duo-agentic 0.2.11 → 0.2.14

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.
Files changed (2) hide show
  1. package/dist/index.js +78 -15
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -547,24 +547,26 @@ var WORKFLOW_STATUS = {
547
547
  function isCheckpointAction(action) {
548
548
  return "newCheckpoint" in action && action.newCheckpoint != null;
549
549
  }
550
- var TURN_COMPLETE_STATUSES = /* @__PURE__ */ new Set([
551
- WORKFLOW_STATUS.INPUT_REQUIRED,
550
+ var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
552
551
  WORKFLOW_STATUS.FINISHED,
553
552
  WORKFLOW_STATUS.FAILED,
554
- WORKFLOW_STATUS.STOPPED,
555
- WORKFLOW_STATUS.PLAN_APPROVAL_REQUIRED,
556
- WORKFLOW_STATUS.TOOL_CALL_APPROVAL_REQUIRED
553
+ WORKFLOW_STATUS.STOPPED
557
554
  ]);
558
- function isTurnComplete(status) {
559
- return TURN_COMPLETE_STATUSES.has(status);
555
+ function isTerminal(status) {
556
+ return TERMINAL_STATUSES.has(status);
560
557
  }
561
- var AWAITING_RESPONSE_STATUSES = /* @__PURE__ */ new Set([
562
- WORKFLOW_STATUS.TOOL_CALL_APPROVAL_REQUIRED,
558
+ var TURN_BOUNDARY_STATUSES = /* @__PURE__ */ new Set([
563
559
  WORKFLOW_STATUS.INPUT_REQUIRED,
564
560
  WORKFLOW_STATUS.PLAN_APPROVAL_REQUIRED
565
561
  ]);
566
- function isAwaitingResponse(status) {
567
- return AWAITING_RESPONSE_STATUSES.has(status);
562
+ function isTurnBoundary(status) {
563
+ return TURN_BOUNDARY_STATUSES.has(status);
564
+ }
565
+ function isToolApproval(status) {
566
+ return status === WORKFLOW_STATUS.TOOL_CALL_APPROVAL_REQUIRED;
567
+ }
568
+ function isTurnComplete(status) {
569
+ return isTerminal(status) || isTurnBoundary(status);
568
570
  }
569
571
 
570
572
  // src/workflow/websocket-client.ts
@@ -798,6 +800,7 @@ var WorkflowSession = class {
798
800
  #socket;
799
801
  #queue;
800
802
  #startRequestSent = false;
803
+ #pendingApproval = false;
801
804
  constructor(client, modelId, cwd) {
802
805
  this.#client = client;
803
806
  this.#tokenService = new WorkflowTokenService(client);
@@ -821,6 +824,7 @@ var WorkflowSession = class {
821
824
  this.#checkpoint = createCheckpointState();
822
825
  this.#tokenService.clear();
823
826
  this.#closeConnection();
827
+ this.#pendingApproval = false;
824
828
  this.#startRequestSent = false;
825
829
  }
826
830
  // ---------------------------------------------------------------------------
@@ -831,13 +835,29 @@ var WorkflowSession = class {
831
835
  if (!this.#workflowId) {
832
836
  this.#workflowId = await this.#createWorkflow(goal);
833
837
  }
838
+ const queue = new AsyncQueue();
839
+ this.#queue = queue;
840
+ await this.#connectSocket(queue);
841
+ }
842
+ /**
843
+ * Open a WebSocket and wire its callbacks to the given queue.
844
+ * Replaces any existing socket but does NOT create a new queue.
845
+ */
846
+ async #connectSocket(queue) {
834
847
  await this.#tokenService.get(this.#rootNamespaceId);
835
- this.#queue = new AsyncQueue();
836
- const queue = this.#queue;
837
848
  const socket = new WorkflowWebSocketClient({
838
849
  action: (action) => this.#handleAction(action, queue),
839
850
  error: (error) => queue.push({ type: "error", message: error.message }),
840
- close: (_code, _reason) => queue.close()
851
+ close: (_code, _reason) => {
852
+ this.#socket = void 0;
853
+ if (this.#pendingApproval) {
854
+ this.#pendingApproval = false;
855
+ this.#reconnectWithApproval(queue);
856
+ } else {
857
+ this.#queue = void 0;
858
+ queue.close();
859
+ }
860
+ }
841
861
  });
842
862
  const url = buildWebSocketUrl(this.#client.instanceUrl, this.#modelId);
843
863
  await socket.connect(url, {
@@ -912,10 +932,15 @@ var WorkflowSession = class {
912
932
  #handleAction(action, queue) {
913
933
  if (isCheckpointAction(action)) {
914
934
  const ckpt = action.newCheckpoint.checkpoint;
935
+ const status = action.newCheckpoint.status;
915
936
  const deltas = extractAgentTextDeltas(ckpt, this.#checkpoint);
916
937
  for (const delta of deltas) {
917
938
  queue.push({ type: "text-delta", value: delta });
918
939
  }
940
+ if (isToolApproval(status)) {
941
+ this.#pendingApproval = true;
942
+ return;
943
+ }
919
944
  const toolRequests = extractToolRequests(ckpt, this.#checkpoint);
920
945
  for (const req of toolRequests) {
921
946
  queue.push({
@@ -925,7 +950,7 @@ var WorkflowSession = class {
925
950
  args: req.args
926
951
  });
927
952
  }
928
- if (isTurnComplete(action.newCheckpoint.status) && !isAwaitingResponse(action.newCheckpoint.status)) {
953
+ if (isTurnComplete(status)) {
929
954
  queue.close();
930
955
  this.#closeConnection();
931
956
  }
@@ -945,7 +970,45 @@ var WorkflowSession = class {
945
970
  // ---------------------------------------------------------------------------
946
971
  // Private: connection management
947
972
  // ---------------------------------------------------------------------------
973
+ /**
974
+ * Auto-approve at DWS protocol level and reconnect.
975
+ *
976
+ * DWS closed the stream after TOOL_CALL_APPROVAL_REQUIRED. We open a new
977
+ * WebSocket, send startRequest with approval, and wire it to the SAME queue
978
+ * so Phase 3 in the model continues consuming events seamlessly.
979
+ *
980
+ * The actual tool execution still goes through OpenCode's permission system
981
+ * when the standalone action arrives on the new stream.
982
+ */
983
+ #reconnectWithApproval(queue) {
984
+ this.#connectSocket(queue).then(() => {
985
+ if (!this.#socket || !this.#workflowId) {
986
+ queue.close();
987
+ return;
988
+ }
989
+ const mcpTools = this.#toolsConfig?.mcpTools ?? [];
990
+ this.#socket.send({
991
+ startRequest: {
992
+ workflowID: this.#workflowId,
993
+ clientVersion: WORKFLOW_CLIENT_VERSION,
994
+ workflowDefinition: WORKFLOW_DEFINITION,
995
+ goal: "",
996
+ workflowMetadata: JSON.stringify({ extended_logging: false }),
997
+ clientCapabilities: ["shell_command"],
998
+ mcpTools,
999
+ additional_context: [],
1000
+ preapproved_tools: mcpTools.map((t) => t.name),
1001
+ approval: { approval: {} }
1002
+ }
1003
+ });
1004
+ this.#startRequestSent = true;
1005
+ }).catch(() => {
1006
+ this.#queue = void 0;
1007
+ queue.close();
1008
+ });
1009
+ }
948
1010
  #closeConnection() {
1011
+ this.#pendingApproval = false;
949
1012
  this.#socket?.close();
950
1013
  this.#socket = void 0;
951
1014
  this.#queue = void 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-gitlab-duo-agentic",
3
- "version": "0.2.11",
3
+ "version": "0.2.14",
4
4
  "description": "OpenCode plugin and provider for GitLab Duo Agentic workflows",
5
5
  "license": "MIT",
6
6
  "type": "module",