@probelabs/visor 0.1.166 → 0.1.167

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 (72) hide show
  1. package/dist/config.d.ts.map +1 -1
  2. package/dist/frontends/github-frontend.d.ts.map +1 -1
  3. package/dist/index.js +344 -29
  4. package/dist/output/traces/{run-2026-03-06T13-08-34-152Z.ndjson → run-2026-03-06T13-29-14-416Z.ndjson} +84 -84
  5. package/dist/output/traces/{run-2026-03-06T13-09-10-593Z.ndjson → run-2026-03-06T13-29-52-749Z.ndjson} +1892 -1892
  6. package/dist/sdk/{check-provider-registry-V6C4LUYJ.mjs → check-provider-registry-6WR2SG66.mjs} +3 -3
  7. package/dist/sdk/{check-provider-registry-TGPICTHD.mjs → check-provider-registry-GPV5DYN5.mjs} +3 -3
  8. package/dist/sdk/{check-provider-registry-WXEBJWXY.mjs → check-provider-registry-P356JWTA.mjs} +6 -6
  9. package/dist/sdk/{chunk-WSYVK6ML.mjs → chunk-2G2PJKHM.mjs} +297 -31
  10. package/dist/sdk/chunk-2G2PJKHM.mjs.map +1 -0
  11. package/dist/sdk/{chunk-HFCOZPAS.mjs → chunk-HM3RZ3NP.mjs} +2 -2
  12. package/dist/sdk/{chunk-HFCOZPAS.mjs.map → chunk-HM3RZ3NP.mjs.map} +1 -1
  13. package/dist/sdk/{chunk-DEAPFYNX.mjs → chunk-KYBKVKBS.mjs} +7 -1
  14. package/dist/sdk/{chunk-DEAPFYNX.mjs.map → chunk-KYBKVKBS.mjs.map} +1 -1
  15. package/dist/sdk/{chunk-KKGMGB4X.mjs → chunk-MHLP6P4V.mjs} +297 -31
  16. package/dist/sdk/chunk-MHLP6P4V.mjs.map +1 -0
  17. package/dist/sdk/{chunk-OQ3CML4F.mjs → chunk-UNUZFJ5I.mjs} +3 -3
  18. package/dist/sdk/{chunk-KBTFMYZQ.mjs → chunk-XYQSWTGC.mjs} +2 -2
  19. package/dist/sdk/{chunk-ZQR4AGS3.mjs → chunk-YSQV7N5H.mjs} +304 -38
  20. package/dist/sdk/chunk-YSQV7N5H.mjs.map +1 -0
  21. package/dist/sdk/{config-D6WF2U4B.mjs → config-DP5QU3XC.mjs} +2 -2
  22. package/dist/sdk/{failure-condition-evaluator-5EAESM44.mjs → failure-condition-evaluator-VWQ54IK4.mjs} +3 -3
  23. package/dist/sdk/{github-frontend-BPRRUIGB.mjs → github-frontend-SOVBEAK4.mjs} +21 -3
  24. package/dist/sdk/{github-frontend-BPRRUIGB.mjs.map → github-frontend-SOVBEAK4.mjs.map} +1 -1
  25. package/dist/sdk/{github-frontend-P274ISBJ.mjs → github-frontend-VM52NX7N.mjs} +19 -1
  26. package/dist/sdk/{github-frontend-P274ISBJ.mjs.map → github-frontend-VM52NX7N.mjs.map} +1 -1
  27. package/dist/sdk/{host-753E6PKF.mjs → host-7MGCKSHM.mjs} +2 -2
  28. package/dist/sdk/{host-AIMRV5YL.mjs → host-JHMDZR6P.mjs} +2 -2
  29. package/dist/sdk/{routing-QHWSMAIH.mjs → routing-3WG46XWU.mjs} +4 -4
  30. package/dist/sdk/{schedule-tool-OCZGLKMJ.mjs → schedule-tool-B6SEZ77N.mjs} +3 -3
  31. package/dist/sdk/{schedule-tool-MQHISNJ6.mjs → schedule-tool-MPHHE2IM.mjs} +3 -3
  32. package/dist/sdk/{schedule-tool-ZVOSSFN2.mjs → schedule-tool-SPJWY2Y2.mjs} +6 -6
  33. package/dist/sdk/{schedule-tool-handler-BGOL2TOP.mjs → schedule-tool-handler-SUYGQJ63.mjs} +3 -3
  34. package/dist/sdk/{schedule-tool-handler-TZYXM664.mjs → schedule-tool-handler-V7A4AQGS.mjs} +3 -3
  35. package/dist/sdk/{schedule-tool-handler-4NCS4ARE.mjs → schedule-tool-handler-VNAVYBCM.mjs} +6 -6
  36. package/dist/sdk/sdk.js +312 -22
  37. package/dist/sdk/sdk.js.map +1 -1
  38. package/dist/sdk/sdk.mjs +5 -5
  39. package/dist/sdk/{trace-helpers-CTHTK6V5.mjs → trace-helpers-7BSOH35A.mjs} +2 -2
  40. package/dist/sdk/{workflow-check-provider-3M5LXLLX.mjs → workflow-check-provider-AECYZCBK.mjs} +3 -3
  41. package/dist/sdk/{workflow-check-provider-QKHL6AFT.mjs → workflow-check-provider-N4ZTFOH6.mjs} +3 -3
  42. package/dist/sdk/{workflow-check-provider-UTNO6XN6.mjs → workflow-check-provider-X7ZGHZA6.mjs} +6 -6
  43. package/dist/state-machine/context/build-engine-context.d.ts.map +1 -1
  44. package/dist/traces/{run-2026-03-06T13-08-34-152Z.ndjson → run-2026-03-06T13-29-14-416Z.ndjson} +84 -84
  45. package/dist/traces/{run-2026-03-06T13-09-10-593Z.ndjson → run-2026-03-06T13-29-52-749Z.ndjson} +1892 -1892
  46. package/dist/utils/fair-concurrency-limiter.d.ts +56 -0
  47. package/dist/utils/fair-concurrency-limiter.d.ts.map +1 -0
  48. package/dist/utils/interactive-prompt.d.ts.map +1 -1
  49. package/package.json +1 -1
  50. package/dist/sdk/chunk-KKGMGB4X.mjs.map +0 -1
  51. package/dist/sdk/chunk-WSYVK6ML.mjs.map +0 -1
  52. package/dist/sdk/chunk-ZQR4AGS3.mjs.map +0 -1
  53. /package/dist/sdk/{check-provider-registry-TGPICTHD.mjs.map → check-provider-registry-6WR2SG66.mjs.map} +0 -0
  54. /package/dist/sdk/{check-provider-registry-V6C4LUYJ.mjs.map → check-provider-registry-GPV5DYN5.mjs.map} +0 -0
  55. /package/dist/sdk/{check-provider-registry-WXEBJWXY.mjs.map → check-provider-registry-P356JWTA.mjs.map} +0 -0
  56. /package/dist/sdk/{chunk-OQ3CML4F.mjs.map → chunk-UNUZFJ5I.mjs.map} +0 -0
  57. /package/dist/sdk/{chunk-KBTFMYZQ.mjs.map → chunk-XYQSWTGC.mjs.map} +0 -0
  58. /package/dist/sdk/{config-D6WF2U4B.mjs.map → config-DP5QU3XC.mjs.map} +0 -0
  59. /package/dist/sdk/{failure-condition-evaluator-5EAESM44.mjs.map → failure-condition-evaluator-VWQ54IK4.mjs.map} +0 -0
  60. /package/dist/sdk/{host-753E6PKF.mjs.map → host-7MGCKSHM.mjs.map} +0 -0
  61. /package/dist/sdk/{host-AIMRV5YL.mjs.map → host-JHMDZR6P.mjs.map} +0 -0
  62. /package/dist/sdk/{routing-QHWSMAIH.mjs.map → routing-3WG46XWU.mjs.map} +0 -0
  63. /package/dist/sdk/{schedule-tool-MQHISNJ6.mjs.map → schedule-tool-B6SEZ77N.mjs.map} +0 -0
  64. /package/dist/sdk/{schedule-tool-OCZGLKMJ.mjs.map → schedule-tool-MPHHE2IM.mjs.map} +0 -0
  65. /package/dist/sdk/{schedule-tool-ZVOSSFN2.mjs.map → schedule-tool-SPJWY2Y2.mjs.map} +0 -0
  66. /package/dist/sdk/{schedule-tool-handler-4NCS4ARE.mjs.map → schedule-tool-handler-SUYGQJ63.mjs.map} +0 -0
  67. /package/dist/sdk/{schedule-tool-handler-BGOL2TOP.mjs.map → schedule-tool-handler-V7A4AQGS.mjs.map} +0 -0
  68. /package/dist/sdk/{schedule-tool-handler-TZYXM664.mjs.map → schedule-tool-handler-VNAVYBCM.mjs.map} +0 -0
  69. /package/dist/sdk/{trace-helpers-CTHTK6V5.mjs.map → trace-helpers-7BSOH35A.mjs.map} +0 -0
  70. /package/dist/sdk/{workflow-check-provider-3M5LXLLX.mjs.map → workflow-check-provider-AECYZCBK.mjs.map} +0 -0
  71. /package/dist/sdk/{workflow-check-provider-QKHL6AFT.mjs.map → workflow-check-provider-N4ZTFOH6.mjs.map} +0 -0
  72. /package/dist/sdk/{workflow-check-provider-UTNO6XN6.mjs.map → workflow-check-provider-X7ZGHZA6.mjs.map} +0 -0
@@ -6,7 +6,7 @@ import {
6
6
  extractSlackContext,
7
7
  init_schedule_tool_handler,
8
8
  isScheduleToolCall
9
- } from "./chunk-ZQR4AGS3.mjs";
9
+ } from "./chunk-YSQV7N5H.mjs";
10
10
  import "./chunk-KFKHU6CM.mjs";
11
11
  import "./chunk-AVMMKGLQ.mjs";
12
12
  import "./chunk-LG4AUKHB.mjs";
@@ -14,11 +14,11 @@ import "./chunk-B7BVQM5K.mjs";
14
14
  import "./chunk-XXAEN5KU.mjs";
15
15
  import "./chunk-GEW6LS32.mjs";
16
16
  import "./chunk-NZADFXHE.mjs";
17
- import "./chunk-DEAPFYNX.mjs";
17
+ import "./chunk-KYBKVKBS.mjs";
18
18
  import "./chunk-NCWIZVOT.mjs";
19
- import "./chunk-OQ3CML4F.mjs";
20
- import "./chunk-KBTFMYZQ.mjs";
21
- import "./chunk-HFCOZPAS.mjs";
19
+ import "./chunk-UNUZFJ5I.mjs";
20
+ import "./chunk-XYQSWTGC.mjs";
21
+ import "./chunk-HM3RZ3NP.mjs";
22
22
  import "./chunk-JL7JXCET.mjs";
23
23
  import "./chunk-ZUEQNCKB.mjs";
24
24
  import "./chunk-25IC7KXZ.mjs";
@@ -36,4 +36,4 @@ export {
36
36
  extractSlackContext,
37
37
  isScheduleToolCall
38
38
  };
39
- //# sourceMappingURL=schedule-tool-handler-4NCS4ARE.mjs.map
39
+ //# sourceMappingURL=schedule-tool-handler-VNAVYBCM.mjs.map
package/dist/sdk/sdk.js CHANGED
@@ -646,7 +646,7 @@ var require_package = __commonJS({
646
646
  "package.json"(exports2, module2) {
647
647
  module2.exports = {
648
648
  name: "@probelabs/visor",
649
- version: "0.1.166",
649
+ version: "0.1.167",
650
650
  main: "dist/index.js",
651
651
  bin: {
652
652
  visor: "./dist/index.js"
@@ -15695,6 +15695,12 @@ ${errors}`);
15695
15695
  if (workflowData.on) {
15696
15696
  visorConfig.on = workflowData.on;
15697
15697
  }
15698
+ if (workflowData.sandboxes) {
15699
+ visorConfig.sandboxes = workflowData.sandboxes;
15700
+ }
15701
+ if (workflowData.sandbox) {
15702
+ visorConfig.sandbox = workflowData.sandbox;
15703
+ }
15698
15704
  logger.debug(
15699
15705
  `Standalone workflow config has ${Object.keys(workflowSteps).length} workflow steps as checks`
15700
15706
  );
@@ -45176,7 +45182,27 @@ async function acquirePromptLock() {
45176
45182
  activePrompt = true;
45177
45183
  return;
45178
45184
  }
45179
- await new Promise((resolve15) => waiters.push(resolve15));
45185
+ console.error(
45186
+ `[human-input] Prompt queued, waiting for active prompt to finish (${waiters.length} already waiting).`
45187
+ );
45188
+ const queuedAt = Date.now();
45189
+ const reminder = setInterval(() => {
45190
+ const waited = Math.round((Date.now() - queuedAt) / 1e3);
45191
+ console.error(
45192
+ `[human-input] Still waiting for prompt lock (${waited}s, ${waiters.length} in queue).`
45193
+ );
45194
+ }, 1e4);
45195
+ try {
45196
+ await new Promise((resolve15) => waiters.push(resolve15));
45197
+ } finally {
45198
+ clearInterval(reminder);
45199
+ const waitedMs = Date.now() - queuedAt;
45200
+ if (waitedMs > 100) {
45201
+ console.error(
45202
+ `[human-input] Prompt lock acquired after ${Math.round(waitedMs / 1e3)}s wait.`
45203
+ );
45204
+ }
45205
+ }
45180
45206
  activePrompt = true;
45181
45207
  }
45182
45208
  function releasePromptLock() {
@@ -50065,7 +50091,29 @@ async function executeCheckGroup(checks, context2, state, maxParallelism, emitEv
50065
50091
  } catch {
50066
50092
  }
50067
50093
  if (pool.length >= maxParallelism) {
50068
- await Promise.race(pool);
50094
+ const activeCount = pool.filter((p) => !p._settled).length;
50095
+ logger.info(
50096
+ `[LevelDispatch] Check pool full (${activeCount}/${maxParallelism} active). Check "${checkId}" queued, waiting for a slot...`
50097
+ );
50098
+ const queuedAt = Date.now();
50099
+ const reminder = setInterval(() => {
50100
+ const waited = Math.round((Date.now() - queuedAt) / 1e3);
50101
+ const stillActive = pool.filter((p) => !p._settled).length;
50102
+ logger.info(
50103
+ `[LevelDispatch] Check "${checkId}" still queued (${waited}s). ${stillActive}/${maxParallelism} slots busy.`
50104
+ );
50105
+ }, 15e3);
50106
+ try {
50107
+ await Promise.race(pool);
50108
+ } finally {
50109
+ clearInterval(reminder);
50110
+ }
50111
+ const waitedMs = Date.now() - queuedAt;
50112
+ if (waitedMs > 100) {
50113
+ logger.info(
50114
+ `[LevelDispatch] Check "${checkId}" dequeued after ${Math.round(waitedMs / 1e3)}s wait.`
50115
+ );
50116
+ }
50069
50117
  pool.splice(
50070
50118
  0,
50071
50119
  pool.length,
@@ -54853,6 +54901,223 @@ var init_workspace_manager = __esm({
54853
54901
  }
54854
54902
  });
54855
54903
 
54904
+ // src/utils/fair-concurrency-limiter.ts
54905
+ var FairConcurrencyLimiter;
54906
+ var init_fair_concurrency_limiter = __esm({
54907
+ "src/utils/fair-concurrency-limiter.ts"() {
54908
+ "use strict";
54909
+ init_logger();
54910
+ FairConcurrencyLimiter = class _FairConcurrencyLimiter {
54911
+ maxConcurrent;
54912
+ globalActive = 0;
54913
+ // Per-session FIFO queues
54914
+ sessionQueues = /* @__PURE__ */ new Map();
54915
+ // Round-robin order of sessions with waiting entries
54916
+ roundRobinSessions = [];
54917
+ roundRobinIndex = 0;
54918
+ // Per-session active count (for stats)
54919
+ sessionActive = /* @__PURE__ */ new Map();
54920
+ constructor(maxConcurrent) {
54921
+ this.maxConcurrent = maxConcurrent;
54922
+ }
54923
+ static getInstance(maxConcurrent) {
54924
+ const key = Symbol.for("visor.fairConcurrencyLimiter");
54925
+ let instance = globalThis[key];
54926
+ if (!instance) {
54927
+ instance = new _FairConcurrencyLimiter(maxConcurrent);
54928
+ globalThis[key] = instance;
54929
+ logger.info(`[FairLimiter] Created global fair concurrency limiter (max: ${maxConcurrent})`);
54930
+ } else if (instance.maxConcurrent !== maxConcurrent) {
54931
+ const old = instance.maxConcurrent;
54932
+ instance.maxConcurrent = maxConcurrent;
54933
+ logger.info(`[FairLimiter] Updated max concurrency: ${old} -> ${maxConcurrent}`);
54934
+ instance._processQueue();
54935
+ }
54936
+ return instance;
54937
+ }
54938
+ /**
54939
+ * Try to acquire a slot immediately (non-blocking).
54940
+ */
54941
+ tryAcquire(sessionId) {
54942
+ if (this.globalActive >= this.maxConcurrent) {
54943
+ return false;
54944
+ }
54945
+ this.globalActive++;
54946
+ const sid = sessionId || "__anonymous__";
54947
+ this.sessionActive.set(sid, (this.sessionActive.get(sid) || 0) + 1);
54948
+ return true;
54949
+ }
54950
+ /**
54951
+ * Acquire a slot, waiting in a fair queue if necessary.
54952
+ * Sessions are served round-robin so no single session can starve others.
54953
+ */
54954
+ async acquire(sessionId, _debug, queueTimeout) {
54955
+ const sid = sessionId || "__anonymous__";
54956
+ if (this.tryAcquire(sid)) {
54957
+ return true;
54958
+ }
54959
+ const totalQueued = this._totalQueued();
54960
+ const sessionsWaiting = this.sessionQueues.size;
54961
+ const sessionQueueLen = this.sessionQueues.get(sid)?.length || 0;
54962
+ logger.info(
54963
+ `[FairLimiter] Slot unavailable (${this.globalActive}/${this.maxConcurrent} active). Session "${sid}" queued (${sessionQueueLen} own + ${totalQueued} total across ${sessionsWaiting} sessions). Waiting...`
54964
+ );
54965
+ const queuedAt = Date.now();
54966
+ const effectiveTimeout = queueTimeout ?? 12e4;
54967
+ return new Promise((resolve15, reject) => {
54968
+ const entry = { resolve: resolve15, reject, queuedAt };
54969
+ entry.reminder = setInterval(() => {
54970
+ const waited = Math.round((Date.now() - queuedAt) / 1e3);
54971
+ const curQueued = this._totalQueued();
54972
+ const curSessions = this._waitingSessions();
54973
+ logger.info(
54974
+ `[FairLimiter] Session "${sid}" still waiting (${waited}s). ${this.globalActive}/${this.maxConcurrent} active, ${curQueued} queued across ${curSessions} sessions.`
54975
+ );
54976
+ }, 15e3);
54977
+ let queue = this.sessionQueues.get(sid);
54978
+ if (!queue) {
54979
+ queue = [];
54980
+ this.sessionQueues.set(sid, queue);
54981
+ this.roundRobinSessions.push(sid);
54982
+ }
54983
+ queue.push(entry);
54984
+ if (effectiveTimeout > 0) {
54985
+ setTimeout(() => {
54986
+ const q = this.sessionQueues.get(sid);
54987
+ if (q) {
54988
+ const idx = q.indexOf(entry);
54989
+ if (idx !== -1) {
54990
+ q.splice(idx, 1);
54991
+ if (q.length === 0) {
54992
+ this.sessionQueues.delete(sid);
54993
+ this._removeFromRoundRobin(sid);
54994
+ }
54995
+ this._clearReminder(entry);
54996
+ reject(
54997
+ new Error(
54998
+ `[FairLimiter] Queue timeout: session "${sid}" waited ${effectiveTimeout}ms for a slot`
54999
+ )
55000
+ );
55001
+ }
55002
+ }
55003
+ }, effectiveTimeout);
55004
+ }
55005
+ });
55006
+ }
55007
+ /**
55008
+ * Release a slot and grant the next one fairly (round-robin across sessions).
55009
+ */
55010
+ release(sessionId, _debug) {
55011
+ const sid = sessionId || "__anonymous__";
55012
+ this.globalActive = Math.max(0, this.globalActive - 1);
55013
+ const active = this.sessionActive.get(sid);
55014
+ if (active !== void 0) {
55015
+ if (active <= 1) {
55016
+ this.sessionActive.delete(sid);
55017
+ } else {
55018
+ this.sessionActive.set(sid, active - 1);
55019
+ }
55020
+ }
55021
+ this._processQueue();
55022
+ }
55023
+ /**
55024
+ * Round-robin queue processing: cycle through sessions and grant one slot per session per round.
55025
+ */
55026
+ _processQueue() {
55027
+ const toGrant = [];
55028
+ while (this.globalActive < this.maxConcurrent && this.roundRobinSessions.length > 0) {
55029
+ if (this.roundRobinIndex >= this.roundRobinSessions.length) {
55030
+ this.roundRobinIndex = 0;
55031
+ }
55032
+ const sid = this.roundRobinSessions[this.roundRobinIndex];
55033
+ const queue = this.sessionQueues.get(sid);
55034
+ if (!queue || queue.length === 0) {
55035
+ this.sessionQueues.delete(sid);
55036
+ this.roundRobinSessions.splice(this.roundRobinIndex, 1);
55037
+ continue;
55038
+ }
55039
+ const entry = queue.shift();
55040
+ if (queue.length === 0) {
55041
+ this.sessionQueues.delete(sid);
55042
+ this.roundRobinSessions.splice(this.roundRobinIndex, 1);
55043
+ } else {
55044
+ this.roundRobinIndex++;
55045
+ }
55046
+ this.globalActive++;
55047
+ this.sessionActive.set(sid, (this.sessionActive.get(sid) || 0) + 1);
55048
+ toGrant.push({ entry, sid });
55049
+ }
55050
+ for (const { entry, sid } of toGrant) {
55051
+ this._clearReminder(entry);
55052
+ const waitedMs = Date.now() - entry.queuedAt;
55053
+ if (waitedMs > 100) {
55054
+ logger.info(
55055
+ `[FairLimiter] Session "${sid}" acquired slot after ${Math.round(waitedMs / 1e3)}s wait.`
55056
+ );
55057
+ }
55058
+ setImmediate(() => entry.resolve(true));
55059
+ }
55060
+ }
55061
+ getStats() {
55062
+ const perSession = {};
55063
+ const allSessions = /* @__PURE__ */ new Set([...this.sessionActive.keys(), ...this.sessionQueues.keys()]);
55064
+ for (const sid of allSessions) {
55065
+ perSession[sid] = {
55066
+ active: this.sessionActive.get(sid) || 0,
55067
+ queued: this.sessionQueues.get(sid)?.length || 0
55068
+ };
55069
+ }
55070
+ return {
55071
+ globalActive: this.globalActive,
55072
+ maxConcurrent: this.maxConcurrent,
55073
+ queueSize: this._totalQueued(),
55074
+ waitingSessions: this._waitingSessions(),
55075
+ perSession
55076
+ };
55077
+ }
55078
+ cleanup() {
55079
+ for (const queue of this.sessionQueues.values()) {
55080
+ for (const entry of queue) {
55081
+ this._clearReminder(entry);
55082
+ }
55083
+ }
55084
+ this.sessionQueues.clear();
55085
+ this.roundRobinSessions = [];
55086
+ this.roundRobinIndex = 0;
55087
+ const key = Symbol.for("visor.fairConcurrencyLimiter");
55088
+ delete globalThis[key];
55089
+ }
55090
+ shutdown() {
55091
+ this.cleanup();
55092
+ }
55093
+ // -- helpers --
55094
+ _totalQueued() {
55095
+ let n = 0;
55096
+ for (const q of this.sessionQueues.values()) n += q.length;
55097
+ return n;
55098
+ }
55099
+ _waitingSessions() {
55100
+ return this.roundRobinSessions.length;
55101
+ }
55102
+ _removeFromRoundRobin(sid) {
55103
+ const idx = this.roundRobinSessions.indexOf(sid);
55104
+ if (idx !== -1) {
55105
+ this.roundRobinSessions.splice(idx, 1);
55106
+ if (this.roundRobinIndex > idx) {
55107
+ this.roundRobinIndex--;
55108
+ }
55109
+ }
55110
+ }
55111
+ _clearReminder(entry) {
55112
+ if (entry.reminder) {
55113
+ clearInterval(entry.reminder);
55114
+ entry.reminder = void 0;
55115
+ }
55116
+ }
55117
+ };
55118
+ }
55119
+ });
55120
+
54856
55121
  // src/state-machine/context/build-engine-context.ts
54857
55122
  var build_engine_context_exports = {};
54858
55123
  __export(build_engine_context_exports, {
@@ -54908,15 +55173,30 @@ function buildEngineContextForRun(workingDirectory, config, prInfo, debug, maxPa
54908
55173
  const journal = new ExecutionJournal();
54909
55174
  const memory = MemoryStore.getInstance(clonedConfig.memory);
54910
55175
  let sharedConcurrencyLimiter = void 0;
54911
- if (clonedConfig.max_ai_concurrency && _DelegationManager) {
54912
- sharedConcurrencyLimiter = new _DelegationManager({
54913
- maxConcurrent: clonedConfig.max_ai_concurrency,
54914
- maxPerSession: 999
54915
- // No per-session limit needed for global AI gating
54916
- });
54917
- logger.debug(
54918
- `[EngineContext] Created shared AI concurrency limiter (max: ${clonedConfig.max_ai_concurrency})`
54919
- );
55176
+ const sessionId = generateHumanId();
55177
+ if (clonedConfig.max_ai_concurrency) {
55178
+ const fairLimiter = FairConcurrencyLimiter.getInstance(clonedConfig.max_ai_concurrency);
55179
+ sharedConcurrencyLimiter = {
55180
+ async acquire(parentSessionId, _dbg, queueTimeout) {
55181
+ const sid = parentSessionId || sessionId;
55182
+ return fairLimiter.acquire(sid, _dbg, queueTimeout);
55183
+ },
55184
+ release(parentSessionId, _dbg) {
55185
+ const sid = parentSessionId || sessionId;
55186
+ return fairLimiter.release(sid, _dbg);
55187
+ },
55188
+ tryAcquire(parentSessionId) {
55189
+ const sid = parentSessionId || sessionId;
55190
+ return fairLimiter.tryAcquire(sid);
55191
+ },
55192
+ getStats() {
55193
+ return fairLimiter.getStats();
55194
+ },
55195
+ shutdown() {
55196
+ },
55197
+ cleanup() {
55198
+ }
55199
+ };
54920
55200
  }
54921
55201
  return {
54922
55202
  mode: "state-machine",
@@ -54926,7 +55206,7 @@ function buildEngineContextForRun(workingDirectory, config, prInfo, debug, maxPa
54926
55206
  memory,
54927
55207
  workingDirectory,
54928
55208
  originalWorkingDirectory: workingDirectory,
54929
- sessionId: generateHumanId(),
55209
+ sessionId,
54930
55210
  event: prInfo.eventType,
54931
55211
  debug,
54932
55212
  maxParallelism,
@@ -54980,7 +55260,6 @@ async function initializeWorkspace(context2) {
54980
55260
  return context2;
54981
55261
  }
54982
55262
  }
54983
- var _DelegationManager;
54984
55263
  var init_build_engine_context = __esm({
54985
55264
  "src/state-machine/context/build-engine-context.ts"() {
54986
55265
  "use strict";
@@ -54989,14 +55268,7 @@ var init_build_engine_context = __esm({
54989
55268
  init_human_id();
54990
55269
  init_logger();
54991
55270
  init_workspace_manager();
54992
- _DelegationManager = null;
54993
- try {
54994
- const probe = require("@probelabs/probe");
54995
- if (probe && typeof probe.DelegationManager === "function") {
54996
- _DelegationManager = probe.DelegationManager;
54997
- }
54998
- } catch {
54999
- }
55271
+ init_fair_concurrency_limiter();
55000
55272
  }
55001
55273
  });
55002
55274
 
@@ -56198,12 +56470,30 @@ ${end}`);
56198
56470
  this.updateLocks.set(group, ourLock);
56199
56471
  try {
56200
56472
  if (existingLock) {
56473
+ logger.info(
56474
+ `[github-frontend] Comment update for group "${group}" queued, waiting for previous update to finish...`
56475
+ );
56476
+ const queuedAt = Date.now();
56477
+ const reminder = setInterval(() => {
56478
+ const waited = Math.round((Date.now() - queuedAt) / 1e3);
56479
+ logger.info(
56480
+ `[github-frontend] Comment update for group "${group}" still queued (${waited}s).`
56481
+ );
56482
+ }, 1e4);
56201
56483
  try {
56202
56484
  await existingLock;
56203
56485
  } catch (error) {
56204
56486
  logger.warn(
56205
56487
  `[github-frontend] Previous update for group ${group} failed: ${error instanceof Error ? error.message : error}`
56206
56488
  );
56489
+ } finally {
56490
+ clearInterval(reminder);
56491
+ const waitedMs = Date.now() - queuedAt;
56492
+ if (waitedMs > 100) {
56493
+ logger.info(
56494
+ `[github-frontend] Comment update for group "${group}" dequeued after ${Math.round(waitedMs / 1e3)}s.`
56495
+ );
56496
+ }
56207
56497
  }
56208
56498
  }
56209
56499
  await this.performGroupedCommentUpdate(ctx, comments, group, changedIds);