koneck 2.25.62 → 2.25.64
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/engine.d.ts.map +1 -1
- package/dist/engine.js +91 -1
- package/dist/engine.js.map +1 -1
- package/dist/ink-chat.d.ts +10 -0
- package/dist/ink-chat.d.ts.map +1 -1
- package/dist/ink-chat.js +64 -11
- package/dist/ink-chat.js.map +1 -1
- package/dist/repetition.d.ts +64 -0
- package/dist/repetition.d.ts.map +1 -0
- package/dist/repetition.js +118 -0
- package/dist/repetition.js.map +1 -0
- package/dist/tool-call-text.d.ts +50 -0
- package/dist/tool-call-text.d.ts.map +1 -1
- package/dist/tool-call-text.js +136 -0
- package/dist/tool-call-text.js.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/ink-chat.js
CHANGED
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
2
2
|
import React, { useState, useEffect, useRef } from 'react';
|
|
3
3
|
import { Box, Static, Text, render, useApp, useInput, useStdin } from 'ink';
|
|
4
4
|
import { execa } from 'execa';
|
|
5
|
-
import { createAgentSession, buildClient, resolveAgentConcurrency, toolsUnsupportedNotice } from './engine.js';
|
|
5
|
+
import { createAgentSession, buildClient, resolveAgentConcurrency, toolsUnsupportedNotice, isLocalRuntime } from './engine.js';
|
|
6
6
|
import { estimateCost, formatCost } from './pricing.js';
|
|
7
7
|
import { generateSessionId, saveSession, listSessions, loadSession, relativeAge, renameSession, forkSession, archiveSession, findSession, } from './session.js';
|
|
8
8
|
import { loadMemory } from './memory.js';
|
|
@@ -766,7 +766,24 @@ Keyboard:
|
|
|
766
766
|
Shift+Tab Cycle mode (auto → plan → code)
|
|
767
767
|
Ctrl+C Cancel task / exit if idle
|
|
768
768
|
`.trim();
|
|
769
|
-
|
|
769
|
+
/**
|
|
770
|
+
* Whether to own the screen, when nothing has been configured either way.
|
|
771
|
+
*
|
|
772
|
+
* Only on a real terminal. A pipe has no cursor to move and no rows to fill, and writing the
|
|
773
|
+
* enter-alternate-screen sequence into a log file is how a captured session becomes unreadable.
|
|
774
|
+
*/
|
|
775
|
+
export function defaultAltScreen(stdout = process.stdout, env = process.env) {
|
|
776
|
+
if (!stdout.isTTY)
|
|
777
|
+
return false;
|
|
778
|
+
if (env['CI'])
|
|
779
|
+
return false;
|
|
780
|
+
// A terminal too short to hold the interface has nothing to gain: the transcript would be
|
|
781
|
+
// clipped to a row or two, and the terminal's own scrollback is more use than that.
|
|
782
|
+
if ((stdout.rows ?? 24) < 14)
|
|
783
|
+
return false;
|
|
784
|
+
return true;
|
|
785
|
+
}
|
|
786
|
+
function App({ config: initialConfig, clearFrame }) {
|
|
770
787
|
const { exit } = useApp();
|
|
771
788
|
const [cfg, setCfg] = useState(initialConfig);
|
|
772
789
|
// Live activity accumulates in a ref and is painted by the 100 ms ticker. Mutating a ref
|
|
@@ -1014,6 +1031,18 @@ function App({ config: initialConfig }) {
|
|
|
1014
1031
|
toolsWarnedRef.current = model;
|
|
1015
1032
|
addSystem(toolsUnsupportedNotice(model));
|
|
1016
1033
|
},
|
|
1034
|
+
onLooping: (copies) => {
|
|
1035
|
+
// The loop itself is the symptom. On a local model the cause is almost always the window:
|
|
1036
|
+
// Ollama serves 4096 tokens unless told otherwise, whatever the model was trained for, and
|
|
1037
|
+
// a conversation that no longer fits is exactly what makes a model start repeating.
|
|
1038
|
+
const local = isLocalRuntime(cfg.provider);
|
|
1039
|
+
addSystem(`${cfg.model} repeated the same text ${copies} times, so the reply was cut short.` +
|
|
1040
|
+
(local
|
|
1041
|
+
? `\n\nThis is usually the context window rather than the model. Ollama serves 4096 ` +
|
|
1042
|
+
`tokens by default however large the model is — set ` +
|
|
1043
|
+
`\`OLLAMA_CONTEXT_LENGTH=32768\` and restart it, then \`/context\` to confirm.`
|
|
1044
|
+
: ''));
|
|
1045
|
+
},
|
|
1017
1046
|
onThinking: (text, totalChars) => {
|
|
1018
1047
|
thinkingRef.current = { chars: totalChars, at: Date.now() };
|
|
1019
1048
|
// The text was discarded before this, so the model's reasoning was never visible — only a
|
|
@@ -1067,9 +1096,21 @@ function App({ config: initialConfig }) {
|
|
|
1067
1096
|
* and what Codex does by default, offering --no-alt-screen to opt out.
|
|
1068
1097
|
*
|
|
1069
1098
|
* The cost is real: the alternate screen has no scrollback of its own, so history has to be
|
|
1070
|
-
* scrolled from inside the application.
|
|
1099
|
+
* scrolled from inside the application. It was a choice rather than the default for that
|
|
1100
|
+
* reason, and the default has changed because the reason on the other side turned out to weigh
|
|
1101
|
+
* more.
|
|
1102
|
+
*
|
|
1103
|
+
* Inline mode depends on Ink counting the lines it wrote so it can erase them, and that count is
|
|
1104
|
+
* the number of newlines in the frame — not the number of rows the terminal used to show it. Any
|
|
1105
|
+
* line the terminal wrapped makes the count too small, the erase falls short, and a whole copy
|
|
1106
|
+
* of the interface is stranded on screen. Three separate reports of exactly that: a prompt
|
|
1107
|
+
* floating mid-screen, two composers with the transcript between them, and a working prompt at
|
|
1108
|
+
* the top with a dead one below. Here the frame is the whole screen, redrawn at fixed
|
|
1109
|
+
* coordinates, so there is nothing to count and nothing to strand.
|
|
1110
|
+
*
|
|
1111
|
+
* /altscreen off, or `altScreen: false` in config, goes back to the terminal's own scrollback.
|
|
1071
1112
|
*/
|
|
1072
|
-
const [altScreen, setAltScreen] = useState(cfg.altScreen ??
|
|
1113
|
+
const [altScreen, setAltScreen] = useState(cfg.altScreen ?? defaultAltScreen());
|
|
1073
1114
|
/**
|
|
1074
1115
|
* How many rows back from the newest the viewport is looking, in alt-screen mode.
|
|
1075
1116
|
*
|
|
@@ -1435,12 +1476,16 @@ function App({ config: initialConfig }) {
|
|
|
1435
1476
|
function redrawScreen() {
|
|
1436
1477
|
if (!process.stdout.isTTY)
|
|
1437
1478
|
return;
|
|
1438
|
-
//
|
|
1439
|
-
//
|
|
1440
|
-
//
|
|
1479
|
+
// Ink's own clear first. It erases the frame using its own count of it and then resets that
|
|
1480
|
+
// count to zero, which is the part that matters: after this Ink believes nothing is on screen,
|
|
1481
|
+
// which is about to be true.
|
|
1482
|
+
clearFrame?.();
|
|
1483
|
+
// Then the screen, and the scrollback with it — a stranded frame that has scrolled out of view
|
|
1484
|
+
// is still in the buffer, and leaving it there means it comes back on the next scroll — and
|
|
1485
|
+
// home the cursor, which is where Ink will now draw.
|
|
1441
1486
|
process.stdout.write('\u001b[2J\u001b[3J\u001b[H');
|
|
1442
|
-
// Ink writes a frame only when its content differs from the last one, and the content has
|
|
1443
|
-
//
|
|
1487
|
+
// Ink writes a frame only when its content differs from the last one, and the content has not
|
|
1488
|
+
// changed — the screen it was drawn on has. Bumping this forces the write.
|
|
1444
1489
|
setRepaint(n => n + 1);
|
|
1445
1490
|
}
|
|
1446
1491
|
async function doSave() {
|
|
@@ -3405,7 +3450,7 @@ function App({ config: initialConfig }) {
|
|
|
3405
3450
|
* by <Static> in inline mode, and re-rendered every frame inside a clipped viewport in
|
|
3406
3451
|
* alt-screen mode. Two copies of this markup would drift apart within a release.
|
|
3407
3452
|
*/
|
|
3408
|
-
const renderRow = (row, index) => (row.role === 'header' ? (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { flexDirection: "column", alignItems: "center", marginTop: 1, marginBottom: 1, children: [logoFor(uiWidth, G.ascii).map((line, i) => (_jsx(Text, { color: CYAN, bold: true, children: line }, i))), _jsx(Text, { color: CYAN, bold: true, children: "KONECK / SOFTWARE DELIVERY SYSTEM" }), _jsx(Text, { color: MUTED, children: "Deliberate engineering, with control at every change." })] }), _jsx(Panel, { width: barWidth, color: CYAN, title: "KONECK", children: [`MODEL: \`${modelShort}\` PROVIDER: \`${cfg.provider}\` WORKSPACE: \`${workspace}\``] })] }, index)) : row.role === 'user' ? (
|
|
3453
|
+
const renderRow = (row, index) => (row.role === 'header' ? (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { flexDirection: "column", alignItems: "center", marginTop: 1, marginBottom: 1, children: [logoFor(uiWidth, G.ascii).map((line, i) => (_jsx(Text, { color: CYAN, bold: true, children: line }, i))), _jsx(Text, { color: CYAN, bold: true, children: "KONECK / SOFTWARE DELIVERY SYSTEM" }), _jsx(Text, { color: MUTED, children: "Deliberate engineering, with control at every change." }), altScreen && (_jsx(Text, { color: DIM, children: "PageUp scrolls \u00B7 /altscreen off to use the terminal's scrollback instead" }))] }), _jsx(Panel, { width: barWidth, color: CYAN, title: "KONECK", children: [`MODEL: \`${modelShort}\` PROVIDER: \`${cfg.provider}\` WORKSPACE: \`${workspace}\``] })] }, index)) : row.role === 'user' ? (
|
|
3409
3454
|
// Painted as a filled bar so the user's own words are the most findable thing
|
|
3410
3455
|
// on screen when scrolling back through a long session.
|
|
3411
3456
|
_jsx(Box, { marginTop: 1, flexDirection: "column", children: wrapPreserving(row.text ?? '', barWidth - 2).map((line, li) => (_jsx(Text, { backgroundColor: USER_BG, color: USER_FG, bold: li === 0, children: (li === 0 ? `${G.caret} ` : ' ') + fitCells(line, barWidth - 2) }, li))) }, index)) : row.role === 'plan' ? (() => {
|
|
@@ -3732,7 +3777,15 @@ export async function runInkChatMode(config) {
|
|
|
3732
3777
|
// overshot — the banner ended up at the bottom with empty screen above it and a gap still
|
|
3733
3778
|
// below. Starting at the top and growing downward is worse only until the screen fills, and
|
|
3734
3779
|
// being wrong in a way that moves the whole interface is worse than that.
|
|
3735
|
-
|
|
3780
|
+
// `clear` is handed to the app because a repaint has to go through Ink, not around it. Ink
|
|
3781
|
+
// tracks how many lines it last wrote and erases exactly that many; writing escape codes to the
|
|
3782
|
+
// same terminal without telling it leaves that count describing a screen that no longer exists,
|
|
3783
|
+
// and the next frame is drawn in the wrong place and pinned there. Reported as the prompt
|
|
3784
|
+
// appearing at the top with a dead copy of the interface below it — caused by the first version
|
|
3785
|
+
// of this repaint, which did exactly that.
|
|
3786
|
+
let inkClear;
|
|
3787
|
+
const app = render(_jsx(App, { config: config, clearFrame: () => inkClear?.() }), { exitOnCtrlC: false, patchConsole: false });
|
|
3788
|
+
inkClear = app.clear;
|
|
3736
3789
|
await app.waitUntilExit();
|
|
3737
3790
|
}
|
|
3738
3791
|
//# sourceMappingURL=ink-chat.js.map
|