@north-light/crouter 0.3.192 → 0.3.193

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 (167) hide show
  1. package/dist/api/client.d.ts +31 -10
  2. package/dist/api/client.js +83 -24
  3. package/dist/api/dto/bash-jobs.d.ts +22 -0
  4. package/dist/api/dto/bash-jobs.js +9 -0
  5. package/dist/api/dto/human.d.ts +3 -4
  6. package/dist/api/dto/inbox.d.ts +106 -65
  7. package/dist/api/dto/inbox.js +2 -8
  8. package/dist/api/index.d.ts +1 -0
  9. package/dist/api/index.js +1 -0
  10. package/dist/api/routes.d.ts +7 -0
  11. package/dist/api/routes.js +7 -0
  12. package/dist/builtin-memory/internal/storage-tiers.md +1 -1
  13. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/serial/provider-rotation.test.ts +101 -3
  14. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +6 -2
  15. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +68 -14
  16. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +87 -13
  17. package/dist/clients/attach/__tests__/chat-view-snapshot-ordering.test.js +2 -2
  18. package/dist/clients/attach/__tests__/group-activity.test.js +2 -2
  19. package/dist/clients/attach/chrome/canvas-panels.d.ts +1 -1
  20. package/dist/clients/attach/chrome/canvas-panels.js +1 -1
  21. package/dist/clients/attach/input/overlay-owner.js +1 -1
  22. package/dist/clients/attach/overlays/auth.js +34 -8
  23. package/dist/clients/attach/overlays/pickers.d.ts +5 -8
  24. package/dist/clients/attach/overlays/pickers.js +37 -43
  25. package/dist/clients/attach/viewer.js +643 -620
  26. package/dist/clients/inbox/__tests__/serial/inbox-controller.test.js +38 -128
  27. package/dist/clients/inbox/__tests__/serial/mount-panel.test.js +72 -148
  28. package/dist/clients/inbox/controller.d.ts +2 -3
  29. package/dist/clients/inbox/controller.js +41 -42
  30. package/dist/clients/inbox/page-adapter.d.ts +33 -0
  31. package/dist/clients/inbox/page-adapter.js +54 -0
  32. package/dist/clients/inbox/resolve.d.ts +2 -2
  33. package/dist/clients/inbox/resolve.js +1 -1
  34. package/dist/clients/inbox/review-visibility.d.ts +1 -1
  35. package/dist/clients/inbox/review-visibility.js +1 -1
  36. package/dist/clients/inbox/tui/ansi.d.ts +1 -1
  37. package/dist/clients/inbox/tui/ansi.js +2 -2
  38. package/dist/clients/inbox/tui/input.d.ts +1 -3
  39. package/dist/clients/inbox/tui/input.js +242 -553
  40. package/dist/clients/inbox/tui/panel.d.ts +3 -1
  41. package/dist/clients/inbox/tui/panel.js +59 -187
  42. package/dist/clients/inbox/tui/render.d.ts +0 -25
  43. package/dist/clients/inbox/tui/render.js +165 -416
  44. package/dist/clients/inbox/tui/slots.d.ts +32 -0
  45. package/dist/clients/inbox/tui/slots.js +156 -0
  46. package/dist/clients/inbox/tui/types.d.ts +25 -13
  47. package/dist/clients/inbox/tui.js +5 -3
  48. package/dist/commands/attention.js +2 -2
  49. package/dist/commands/human/doc.js +66 -20
  50. package/dist/commands/human/prompts.d.ts +3 -3
  51. package/dist/commands/human/prompts.js +158 -112
  52. package/dist/commands/human/queue.d.ts +0 -1
  53. package/dist/commands/human/queue.js +34 -94
  54. package/dist/commands/human/shared.d.ts +10 -4
  55. package/dist/commands/human/shared.js +62 -13
  56. package/dist/commands/human.js +8 -4
  57. package/dist/commands/memory/read.js +13 -5
  58. package/dist/commands/node/bash.js +15 -28
  59. package/dist/commands/surface/node/focus.js +1 -1
  60. package/dist/core/__tests__/human-deliver.test.js +40 -46
  61. package/dist/core/__tests__/seam/broker-attach-stream.test.js +7 -1
  62. package/dist/core/__tests__/serial/human-deliver-e2e.test.js +40 -31
  63. package/dist/core/__tests__/serial/spawn-root.test.js +3 -1
  64. package/dist/core/__tests__/spawn-worktree-id-conflict.test.js +3 -1
  65. package/dist/core/auth-interaction.d.ts +2 -2
  66. package/dist/core/bash-jobs.d.ts +32 -0
  67. package/dist/core/bash-jobs.js +72 -1
  68. package/dist/core/canvas/__tests__/attention.test.js +16 -10
  69. package/dist/core/canvas/__tests__/render-remote.test.js +9 -3
  70. package/dist/core/canvas/attention.js +1 -1
  71. package/dist/core/canvas/browse/app.js +1 -1
  72. package/dist/core/canvas/nav-model.d.ts +1 -1
  73. package/dist/core/canvas/nav-model.js +1 -1
  74. package/dist/core/canvas/remote-canvas-source.js +1 -1
  75. package/dist/core/config.js +4 -1
  76. package/dist/core/human/__tests__/page-render.test.d.ts +1 -0
  77. package/dist/core/human/__tests__/page-render.test.js +49 -0
  78. package/dist/core/human/__tests__/page-tickets.test.d.ts +1 -0
  79. package/dist/core/human/__tests__/page-tickets.test.js +112 -0
  80. package/dist/core/human/__tests__/page.test.d.ts +1 -0
  81. package/dist/core/human/__tests__/page.test.js +139 -0
  82. package/dist/core/human/__tests__/serial/inbox-core.test.js +42 -32
  83. package/dist/core/human/claim.js +2 -2
  84. package/dist/core/human/convention.d.ts +4 -4
  85. package/dist/core/human/convention.js +6 -13
  86. package/dist/core/human/markdown-html.d.ts +8 -0
  87. package/dist/core/human/markdown-html.js +581 -0
  88. package/dist/core/human/page-catalog.d.ts +6 -0
  89. package/dist/core/human/page-catalog.js +43 -0
  90. package/dist/core/human/page-render.d.ts +3 -0
  91. package/dist/core/human/page-render.js +131 -0
  92. package/dist/core/human/page-schema.d.ts +312 -0
  93. package/dist/core/human/page-schema.js +291 -0
  94. package/dist/core/human/page-synth.d.ts +9 -0
  95. package/dist/core/human/page-synth.js +17 -0
  96. package/dist/core/human/page.d.ts +22 -0
  97. package/dist/core/human/page.js +427 -0
  98. package/dist/core/human/review-schema.d.ts +19 -0
  99. package/dist/core/human/review-schema.js +34 -0
  100. package/dist/core/human/scan.d.ts +12 -3
  101. package/dist/core/human/scan.js +69 -26
  102. package/dist/core/human/summary.d.ts +5 -6
  103. package/dist/core/human/summary.js +54 -37
  104. package/dist/core/human/tickets.d.ts +61 -11
  105. package/dist/core/human/tickets.js +100 -57
  106. package/dist/core/human/types.d.ts +21 -66
  107. package/dist/core/human/types.js +1 -5
  108. package/dist/core/preview-registry.js +0 -1
  109. package/dist/core/review/ticket-filter.d.ts +1 -1
  110. package/dist/core/review/ticket-filter.js +2 -8
  111. package/dist/core/runtime/broker/read-ops.js +3 -0
  112. package/dist/core/runtime/broker.js +19 -10
  113. package/dist/core/runtime/package-health.js +1 -1
  114. package/dist/core/termrender/termrender.d.ts +1 -1
  115. package/dist/core/termrender/termrender.js +2 -2
  116. package/dist/core/tui/page-host.d.ts +1 -1
  117. package/dist/core/tui/page-host.js +2 -2
  118. package/dist/core/user-settings.d.ts +19 -0
  119. package/dist/core/user-settings.js +22 -0
  120. package/dist/daemon/api/handlers/bash-jobs.d.ts +2 -0
  121. package/dist/daemon/api/handlers/bash-jobs.js +89 -0
  122. package/dist/daemon/api/handlers/human.js +16 -14
  123. package/dist/daemon/api/handlers/inbox.js +311 -227
  124. package/dist/daemon/api/router.d.ts +5 -1
  125. package/dist/daemon/api/router.js +5 -0
  126. package/dist/daemon/api/server.js +2 -0
  127. package/dist/daemon/cron-run.js +23 -10
  128. package/dist/daemon/human/finish.d.ts +8 -3
  129. package/dist/daemon/human/finish.js +35 -15
  130. package/dist/pages/bundle.css +1 -0
  131. package/dist/pages/bundle.js +1347 -0
  132. package/dist/pages/comments.d.ts +34 -0
  133. package/dist/pages/comments.js +72 -0
  134. package/dist/pages/elements/cards.d.ts +17 -0
  135. package/dist/pages/elements/cards.js +785 -0
  136. package/dist/pages/elements/chart.d.ts +1 -0
  137. package/dist/pages/elements/chart.js +648 -0
  138. package/dist/pages/elements/options.d.ts +21 -0
  139. package/dist/pages/elements/options.js +604 -0
  140. package/dist/pages/elements/pages.d.ts +24 -0
  141. package/dist/pages/elements/pages.js +355 -0
  142. package/dist/pages/elements/slot.d.ts +21 -0
  143. package/dist/pages/elements/slot.js +105 -0
  144. package/dist/pages/elements/table.d.ts +19 -0
  145. package/dist/pages/elements/table.js +906 -0
  146. package/dist/pages/elements/text.d.ts +25 -0
  147. package/dist/pages/elements/text.js +951 -0
  148. package/dist/pages/entry.d.ts +8 -0
  149. package/dist/pages/entry.js +8 -0
  150. package/dist/pages/host.d.ts +132 -0
  151. package/dist/pages/host.js +149 -0
  152. package/dist/pages/register.d.ts +2 -0
  153. package/dist/pages/register.js +3 -0
  154. package/dist/pages/slot-config.d.ts +36 -0
  155. package/dist/pages/slot-config.js +50 -0
  156. package/dist/pages/types.d.ts +98 -0
  157. package/dist/pages/types.js +23 -0
  158. package/dist/types.d.ts +4 -0
  159. package/dist/types.js +2 -0
  160. package/package.json +8 -8
  161. package/runtime.lock.json +156 -101
  162. package/dist/clients/inbox/deck-adapter.d.ts +0 -29
  163. package/dist/clients/inbox/deck-adapter.js +0 -63
  164. package/dist/core/human/deck-factories.d.ts +0 -8
  165. package/dist/core/human/deck-factories.js +0 -15
  166. package/dist/core/human/deck-schema.d.ts +0 -70
  167. package/dist/core/human/deck-schema.js +0 -92
@@ -1,2 +1,4 @@
1
- import type { MountedPanel, MountedPanelOpts } from './types.js';
1
+ import type { PageResponses } from '../../../core/human/page-schema.js';
2
+ import type { MountedPanel, MountedPanelOpts, TuiState } from './types.js';
3
+ export declare function collectResponses(state: TuiState): PageResponses;
2
4
  export declare function mountPanel(opts: MountedPanelOpts): MountedPanel;
@@ -1,125 +1,56 @@
1
- import { readFileSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
2
- import { assignShortcuts, handleKeypress } from './input.js';
1
+ import { handleKeypress } from './input.js';
3
2
  import { clampItemReviewScroll, renderFinal, renderItemReview, renderOverview } from './render.js';
4
- // ── Internal helpers ──────────────────────────────────────────────────────────
5
- function buildInitialState(deck, editorAvailable = false, wrapWidth = 80) {
6
- // Single-question decks skip the overview list — there's nothing to overview,
7
- // and overview hides the option hotkeys so users press 'y' and nothing happens.
8
- const initialPhase = deck.interactions.length === 1 ? 'item-review' : 'overview';
9
- const responses = new Map();
10
- const preAnsweredIds = new Set();
11
- // Seed responses + preAnsweredIds from any `preAnswered` field. The seeded
12
- // response counts as answered for navigation/auto-advance, but is rendered
13
- // distinctly so the human knows it carried over. `tryResume` runs after and
14
- // takes priority — mid-deck progress should not be overwritten by defaults.
15
- for (const interaction of deck.interactions) {
16
- const pa = interaction.preAnswered;
17
- if (pa === undefined)
3
+ import { pageComplete, slotAnswered } from './slots.js';
4
+ function projectProse(projection) {
5
+ const overviewProse = [];
6
+ const slotProse = new Map();
7
+ let pending = [];
8
+ let seenSlot = false;
9
+ for (const block of projection) {
10
+ if (block.kind === 'prose') {
11
+ if (block.markdown.trim() !== '')
12
+ pending.push(block.markdown);
18
13
  continue;
19
- const response = { id: interaction.id };
20
- if (pa.selectedOptionId !== undefined)
21
- response.selectedOptionId = pa.selectedOptionId;
22
- if (pa.selectedOptionIds !== undefined)
23
- response.selectedOptionIds = [...pa.selectedOptionIds];
24
- if (pa.freetext !== undefined)
25
- response.freetext = pa.freetext;
26
- responses.set(interaction.id, response);
27
- preAnsweredIds.add(interaction.id);
28
- }
29
- // Start cursor on the first unanswered interaction — humans land where they
30
- // need to act. If every interaction is pre-answered, fall back to index 0.
31
- const firstUnanswered = deck.interactions.findIndex((i) => !responses.has(i.id));
32
- return {
33
- phase: initialPhase,
34
- currentIndex: firstUnanswered >= 0 ? firstUnanswered : 0,
35
- interactions: deck.interactions,
36
- responses,
37
- preAnsweredIds,
38
- inputMode: null,
39
- selectedAction: 0,
40
- bodyMode: 'question',
41
- scrollOffset: 0,
42
- bodyScrollOffsets: { question: 0 },
43
- hscrollOffset: 0,
44
- hscrollMax: 0,
45
- wrapWidth,
46
- editorAvailable,
47
- };
48
- }
49
- function collectResponses(state) {
50
- const out = [];
51
- for (const interaction of state.interactions) {
52
- const r = state.responses.get(interaction.id);
53
- if (r !== undefined)
54
- out.push(r);
55
- }
56
- return out;
57
- }
58
- function tryResume(state, progressPath, interactions) {
59
- try {
60
- const prior = JSON.parse(readFileSync(progressPath, 'utf8'));
61
- if (!Array.isArray(prior.responses))
62
- return;
63
- const validIds = new Set(interactions.map((i) => i.id));
64
- for (const r of prior.responses) {
65
- if (validIds.has(r.id))
66
- state.responses.set(r.id, r);
67
14
  }
68
- const firstUnanswered = interactions.findIndex((i) => !state.responses.has(i.id));
69
- state.currentIndex = firstUnanswered >= 0 ? firstUnanswered : 0;
15
+ if (!seenSlot)
16
+ overviewProse.push(...pending);
17
+ else
18
+ slotProse.set(block.slotIndex, pending);
19
+ pending = [];
20
+ seenSlot = true;
70
21
  }
71
- catch {
72
- // corrupt or missing progress file — start fresh
22
+ // A page with no slots has no final phase to reach — its prose is the overview.
23
+ if (!seenSlot) {
24
+ overviewProse.push(...pending);
25
+ return { overviewProse, slotProse, finalProse: [] };
73
26
  }
27
+ return { overviewProse, slotProse, finalProse: pending };
74
28
  }
75
- function atomicWriteProgress(progressPath, responses) {
76
- const payload = JSON.stringify({ partial: true, responses, savedAt: new Date().toISOString() }, null, 2);
77
- const tmp = `${progressPath}.tmp`;
78
- try {
79
- writeFileSync(tmp, payload);
80
- renameSync(tmp, progressPath);
81
- }
82
- catch {
83
- // best-effort
84
- }
85
- }
86
- function rebindPersist(internals) {
87
- internals.state.persist = () => {
88
- const responses = collectResponses(internals.state);
89
- if (internals.progressPath !== undefined)
90
- atomicWriteProgress(internals.progressPath, responses);
91
- internals.callbacks.onProgress?.(responses);
92
- };
29
+ function buildInitialState(manifest, projection, initialResponses, productKinds, editorAvailable, wrapWidth) {
30
+ const prose = projectProse(projection);
31
+ const responses = new Map();
32
+ const validIds = new Set(manifest.slots.flatMap((slot) => slot.id === undefined ? [] : [slot.id]));
33
+ for (const [id, response] of Object.entries(initialResponses ?? {}))
34
+ if (validIds.has(id))
35
+ responses.set(id, response);
36
+ const state = { phase: manifest.slots.length === 1 ? 'item-review' : 'overview', currentIndex: 0, manifest, slots: manifest.slots, ...prose, responses, productKinds, inputMode: null, selectedAction: 0, bodyMode: 'question', scrollOffset: 0, bodyScrollOffsets: { question: 0 }, hscrollOffset: 0, hscrollMax: 0, wrapWidth, editorAvailable };
37
+ const first = manifest.slots.findIndex((slot) => slot.id !== undefined && !slotAnswered(state, slot));
38
+ if (first >= 0)
39
+ state.currentIndex = first;
40
+ return state;
93
41
  }
42
+ export function collectResponses(state) { return Object.fromEntries(state.responses); }
43
+ function rebindPersist(internals) { internals.state.persist = () => internals.callbacks.onProgress?.(collectResponses(internals.state)); }
94
44
  export function mountPanel(opts) {
95
- const internals = {
96
- state: buildInitialState(opts.deck, opts.onEditorRequest !== undefined, opts.cols),
97
- cols: opts.cols,
98
- rows: opts.rows,
99
- mounted: true,
100
- progressPath: opts.progressPath,
101
- callbacks: {
102
- onProgress: opts.onProgress, onComplete: opts.onComplete, onExit: opts.onExit,
103
- onDirty: opts.onDirty, onEditorRequest: opts.onEditorRequest,
104
- },
105
- };
106
- assignShortcuts(internals.state.interactions);
45
+ const internals = { state: buildInitialState(opts.manifest, opts.projection, opts.initialResponses, opts.productKinds ?? [], opts.onEditorRequest !== undefined, opts.cols), cols: opts.cols, rows: opts.rows, mounted: true, callbacks: { onProgress: opts.onProgress, onComplete: opts.onComplete, onExit: opts.onExit, onDirty: opts.onDirty, onEditorRequest: opts.onEditorRequest } };
107
46
  rebindPersist(internals);
108
- if (internals.progressPath !== undefined) {
109
- tryResume(internals.state, internals.progressPath, opts.deck.interactions);
110
- }
111
47
  const renderLines = () => {
112
- switch (internals.state.phase) {
113
- case 'overview': return renderOverview(internals.state, internals.cols, internals.rows);
114
- case 'item-review':
115
- // The one pre-render clamp: keeps scrollOffset/hscrollOffset inside the
116
- // current body's bounds (so u/d and h/l stay responsive) and publishes
117
- // the live horizontal reach the input layer reads. The renderer itself
118
- // stays pure; running it here covers mount, resize and every keypress.
119
- clampItemReviewScroll(internals.state, internals.cols, internals.rows);
120
- return renderItemReview(internals.state, internals.cols, internals.rows);
121
- case 'final': return renderFinal(internals.state, internals.cols, internals.rows);
122
- }
48
+ if (internals.state.phase === 'overview')
49
+ return renderOverview(internals.state, internals.cols, internals.rows);
50
+ if (internals.state.phase === 'final')
51
+ return renderFinal(internals.state, internals.cols, internals.rows);
52
+ clampItemReviewScroll(internals.state, internals.cols, internals.rows);
53
+ return renderItemReview(internals.state, internals.cols, internals.rows);
123
54
  };
124
55
  return {
125
56
  handleKey(input, key) {
@@ -129,89 +60,30 @@ export function mountPanel(opts) {
129
60
  internals.callbacks.onEditorRequest();
130
61
  return;
131
62
  }
132
- const onAutoComplete = () => {
133
- const responses = collectResponses(internals.state);
134
- if (internals.progressPath !== undefined) {
135
- try {
136
- unlinkSync(internals.progressPath);
137
- }
138
- catch { /* ignore */ }
139
- }
140
- internals.callbacks.onComplete?.(responses);
141
- };
142
- handleKeypress(input, key, internals.state, () => { }, () => {
63
+ handleKeypress(input, key, internals.state, () => internals.callbacks.onDirty?.(), (submit) => {
143
64
  const responses = collectResponses(internals.state);
144
- if (responses.length >= internals.state.interactions.length) {
145
- onAutoComplete();
146
- }
147
- else {
65
+ if (submit === true && pageComplete(internals.state))
66
+ internals.callbacks.onComplete?.(responses);
67
+ else
148
68
  internals.callbacks.onExit?.();
149
- }
150
69
  });
70
+ internals.callbacks.onDirty?.();
151
71
  },
152
- render() {
153
- if (!internals.mounted)
154
- return [];
155
- return renderLines();
156
- },
157
- handleResize(cols, rows) {
158
- internals.cols = cols;
159
- internals.rows = rows;
160
- internals.state.wrapWidth = cols;
161
- return renderLines();
162
- },
163
- unmount() {
164
- if (!internals.mounted)
165
- return;
166
- internals.mounted = false;
167
- internals.state.persist = undefined;
168
- },
169
- loadDeck(deck, loadOpts) {
72
+ render: () => internals.mounted ? renderLines() : [],
73
+ handleResize(cols, rows) { internals.cols = cols; internals.rows = rows; internals.state.wrapWidth = cols; return renderLines(); },
74
+ unmount() { internals.mounted = false; internals.state.persist = undefined; },
75
+ loadPage(manifest, projection, loadOpts) {
170
76
  if (!internals.mounted)
171
77
  return;
172
78
  const prior = collectResponses(internals.state);
173
- internals.state = buildInitialState(deck, internals.callbacks.onEditorRequest !== undefined, internals.cols);
174
- if (loadOpts !== undefined && loadOpts.progressPath !== undefined) {
175
- internals.progressPath = loadOpts.progressPath;
176
- }
177
- assignShortcuts(internals.state.interactions);
79
+ const merged = { ...(loadOpts?.initialResponses ?? {}), ...prior };
80
+ internals.state = buildInitialState(manifest, projection, merged, loadOpts?.productKinds ?? internals.state.productKinds, internals.callbacks.onEditorRequest !== undefined, internals.cols);
178
81
  rebindPersist(internals);
179
- if (internals.progressPath !== undefined) {
180
- tryResume(internals.state, internals.progressPath, deck.interactions);
181
- }
182
- // A live request replacement is allowed to add/remove questions but not
183
- // discard answers the human has already made to surviving ids.
184
- const validIds = new Set(deck.interactions.map((interaction) => interaction.id));
185
- for (const response of prior) {
186
- if (validIds.has(response.id))
187
- internals.state.responses.set(response.id, response);
188
- }
189
- const currentId = internals.state.interactions[internals.state.currentIndex]?.id;
190
- if (currentId === undefined || !validIds.has(currentId)) {
191
- const firstUnanswered = internals.state.interactions.findIndex((interaction) => !internals.state.responses.has(interaction.id));
192
- internals.state.currentIndex = firstUnanswered >= 0 ? firstUnanswered : 0;
193
- }
194
- },
195
- canAcceptHostKeys() {
196
- if (!internals.mounted)
197
- return false;
198
- return internals.state.inputMode === null;
199
- },
200
- atDeckTop() {
201
- if (!internals.mounted)
202
- return true;
203
- return internals.state.phase === 'overview' && internals.state.inputMode === null;
204
- },
205
- getInputBuffer() {
206
- if (!internals.mounted || internals.state.inputMode === null)
207
- return undefined;
208
- return internals.state.inputMode.buffer;
209
- },
210
- setInputBuffer(text) {
211
- if (!internals.mounted || internals.state.inputMode === null)
212
- return;
213
- internals.state.inputMode.buffer = text;
214
- internals.state.inputMode.cursor = [...text].length;
215
82
  },
83
+ canAcceptHostKeys: () => internals.mounted && internals.state.inputMode === null,
84
+ atPageTop: () => !internals.mounted || (internals.state.phase === 'overview' && internals.state.inputMode === null),
85
+ getInputBuffer: () => !internals.mounted || internals.state.inputMode === null ? undefined : internals.state.inputMode.buffer,
86
+ setInputBuffer(text) { if (!internals.mounted || internals.state.inputMode === null)
87
+ return; internals.state.inputMode.buffer = text; internals.state.inputMode.cursor = [...text].length; },
216
88
  };
217
89
  }
@@ -1,37 +1,12 @@
1
1
  import type { TuiState } from './types.js';
2
- import type { Interaction, InteractionResponse } from '../../../core/human/types.js';
3
2
  export declare function renderOverview(state: TuiState, cols: number, rows: number): string[];
4
- /**
5
- * Render a (possibly multiline) input buffer with a visible cursor at
6
- * `cursor` (a code-point index). A private-use sentinel is inserted at the
7
- * cursor position, the result is hard-wrapped (so `\n` and width-wrapping
8
- * behave exactly as they would without a cursor), then the sentinel is
9
- * swapped for a reverse-video block on whichever wrapped line it landed on.
10
- * `stringWidth('\uE000') === 1`, so it occupies exactly one column and never
11
- * throws off the wrap math.
12
- */
13
3
  export declare function renderInputBuffer(buffer: string, cursor: number, maxWidth: number): string[];
14
- /** Code-point bounds of every visual row `renderInputBuffer` paints, mirroring
15
- * `hardWrap` (character-based, lossless) so a cursor index maps to the row the
16
- * human actually sees. `end` is exclusive of the row's trailing '\n', if any. */
17
4
  export declare function wrappedRowBounds(buffer: string, width: number): {
18
5
  start: number;
19
6
  end: number;
20
7
  }[];
21
- /** Vertical motion by *visual* row — what up/down mean in a wrapped input box,
22
- * where one long soft-wrapped paragraph spans many rows. Returns the new
23
- * code-point cursor, unchanged when there is no row in that direction. */
24
8
  export declare function verticalCursor(buffer: string, cursor: number, delta: number, width: number): number;
25
- /**
26
- * Clamp state.scrollOffset to the current body's scroll bounds. The host runs
27
- * this as a pre-render step (from the input path) so `renderItemReview` stays a
28
- * pure function of state — the clamp keeps u/d scrolling responsive without the
29
- * renderer mutating state mid-frame.
30
- */
31
9
  export declare function clampItemReviewScroll(state: TuiState, cols: number, rows: number): void;
32
- /** Pan the card body horizontally. Clamping happens in the pre-render clamp
33
- * the host already runs, exactly like vertical over-scroll. */
34
10
  export declare function panItemReview(state: TuiState, direction: -1 | 1): void;
35
11
  export declare function renderItemReview(state: TuiState, cols: number, rows: number): string[];
36
12
  export declare function renderFinal(state: TuiState, cols: number, rows: number): string[];
37
- export declare function responseSummary(r: InteractionResponse, interaction: Interaction): string;