poly-weaver 0.5.0 → 0.6.0

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 (146) hide show
  1. package/dist/agents/implementors/handler.d.ts.map +1 -1
  2. package/dist/agents/implementors/handler.js +2 -1
  3. package/dist/agents/implementors/handler.js.map +1 -1
  4. package/dist/agents/planners/handler.d.ts.map +1 -1
  5. package/dist/agents/planners/handler.js +2 -1
  6. package/dist/agents/planners/handler.js.map +1 -1
  7. package/dist/agents/reviewers/handler.d.ts.map +1 -1
  8. package/dist/agents/reviewers/handler.js +9 -2
  9. package/dist/agents/reviewers/handler.js.map +1 -1
  10. package/dist/agents/runner.d.ts +40 -1
  11. package/dist/agents/runner.d.ts.map +1 -1
  12. package/dist/agents/runner.js +213 -14
  13. package/dist/agents/runner.js.map +1 -1
  14. package/dist/agents/simplifiers/handler.d.ts.map +1 -1
  15. package/dist/agents/simplifiers/handler.js +2 -1
  16. package/dist/agents/simplifiers/handler.js.map +1 -1
  17. package/dist/ansi.d.ts +26 -0
  18. package/dist/ansi.d.ts.map +1 -1
  19. package/dist/ansi.js +26 -0
  20. package/dist/ansi.js.map +1 -1
  21. package/dist/cli.js +46 -16
  22. package/dist/cli.js.map +1 -1
  23. package/dist/flow/built-in/default.js +1 -1
  24. package/dist/flow/built-in/default.js.map +1 -1
  25. package/dist/flow/built-in/default.ts +1 -1
  26. package/dist/flow/built-in/why-so-serious.js +1 -1
  27. package/dist/flow/built-in/why-so-serious.js.map +1 -1
  28. package/dist/flow/executor.d.ts.map +1 -1
  29. package/dist/flow/executor.js +7 -2
  30. package/dist/flow/executor.js.map +1 -1
  31. package/dist/flow/types.d.ts +5 -0
  32. package/dist/flow/types.d.ts.map +1 -1
  33. package/dist/flow/types.js.map +1 -1
  34. package/dist/orchestrator.d.ts +10 -4
  35. package/dist/orchestrator.d.ts.map +1 -1
  36. package/dist/orchestrator.js +34 -14
  37. package/dist/orchestrator.js.map +1 -1
  38. package/dist/providers/claude/session.d.ts +3 -1
  39. package/dist/providers/claude/session.d.ts.map +1 -1
  40. package/dist/providers/claude/session.js +10 -2
  41. package/dist/providers/claude/session.js.map +1 -1
  42. package/dist/providers/codex/session.d.ts +6 -3
  43. package/dist/providers/codex/session.d.ts.map +1 -1
  44. package/dist/providers/codex/session.js +24 -4
  45. package/dist/providers/codex/session.js.map +1 -1
  46. package/dist/providers/copilot/session.d.ts +3 -1
  47. package/dist/providers/copilot/session.d.ts.map +1 -1
  48. package/dist/providers/copilot/session.js +15 -2
  49. package/dist/providers/copilot/session.js.map +1 -1
  50. package/dist/providers/types.d.ts +14 -2
  51. package/dist/providers/types.d.ts.map +1 -1
  52. package/dist/providers/types.js.map +1 -1
  53. package/dist/pty/exit.d.ts +13 -5
  54. package/dist/pty/exit.d.ts.map +1 -1
  55. package/dist/pty/exit.js +19 -19
  56. package/dist/pty/exit.js.map +1 -1
  57. package/dist/pty/spawn.d.ts +12 -6
  58. package/dist/pty/spawn.d.ts.map +1 -1
  59. package/dist/pty/spawn.js +22 -70
  60. package/dist/pty/spawn.js.map +1 -1
  61. package/dist/pty/types.d.ts +12 -3
  62. package/dist/pty/types.d.ts.map +1 -1
  63. package/dist/session/locator.d.ts +23 -2
  64. package/dist/session/locator.d.ts.map +1 -1
  65. package/dist/session/locator.js +67 -4
  66. package/dist/session/locator.js.map +1 -1
  67. package/dist/status-bar.d.ts +21 -1
  68. package/dist/status-bar.d.ts.map +1 -1
  69. package/dist/status-bar.js +109 -34
  70. package/dist/status-bar.js.map +1 -1
  71. package/dist/terminal/cleanup.d.ts +21 -0
  72. package/dist/terminal/cleanup.d.ts.map +1 -0
  73. package/dist/terminal/cleanup.js +22 -0
  74. package/dist/terminal/cleanup.js.map +1 -0
  75. package/dist/terminal/host.d.ts +244 -0
  76. package/dist/terminal/host.d.ts.map +1 -0
  77. package/dist/terminal/host.js +642 -0
  78. package/dist/terminal/host.js.map +1 -0
  79. package/dist/terminal/input-router.d.ts +146 -0
  80. package/dist/terminal/input-router.d.ts.map +1 -0
  81. package/dist/terminal/input-router.js +426 -0
  82. package/dist/terminal/input-router.js.map +1 -0
  83. package/dist/terminal/layout.d.ts +55 -0
  84. package/dist/terminal/layout.d.ts.map +1 -0
  85. package/dist/terminal/layout.js +51 -0
  86. package/dist/terminal/layout.js.map +1 -0
  87. package/dist/terminal/output.d.ts +83 -0
  88. package/dist/terminal/output.d.ts.map +1 -0
  89. package/dist/terminal/output.js +107 -0
  90. package/dist/terminal/output.js.map +1 -0
  91. package/dist/terminal/render.d.ts +36 -0
  92. package/dist/terminal/render.d.ts.map +1 -0
  93. package/dist/terminal/render.js +233 -0
  94. package/dist/terminal/render.js.map +1 -0
  95. package/dist/terminal/virtual-terminal.d.ts +54 -0
  96. package/dist/terminal/virtual-terminal.d.ts.map +1 -0
  97. package/dist/terminal/virtual-terminal.js +110 -0
  98. package/dist/terminal/virtual-terminal.js.map +1 -0
  99. package/dist/terminal-input.d.ts +10 -0
  100. package/dist/terminal-input.d.ts.map +1 -1
  101. package/dist/terminal-input.js +46 -0
  102. package/dist/terminal-input.js.map +1 -1
  103. package/dist/user/auto-curate-prompt.d.ts +17 -0
  104. package/dist/user/auto-curate-prompt.d.ts.map +1 -0
  105. package/dist/user/auto-curate-prompt.js +22 -0
  106. package/dist/user/auto-curate-prompt.js.map +1 -0
  107. package/dist/user/curate-handler.d.ts.map +1 -1
  108. package/dist/user/curate-handler.js +10 -2
  109. package/dist/user/curate-handler.js.map +1 -1
  110. package/dist/user/curate-prompt.d.ts +9 -7
  111. package/dist/user/curate-prompt.d.ts.map +1 -1
  112. package/dist/user/curate-prompt.js +2 -341
  113. package/dist/user/curate-prompt.js.map +1 -1
  114. package/dist/user/handler.d.ts +13 -1
  115. package/dist/user/handler.d.ts.map +1 -1
  116. package/dist/user/handler.js +27 -15
  117. package/dist/user/handler.js.map +1 -1
  118. package/dist/user/hard-wrap.d.ts +11 -0
  119. package/dist/user/hard-wrap.d.ts.map +1 -0
  120. package/dist/user/hard-wrap.js +44 -0
  121. package/dist/user/hard-wrap.js.map +1 -0
  122. package/dist/user/host-curate-prompt.d.ts +34 -0
  123. package/dist/user/host-curate-prompt.d.ts.map +1 -0
  124. package/dist/user/host-curate-prompt.js +453 -0
  125. package/dist/user/host-curate-prompt.js.map +1 -0
  126. package/dist/user/host-prompt.d.ts +21 -0
  127. package/dist/user/host-prompt.d.ts.map +1 -0
  128. package/dist/user/host-prompt.js +337 -0
  129. package/dist/user/host-prompt.js.map +1 -0
  130. package/dist/user/index.d.ts +3 -3
  131. package/dist/user/index.d.ts.map +1 -1
  132. package/dist/user/index.js +2 -2
  133. package/dist/user/index.js.map +1 -1
  134. package/dist/user/plan-pane.d.ts +18 -0
  135. package/dist/user/plan-pane.d.ts.map +1 -0
  136. package/dist/user/plan-pane.js +33 -0
  137. package/dist/user/plan-pane.js.map +1 -0
  138. package/dist/user/prompt.d.ts +25 -42
  139. package/dist/user/prompt.d.ts.map +1 -1
  140. package/dist/user/prompt.js +16 -278
  141. package/dist/user/prompt.js.map +1 -1
  142. package/dist/user/split-surface.d.ts +32 -0
  143. package/dist/user/split-surface.d.ts.map +1 -0
  144. package/dist/user/split-surface.js +66 -0
  145. package/dist/user/split-surface.js.map +1 -0
  146. package/package.json +2 -1
@@ -0,0 +1,146 @@
1
+ import type { PtyHandle } from "../pty/types.js";
2
+ /**
3
+ * Active parent UI mode (e.g. user-review prompt). When attached, raw
4
+ * stdin chunks are routed to it BEFORE host shortcuts / mouse / interrupt
5
+ * (but AFTER the global Ctrl+] dump detector). A host-backed prompt that
6
+ * wants to own wheel/mouse input simply consumes the chunk by returning
7
+ * `true` (the default).
8
+ */
9
+ export interface ParentUiMode {
10
+ /** Receive a chunk of raw input. Return true if consumed (don't forward). */
11
+ onInput(chunk: Buffer): boolean | void;
12
+ }
13
+ /**
14
+ * Number of lines to scroll for a single mouse-wheel event. Small enough
15
+ * to feel precise while still moving meaningfully on every notch.
16
+ */
17
+ export declare const WHEEL_LINES_PER_EVENT = 3;
18
+ export interface InputRouterOptions {
19
+ /** Trigger a dump capture when Ctrl+] is observed. */
20
+ onDump?: () => void;
21
+ /** Host interrupt: invoked when raw Ctrl+C (byte 0x03) is observed and no parent UI consumes it. */
22
+ onInterrupt?: () => void;
23
+ /** Scroll back by N lines (older content). */
24
+ onScrollBackLines?: (lines: number) => void;
25
+ /** Scroll forward by N lines (newer content). */
26
+ onScrollForwardLines?: (lines: number) => void;
27
+ /** Scroll by N pages. Positive = forward (newer), negative = back (older). */
28
+ onScrollPages?: (pages: number) => void;
29
+ /** Jump to the top of scrollback. */
30
+ onScrollToTop?: () => void;
31
+ /** Jump to the live tail (bottom). */
32
+ onScrollToBottom?: () => void;
33
+ }
34
+ /**
35
+ * Centralizes stdin ownership while the orchestration host is active.
36
+ *
37
+ * Routing order on each chunk:
38
+ *
39
+ * 1. Dump hotkey detector (Ctrl+]) — strips dump bytes from forward.
40
+ * The detector also reassembles split CSI sequences for kitty /
41
+ * win32 dump variants, so when configured, downstream stages see
42
+ * whole sequences for those paths.
43
+ * 2. Active parent UI mode (if attached) — fully consumes by default.
44
+ * Parent UI receives Ctrl+C, mouse, and nav keys first and may
45
+ * handle them. Only when there is no parent UI, or it returns
46
+ * `false`, does routing fall through to the host's own handlers.
47
+ * 3. SGR mouse-wheel parsing — consumes `CSI < 64/65 ; … M` for
48
+ * vertical wheel events and dispatches scroll callbacks. Non-wheel
49
+ * SGR mouse events flow through unchanged. A small first-class
50
+ * buffer reassembles SGR mouse sequences split across chunks so
51
+ * the routing works regardless of whether the dump detector is
52
+ * configured.
53
+ * 4. Host shortcut routing on remaining bytes:
54
+ * - Ctrl+C (0x03) → `onInterrupt()`
55
+ * - PageUp (CSI 5~) → `onScrollPages(-1)`
56
+ * - PageDown (CSI 6~) → `onScrollPages(+1)`
57
+ * - Home (CSI 1~/H) → `onScrollToTop()`
58
+ * - End (CSI 4~/F) → `onScrollToBottom()`
59
+ * 5. Attached child PTY when `gateOpen` is true — `handle.write(forward)`.
60
+ * 6. Otherwise the chunk is dropped.
61
+ */
62
+ export declare class InputRouter {
63
+ private readonly options;
64
+ private parentUiMode;
65
+ private childHandle;
66
+ private dumpDetector;
67
+ /** Buffered head of a split SGR mouse sequence (`ESC [ < … `). */
68
+ private sgrPartial;
69
+ private sgrPartialTimer;
70
+ constructor(options?: InputRouterOptions);
71
+ attachChild(handle: PtyHandle): void;
72
+ detachChild(handle?: PtyHandle): void;
73
+ attachParentUi(mode: ParentUiMode): void;
74
+ detachParentUi(mode?: ParentUiMode): void;
75
+ /** Process a stdin chunk. Returns true when at least one byte was consumed. */
76
+ handleChunk(chunk: Buffer): boolean;
77
+ private forwardToChild;
78
+ /**
79
+ * Strip SGR mouse wheel events (`CSI < 64;…M` and `CSI < 65;…M`) from
80
+ * the chunk, dispatching scrollback callbacks. Non-wheel SGR mouse
81
+ * events (clicks, motion, releases) and other CSI sequences (Home,
82
+ * PageUp, etc.) are left in the chunk so callers can still forward
83
+ * them or run them through host shortcut routing.
84
+ *
85
+ * Sequences split across chunk boundaries are first-class. The buffer
86
+ * holds any incomplete CSI prefix — bare ESC, ESC `[`, ESC `[ < …` —
87
+ * and prepends it to the next chunk. This works even when the dump
88
+ * detector is not configured (the detector reassembles split CSI for
89
+ * its own purposes when it is configured, but mouse-wheel scrollback
90
+ * MUST NOT depend on it). A 50 ms safety timer flushes a stale
91
+ * partial through `consumeHostShortcuts` and the child gate so a
92
+ * bare Esc keypress eventually reaches the child even when there is
93
+ * no continuation, and so a stray ESC byte cannot permanently block
94
+ * future input.
95
+ */
96
+ private consumeSgrMouseWheel;
97
+ private savePartialSgr;
98
+ /**
99
+ * Stale-partial flush. Two distinct cases:
100
+ *
101
+ * - Bare `ESC` (1 byte): flush through host shortcuts and the child
102
+ * gate. The user pressed Esc and there is no continuation; the
103
+ * child must still receive the byte after the safety window
104
+ * (matching the dump detector's bare-Esc deferred-flush).
105
+ *
106
+ * - Truncated CSI (`ESC [ …`, 2+ bytes): drop. The user pressed
107
+ * Home/PageUp/wheel/etc. and the terminal failed to deliver the
108
+ * rest within the window. Forwarding raw `ESC [ < 6 4 ;` would
109
+ * inject random bytes into the child agent — much worse than
110
+ * losing one stray nav event.
111
+ */
112
+ private flushPartialSgr;
113
+ private resetSgrPartialTimer;
114
+ private resetSgrPartial;
115
+ /**
116
+ * Consume host scrollback / interrupt shortcuts from the chunk. Returns
117
+ * the chunk with any consumed bytes removed.
118
+ *
119
+ * Recognized sequences (single-chunk only — split CSI across two
120
+ * chunks falls through to the child unchanged, which is acceptable
121
+ * because real terminals deliver these in one chunk):
122
+ *
123
+ * - 0x03 Ctrl+C → onInterrupt()
124
+ * - ESC [ 5 ~ PageUp → onScrollPages(-1)
125
+ * - ESC [ 6 ~ PageDown → onScrollPages(+1)
126
+ * - ESC [ 1 ~ / ESC [ H Home → onScrollToTop()
127
+ * - ESC [ 4 ~ / ESC [ F End → onScrollToBottom()
128
+ *
129
+ * Modifier-prefixed variants (e.g. `ESC [ 1;5 H` for Ctrl+Home) match
130
+ * the same callback as their unmodified form.
131
+ */
132
+ private consumeHostShortcuts;
133
+ private dispatchCsi;
134
+ /**
135
+ * Route a deferred buffer (produced by `DumpHotkeyDetector` when a
136
+ * pending escape sequence times out). The deferred bytes have already
137
+ * been screened for the dump hotkey — they must NOT pass through the
138
+ * detector again. They DO continue through the parent UI mode, the
139
+ * SGR mouse parser, host shortcuts, and the child gate so a bare Esc
140
+ * reaches host-backed prompts and a deferred mouse sequence is still
141
+ * correctly classified.
142
+ */
143
+ private routeDeferred;
144
+ destroy(): void;
145
+ }
146
+ //# sourceMappingURL=input-router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-router.d.ts","sourceRoot":"","sources":["../../src/terminal/input-router.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEjD;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,6EAA6E;IAC7E,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;CACxC;AAED;;;GAGG;AACH,eAAO,MAAM,qBAAqB,IAAI,CAAC;AAEvC,MAAM,WAAW,kBAAkB;IACjC,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,oGAAoG;IACpG,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IACzB,8CAA8C;IAC9C,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,iDAAiD;IACjD,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/C,8EAA8E;IAC9E,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,qCAAqC;IACrC,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,sCAAsC;IACtC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;CAC/B;AAWD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,qBAAa,WAAW;IAQV,OAAO,CAAC,QAAQ,CAAC,OAAO;IAPpC,OAAO,CAAC,YAAY,CAA2B;IAC/C,OAAO,CAAC,WAAW,CAAwB;IAC3C,OAAO,CAAC,YAAY,CAAiC;IACrD,kEAAkE;IAClE,OAAO,CAAC,UAAU,CAAgB;IAClC,OAAO,CAAC,eAAe,CAA4C;gBAEtC,OAAO,GAAE,kBAAuB;IAmB7D,WAAW,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;IAIpC,WAAW,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,IAAI;IAKrC,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI;IAIxC,cAAc,CAAC,IAAI,CAAC,EAAE,YAAY,GAAG,IAAI;IAKzC,+EAA+E;IAC/E,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO;IAmCnC,OAAO,CAAC,cAAc;IAOtB;;;;;;;;;;;;;;;;;OAiBG;IACH,OAAO,CAAC,oBAAoB;IAsF5B,OAAO,CAAC,cAAc;IAMtB;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,eAAe;IAgBvB,OAAO,CAAC,oBAAoB;IAO5B,OAAO,CAAC,eAAe;IAOvB;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,oBAAoB;IAmD5B,OAAO,CAAC,WAAW;IAqDnB;;;;;;;;OAQG;IACH,OAAO,CAAC,aAAa;IAgBrB,OAAO,IAAI,IAAI;CAOhB"}
@@ -0,0 +1,426 @@
1
+ import { DumpHotkeyDetector } from "../dump/hotkey.js";
2
+ /**
3
+ * Number of lines to scroll for a single mouse-wheel event. Small enough
4
+ * to feel precise while still moving meaningfully on every notch.
5
+ */
6
+ export const WHEEL_LINES_PER_EVENT = 3;
7
+ const ETX = 0x03; // Ctrl+C
8
+ const ESC = 0x1b;
9
+ const LBRACKET = 0x5b; // '['
10
+ const LT = 0x3c; // '<'
11
+ const TILDE = 0x7e; // '~'
12
+ /** Maximum dwell for a buffered partial SGR mouse sequence before we drop it. */
13
+ const SGR_MOUSE_PARTIAL_TIMEOUT_MS = 50;
14
+ /**
15
+ * Centralizes stdin ownership while the orchestration host is active.
16
+ *
17
+ * Routing order on each chunk:
18
+ *
19
+ * 1. Dump hotkey detector (Ctrl+]) — strips dump bytes from forward.
20
+ * The detector also reassembles split CSI sequences for kitty /
21
+ * win32 dump variants, so when configured, downstream stages see
22
+ * whole sequences for those paths.
23
+ * 2. Active parent UI mode (if attached) — fully consumes by default.
24
+ * Parent UI receives Ctrl+C, mouse, and nav keys first and may
25
+ * handle them. Only when there is no parent UI, or it returns
26
+ * `false`, does routing fall through to the host's own handlers.
27
+ * 3. SGR mouse-wheel parsing — consumes `CSI < 64/65 ; … M` for
28
+ * vertical wheel events and dispatches scroll callbacks. Non-wheel
29
+ * SGR mouse events flow through unchanged. A small first-class
30
+ * buffer reassembles SGR mouse sequences split across chunks so
31
+ * the routing works regardless of whether the dump detector is
32
+ * configured.
33
+ * 4. Host shortcut routing on remaining bytes:
34
+ * - Ctrl+C (0x03) → `onInterrupt()`
35
+ * - PageUp (CSI 5~) → `onScrollPages(-1)`
36
+ * - PageDown (CSI 6~) → `onScrollPages(+1)`
37
+ * - Home (CSI 1~/H) → `onScrollToTop()`
38
+ * - End (CSI 4~/F) → `onScrollToBottom()`
39
+ * 5. Attached child PTY when `gateOpen` is true — `handle.write(forward)`.
40
+ * 6. Otherwise the chunk is dropped.
41
+ */
42
+ export class InputRouter {
43
+ options;
44
+ parentUiMode;
45
+ childHandle;
46
+ dumpDetector;
47
+ /** Buffered head of a split SGR mouse sequence (`ESC [ < … `). */
48
+ sgrPartial = [];
49
+ sgrPartialTimer;
50
+ constructor(options = {}) {
51
+ this.options = options;
52
+ if (this.options.onDump) {
53
+ const onDump = this.options.onDump;
54
+ this.dumpDetector = new DumpHotkeyDetector(() => onDump(), (deferred) => {
55
+ // Deferred flush — fires when DumpHotkeyDetector buffered an
56
+ // ESC (or partial CSI) and the timeout expired without a final
57
+ // byte arriving. Re-enter the routing pipeline so a bare ESC
58
+ // reaches an active parent UI mode (HostBackedCuratePrompt
59
+ // uses Esc to cancel comment editing). Only when there is no
60
+ // parent UI and the child gate is open does the bytes reach
61
+ // the child.
62
+ this.routeDeferred(deferred);
63
+ });
64
+ }
65
+ }
66
+ attachChild(handle) {
67
+ this.childHandle = handle;
68
+ }
69
+ detachChild(handle) {
70
+ if (handle && this.childHandle !== handle)
71
+ return;
72
+ this.childHandle = undefined;
73
+ }
74
+ attachParentUi(mode) {
75
+ this.parentUiMode = mode;
76
+ }
77
+ detachParentUi(mode) {
78
+ if (mode && this.parentUiMode !== mode)
79
+ return;
80
+ this.parentUiMode = undefined;
81
+ }
82
+ /** Process a stdin chunk. Returns true when at least one byte was consumed. */
83
+ handleChunk(chunk) {
84
+ // Global parent shortcuts run FIRST so Ctrl+] reliably triggers a
85
+ // dump regardless of which UI mode currently owns input. The detector
86
+ // strips the hotkey bytes from the forward buffer; everything else
87
+ // continues down the routing pipeline.
88
+ let forward = chunk;
89
+ if (this.dumpDetector) {
90
+ forward = this.dumpDetector.process(chunk);
91
+ }
92
+ if (forward.length === 0)
93
+ return true;
94
+ // Parent UI gets first crack at every byte that isn't the dump
95
+ // hotkey — including mouse events and nav keys. A host-backed
96
+ // prompt that wants to own wheel input simply consumes the chunk.
97
+ if (this.parentUiMode) {
98
+ const consumed = this.parentUiMode.onInput(forward);
99
+ // Default behaviour: parent UI swallows everything until detached.
100
+ if (consumed !== false) {
101
+ // The parent UI took ownership. Any partial SGR mouse sequence
102
+ // we previously buffered no longer applies — clear the buffer.
103
+ this.resetSgrPartial();
104
+ return true;
105
+ }
106
+ }
107
+ // Host owns the bytes. SGR mouse-wheel parsing comes BEFORE host
108
+ // shortcuts so wheel events don't accidentally match nav keys.
109
+ forward = this.consumeSgrMouseWheel(forward);
110
+ if (forward.length === 0)
111
+ return true;
112
+ const afterShortcuts = this.consumeHostShortcuts(forward);
113
+ if (afterShortcuts.length === 0)
114
+ return true;
115
+ return this.forwardToChild(afterShortcuts);
116
+ }
117
+ forwardToChild(buf) {
118
+ const child = this.childHandle;
119
+ if (!child || !child.gateOpen)
120
+ return false;
121
+ child.write(buf.toString());
122
+ return true;
123
+ }
124
+ /**
125
+ * Strip SGR mouse wheel events (`CSI < 64;…M` and `CSI < 65;…M`) from
126
+ * the chunk, dispatching scrollback callbacks. Non-wheel SGR mouse
127
+ * events (clicks, motion, releases) and other CSI sequences (Home,
128
+ * PageUp, etc.) are left in the chunk so callers can still forward
129
+ * them or run them through host shortcut routing.
130
+ *
131
+ * Sequences split across chunk boundaries are first-class. The buffer
132
+ * holds any incomplete CSI prefix — bare ESC, ESC `[`, ESC `[ < …` —
133
+ * and prepends it to the next chunk. This works even when the dump
134
+ * detector is not configured (the detector reassembles split CSI for
135
+ * its own purposes when it is configured, but mouse-wheel scrollback
136
+ * MUST NOT depend on it). A 50 ms safety timer flushes a stale
137
+ * partial through `consumeHostShortcuts` and the child gate so a
138
+ * bare Esc keypress eventually reaches the child even when there is
139
+ * no continuation, and so a stray ESC byte cannot permanently block
140
+ * future input.
141
+ */
142
+ consumeSgrMouseWheel(buf) {
143
+ // Prepend any buffered partial to this chunk before parsing.
144
+ if (this.sgrPartial.length > 0) {
145
+ const merged = Buffer.allocUnsafe(this.sgrPartial.length + buf.length);
146
+ for (let k = 0; k < this.sgrPartial.length; k++)
147
+ merged[k] = this.sgrPartial[k];
148
+ buf.copy(merged, this.sgrPartial.length);
149
+ buf = merged;
150
+ this.resetSgrPartialTimer();
151
+ this.sgrPartial = [];
152
+ }
153
+ if (buf.length === 0)
154
+ return buf;
155
+ const out = [];
156
+ let i = 0;
157
+ while (i < buf.length) {
158
+ const b = buf[i];
159
+ if (b !== ESC) {
160
+ out.push(b);
161
+ i++;
162
+ continue;
163
+ }
164
+ // ESC byte. The chunk ends here, after `[`, or after `[ < …`
165
+ // — buffer the partial in every case so a split mouse sequence
166
+ // never leaks to the child as half-bytes.
167
+ if (i + 1 >= buf.length) {
168
+ // Bare ESC at end-of-chunk. Could be (a) the Esc key, (b) the
169
+ // start of an Alt+key combo, or (c) the start of any CSI
170
+ // including SGR mouse. Buffering all three for 50 ms costs a
171
+ // small delay on the Esc key (matching the dump detector's
172
+ // own delay) but is the price of not forwarding partial mouse
173
+ // sequences to the child.
174
+ this.savePartialSgr(buf.subarray(i));
175
+ return Buffer.from(out);
176
+ }
177
+ if (buf[i + 1] !== LBRACKET) {
178
+ // ESC + non-`[` — Alt+key or another ESC-prefixed combo. Emit
179
+ // both bytes immediately so Alt+key combos are not delayed.
180
+ out.push(b);
181
+ i++;
182
+ continue;
183
+ }
184
+ // We have ESC `[`. Find the CSI final byte in the range 0x40-0x7e.
185
+ let j = i + 2;
186
+ while (j < buf.length) {
187
+ const t = buf[j];
188
+ if (t >= 0x40 && t <= 0x7e)
189
+ break;
190
+ j++;
191
+ }
192
+ if (j >= buf.length) {
193
+ // Unterminated CSI — buffer the partial for the next chunk to
194
+ // complete. This covers all reviewer-flagged splits: ESC alone,
195
+ // `ESC [`, `ESC [ <`, `ESC [ < 64 ;`, etc.
196
+ this.savePartialSgr(buf.subarray(i));
197
+ return Buffer.from(out);
198
+ }
199
+ const params = buf.subarray(i + 2, j).toString("ascii");
200
+ const final = buf[j];
201
+ // SGR mouse-wheel sequence: ESC `[ < cb ; cx ; cy M` where
202
+ // cb=64 (wheel up) or cb=65 (wheel down). Anything else (clicks,
203
+ // releases, non-mouse CSI) is passed through unchanged.
204
+ if (params.startsWith("<") && final === 0x4d /* M */) {
205
+ const cb = parseInt(params.slice(1).split(";")[0] ?? "", 10);
206
+ if (cb === 64) {
207
+ this.options.onScrollBackLines?.(WHEEL_LINES_PER_EVENT);
208
+ i = j + 1;
209
+ continue;
210
+ }
211
+ if (cb === 65) {
212
+ this.options.onScrollForwardLines?.(WHEEL_LINES_PER_EVENT);
213
+ i = j + 1;
214
+ continue;
215
+ }
216
+ }
217
+ // Not a mouse wheel — emit the entire CSI sequence intact.
218
+ for (let k = i; k <= j; k++)
219
+ out.push(buf[k]);
220
+ i = j + 1;
221
+ }
222
+ return Buffer.from(out);
223
+ }
224
+ savePartialSgr(partial) {
225
+ this.sgrPartial = Array.from(partial);
226
+ if (this.sgrPartialTimer)
227
+ clearTimeout(this.sgrPartialTimer);
228
+ this.sgrPartialTimer = setTimeout(() => this.flushPartialSgr(), SGR_MOUSE_PARTIAL_TIMEOUT_MS);
229
+ }
230
+ /**
231
+ * Stale-partial flush. Two distinct cases:
232
+ *
233
+ * - Bare `ESC` (1 byte): flush through host shortcuts and the child
234
+ * gate. The user pressed Esc and there is no continuation; the
235
+ * child must still receive the byte after the safety window
236
+ * (matching the dump detector's bare-Esc deferred-flush).
237
+ *
238
+ * - Truncated CSI (`ESC [ …`, 2+ bytes): drop. The user pressed
239
+ * Home/PageUp/wheel/etc. and the terminal failed to deliver the
240
+ * rest within the window. Forwarding raw `ESC [ < 6 4 ;` would
241
+ * inject random bytes into the child agent — much worse than
242
+ * losing one stray nav event.
243
+ */
244
+ flushPartialSgr() {
245
+ if (this.sgrPartial.length === 0) {
246
+ this.sgrPartialTimer = undefined;
247
+ return;
248
+ }
249
+ const buf = Buffer.from(this.sgrPartial);
250
+ this.sgrPartial = [];
251
+ this.sgrPartialTimer = undefined;
252
+ if (buf.length === 1 && buf[0] === ESC) {
253
+ const afterShortcuts = this.consumeHostShortcuts(buf);
254
+ if (afterShortcuts.length > 0)
255
+ this.forwardToChild(afterShortcuts);
256
+ }
257
+ // Else: drop the truncated CSI prefix.
258
+ }
259
+ resetSgrPartialTimer() {
260
+ if (this.sgrPartialTimer) {
261
+ clearTimeout(this.sgrPartialTimer);
262
+ this.sgrPartialTimer = undefined;
263
+ }
264
+ }
265
+ resetSgrPartial() {
266
+ this.resetSgrPartialTimer();
267
+ if (this.sgrPartial.length > 0) {
268
+ this.sgrPartial = [];
269
+ }
270
+ }
271
+ /**
272
+ * Consume host scrollback / interrupt shortcuts from the chunk. Returns
273
+ * the chunk with any consumed bytes removed.
274
+ *
275
+ * Recognized sequences (single-chunk only — split CSI across two
276
+ * chunks falls through to the child unchanged, which is acceptable
277
+ * because real terminals deliver these in one chunk):
278
+ *
279
+ * - 0x03 Ctrl+C → onInterrupt()
280
+ * - ESC [ 5 ~ PageUp → onScrollPages(-1)
281
+ * - ESC [ 6 ~ PageDown → onScrollPages(+1)
282
+ * - ESC [ 1 ~ / ESC [ H Home → onScrollToTop()
283
+ * - ESC [ 4 ~ / ESC [ F End → onScrollToBottom()
284
+ *
285
+ * Modifier-prefixed variants (e.g. `ESC [ 1;5 H` for Ctrl+Home) match
286
+ * the same callback as their unmodified form.
287
+ */
288
+ consumeHostShortcuts(buf) {
289
+ if (buf.length === 0)
290
+ return buf;
291
+ const out = [];
292
+ let i = 0;
293
+ while (i < buf.length) {
294
+ const b = buf[i];
295
+ if (b === ETX) {
296
+ if (this.options.onInterrupt) {
297
+ this.options.onInterrupt();
298
+ i++;
299
+ continue;
300
+ }
301
+ // No interrupt handler — fall through to child.
302
+ out.push(b);
303
+ i++;
304
+ continue;
305
+ }
306
+ if (b === ESC && i + 1 < buf.length && buf[i + 1] === LBRACKET) {
307
+ // Find the CSI final byte.
308
+ let j = i + 2;
309
+ while (j < buf.length) {
310
+ const t = buf[j];
311
+ if (t >= 0x40 && t <= 0x7e)
312
+ break;
313
+ j++;
314
+ }
315
+ if (j >= buf.length) {
316
+ // Unterminated — emit remainder unchanged.
317
+ for (let k = i; k < buf.length; k++)
318
+ out.push(buf[k]);
319
+ return Buffer.from(out);
320
+ }
321
+ const params = buf.subarray(i + 2, j).toString("ascii");
322
+ const final = buf[j];
323
+ const handled = this.dispatchCsi(params, final);
324
+ if (handled) {
325
+ i = j + 1;
326
+ continue;
327
+ }
328
+ // Not a host shortcut — pass through unchanged.
329
+ for (let k = i; k <= j; k++)
330
+ out.push(buf[k]);
331
+ i = j + 1;
332
+ continue;
333
+ }
334
+ out.push(b);
335
+ i++;
336
+ }
337
+ return Buffer.from(out);
338
+ }
339
+ dispatchCsi(params, final) {
340
+ // PageUp = ESC [ 5 ~ ; PageDown = ESC [ 6 ~ ; Home = ESC [ 1 ~ or H ;
341
+ // End = ESC [ 4 ~ or F. Modifier params (e.g. "1;5") are accepted so
342
+ // Ctrl/Shift+nav routes through the same scroll callback.
343
+ if (final === TILDE) {
344
+ const code = parseInt(params.split(";")[0] ?? "", 10);
345
+ if (code === 5) {
346
+ if (this.options.onScrollPages) {
347
+ this.options.onScrollPages(-1);
348
+ return true;
349
+ }
350
+ return false;
351
+ }
352
+ if (code === 6) {
353
+ if (this.options.onScrollPages) {
354
+ this.options.onScrollPages(1);
355
+ return true;
356
+ }
357
+ return false;
358
+ }
359
+ if (code === 1 || code === 7) {
360
+ if (this.options.onScrollToTop) {
361
+ this.options.onScrollToTop();
362
+ return true;
363
+ }
364
+ return false;
365
+ }
366
+ if (code === 4 || code === 8) {
367
+ if (this.options.onScrollToBottom) {
368
+ this.options.onScrollToBottom();
369
+ return true;
370
+ }
371
+ return false;
372
+ }
373
+ return false;
374
+ }
375
+ if (final === 0x48 /* H */) {
376
+ if (this.options.onScrollToTop) {
377
+ this.options.onScrollToTop();
378
+ return true;
379
+ }
380
+ return false;
381
+ }
382
+ if (final === 0x46 /* F */) {
383
+ if (this.options.onScrollToBottom) {
384
+ this.options.onScrollToBottom();
385
+ return true;
386
+ }
387
+ return false;
388
+ }
389
+ return false;
390
+ }
391
+ /**
392
+ * Route a deferred buffer (produced by `DumpHotkeyDetector` when a
393
+ * pending escape sequence times out). The deferred bytes have already
394
+ * been screened for the dump hotkey — they must NOT pass through the
395
+ * detector again. They DO continue through the parent UI mode, the
396
+ * SGR mouse parser, host shortcuts, and the child gate so a bare Esc
397
+ * reaches host-backed prompts and a deferred mouse sequence is still
398
+ * correctly classified.
399
+ */
400
+ routeDeferred(buf) {
401
+ if (buf.length === 0)
402
+ return false;
403
+ if (this.parentUiMode) {
404
+ const consumed = this.parentUiMode.onInput(buf);
405
+ if (consumed !== false) {
406
+ this.resetSgrPartial();
407
+ return true;
408
+ }
409
+ }
410
+ const afterMouse = this.consumeSgrMouseWheel(buf);
411
+ if (afterMouse.length === 0)
412
+ return true;
413
+ const afterShortcuts = this.consumeHostShortcuts(afterMouse);
414
+ if (afterShortcuts.length === 0)
415
+ return true;
416
+ return this.forwardToChild(afterShortcuts);
417
+ }
418
+ destroy() {
419
+ this.dumpDetector?.destroy();
420
+ this.dumpDetector = undefined;
421
+ this.resetSgrPartial();
422
+ this.childHandle = undefined;
423
+ this.parentUiMode = undefined;
424
+ }
425
+ }
426
+ //# sourceMappingURL=input-router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"input-router.js","sourceRoot":"","sources":["../../src/terminal/input-router.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Pure layout computation for the orchestration terminal host.
3
+ *
4
+ * The host owns the real terminal during orchestration. The single
5
+ * source of truth for "how big is the child viewport", "where does the
6
+ * warning strip go", and "where does the status row go" is
7
+ * `computeTerminalLayout()`. PTY spawn, virtual-terminal sizing, child
8
+ * rendering, warning rendering, and status-bar rendering all read from
9
+ * the same layout object.
10
+ *
11
+ * Policy:
12
+ * - When status is enabled and rows >= 2, reserve exactly 1 status row.
13
+ * - When rows === 1, reserve 0 status rows; the child gets the only row.
14
+ * - When status is disabled (non-host or non-TTY), reserve 0 status rows.
15
+ * - `warningRows` is the host-owned warning strip immediately above the
16
+ * status row. It is clamped to 0..3 and capped further so the child
17
+ * viewport always keeps at least 1 row.
18
+ */
19
+ export interface TerminalLayout {
20
+ /** Total visible columns. */
21
+ columns: number;
22
+ /** Total visible rows. */
23
+ rows: number;
24
+ /** Number of bottom rows reserved for the status bar (0 or 1). */
25
+ statusRows: 0 | 1;
26
+ /** Number of rows reserved for the host-owned warning strip (0..3). */
27
+ warningRows: number;
28
+ /** Child viewport columns — currently equals `columns`. */
29
+ childCols: number;
30
+ /** Child viewport rows = max(1, rows - statusRows - warningRows). */
31
+ childRows: number;
32
+ /** 1-based row index of the first warning row, or undefined when warningRows === 0. */
33
+ warningStartRow: number | undefined;
34
+ /** 1-based row index of the status line, or undefined when statusRows === 0. */
35
+ statusRow: number | undefined;
36
+ }
37
+ export interface LayoutInput {
38
+ columns: number;
39
+ rows: number;
40
+ statusEnabled: boolean;
41
+ /** Requested warning strip height. Clamped to 0..3 and to available height. */
42
+ warningRows?: number;
43
+ }
44
+ /**
45
+ * Compute the host layout. Pure: no side effects.
46
+ *
47
+ * - `columns` and `rows` are clamped to >= 1 even if the input is 0/negative.
48
+ * - `statusRows` is 1 only when `statusEnabled` AND `rows >= 2`.
49
+ * - `warningRows` is clamped to 0..3, then capped so `childRows >= 1`.
50
+ * - `childRows` is always >= 1.
51
+ * - `warningStartRow` is the first warning row (1-based) when `warningRows > 0`, else undefined.
52
+ * - `statusRow` is the 1-based bottom row when reserved, otherwise undefined.
53
+ */
54
+ export declare function computeTerminalLayout(input: LayoutInput): TerminalLayout;
55
+ //# sourceMappingURL=layout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../src/terminal/layout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,WAAW,cAAc;IAC7B,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,UAAU,EAAE,CAAC,GAAG,CAAC,CAAC;IAClB,uEAAuE;IACvE,WAAW,EAAE,MAAM,CAAC;IACpB,2DAA2D;IAC3D,SAAS,EAAE,MAAM,CAAC;IAClB,qEAAqE;IACrE,SAAS,EAAE,MAAM,CAAC;IAClB,uFAAuF;IACvF,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,gFAAgF;IAChF,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,OAAO,CAAC;IACvB,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,WAAW,GAAG,cAAc,CAqBxE"}