koneck 2.128.41 → 2.128.43
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/context-limit.d.ts +26 -0
- package/dist/context-limit.d.ts.map +1 -1
- package/dist/context-limit.js +17 -0
- package/dist/context-limit.js.map +1 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +87 -21
- package/dist/engine.js.map +1 -1
- package/dist/ink-chat.d.ts.map +1 -1
- package/dist/ink-chat.js +124 -64
- package/dist/ink-chat.js.map +1 -1
- package/dist/model-catalog.d.ts +6 -0
- package/dist/model-catalog.d.ts.map +1 -1
- package/dist/model-catalog.js +4 -3
- package/dist/model-catalog.js.map +1 -1
- package/dist/tool-call-text.d.ts +14 -0
- package/dist/tool-call-text.d.ts.map +1 -1
- package/dist/tool-call-text.js +27 -0
- package/dist/tool-call-text.js.map +1 -1
- package/package.json +1 -1
package/dist/ink-chat.js
CHANGED
|
@@ -221,7 +221,17 @@ function fitCells(text, width, ellipsis = false) {
|
|
|
221
221
|
}
|
|
222
222
|
/** A picker label uses all of its allocated column, only ellipsising at the actual boundary. */
|
|
223
223
|
export function pickerLabel(text, width) {
|
|
224
|
-
|
|
224
|
+
/*
|
|
225
|
+
* One column of the field always stays blank, so the label cannot touch what follows it.
|
|
226
|
+
*
|
|
227
|
+
* Padding to exactly `width` left no gap for a label that filled the field, and the row ran
|
|
228
|
+
* together: `muse-glimmer:latestlibrary · local` in an Ollama list, where the name ends and its
|
|
229
|
+
* group begins is anybody's guess. Every shorter label already had a gap, so this only ever
|
|
230
|
+
* showed up on the longest one — which is also the one the field was sized from.
|
|
231
|
+
*
|
|
232
|
+
* A label one cell shorter beats a label welded to its description.
|
|
233
|
+
*/
|
|
234
|
+
return fitCells(text, Math.max(1, width - 1), true) + ' ';
|
|
225
235
|
}
|
|
226
236
|
/**
|
|
227
237
|
* Wraps text while keeping the shape it was written in.
|
|
@@ -1033,7 +1043,9 @@ export function pickerLabelWidth(labels, descs, width) {
|
|
|
1033
1043
|
// Terminal cells, not JS code units: one wide glyph in a model name or session title used to
|
|
1034
1044
|
// make a supposedly exact row spill past the palette edge.
|
|
1035
1045
|
const longestDesc = Math.max(0, ...descs.map(displayWidth));
|
|
1036
|
-
|
|
1046
|
+
// Plus the blank column pickerLabel always keeps, so the longest label is sized to fit whole
|
|
1047
|
+
// rather than being the one label the field truncates.
|
|
1048
|
+
const longestLabel = Math.max(18, ...labels.map(l => displayWidth(l) + 1));
|
|
1037
1049
|
return Math.max(18, Math.min(longestLabel, width - longestDesc - 4));
|
|
1038
1050
|
}
|
|
1039
1051
|
/**
|
|
@@ -2205,6 +2217,37 @@ export function App({ config: initialConfig, clearFrame, synchronizedFrames = fa
|
|
|
2205
2217
|
*/
|
|
2206
2218
|
const [selAnchor, setSelAnchor] = useState(null);
|
|
2207
2219
|
const [busy, setBusy] = useState(false);
|
|
2220
|
+
/**
|
|
2221
|
+
* Whether a turn is running, readable from an async path.
|
|
2222
|
+
*
|
|
2223
|
+
* A command started while the agent works must not take ownership of this flag, and cannot know
|
|
2224
|
+
* from a captured render whether it already belonged to somebody.
|
|
2225
|
+
*/
|
|
2226
|
+
const busyRef = useRef(false);
|
|
2227
|
+
busyRef.current = busy;
|
|
2228
|
+
/**
|
|
2229
|
+
* Run a command, holding `busy` only if nothing else already is.
|
|
2230
|
+
*
|
|
2231
|
+
* Both callers used to do `setBusy(true)` and then clear it unconditionally when the command
|
|
2232
|
+
* finished — including when a turn was already running, whose flag it then cleared. The live
|
|
2233
|
+
* region is gated on `busy` and the status bar on `agentState`, so the working line vanished
|
|
2234
|
+
* while the bar went on saying "processing" and the turn carried on unseen. Reported as the
|
|
2235
|
+
* agent looking stuck: "it is working on the background, that is bad".
|
|
2236
|
+
*
|
|
2237
|
+
* The command is not what makes the interface busy. A turn is.
|
|
2238
|
+
*/
|
|
2239
|
+
async function runCommandDetached(cmd, arg) {
|
|
2240
|
+
const alreadyBusy = busyRef.current;
|
|
2241
|
+
if (!alreadyBusy)
|
|
2242
|
+
setBusy(true);
|
|
2243
|
+
try {
|
|
2244
|
+
await handleCommand(cmd, arg);
|
|
2245
|
+
}
|
|
2246
|
+
finally {
|
|
2247
|
+
if (!alreadyBusy)
|
|
2248
|
+
setBusy(false);
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2208
2251
|
const [agentState, setAgentState] = useState('ready');
|
|
2209
2252
|
// A shell normally uses the machine name as its tab title. Keep the KONECK mark and workspace
|
|
2210
2253
|
// there instead. The working marker changes in the terminal chrome only: it does not set React
|
|
@@ -3648,10 +3691,16 @@ export function App({ config: initialConfig, clearFrame, synchronizedFrames = fa
|
|
|
3648
3691
|
}
|
|
3649
3692
|
}
|
|
3650
3693
|
/** The provider's own model listing, kept so the models tab and picker agree on the facts. */
|
|
3694
|
+
const catalogEndpoint = useRef('');
|
|
3651
3695
|
async function loadModelCatalog() {
|
|
3652
3696
|
const { listModels } = await import('./model-catalog.js');
|
|
3653
3697
|
const catalog = await listModels(cfg);
|
|
3654
3698
|
setModelCatalog(catalog.entries);
|
|
3699
|
+
// The host that answered, kept for the picker's header. endpointFor() resolves from the saved
|
|
3700
|
+
// layers and does not see the session's live baseURL, so it reported ollama's default
|
|
3701
|
+
// localhost:11434 for a list fetched from somewhere else entirely — the one label whose whole
|
|
3702
|
+
// job is to show that the request went to the wrong place.
|
|
3703
|
+
catalogEndpoint.current = catalog.endpoint;
|
|
3655
3704
|
catalogNote.current = catalog.listed ? null : (catalog.note ?? null);
|
|
3656
3705
|
return catalog.entries; // empty says so rather than showing zeroes
|
|
3657
3706
|
}
|
|
@@ -3937,8 +3986,7 @@ export function App({ config: initialConfig, clearFrame, synchronizedFrames = fa
|
|
|
3937
3986
|
}
|
|
3938
3987
|
setDraft('');
|
|
3939
3988
|
setCaret(0);
|
|
3940
|
-
|
|
3941
|
-
await handleCommand(item.value, '').finally(() => setBusy(false));
|
|
3989
|
+
await runCommandDetached(item.value, '');
|
|
3942
3990
|
return;
|
|
3943
3991
|
}
|
|
3944
3992
|
if (kind === 'resume') {
|
|
@@ -4829,9 +4877,15 @@ export function App({ config: initialConfig, clearFrame, synchronizedFrames = fa
|
|
|
4829
4877
|
? 'File changes hidden. Edits are still listed with what they touched, just not shown.'
|
|
4830
4878
|
: canPin
|
|
4831
4879
|
? 'Live diff panel open and pinned beside the conversation, until `/diff off`.'
|
|
4880
|
+
// Names where the setting came from. "off for this workspace" was true and unusable:
|
|
4881
|
+
// reported as `/diff` looking right on one machine and printing this on another, with
|
|
4882
|
+
// no way to tell that the difference was a saved `altScreen: false` on one of them
|
|
4883
|
+
// rather than the platform.
|
|
4832
4884
|
: 'File changes shown inline in the conversation, until `/diff off`.\n\n'
|
|
4833
|
-
+ 'The side panel needs the alternate screen,
|
|
4834
|
-
+ '
|
|
4885
|
+
+ 'The pinned side panel needs the alternate screen, and `altScreen: false` is set '
|
|
4886
|
+
+ 'in this workspace\'s config — so it is off by your choice, not by platform. '
|
|
4887
|
+
+ '`/altscreen on` turns it back on and moves the changes into a pinned panel; '
|
|
4888
|
+
+ '`/config altScreen` shows the current value.');
|
|
4835
4889
|
return;
|
|
4836
4890
|
}
|
|
4837
4891
|
case '/compact': {
|
|
@@ -6431,8 +6485,7 @@ export function App({ config: initialConfig, clearFrame, synchronizedFrames = fa
|
|
|
6431
6485
|
const spaceIdx = task.indexOf(' ');
|
|
6432
6486
|
const cmd = spaceIdx === -1 ? task : task.slice(0, spaceIdx);
|
|
6433
6487
|
const arg = spaceIdx === -1 ? '' : task.slice(spaceIdx + 1).trim();
|
|
6434
|
-
|
|
6435
|
-
void handleCommand(cmd, arg).finally(() => setBusy(false));
|
|
6488
|
+
void runCommandDetached(cmd, arg);
|
|
6436
6489
|
return;
|
|
6437
6490
|
}
|
|
6438
6491
|
if (!containsSecret(task))
|
|
@@ -7241,61 +7294,6 @@ export function App({ config: initialConfig, clearFrame, synchronizedFrames = fa
|
|
|
7241
7294
|
lines.push('**Sessions** /sessions · /send <repo> <task> · /ask <repo> <q> · /resume');
|
|
7242
7295
|
lines.push('**Changelog** github.com/Gubevu/konech/commits/main');
|
|
7243
7296
|
return (_jsx(Box, { marginTop: 1, justifyContent: "flex-end", children: _jsx(Panel, { width: Math.min(barWidth, 62), color: AMBER, title: "KONECK \u00B7 updates & guide", children: lines }) }));
|
|
7244
|
-
})(), picker && (() => {
|
|
7245
|
-
const list = visiblePickerItems;
|
|
7246
|
-
// In the alternate screen, the picker shares a fixed frame with a bordered composer and
|
|
7247
|
-
// footer. They consume six rows and the picker itself has six non-choice rows (margin,
|
|
7248
|
-
// border, title/search and pager), so reserve thirteen in total. Letting 16 choices into
|
|
7249
|
-
// a 24-row frame made Ink reflow the live region and visibly blink on every keypress.
|
|
7250
|
-
const pickerRows = pickerRowLimit(picker.kind, list.length, termRows, altScreen ? 13 : undefined);
|
|
7251
|
-
// Keep the highlighted row inside the visible window as the selection moves.
|
|
7252
|
-
const start = Math.max(0, Math.min(pickIndex - Math.floor(pickerRows / 2), list.length - pickerRows));
|
|
7253
|
-
const shown = list.slice(Math.max(0, start), Math.max(0, start) + pickerRows);
|
|
7254
|
-
const title = picker.kind === 'command' ? 'Commands'
|
|
7255
|
-
/*
|
|
7256
|
-
* The provider's name and the address the list actually came from.
|
|
7257
|
-
*
|
|
7258
|
-
* The name alone was a claim the list could not support: a header reading "Models -
|
|
7259
|
-
* b.ai" over `muse-glimmer:latest`, `qwen2.5-coder:14b` and `qwen3-coder:30b` — an
|
|
7260
|
-
* Ollama library, listed from an Ollama endpoint, under somebody else's name. Nothing
|
|
7261
|
-
* on screen said where the answer had come from, so a misrouted endpoint looked like a
|
|
7262
|
-
* provider serving the wrong models rather than a request going to the wrong host.
|
|
7263
|
-
*
|
|
7264
|
-
* The host is enough: it is the part that differs when this goes wrong, and a full URL
|
|
7265
|
-
* would push the count and the hint off a narrow palette.
|
|
7266
|
-
*/
|
|
7267
|
-
: picker.kind === 'model' ? `Models - ${cfg.provider} · ${endpointHost(endpointFor(cfg.provider).url)}`
|
|
7268
|
-
: picker.kind === 'effort' ? 'Reasoning effort'
|
|
7269
|
-
: picker.kind === 'resume' ? 'Resume a saved session'
|
|
7270
|
-
: picker.kind === 'file' ? 'Reference a file or directory'
|
|
7271
|
-
: 'Connect provider';
|
|
7272
|
-
// The palette is sized to the rows it is showing rather than to the terminal. On a wide
|
|
7273
|
-
// screen a list of short model names in a full-width box is mostly empty box.
|
|
7274
|
-
// The header is a title on the left and a count on the right, on one line. Estimating the
|
|
7275
|
-
// right-hand side at a constant made "Reference a file or directory" wrap onto two rows.
|
|
7276
|
-
const countText = pickerCountText(pickIndex, list.length, picker.items.length);
|
|
7277
|
-
const headWidth = displayWidth(title) + displayWidth(countText) + 3;
|
|
7278
|
-
// Measure the filtered list, not just its current scroll window. A palette whose right
|
|
7279
|
-
// edge breathes as the highlight crosses a long description feels broken even when the
|
|
7280
|
-
// selection itself is correct.
|
|
7281
|
-
const rowWidth = Math.max(headWidth, ...list.map(it => 38 + (it.current ? 10 : 0) + displayWidth(it.desc) + displayWidth(it.group ?? '') + 3));
|
|
7282
|
-
const boxWidth = pickerBoxWidth(barWidth, rowWidth + 4);
|
|
7283
|
-
const width = boxWidth - 4;
|
|
7284
|
-
// Room for the longest label the list actually holds, rather than a constant. A session
|
|
7285
|
-
// title is what identifies the row, and 36 cells cut most of them in half.
|
|
7286
|
-
const labelWidth = pickerLabelWidth(list.map(it => it.label), list.map(it => it.desc), width);
|
|
7287
|
-
let lastGroup;
|
|
7288
|
-
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: CYAN, paddingX: 1, marginTop: 1, width: boxWidth, children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsx(Text, { color: CYAN, bold: true, children: title }), _jsx(Text, { color: DIM, children: countText })] }), _jsxs(Box, { children: [_jsxs(Text, { color: DIM, children: [G.search, " "] }), pickQuery === ''
|
|
7289
|
-
? _jsx(Text, { color: DIM, children: "type to search" })
|
|
7290
|
-
: _jsx(Text, { color: INK, children: pickQuery }), _jsx(Text, { color: CYAN, children: pickQuery === '' ? '' : '▌' })] }), list.length === 0 && _jsxs(Text, { color: MUTED, children: ["Nothing matches \"", pickQuery, "\""] }), shown.map((item, i) => {
|
|
7291
|
-
const absolute = Math.max(0, start) + i;
|
|
7292
|
-
const selected = absolute === pickIndex;
|
|
7293
|
-
const header = item.group && item.group !== lastGroup ? item.group : null;
|
|
7294
|
-
lastGroup = item.group;
|
|
7295
|
-
const label = pickerLabel(item.label, labelWidth);
|
|
7296
|
-
return (_jsx(Box, { flexDirection: "column", children: _jsx(Text, { backgroundColor: selected ? CYAN : undefined, color: selected ? '#10222A' : INK, bold: selected, children: fitCells(`${selected ? G.caret + ' ' : ' '}${label}` +
|
|
7297
|
-
`${item.current ? '(current) ' : ''}${header ? `${header} · ` : ''}${item.desc}`, width) }) }, item.value + absolute));
|
|
7298
|
-
}), list.length > pickerRows && (_jsxs(Text, { color: DIM, children: ["\u2191\u2193 navigate \u00B7 pgup/pgdn jump \u00B7 enter select \u00B7 showing ", Math.max(0, start) + 1, "\u2013", Math.max(0, start) + shown.length, " of ", list.length] }))] }));
|
|
7299
7297
|
})(), addProv && (() => {
|
|
7300
7298
|
const shadowed = BUILT_IN_PROVIDERS[addProv.name];
|
|
7301
7299
|
const ask = addProv.step === 'name' ? { label: 'name', hint: 'short and lowercase, e.g. openrouter' }
|
|
@@ -7368,7 +7366,69 @@ export function App({ config: initialConfig, clearFrame, synchronizedFrames = fa
|
|
|
7368
7366
|
return (_jsx(Box, { marginTop: 1, children: _jsx(Panel, { width: panelWidth(lines, barWidth, 46), color: AMBER, title: `Permission — ${modeSpec(mode).label} mode`, children: lines }) }));
|
|
7369
7367
|
})()] }), sidePanelOpen && (_jsx(Box, { flexDirection: "column", width: diffPanelWidth, flexShrink: 0, children: diffPanelOpen && _jsx(DiffPanel, { files: liveDiffs, width: diffPanelWidth, scroll: panelScroll, height: Math.max(6, frameRows - 6), activityRows: activityPanelOpen ? 4 : 0, activity: activityPanelOpen ? _jsxs(_Fragment, { children: [_jsxs(Text, { color: CYAN, bold: true, children: ["Activity \u00B7 ", fmtElapsed(busyStart.current ? Date.now() - busyStart.current : 0)] }), _jsx(Text, { color: AMBER, wrap: "truncate", children: ask ? 'Waiting for your approval' : liveToolRef.current
|
|
7370
7368
|
? 'Running ' + liveToolRef.current.name : thinkingRef.current.chars > 0
|
|
7371
|
-
? 'Waiting for model · reasoning received' : 'Waiting for model' }), _jsx(Text, { color: MUTED, wrap: "truncate", children: liveToolRef.current?.detail || plan?.steps.find(s => s.state !== 'done')?.text || 'esc to interrupt' })] }) : undefined }) }))] }),
|
|
7369
|
+
? 'Waiting for model · reasoning received' : 'Waiting for model' }), _jsx(Text, { color: MUTED, wrap: "truncate", children: liveToolRef.current?.detail || plan?.steps.find(s => s.state !== 'done')?.text || 'esc to interrupt' })] }) : undefined }) }))] }), picker && (() => {
|
|
7370
|
+
const list = visiblePickerItems;
|
|
7371
|
+
// In the alternate screen, the picker shares a fixed frame with a bordered composer and
|
|
7372
|
+
// footer. They consume six rows and the picker itself has six non-choice rows (margin,
|
|
7373
|
+
// border, title/search and pager), so reserve thirteen in total. Letting 16 choices into
|
|
7374
|
+
// a 24-row frame made Ink reflow the live region and visibly blink on every keypress.
|
|
7375
|
+
const pickerRows = pickerRowLimit(picker.kind, list.length, termRows, altScreen ? 13 : undefined);
|
|
7376
|
+
// Keep the highlighted row inside the visible window as the selection moves.
|
|
7377
|
+
const start = Math.max(0, Math.min(pickIndex - Math.floor(pickerRows / 2), list.length - pickerRows));
|
|
7378
|
+
const shown = list.slice(Math.max(0, start), Math.max(0, start) + pickerRows);
|
|
7379
|
+
const title = picker.kind === 'command' ? 'Commands'
|
|
7380
|
+
/*
|
|
7381
|
+
* The provider's name and the address the list actually came from.
|
|
7382
|
+
*
|
|
7383
|
+
* The name alone was a claim the list could not support: a header reading "Models -
|
|
7384
|
+
* b.ai" over `muse-glimmer:latest`, `qwen2.5-coder:14b` and `qwen3-coder:30b` — an
|
|
7385
|
+
* Ollama library, listed from an Ollama endpoint, under somebody else's name. Nothing
|
|
7386
|
+
* on screen said where the answer had come from, so a misrouted endpoint looked like a
|
|
7387
|
+
* provider serving the wrong models rather than a request going to the wrong host.
|
|
7388
|
+
*
|
|
7389
|
+
* The host is enough: it is the part that differs when this goes wrong, and a full URL
|
|
7390
|
+
* would push the count and the hint off a narrow palette.
|
|
7391
|
+
*/
|
|
7392
|
+
: picker.kind === 'model' ? `Models - ${cfg.provider} · ${endpointHost(catalogEndpoint.current || endpointFor(cfg.provider).url)}`
|
|
7393
|
+
: picker.kind === 'effort' ? 'Reasoning effort'
|
|
7394
|
+
: picker.kind === 'resume' ? 'Resume a saved session'
|
|
7395
|
+
: picker.kind === 'file' ? 'Reference a file or directory'
|
|
7396
|
+
: 'Connect provider';
|
|
7397
|
+
// The palette is sized to the rows it is showing rather than to the terminal. On a wide
|
|
7398
|
+
// screen a list of short model names in a full-width box is mostly empty box.
|
|
7399
|
+
// The header is a title on the left and a count on the right, on one line. Estimating the
|
|
7400
|
+
// right-hand side at a constant made "Reference a file or directory" wrap onto two rows.
|
|
7401
|
+
const countText = pickerCountText(pickIndex, list.length, picker.items.length);
|
|
7402
|
+
const headWidth = displayWidth(title) + displayWidth(countText) + 3;
|
|
7403
|
+
// Measure the filtered list, not just its current scroll window. A palette whose right
|
|
7404
|
+
// edge breathes as the highlight crosses a long description feels broken even when the
|
|
7405
|
+
// selection itself is correct.
|
|
7406
|
+
const rowWidth = Math.max(headWidth, ...list.map(it => 38 + (it.current ? 10 : 0) + displayWidth(it.desc) + displayWidth(it.group ?? '') + 3));
|
|
7407
|
+
/*
|
|
7408
|
+
* The frame's width, not the conversation column's. `barWidth` is narrowed to make room
|
|
7409
|
+
* for the diff panel, and the palette no longer lives in that column — measuring it
|
|
7410
|
+
* against barWidth is what squeezed the box to 37 cells beside an open panel and turned
|
|
7411
|
+
* `muse-glimmer:latest` into `muse-glimmer:la...`. The composer below uses the same
|
|
7412
|
+
* width for the same reason.
|
|
7413
|
+
*/
|
|
7414
|
+
const boxWidth = pickerBoxWidth(uiWidth - 5, rowWidth + 4);
|
|
7415
|
+
const width = boxWidth - 4;
|
|
7416
|
+
// Room for the longest label the list actually holds, rather than a constant. A session
|
|
7417
|
+
// title is what identifies the row, and 36 cells cut most of them in half.
|
|
7418
|
+
const labelWidth = pickerLabelWidth(list.map(it => it.label), list.map(it => it.desc), width);
|
|
7419
|
+
let lastGroup;
|
|
7420
|
+
return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: CYAN, paddingX: 1, marginTop: 1, width: boxWidth, flexShrink: 0, children: [_jsxs(Box, { justifyContent: "space-between", children: [_jsx(Text, { color: CYAN, bold: true, children: title }), _jsx(Text, { color: DIM, children: countText })] }), _jsxs(Box, { children: [_jsxs(Text, { color: DIM, children: [G.search, " "] }), pickQuery === ''
|
|
7421
|
+
? _jsx(Text, { color: DIM, children: "type to search" })
|
|
7422
|
+
: _jsx(Text, { color: INK, children: pickQuery }), _jsx(Text, { color: CYAN, children: pickQuery === '' ? '' : '▌' })] }), list.length === 0 && _jsxs(Text, { color: MUTED, children: ["Nothing matches \"", pickQuery, "\""] }), shown.map((item, i) => {
|
|
7423
|
+
const absolute = Math.max(0, start) + i;
|
|
7424
|
+
const selected = absolute === pickIndex;
|
|
7425
|
+
const header = item.group && item.group !== lastGroup ? item.group : null;
|
|
7426
|
+
lastGroup = item.group;
|
|
7427
|
+
const label = pickerLabel(item.label, labelWidth);
|
|
7428
|
+
return (_jsx(Box, { flexDirection: "column", children: _jsx(Text, { backgroundColor: selected ? CYAN : undefined, color: selected ? '#10222A' : INK, bold: selected, children: fitCells(`${selected ? G.caret + ' ' : ' '}${label}` +
|
|
7429
|
+
`${item.current ? '(current) ' : ''}${header ? `${header} · ` : ''}${item.desc}`, width) }) }, item.value + absolute));
|
|
7430
|
+
}), list.length > pickerRows && (_jsxs(Text, { color: DIM, children: ["\u2191\u2193 navigate \u00B7 pgup/pgdn jump \u00B7 enter select \u00B7 showing ", Math.max(0, start) + 1, "\u2013", Math.max(0, start) + shown.length, " of ", list.length] }))] }));
|
|
7431
|
+
})(), _jsx(Box, { marginTop: 1, borderStyle: "round", borderColor: busy ? DIM : CYAN, paddingX: 1, width: uiWidth - 5, flexShrink: 0, children: _jsxs(Text, { wrap: "wrap", children: [_jsxs(Text, { color: CYAN, bold: true, children: [G.caret, " "] }), (() => {
|
|
7372
7432
|
const sel = selectionRange(selAnchor, caret, draft.length);
|
|
7373
7433
|
if (sel) {
|
|
7374
7434
|
return (_jsxs(_Fragment, { children: [_jsx(Text, { color: INK, children: draft.slice(0, sel[0]) }), _jsx(Text, { backgroundColor: CYAN, color: "#10222A", children: draft.slice(sel[0], sel[1]) }), _jsx(Text, { color: INK, children: draft.slice(sel[1]) })] }));
|