omniharness-cli 0.1.86 → 0.1.88

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/ui/keys.js CHANGED
@@ -102,10 +102,22 @@ export function parseRawKey(chunk) {
102
102
  return null;
103
103
  }
104
104
  /**
105
- * True when `value` is a CSI-u encoded key or protocol response (kitty key
106
- * events, push/pop echoes, query answers), never plain text to insert.
105
+ * True when `value` is a CSI-u encoded key, a protocol response (kitty key
106
+ * events, push/pop echoes, query answers), or a DECRQM mode-report reply
107
+ * (`CSI ? Ps ; Pm $ y`, e.g. the answer to the synchronized-output query) —
108
+ * never plain text to insert.
109
+ *
110
+ * `value` here is Ink's own parsed form, which strips the leading ESC before
111
+ * handing the rest to `useInput`. A terminal's reply to a query this project
112
+ * sends (synchronized output, in particular) arrives on the same stdin the
113
+ * editor reads from, and if nothing recognises it in this stripped form it is
114
+ * treated as pasted text and typed into whatever the user was editing — the
115
+ * escape sequence itself, landing in the input box. Some terminals are slow
116
+ * to answer that specific query, so this has to keep matching however late
117
+ * the reply arrives, not just during a short probe window at startup.
107
118
  */
108
119
  export function isEncodedKey(value) {
109
- return /^\[\d+(?:;\d+)*u$|^\[[><?]\d+(?:;\d+)*u$/.test(value);
120
+ return /^\[\d+(?:;\d+)*u$|^\[[><?]\d+(?:;\d+)*u$/.test(value)
121
+ || /^\[\?\d+;\d\$y$/.test(value);
110
122
  }
111
123
  //# sourceMappingURL=keys.js.map
@@ -334,22 +334,41 @@ export function TerminalInterface({ engine }) {
334
334
  stdout.on('resize', onResize);
335
335
  stdout.write(KITTY_PUSH);
336
336
  let kittyTimer;
337
- // One probe pass: kitty keyboard protocol + synchronized output (DECSET 2026).
338
- const onProbe = (chunk) => {
339
- const text = chunk.toString();
340
- if (isSyncOutputReply(text) && syncRestoreRef.current === null) {
341
- syncRestoreRef.current = wrapSynchronizedOutput(stdout);
342
- }
343
- if (!isKittyQueryResponse(text))
337
+ // Two independent probes, not one shared listener. They used to be a
338
+ // single handler torn down together after 300ms, on the assumption both
339
+ // replies would have arrived by then. Some terminals answer the
340
+ // synchronized-output query well after that — observed landing right
341
+ // around a resize, though the terminal's own reasons for the delay are
342
+ // opaque from here — and a listener already removed cannot catch a late
343
+ // reply. Two things followed from that: synchronized output silently
344
+ // never turned on for the rest of the session, and the reply itself, with
345
+ // nothing left to claim it, reached Ink's own useInput and got typed into
346
+ // the input box as literal text (the isEncodedKey guard now recognises
347
+ // and drops that shape regardless, but the actual fix is to keep
348
+ // listening for it rather than lean on that alone).
349
+ const onSyncProbe = (chunk) => {
350
+ if (syncRestoreRef.current !== null)
351
+ return;
352
+ if (!isSyncOutputReply(chunk.toString()))
353
+ return;
354
+ syncRestoreRef.current = wrapSynchronizedOutput(stdout);
355
+ stdin?.off('data', onSyncProbe);
356
+ };
357
+ // The kitty check is a UI decision — whether Ctrl+letter and a distinct
358
+ // Shift+Tab are available — that has to resolve one way or the other, so
359
+ // it keeps a bounded timeout; "no answer in 300ms" is itself the answer.
360
+ const onKittyProbe = (chunk) => {
361
+ if (!isKittyQueryResponse(chunk.toString()))
344
362
  return;
345
363
  if (kittyTimer)
346
364
  clearTimeout(kittyTimer);
347
- stdin?.off('data', onProbe);
365
+ stdin?.off('data', onKittyProbe);
348
366
  setKitty(true);
349
367
  };
350
368
  if (stdin) {
351
- stdin.on('data', onProbe);
352
- kittyTimer = setTimeout(() => { setKitty(false); stdin.off('data', onProbe); }, 300);
369
+ stdin.on('data', onSyncProbe);
370
+ stdin.on('data', onKittyProbe);
371
+ kittyTimer = setTimeout(() => { setKitty(false); stdin.off('data', onKittyProbe); }, 300);
353
372
  stdout.write(SYNC_QUERY);
354
373
  stdout.write(KITTY_QUERY);
355
374
  }
@@ -432,7 +451,8 @@ export function TerminalInterface({ engine }) {
432
451
  return () => {
433
452
  if (kittyTimer)
434
453
  clearTimeout(kittyTimer);
435
- stdin?.off('data', onProbe);
454
+ stdin?.off('data', onSyncProbe);
455
+ stdin?.off('data', onKittyProbe);
436
456
  stdout.off('resize', onResize); // resizeDebounce cancels the coalesced timer on .off itself
437
457
  const pendingApproval = approvalResolve.current;
438
458
  approvalResolve.current = null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omniharness-cli",
3
- "version": "0.1.86",
3
+ "version": "0.1.88",
4
4
  "description": "OmniHarness — local-first agent orchestration harness for OmniRoute.",
5
5
  "license": "MIT",
6
6
  "type": "module",