@adhdev/daemon-core 0.9.82-rc.356 → 0.9.82-rc.358

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.mjs CHANGED
@@ -311,10 +311,10 @@ function readInjected(value) {
311
311
  }
312
312
  function getDaemonBuildInfo() {
313
313
  if (cached) return cached;
314
- const commit = readInjected(true ? "91500e054cf2b6258f6041f90c18be03ad05a8ad" : void 0) ?? "unknown";
315
- const commitShort = readInjected(true ? "91500e05" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
316
- const version = readInjected(true ? "0.9.82-rc.356" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
317
- const builtAt = readInjected(true ? "2026-06-22T22:47:29.082Z" : void 0);
314
+ const commit = readInjected(true ? "7210e80591d8d9ab378ee786ffb233027437461a" : void 0) ?? "unknown";
315
+ const commitShort = readInjected(true ? "7210e805" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
316
+ const version = readInjected(true ? "0.9.82-rc.358" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
317
+ const builtAt = readInjected(true ? "2026-06-23T01:40:53.249Z" : void 0);
318
318
  cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
319
319
  return cached;
320
320
  }
@@ -12670,8 +12670,22 @@ function sweepExpiredRemoteIdleSessions() {
12670
12670
  }
12671
12671
  function getMeshWithCache(components, meshId) {
12672
12672
  const localMesh = getMesh(meshId);
12673
- if (localMesh) return localMesh;
12674
- return components.router?.getCachedInlineMesh(meshId);
12673
+ const cachedMesh = components.router?.getCachedInlineMesh(meshId);
12674
+ if (!localMesh) return cachedMesh;
12675
+ if (!cachedMesh) return localMesh;
12676
+ return mergeInlineCacheOnlyNodes(localMesh, cachedMesh);
12677
+ }
12678
+ function mergeInlineCacheOnlyNodes(localMesh, cachedMesh) {
12679
+ const localNodes = Array.isArray(localMesh?.nodes) ? localMesh.nodes : [];
12680
+ const cachedNodes = Array.isArray(cachedMesh?.nodes) ? cachedMesh.nodes : [];
12681
+ if (!cachedNodes.length) return localMesh;
12682
+ const cacheOnly = cachedNodes.filter((cachedNode) => {
12683
+ const cachedId = readMeshNodeId(cachedNode);
12684
+ if (!cachedId) return false;
12685
+ return !localNodes.some((localNode) => meshNodeIdMatches(localNode, cachedId));
12686
+ });
12687
+ if (!cacheOnly.length) return localMesh;
12688
+ return { ...localMesh, nodes: [...localNodes, ...cacheOnly] };
12675
12689
  }
12676
12690
  function isIntentionalCleanupStopMetadata(event) {
12677
12691
  return event.intentional === true || event.intentionalStop === true || event.operatorCleanup === true || event.reason === "operator_cleanup" || event.stopReason === "operator_cleanup" || event.cleanupReason === "operator_cleanup" || event.source === "mesh_cleanup_sessions" || event.source === "mesh_remove_node";
@@ -13734,7 +13748,7 @@ function injectMeshSystemMessage(components, args) {
13734
13748
  occurredAt: occurredAtMs != null ? new Date(occurredAtMs).toISOString() : void 0,
13735
13749
  taskId: eventTaskId
13736
13750
  });
13737
- const leaveDirectDispatchActive = !task && opts?.tentativeIfDirect === true;
13751
+ const leaveDirectDispatchActive = !task && opts?.tentativeIfDirect === true || !eventTaskId && !sessionHasActiveAssignment(args.meshId, sessionId);
13738
13752
  if (!leaveDirectDispatchActive) {
13739
13753
  updateDirectDispatchStatus(args.meshId, sessionId, outcome, eventTaskId);
13740
13754
  }
@@ -13833,7 +13847,9 @@ function injectMeshSystemMessage(components, args) {
13833
13847
  }
13834
13848
  if (sessionId) {
13835
13849
  const startedTaskId = readNonEmptyString2(args.metadataEvent.taskId) || void 0;
13836
- updateDirectDispatchStatus(args.meshId, sessionId, "acked", startedTaskId);
13850
+ if (startedTaskId || sessionHasActiveAssignment(args.meshId, sessionId)) {
13851
+ updateDirectDispatchStatus(args.meshId, sessionId, "acked", startedTaskId);
13852
+ }
13837
13853
  const activeDeliveries = (() => {
13838
13854
  try {
13839
13855
  return MeshRuntimeStore.getInstance().getActiveSessionDeliveries(args.meshId, sessionId);
@@ -14008,6 +14024,76 @@ function injectMeshSystemMessage(components, args) {
14008
14024
  }
14009
14025
  return { success: true, forwarded: 0 };
14010
14026
  }
14027
+ function buildRelayMetadataEvent(payload) {
14028
+ const relayModalMessage = readNonEmptyString2(payload.modalMessage);
14029
+ const relayModalButtons = Array.isArray(payload.modalButtons) ? payload.modalButtons.filter((b) => typeof b === "string" && b.trim().length > 0) : null;
14030
+ return {
14031
+ // Preserve the dispatch task id across the machine boundary. The `received` trace
14032
+ // stage reads payload.taskId; without mirroring it here the rebuilt metadataEvent
14033
+ // loses it, so injectMeshSystemMessage's traceCtx.taskId and the
14034
+ // updateDirectDispatchStatus(eventTaskId) call go undefined — the EvtTrace
14035
+ // queued/surfaced stages show task=- and the direct-dispatch ledger falls back to a
14036
+ // session_id match (which can flip a sibling row). The local in-process forward path
14037
+ // keeps event.taskId/meshActiveTaskId for free; this mirrors it for the remote relay.
14038
+ // Same taskId/meshActiveTaskId ordering the local unroutable trace uses.
14039
+ taskId: readNonEmptyString2(payload.taskId) || readNonEmptyString2(payload.meshActiveTaskId),
14040
+ targetSessionId: readNonEmptyString2(payload.targetSessionId) || readNonEmptyString2(payload.sessionId) || readNonEmptyString2(payload.instanceId),
14041
+ providerType: readNonEmptyString2(payload.providerType),
14042
+ providerSessionId: readNonEmptyString2(payload.providerSessionId),
14043
+ // Preserve the originating coordinator SESSION id across the machine boundary so
14044
+ // the completion routes back to the exact coordinator session (multi-coordinator).
14045
+ // buildForwardPayloadFromPending spreads the worker event's metadata, so the id
14046
+ // arrives as payload.meshCoordinatorSessionId; the top-level targetCoordinatorSessionId
14047
+ // is also accepted as a fallback. injectMeshSystemMessage re-derives the routing
14048
+ // anchors from this. Absent → daemon-level fallback (version-skew safe).
14049
+ meshCoordinatorSessionId: readNonEmptyString2(payload.meshCoordinatorSessionId) || readNonEmptyString2(payload.targetCoordinatorSessionId),
14050
+ // Carry the session identity fields the worker provider event emits so the
14051
+ // coordinator's mirror (updateMeshOwnedSession) gets a real workspace/title/
14052
+ // settings. Without these the remote-relay hop reconstructs metadataEvent with
14053
+ // an empty workspace, and the dashboard flaps to the generic
14054
+ // "Terminal (Mesh Node)" title (and degrades the provider label) between live
14055
+ // events and the periodic get_status_metadata snapshot. The local in-process
14056
+ // forward path (onMeshCoordinatorEventForwarded) already preserves these; this
14057
+ // mirrors them for the remote-only relay path.
14058
+ workspace: readNonEmptyString2(payload.workspace) || readNonEmptyString2(payload.workspaceName),
14059
+ workspaceName: readNonEmptyString2(payload.workspaceName) || readNonEmptyString2(payload.workspace),
14060
+ sessionTitle: readNonEmptyString2(payload.sessionTitle),
14061
+ sessionStatus: readNonEmptyString2(payload.sessionStatus),
14062
+ sessionChatStatus: readNonEmptyString2(payload.sessionChatStatus),
14063
+ providerName: readNonEmptyString2(payload.providerName),
14064
+ ...payload.sessionSettings && typeof payload.sessionSettings === "object" && !Array.isArray(payload.sessionSettings) ? { sessionSettings: payload.sessionSettings } : {},
14065
+ finalSummary: readNonEmptyString2(payload.finalSummary) || readNonEmptyString2(payload.summary),
14066
+ // T2: carry the worker's status-snapshot last-message preview across the machine
14067
+ // boundary so a summary-less completion still surfaces the assistant reply in the
14068
+ // coordinator's inbox mirror. resolveMeshSurfacedSessionPreview reads these
14069
+ // (assistant-role only) when finalSummary is absent.
14070
+ lastMessagePreview: readNonEmptyString2(payload.lastMessagePreview),
14071
+ lastMessageRole: readNonEmptyString2(payload.lastMessageRole),
14072
+ ...payload.lastMessageAt !== void 0 ? { lastMessageAt: payload.lastMessageAt } : {},
14073
+ jobId: readNonEmptyString2(payload.jobId),
14074
+ interactionId: readNonEmptyString2(payload.interactionId),
14075
+ status: readNonEmptyString2(payload.status),
14076
+ targetDaemonId: readNonEmptyString2(payload.targetDaemonId),
14077
+ startedAt: readNonEmptyString2(payload.startedAt),
14078
+ completedAt: readNonEmptyString2(payload.completedAt),
14079
+ retryOfJobId: readNonEmptyString2(payload.retryOfJobId),
14080
+ ...relayModalMessage ? { modalMessage: relayModalMessage } : {},
14081
+ ...relayModalButtons && relayModalButtons.length > 0 ? { modalButtons: relayModalButtons } : {},
14082
+ ...payload.result && typeof payload.result === "object" && !Array.isArray(payload.result) ? { result: payload.result } : {},
14083
+ ...payload.completionDiagnostic && typeof payload.completionDiagnostic === "object" && !Array.isArray(payload.completionDiagnostic) ? { completionDiagnostic: payload.completionDiagnostic } : {},
14084
+ ...payload.workerResult && typeof payload.workerResult === "object" && !Array.isArray(payload.workerResult) ? { workerResult: payload.workerResult } : {},
14085
+ ...payload.meshWorkerResult && typeof payload.meshWorkerResult === "object" && !Array.isArray(payload.meshWorkerResult) ? { meshWorkerResult: payload.meshWorkerResult } : {},
14086
+ ...payload.structuredResult && typeof payload.structuredResult === "object" && !Array.isArray(payload.structuredResult) ? { structuredResult: payload.structuredResult } : {},
14087
+ ...payload.timestamp !== void 0 ? { timestamp: payload.timestamp } : {},
14088
+ intentional: payload.intentional === true,
14089
+ intentionalStop: payload.intentionalStop === true,
14090
+ operatorCleanup: payload.operatorCleanup === true,
14091
+ reason: readNonEmptyString2(payload.reason),
14092
+ stopReason: readNonEmptyString2(payload.stopReason),
14093
+ cleanupReason: readNonEmptyString2(payload.cleanupReason),
14094
+ source: readNonEmptyString2(payload.source)
14095
+ };
14096
+ }
14011
14097
  function handleMeshForwardEvent(components, payload) {
14012
14098
  const eventName = readNonEmptyString2(payload.event);
14013
14099
  if (!isMeshCoordinatorEvent(eventName)) {
@@ -14033,70 +14119,12 @@ function handleMeshForwardEvent(components, payload) {
14033
14119
  event: eventName
14034
14120
  });
14035
14121
  const nodeLabel = nodeId ? `Node '${nodeId}'` : workspace ? `Agent at ${workspace}` : "Remote agent";
14036
- const relayModalMessage = readNonEmptyString2(payload.modalMessage);
14037
- const relayModalButtons = Array.isArray(payload.modalButtons) ? payload.modalButtons.filter((b) => typeof b === "string" && b.trim().length > 0) : null;
14038
14122
  return injectMeshSystemMessage(components, {
14039
14123
  meshId,
14040
14124
  nodeId,
14041
14125
  nodeLabel,
14042
14126
  event: eventName,
14043
- metadataEvent: {
14044
- targetSessionId: readNonEmptyString2(payload.targetSessionId) || readNonEmptyString2(payload.sessionId) || readNonEmptyString2(payload.instanceId),
14045
- providerType: readNonEmptyString2(payload.providerType),
14046
- providerSessionId: readNonEmptyString2(payload.providerSessionId),
14047
- // Preserve the originating coordinator SESSION id across the machine boundary so
14048
- // the completion routes back to the exact coordinator session (multi-coordinator).
14049
- // buildForwardPayloadFromPending spreads the worker event's metadata, so the id
14050
- // arrives as payload.meshCoordinatorSessionId; the top-level targetCoordinatorSessionId
14051
- // is also accepted as a fallback. injectMeshSystemMessage re-derives the routing
14052
- // anchors from this. Absent → daemon-level fallback (version-skew safe).
14053
- meshCoordinatorSessionId: readNonEmptyString2(payload.meshCoordinatorSessionId) || readNonEmptyString2(payload.targetCoordinatorSessionId),
14054
- // Carry the session identity fields the worker provider event emits so the
14055
- // coordinator's mirror (updateMeshOwnedSession) gets a real workspace/title/
14056
- // settings. Without these the remote-relay hop reconstructs metadataEvent with
14057
- // an empty workspace, and the dashboard flaps to the generic
14058
- // "Terminal (Mesh Node)" title (and degrades the provider label) between live
14059
- // events and the periodic get_status_metadata snapshot. The local in-process
14060
- // forward path (onMeshCoordinatorEventForwarded) already preserves these; this
14061
- // mirrors them for the remote-only relay path.
14062
- workspace: readNonEmptyString2(payload.workspace) || readNonEmptyString2(payload.workspaceName),
14063
- workspaceName: readNonEmptyString2(payload.workspaceName) || readNonEmptyString2(payload.workspace),
14064
- sessionTitle: readNonEmptyString2(payload.sessionTitle),
14065
- sessionStatus: readNonEmptyString2(payload.sessionStatus),
14066
- sessionChatStatus: readNonEmptyString2(payload.sessionChatStatus),
14067
- providerName: readNonEmptyString2(payload.providerName),
14068
- ...payload.sessionSettings && typeof payload.sessionSettings === "object" && !Array.isArray(payload.sessionSettings) ? { sessionSettings: payload.sessionSettings } : {},
14069
- finalSummary: readNonEmptyString2(payload.finalSummary) || readNonEmptyString2(payload.summary),
14070
- // T2: carry the worker's status-snapshot last-message preview across the machine
14071
- // boundary so a summary-less completion still surfaces the assistant reply in the
14072
- // coordinator's inbox mirror. resolveMeshSurfacedSessionPreview reads these
14073
- // (assistant-role only) when finalSummary is absent.
14074
- lastMessagePreview: readNonEmptyString2(payload.lastMessagePreview),
14075
- lastMessageRole: readNonEmptyString2(payload.lastMessageRole),
14076
- ...payload.lastMessageAt !== void 0 ? { lastMessageAt: payload.lastMessageAt } : {},
14077
- jobId: readNonEmptyString2(payload.jobId),
14078
- interactionId: readNonEmptyString2(payload.interactionId),
14079
- status: readNonEmptyString2(payload.status),
14080
- targetDaemonId: readNonEmptyString2(payload.targetDaemonId),
14081
- startedAt: readNonEmptyString2(payload.startedAt),
14082
- completedAt: readNonEmptyString2(payload.completedAt),
14083
- retryOfJobId: readNonEmptyString2(payload.retryOfJobId),
14084
- ...relayModalMessage ? { modalMessage: relayModalMessage } : {},
14085
- ...relayModalButtons && relayModalButtons.length > 0 ? { modalButtons: relayModalButtons } : {},
14086
- ...payload.result && typeof payload.result === "object" && !Array.isArray(payload.result) ? { result: payload.result } : {},
14087
- ...payload.completionDiagnostic && typeof payload.completionDiagnostic === "object" && !Array.isArray(payload.completionDiagnostic) ? { completionDiagnostic: payload.completionDiagnostic } : {},
14088
- ...payload.workerResult && typeof payload.workerResult === "object" && !Array.isArray(payload.workerResult) ? { workerResult: payload.workerResult } : {},
14089
- ...payload.meshWorkerResult && typeof payload.meshWorkerResult === "object" && !Array.isArray(payload.meshWorkerResult) ? { meshWorkerResult: payload.meshWorkerResult } : {},
14090
- ...payload.structuredResult && typeof payload.structuredResult === "object" && !Array.isArray(payload.structuredResult) ? { structuredResult: payload.structuredResult } : {},
14091
- ...payload.timestamp !== void 0 ? { timestamp: payload.timestamp } : {},
14092
- intentional: payload.intentional === true,
14093
- intentionalStop: payload.intentionalStop === true,
14094
- operatorCleanup: payload.operatorCleanup === true,
14095
- reason: readNonEmptyString2(payload.reason),
14096
- stopReason: readNonEmptyString2(payload.stopReason),
14097
- cleanupReason: readNonEmptyString2(payload.cleanupReason),
14098
- source: readNonEmptyString2(payload.source)
14099
- }
14127
+ metadataEvent: buildRelayMetadataEvent(payload)
14100
14128
  });
14101
14129
  }
14102
14130
  function forwardUnresolvedDelegateEvent(components, routing, event) {
@@ -19509,6 +19537,7 @@ __export(evaluator_exports, {
19509
19537
  evaluateCondition: () => evaluateCondition,
19510
19538
  extractButtonsFromRule: () => extractButtonsFromRule,
19511
19539
  extractTitle: () => extractTitle,
19540
+ lastContiguousNumberedBlock: () => lastContiguousNumberedBlock,
19512
19541
  resolveSections: () => resolveSections,
19513
19542
  sectionText: () => sectionText
19514
19543
  });
@@ -19749,7 +19778,6 @@ function extractButtonsFromRule(rule, hay) {
19749
19778
  label += " " + next.trim();
19750
19779
  j += 1;
19751
19780
  }
19752
- if (buttons.some((b) => b.index === idx)) continue;
19753
19781
  const key = keyTemplate.replace(/\{index\}/g, String(idx));
19754
19782
  buttons.push({ index: idx, label, key, current });
19755
19783
  i = j - 1;
@@ -19761,13 +19789,22 @@ function extractButtonsFromRule(rule, hay) {
19761
19789
  const idx = Number(m[1]);
19762
19790
  const label = String(m[2] ?? "").trim();
19763
19791
  if (!Number.isFinite(idx) || idx <= 0 || !label) continue;
19764
- if (buttons.some((b) => b.index === idx)) continue;
19765
19792
  const key = keyTemplate.replace(/\{index\}/g, String(idx));
19766
19793
  buttons.push({ index: idx, label, key, current: hasCursorMarker(m[0]) });
19767
19794
  }
19768
19795
  }
19769
- buttons.sort((a, b) => a.index - b.index);
19770
- return buttons;
19796
+ const block2 = lastContiguousNumberedBlock(buttons);
19797
+ block2.sort((a, b) => a.index - b.index);
19798
+ return block2;
19799
+ }
19800
+ function lastContiguousNumberedBlock(entries) {
19801
+ if (entries.length <= 1) return entries.slice();
19802
+ let start = entries.length - 1;
19803
+ for (let i = entries.length - 1; i > 0; i -= 1) {
19804
+ if (entries[i - 1].index === entries[i].index - 1) start = i - 1;
19805
+ else break;
19806
+ }
19807
+ return entries.slice(start);
19771
19808
  }
19772
19809
  function hasCursorMarker(text) {
19773
19810
  return /^\s*[❯›>]/.test(text);
@@ -19802,6 +19839,11 @@ function statusForState(state) {
19802
19839
  if (state.id === "busy" || state.id === "generating") return "generating";
19803
19840
  return "idle";
19804
19841
  }
19842
+ function modalKindForState(state) {
19843
+ if (state.modal_kind) return state.modal_kind;
19844
+ if (state.modal) return "approval";
19845
+ return null;
19846
+ }
19805
19847
  var init_fsm_types = __esm({
19806
19848
  "src/providers/spec/fsm-types.ts"() {
19807
19849
  "use strict";
@@ -33330,7 +33372,12 @@ var FsmDriver = class {
33330
33372
  this.emit({
33331
33373
  kind: "state_changed",
33332
33374
  state: next.state,
33333
- modal: next.modal ? { title: next.modal.title, buttons: next.modal.buttons.map((b) => ({ index: b.index, label: b.label })) } : null,
33375
+ // kind is the SEMANTIC modal class (approval vs picker/confirm)
33376
+ // derived from the FSM state, NOT from the parsed buttons — the
33377
+ // status field already collapsed it to 'approval' so the modal is
33378
+ // surfaced. The auto-approve worker needs the distinction back to
33379
+ // avoid answering a /model picker on the user's behalf.
33380
+ modal: next.modal ? { title: next.modal.title, buttons: next.modal.buttons.map((b) => ({ index: b.index, label: b.label })), kind: modalKindForState(state) } : null,
33334
33381
  controls: next.controls.map((c) => ({ id: c.id, label: c.label, action_type: c.actionType }))
33335
33382
  });
33336
33383
  this.fireNotifications(state.id, title);
@@ -33812,6 +33859,9 @@ function collectStableSizes(when, sizes) {
33812
33859
  }
33813
33860
  }
33814
33861
 
33862
+ // src/providers/spec/cli-adapter.ts
33863
+ init_evaluator();
33864
+
33815
33865
  // src/providers/spec/native-history-executor.ts
33816
33866
  init_logger();
33817
33867
  init_load_better_sqlite3();
@@ -34750,7 +34800,9 @@ var SpecCliAdapter = class _SpecCliAdapter {
34750
34800
  messages: [],
34751
34801
  // Surface buttons when we have them; an approval state with no parsed
34752
34802
  // modal this frame still stays waiting_approval (no activeModal yet).
34753
- activeModal: modal ? { message: modal.title ?? state.label, buttons: modal.buttons.map((b) => b.label) } : null,
34803
+ // `kind` carries the semantic modal class through to the auto-approve
34804
+ // gate so a /model picker (kind='picker') is never auto-answered.
34805
+ activeModal: modal ? { message: modal.title ?? state.label, buttons: modal.buttons.map((b) => b.label), kind: modal.kind ?? null } : null,
34754
34806
  activeInteractivePrompt: this.activeInteractivePrompt,
34755
34807
  ...sessionFields
34756
34808
  };
@@ -35024,21 +35076,19 @@ var SpecCliAdapter = class _SpecCliAdapter {
35024
35076
  const ec = action.extract_choices;
35025
35077
  if (!ec?.pattern) return [];
35026
35078
  const text = this.readScreenSectionText(ec.section);
35027
- const out = [];
35028
- const seen = /* @__PURE__ */ new Set();
35079
+ const all = [];
35029
35080
  for (const rawLine of text.split("\n")) {
35030
35081
  const line = rawLine.replace(/\r$/, "");
35031
35082
  const m = new RegExp(ec.pattern, ec.flags ?? "").exec(line);
35032
35083
  if (!m) continue;
35033
35084
  const idx = Number(m[1]);
35034
- if (!Number.isFinite(idx) || seen.has(idx)) continue;
35085
+ if (!Number.isFinite(idx) || idx <= 0) continue;
35035
35086
  const label = (m[2] ?? "").replace(/\s+/g, " ").trim();
35036
35087
  if (!label) continue;
35037
35088
  const current = /^\s*[❯›>]/.test(line) || /[✔✓●]\s*$/.test(label);
35038
- seen.add(idx);
35039
- out.push({ index: idx, label, current });
35089
+ all.push({ index: idx, label, current });
35040
35090
  }
35041
- return out;
35091
+ return lastContiguousNumberedBlock(all);
35042
35092
  }
35043
35093
  /** Live text of a named screen section (or the whole screen when no
35044
35094
  * section is named), resolved from the driver's current sections. */
@@ -36717,8 +36767,12 @@ var CliProviderInstance = class _CliProviderInstance {
36717
36767
  if (!modal || buttons.length === 0) {
36718
36768
  return autoApproveActive;
36719
36769
  }
36720
- const { index: buttonIndex, label: buttonLabel } = pickAutoApprovalButton(buttons);
36721
- if (buttonIndex < 0) {
36770
+ const modalKind = typeof modal?.kind === "string" ? modal.kind : "approval";
36771
+ if (modalKind !== "approval") {
36772
+ return autoApproveActive;
36773
+ }
36774
+ const { index: buttonIndex, label: buttonLabel } = pickApprovalButton(buttons, this.provider);
36775
+ if (buttonIndex < 0 || !hasNegativeApprovalOption(buttons)) {
36722
36776
  return autoApproveActive;
36723
36777
  }
36724
36778
  const modalSignature = [