Summary
Intermittent RangeError: Maximum call stack size exceeded on the OMP TUI. Stack is a true cycle (same frames repeating), not the finite session_start wrapper chain fixed in #115.
[Unhandled Rejection] RangeError: Maximum call stack size exceeded.
at onRequest (.../packages/extension/src/bridge.ts:2347:49)
at <anonymous> (.../packages/extension/src/prompt-bus.ts:165:33)
at new Promise (native:1:11)
at request (.../packages/extension/src/prompt-bus.ts:141:16)
at <anonymous> (.../packages/extension/src/bridge.ts:2401:12)
at <anonymous> (.../packages/extension/src/bridge.ts:2230:42)
at onRequest (.../packages/extension/src/bridge.ts:2347:49)
...
Installed path: ~/.omp-dashboard/packages/extension/src/. #115's getOrCreatePristineOriginals is present in that tree. This is a leftover hole, not a missing deploy.
Cycle
Line map on the installed file:
| Stack frame |
What it is |
bridge.ts:2230 |
TUI adapter batch arm (prompt.metadata.questions) |
bridge.ts:2401 |
inputWrapper → bus.request(...) |
prompt-bus.ts:141/165 |
PromptBus.request distributes to adapters, calls onRequest synchronously |
bridge.ts:2347 |
TUI adapter onRequest / present() (line may be onResponse after drift; cycle is the same) |
present() does await originals.input(...). If originals.input is the PromptBus inputWrapper, evaluating that call synchronously re-enters bus.request → tui.onRequest → originals.input forever. No await tick; stack blows immediately. Batch is just the prompt that hit it — any originals.select/input/confirm/editor would recurse the same way.
Why #115 does not cover this
#115 (ctx-ui-originals.ts) caches pristine ctx.ui.* in a module-level WeakMap. That is correct across repeated session_start in the same module instance.
It is not correct across:
- jiti module cache invalidation / extension reload (
/__dashboard_reload, npm run reload, dashboard reload). New module = empty WeakMap. ctx.ui is the same object, still patched. First capture after reload reads the wrappers.
- Isolated extension vm contexts.
bridge.ts already parks BridgeState on process.__pi_dashboard_bridge__ because module state does not survive those. The originals map does not.
On a cache miss, already-wrapped methods only console.warn and are still stored:
// ctx-ui-originals.ts
if (typeof ui[key] === 'function' && (ui[key] as any).__isPromptBusWrapper) {
console.warn('[bridge] getOrCreatePristineOriginals: captured an already-wrapped ui method');
break;
}
// then unconditionally:
captured.input = ui.input.bind(ui); // bind() drops __isPromptBusWrapper
pristineUiMap.set(ui, captured);
After that, every prompt is a true cycle. Matches "from time to time": next interactive prompt after a reload / new vm context.
#115's finite chain grew with session_start count. This overflows on the first prompt after a bad capture.
Related
Suggested fix
- Persist pristine originals on
process (same BRIDGE_KEY / sibling key) so they survive jiti invalidation and vm sandboxes. Key by ctx.ui identity.
- On capture, refuse to store a method with
__isPromptBusWrapper. Walk/unwrap or fail loud. Never cache a wrapper as pristine.
- Regression: patch
ctx.ui, drop the module WeakMap (simulate reload), recapture, invoke select/input/batch — must call the native once, never RangeError.
Notes
- Observed on a long-lived TUI session; batch/
ask 2+ questions is the recorded trigger.
- Unrelated to
omp-tool-ui-collapse.
Summary
Intermittent
RangeError: Maximum call stack size exceededon the OMP TUI. Stack is a true cycle (same frames repeating), not the finitesession_startwrapper chain fixed in #115.Installed path:
~/.omp-dashboard/packages/extension/src/. #115'sgetOrCreatePristineOriginalsis present in that tree. This is a leftover hole, not a missing deploy.Cycle
Line map on the installed file:
bridge.ts:2230prompt.metadata.questions)bridge.ts:2401inputWrapper→bus.request(...)prompt-bus.ts:141/165PromptBus.requestdistributes to adapters, callsonRequestsynchronouslybridge.ts:2347onRequest/present()(line may beonResponseafter drift; cycle is the same)present()doesawait originals.input(...). Iforiginals.inputis the PromptBusinputWrapper, evaluating that call synchronously re-entersbus.request→tui.onRequest→originals.inputforever. No await tick; stack blows immediately. Batch is just the prompt that hit it — anyoriginals.select/input/confirm/editorwould recurse the same way.Why #115 does not cover this
#115 (
ctx-ui-originals.ts) caches pristinectx.ui.*in a module-levelWeakMap. That is correct across repeatedsession_startin the same module instance.It is not correct across:
/__dashboard_reload,npm run reload, dashboard reload). New module = empty WeakMap.ctx.uiis the same object, still patched. First capture after reload reads the wrappers.bridge.tsalready parksBridgeStateonprocess.__pi_dashboard_bridge__because module state does not survive those. The originals map does not.On a cache miss, already-wrapped methods only
console.warnand are still stored:After that, every prompt is a true cycle. Matches "from time to time": next interactive prompt after a reload / new vm context.
#115's finite chain grew with
session_startcount. This overflows on the first prompt after a bad capture.Related
session_start). Closed. Residual: cache does not survive the reload/sandbox boundary the rest of the bridge already special-cases.Suggested fix
process(sameBRIDGE_KEY/ sibling key) so they survive jiti invalidation and vm sandboxes. Key byctx.uiidentity.__isPromptBusWrapper. Walk/unwrap or fail loud. Never cache a wrapper as pristine.ctx.ui, drop the module WeakMap (simulate reload), recapture, invokeselect/input/batch — must call the native once, neverRangeError.Notes
ask2+ questions is the recorded trigger.omp-tool-ui-collapse.