@adhdev/daemon-core 0.9.82-rc.565 → 0.9.82-rc.567
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/cli-adapter-types.d.ts +14 -0
- package/dist/index.js +148 -20
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +148 -20
- package/dist/index.mjs.map +1 -1
- package/dist/mesh/mesh-active-work.d.ts +4 -0
- package/dist/providers/cli-provider-instance.d.ts +25 -0
- package/dist/providers/spec/cli-adapter.d.ts +1 -0
- package/dist/providers/spec/fsm-driver.d.ts +18 -0
- package/package.json +3 -3
- package/src/cli-adapter-types.d.ts +1 -0
- package/src/cli-adapter-types.ts +17 -0
- package/src/commands/chat-commands-write.ts +15 -1
- package/src/mesh/mesh-active-work.ts +22 -4
- package/src/mesh/mesh-event-forwarding.ts +41 -23
- package/src/mesh/mesh-reconcile-loop.ts +52 -0
- package/src/providers/cli-provider-instance.ts +75 -1
- package/src/providers/spec/cli-adapter.ts +37 -3
- package/src/providers/spec/fsm-driver.ts +27 -5
package/dist/index.mjs
CHANGED
|
@@ -423,10 +423,10 @@ function readInjected(value) {
|
|
|
423
423
|
}
|
|
424
424
|
function getDaemonBuildInfo() {
|
|
425
425
|
if (cached) return cached;
|
|
426
|
-
const commit = readInjected(true ? "
|
|
427
|
-
const commitShort = readInjected(true ? "
|
|
428
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
429
|
-
const builtAt = readInjected(true ? "2026-07-
|
|
426
|
+
const commit = readInjected(true ? "86f8d403efe203d7ff1d9b6997ede5f30620a485" : void 0) ?? "unknown";
|
|
427
|
+
const commitShort = readInjected(true ? "86f8d403" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
428
|
+
const version = readInjected(true ? "0.9.82-rc.567" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
429
|
+
const builtAt = readInjected(true ? "2026-07-18T09:04:16.210Z" : void 0);
|
|
430
430
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
431
431
|
return cached;
|
|
432
432
|
}
|
|
@@ -14976,12 +14976,16 @@ function buildMeshActiveWork(opts) {
|
|
|
14976
14976
|
for (const task of opts.queue || []) {
|
|
14977
14977
|
if (task.status !== "pending" && task.status !== "assigned") continue;
|
|
14978
14978
|
const { title, summary: summary2 } = summarizeMessage(task.message || "");
|
|
14979
|
+
const queueNodeId = task.assignedNodeId || task.targetNodeId;
|
|
14980
|
+
const queueSessionId = task.assignedSessionId || task.targetSessionId;
|
|
14981
|
+
const queueLive = task.status === "assigned" ? sessionStatusFromNodes(opts.nodes, queueNodeId ?? void 0, queueSessionId ?? void 0) : {};
|
|
14982
|
+
const queueStatus = queueLive.status === "awaiting_approval" || queueLive.status === "generating" ? queueLive.status : task.status;
|
|
14979
14983
|
records.push({
|
|
14980
14984
|
taskId: task.id,
|
|
14981
14985
|
source: "queue",
|
|
14982
|
-
status:
|
|
14983
|
-
nodeId:
|
|
14984
|
-
sessionId:
|
|
14986
|
+
status: queueStatus,
|
|
14987
|
+
nodeId: queueNodeId,
|
|
14988
|
+
sessionId: queueSessionId,
|
|
14985
14989
|
taskTitle: title,
|
|
14986
14990
|
taskSummary: summary2,
|
|
14987
14991
|
message: task.message,
|
|
@@ -20564,12 +20568,15 @@ function evaluateMeshEventSuppression(args, ctx) {
|
|
|
20564
20568
|
}
|
|
20565
20569
|
return null;
|
|
20566
20570
|
}
|
|
20567
|
-
function
|
|
20571
|
+
function shouldSuppressAutoApprovingWorkerApproval(components, sessionId) {
|
|
20568
20572
|
if (!sessionId) return false;
|
|
20569
20573
|
try {
|
|
20570
|
-
const
|
|
20574
|
+
const instance = components.instanceManager?.getInstance?.(sessionId);
|
|
20575
|
+
const state = instance?.getState?.();
|
|
20571
20576
|
const settings = state?.settings || {};
|
|
20572
|
-
|
|
20577
|
+
if (settings.autoApprove !== true) return false;
|
|
20578
|
+
const resolvedLocally = instance?.approvalRecentlyResolvedLocally;
|
|
20579
|
+
return typeof resolvedLocally === "function" ? resolvedLocally.call(instance) === true : false;
|
|
20573
20580
|
} catch {
|
|
20574
20581
|
return false;
|
|
20575
20582
|
}
|
|
@@ -20714,8 +20721,8 @@ function injectMeshSystemMessage(components, args) {
|
|
|
20714
20721
|
}
|
|
20715
20722
|
}
|
|
20716
20723
|
const eventTimestamp = readEventTimestamp(args.metadataEvent.timestamp);
|
|
20717
|
-
if (args.event === "agent:waiting_approval" &&
|
|
20718
|
-
LOG.info("MeshEvents", `Suppressed agent:waiting_approval for auto-approving worker session ${eventSessionId || "(unknown)"} (mesh ${args.meshId}) \u2014 modal
|
|
20724
|
+
if (args.event === "agent:waiting_approval" && shouldSuppressAutoApprovingWorkerApproval(components, eventSessionId)) {
|
|
20725
|
+
LOG.info("MeshEvents", `Suppressed agent:waiting_approval for auto-approving worker session ${eventSessionId || "(unknown)"} (mesh ${args.meshId}) \u2014 modal resolved locally within cooldown, coordinator not notified`);
|
|
20719
20726
|
traceMeshEventDrop("waiting_approval_auto_approving_worker", traceCtx);
|
|
20720
20727
|
return { success: true, forwarded: 0, suppressed: true, autoApprovingWorkerApproval: true };
|
|
20721
20728
|
}
|
|
@@ -22414,6 +22421,14 @@ function drainAndDeliverApprovalNudges(meshId, drainDaemonIds, localDaemonId, me
|
|
|
22414
22421
|
}
|
|
22415
22422
|
return delivered;
|
|
22416
22423
|
}
|
|
22424
|
+
function assignedRowLiveStatusIsAwaitingApproval(mesh, nodeId, sessionId) {
|
|
22425
|
+
if (!nodeId || !sessionId) return false;
|
|
22426
|
+
try {
|
|
22427
|
+
return sessionStatusFromNodes(mesh.nodes, nodeId, sessionId).status === "awaiting_approval";
|
|
22428
|
+
} catch {
|
|
22429
|
+
return false;
|
|
22430
|
+
}
|
|
22431
|
+
}
|
|
22417
22432
|
async function recoverStrandedAssignedDispatches(components, mesh, store) {
|
|
22418
22433
|
const meshId = mesh.id;
|
|
22419
22434
|
const assigned = getQueue(meshId, { status: ["assigned"] });
|
|
@@ -22445,6 +22460,15 @@ async function recoverStrandedAssignedDispatches(components, mesh, store) {
|
|
|
22445
22460
|
} else {
|
|
22446
22461
|
if (verdict === "IDLE_CONFIRMED") {
|
|
22447
22462
|
deliveredUnconsumedUnknownStreak.delete(shortStreakKey);
|
|
22463
|
+
} else if (assignedRowLiveStatusIsAwaitingApproval(mesh, row.assignedNodeId, row.assignedSessionId)) {
|
|
22464
|
+
traceMeshEventDrop("short_redrive_deferred_awaiting_approval", {
|
|
22465
|
+
taskId: row.id,
|
|
22466
|
+
sessionId: row.assignedSessionId,
|
|
22467
|
+
nodeId: row.assignedNodeId,
|
|
22468
|
+
meshId,
|
|
22469
|
+
event: "agent:waiting_approval"
|
|
22470
|
+
}, "live_awaiting_approval");
|
|
22471
|
+
continue;
|
|
22448
22472
|
} else {
|
|
22449
22473
|
const streak = (deliveredUnconsumedUnknownStreak.get(shortStreakKey) ?? 0) + 1;
|
|
22450
22474
|
deliveredUnconsumedUnknownStreak.set(shortStreakKey, streak);
|
|
@@ -22507,6 +22531,15 @@ async function recoverStrandedAssignedDispatches(components, mesh, store) {
|
|
|
22507
22531
|
if (verdict === "IDLE_CONFIRMED") {
|
|
22508
22532
|
deliveredNoTurnUnknownStreak.delete(streakKey);
|
|
22509
22533
|
reclaimReason = "delivered_no_turn_deadline";
|
|
22534
|
+
} else if (assignedRowLiveStatusIsAwaitingApproval(mesh, row.assignedNodeId, row.assignedSessionId)) {
|
|
22535
|
+
traceMeshEventDrop("reclaim_deferred_awaiting_approval", {
|
|
22536
|
+
taskId: row.id,
|
|
22537
|
+
sessionId: row.assignedSessionId,
|
|
22538
|
+
nodeId: row.assignedNodeId,
|
|
22539
|
+
meshId,
|
|
22540
|
+
event: "agent:waiting_approval"
|
|
22541
|
+
}, "live_awaiting_approval");
|
|
22542
|
+
continue;
|
|
22510
22543
|
} else {
|
|
22511
22544
|
const streak = (deliveredNoTurnUnknownStreak.get(streakKey) ?? 0) + 1;
|
|
22512
22545
|
deliveredNoTurnUnknownStreak.set(streakKey, streak);
|
|
@@ -23074,6 +23107,7 @@ var init_mesh_reconcile_loop = __esm({
|
|
|
23074
23107
|
init_mesh_reconcile_config();
|
|
23075
23108
|
init_mesh_remote_event_pull();
|
|
23076
23109
|
init_mesh_completion_synthesis();
|
|
23110
|
+
init_mesh_active_work();
|
|
23077
23111
|
init_mesh_reconcile_v2_backstop();
|
|
23078
23112
|
init_mesh_reconcile_acked_hold();
|
|
23079
23113
|
coordinatorModalParkState = /* @__PURE__ */ new Map();
|
|
@@ -39008,7 +39042,13 @@ async function handleResolveAction(h, args) {
|
|
|
39008
39042
|
LOG.info("Command", `[resolveAction] CLI PTY \u2192 stale_prompt (already resolved within cooldown)`);
|
|
39009
39043
|
return { success: true, stalePrompt: true, buttonIndex, button: buttons[buttonIndex] ?? button };
|
|
39010
39044
|
}
|
|
39011
|
-
if (typeof adapter.
|
|
39045
|
+
if (typeof adapter.resolveModalMatched === "function") {
|
|
39046
|
+
const matched = adapter.resolveModalMatched(buttonIndex);
|
|
39047
|
+
if (!matched) {
|
|
39048
|
+
LOG.warn("Command", `[resolveAction] CLI PTY \u2192 no button matched for buttonIndex=${buttonIndex} "${buttons[buttonIndex] ?? "?"}" (modal not resolved)`);
|
|
39049
|
+
return { success: false, error: "Approval button index did not map to a visible modal button", buttonIndex, button: buttons[buttonIndex] ?? button };
|
|
39050
|
+
}
|
|
39051
|
+
} else if (typeof adapter.resolveModal === "function") {
|
|
39012
39052
|
adapter.resolveModal(buttonIndex);
|
|
39013
39053
|
} else {
|
|
39014
39054
|
const keys = "\x1B[B".repeat(Math.max(0, buttonIndex)) + "\r";
|
|
@@ -43601,7 +43641,7 @@ var FsmDriver = class {
|
|
|
43601
43641
|
this.handleClickControl(cmd.control_id, cmd.payload);
|
|
43602
43642
|
return;
|
|
43603
43643
|
case "click_modal_button":
|
|
43604
|
-
this.
|
|
43644
|
+
this.clickModalButton(cmd.index);
|
|
43605
43645
|
return;
|
|
43606
43646
|
case "attach_image":
|
|
43607
43647
|
this.handleAttachImage(cmd.blob, cmd.mime);
|
|
@@ -44344,11 +44384,24 @@ var FsmDriver = class {
|
|
|
44344
44384
|
}
|
|
44345
44385
|
}
|
|
44346
44386
|
}
|
|
44387
|
+
/**
|
|
44388
|
+
* BUTTON-INDEX-MISMAP (Fix C.3): public modal-click entry that returns whether a button
|
|
44389
|
+
* matching the requested FSM display index was actually found and its confirm keys were
|
|
44390
|
+
* dispatched. The old private handleClickModalButton silently `return`ed on a miss (no
|
|
44391
|
+
* modal captured, or no button whose `.index` equals the requested display index), so a
|
|
44392
|
+
* mis-mapped index looked identical to a successful press. Callers that need to know
|
|
44393
|
+
* whether the click landed (mesh_approve → resolveModal) can now observe the miss instead
|
|
44394
|
+
* of reporting success into the void. The generic `dispatch('click_modal_button')` path
|
|
44395
|
+
* keeps ignoring the return (fire-and-forget UI clicks).
|
|
44396
|
+
*/
|
|
44397
|
+
clickModalButton(index) {
|
|
44398
|
+
return this.handleClickModalButton(index);
|
|
44399
|
+
}
|
|
44347
44400
|
handleClickModalButton(index) {
|
|
44348
44401
|
const m = this.currentEval?.modal;
|
|
44349
|
-
if (!m) return;
|
|
44402
|
+
if (!m) return false;
|
|
44350
44403
|
const btn = m.buttons.find((b) => b.index === index);
|
|
44351
|
-
if (!btn) return;
|
|
44404
|
+
if (!btn) return false;
|
|
44352
44405
|
const rule = stateById(this.spec, this.currentStateId)?.extract?.buttons;
|
|
44353
44406
|
if (rule?.select_mode === "arrow_keys") {
|
|
44354
44407
|
const from = m.buttons.find((b) => b.current)?.index ?? 1;
|
|
@@ -44360,9 +44413,10 @@ var FsmDriver = class {
|
|
|
44360
44413
|
const confirm = (rule.key_for_index || "\r").replace(/\{index\}/g, "") || "\r";
|
|
44361
44414
|
if (nav) this.adapter.send_keys(nav);
|
|
44362
44415
|
this.submitModalConfirm(confirm);
|
|
44363
|
-
return;
|
|
44416
|
+
return true;
|
|
44364
44417
|
}
|
|
44365
44418
|
this.submitModalConfirm(btn.key);
|
|
44419
|
+
return true;
|
|
44366
44420
|
}
|
|
44367
44421
|
/**
|
|
44368
44422
|
* Submit a modal-confirm key sequence (the choice key + its trailing CR).
|
|
@@ -45794,7 +45848,20 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
45794
45848
|
// modal this frame still stays waiting_approval (no activeModal yet).
|
|
45795
45849
|
// `kind` carries the semantic modal class through to the auto-approve
|
|
45796
45850
|
// gate so a /model picker (kind='picker') is never auto-answered.
|
|
45797
|
-
|
|
45851
|
+
// BUTTON-INDEX-MISMAP (Fix C.1): keep `buttons` as the label list every
|
|
45852
|
+
// existing consumer (pickApprovalButton, mesh_approve, auto-approve) reads,
|
|
45853
|
+
// but ALSO surface `buttonMeta` carrying each button's real FSM display index
|
|
45854
|
+
// alongside its label. A partial/non-contiguous modal (display indices [1,3,4]
|
|
45855
|
+
// at array positions [0,1,2]) then no longer loses the index → label mapping
|
|
45856
|
+
// once it leaves the adapter: a consumer that has an array position can recover
|
|
45857
|
+
// the true FSM index without re-parsing. resolveModal() below relies on the same
|
|
45858
|
+
// ordered list to translate an array position to the correct FSM index.
|
|
45859
|
+
activeModal: modal ? {
|
|
45860
|
+
message: modal.title ?? state.label,
|
|
45861
|
+
buttons: modal.buttons.map((b) => b.label),
|
|
45862
|
+
buttonMeta: modal.buttons.map((b) => ({ index: b.index, label: b.label })),
|
|
45863
|
+
kind: modal.kind ?? null
|
|
45864
|
+
} : null,
|
|
45798
45865
|
activeInteractivePrompt: this.activeInteractivePrompt,
|
|
45799
45866
|
...sessionFields
|
|
45800
45867
|
};
|
|
@@ -45966,7 +46033,12 @@ var SpecCliAdapter = class _SpecCliAdapter {
|
|
|
45966
46033
|
this.driver.dispatch({ kind: "resize", cols, rows });
|
|
45967
46034
|
}
|
|
45968
46035
|
resolveModal(buttonIndex) {
|
|
45969
|
-
this.
|
|
46036
|
+
this.resolveModalMatched(buttonIndex);
|
|
46037
|
+
}
|
|
46038
|
+
resolveModalMatched(buttonIndex) {
|
|
46039
|
+
const buttons = this.latestModal?.buttons ?? [];
|
|
46040
|
+
const target = buttonIndex >= 0 && buttonIndex < buttons.length ? buttons[buttonIndex].index : buttonIndex + 1;
|
|
46041
|
+
return this.driver.clickModalButton(target);
|
|
45970
46042
|
}
|
|
45971
46043
|
async resolveAction(data) {
|
|
45972
46044
|
const args = data && typeof data === "object" ? data : {};
|
|
@@ -47126,6 +47198,15 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
47126
47198
|
* keystroke until the modal *content* has settled.
|
|
47127
47199
|
*/
|
|
47128
47200
|
static AUTO_APPROVE_SETTLE_MS = 600;
|
|
47201
|
+
/**
|
|
47202
|
+
* APPROVAL-INBOX-BLINDSPOT (Fix A): how long after a LOCAL auto-approve fire the mesh
|
|
47203
|
+
* event forwarder still treats the modal as "being resolved locally" and suppresses the
|
|
47204
|
+
* coordinator notification. Chosen to comfortably cover the resolveModal → PTY absorb →
|
|
47205
|
+
* status-leaves-approval round trip (incl. the win32 CR-resend loop) while staying short
|
|
47206
|
+
* enough that a modal which auto-approve fired at but did NOT resolve re-surfaces to the
|
|
47207
|
+
* coordinator on the next event. Aligned with the adapter's own approval cooldown scale.
|
|
47208
|
+
*/
|
|
47209
|
+
static APPROVAL_LOCAL_RESOLUTION_COOLDOWN_MS = 8e3;
|
|
47129
47210
|
/**
|
|
47130
47211
|
* Busy-side hysteresis for the settle gate. A momentary `generating` flip
|
|
47131
47212
|
* while the SAME approval modal's button block is still on screen (its
|
|
@@ -47398,6 +47479,16 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
47398
47479
|
// signature) while a genuinely closed modal — buttons empty continuously past
|
|
47399
47480
|
// the continuity window — is still recognised and resets the gate.
|
|
47400
47481
|
autoApproveLastModalSeenAt = 0;
|
|
47482
|
+
// APPROVAL-INBOX-BLINDSPOT (Fix A): wall-clock of the last time this session actually
|
|
47483
|
+
// FIRED a local auto-approve resolveModal (the settle gate passed → resolveModal
|
|
47484
|
+
// dispatched). The mesh event forwarder keys its agent:waiting_approval suppression on
|
|
47485
|
+
// this + a cooldown so it only drops the coordinator notification when we can positively
|
|
47486
|
+
// confirm the modal was (or is being) resolved LOCALLY. If auto-approve is merely
|
|
47487
|
+
// *configured* on but has NOT recently fired for this modal, the raw waiting_approval is
|
|
47488
|
+
// forwarded so a task_approval_needed ledger row is created and the coordinator/inbox is
|
|
47489
|
+
// told — closing the blind spot where a never-resolving worker approval was silently
|
|
47490
|
+
// dropped just because settings.autoApprove===true.
|
|
47491
|
+
lastAutoApproveFiredAt = 0;
|
|
47401
47492
|
// AUTOAPPROVE-FLAP-INBOX-MISSING sticky-approval overlay (see APPROVAL_STICKY_FLAP_MS).
|
|
47402
47493
|
// The wall-clock of the last frame where the RAW adapter reported waiting_approval with
|
|
47403
47494
|
// a CONCRETE modal (buttons present), the cached modal to re-present across a busy blip,
|
|
@@ -47883,6 +47974,33 @@ var CliProviderInstance = class _CliProviderInstance {
|
|
|
47883
47974
|
}
|
|
47884
47975
|
return null;
|
|
47885
47976
|
}
|
|
47977
|
+
/**
|
|
47978
|
+
* APPROVAL-INBOX-BLINDSPOT (Fix A): true when this session's approval modal was — or is
|
|
47979
|
+
* being — resolved LOCALLY within the recent cooldown. Two independent positive signals:
|
|
47980
|
+
* (1) auto-approve fired its resolveModal within APPROVAL_LOCAL_RESOLUTION_COOLDOWN_MS
|
|
47981
|
+
* (lastAutoApproveFiredAt), or
|
|
47982
|
+
* (2) the underlying adapter reports isApprovalRecentlyResolved() — its own resolve
|
|
47983
|
+
* cooldown, which also covers a dashboard / mesh_approve resolution.
|
|
47984
|
+
* The mesh event forwarder uses this to decide whether an agent:waiting_approval from an
|
|
47985
|
+
* auto-approving worker can be safely SUPPRESSED (a local resolution is in flight) or must
|
|
47986
|
+
* be FORWARDED (auto-approve is configured but has NOT actually resolved this modal, so the
|
|
47987
|
+
* coordinator/inbox must be told). Keying suppression on real resolution — not just the
|
|
47988
|
+
* autoApprove *intent* — is the blind-spot fix: a never-resolving worker approval is no
|
|
47989
|
+
* longer silently dropped.
|
|
47990
|
+
*/
|
|
47991
|
+
approvalRecentlyResolvedLocally(now = Date.now()) {
|
|
47992
|
+
if (this.lastAutoApproveFiredAt && now - this.lastAutoApproveFiredAt < _CliProviderInstance.APPROVAL_LOCAL_RESOLUTION_COOLDOWN_MS) {
|
|
47993
|
+
return true;
|
|
47994
|
+
}
|
|
47995
|
+
try {
|
|
47996
|
+
const adapter = this.adapter;
|
|
47997
|
+
if (typeof adapter.isApprovalRecentlyResolved === "function") {
|
|
47998
|
+
return adapter.isApprovalRecentlyResolved() === true;
|
|
47999
|
+
}
|
|
48000
|
+
} catch {
|
|
48001
|
+
}
|
|
48002
|
+
return false;
|
|
48003
|
+
}
|
|
47886
48004
|
/**
|
|
47887
48005
|
* NOTIF-HELD-DRAIN: true when this `waiting_approval` is a routine, transient tool-consent
|
|
47888
48006
|
* of an autonomously-progressing mesh session rather than a genuine human-await modal —
|
|
@@ -49233,8 +49351,18 @@ ${buttons.join("\n")}`;
|
|
|
49233
49351
|
this.lastAutoApprovalSignature = "";
|
|
49234
49352
|
}, 5e3);
|
|
49235
49353
|
this.recordAutoApproval(modal?.message, buttonLabel, now);
|
|
49354
|
+
this.lastAutoApproveFiredAt = now;
|
|
49236
49355
|
setTimeout(() => {
|
|
49237
|
-
this.adapter
|
|
49356
|
+
const adapter = this.adapter;
|
|
49357
|
+
if (typeof adapter.resolveModalMatched === "function") {
|
|
49358
|
+
const matched = adapter.resolveModalMatched(buttonIndex);
|
|
49359
|
+
if (!matched) {
|
|
49360
|
+
if (this.lastAutoApproveFiredAt === now) this.lastAutoApproveFiredAt = 0;
|
|
49361
|
+
LOG.warn("CLI", `[${this.type}] auto-approve resolveModal matched no button (index ${buttonIndex}) \u2014 surfacing approval to coordinator`);
|
|
49362
|
+
}
|
|
49363
|
+
} else {
|
|
49364
|
+
adapter.resolveModal?.(buttonIndex);
|
|
49365
|
+
}
|
|
49238
49366
|
}, 0);
|
|
49239
49367
|
return autoApproveActive;
|
|
49240
49368
|
}
|