koneck 2.25.51 → 2.25.53
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/activity.d.ts +30 -0
- package/dist/activity.d.ts.map +1 -0
- package/dist/activity.js +59 -0
- package/dist/activity.js.map +1 -0
- package/dist/ink-chat.d.ts +8 -0
- package/dist/ink-chat.d.ts.map +1 -1
- package/dist/ink-chat.js +52 -2
- package/dist/ink-chat.js.map +1 -1
- package/dist/key-choice.d.ts +22 -0
- package/dist/key-choice.d.ts.map +1 -0
- package/dist/key-choice.js +110 -0
- package/dist/key-choice.js.map +1 -0
- package/dist/logo.d.ts +16 -3
- package/dist/logo.d.ts.map +1 -1
- package/dist/logo.js +38 -17
- package/dist/logo.js.map +1 -1
- package/dist/workspace-trust.d.ts.map +1 -1
- package/dist/workspace-trust.js +13 -14
- package/dist/workspace-trust.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Plan } from './plan.js';
|
|
2
|
+
/**
|
|
3
|
+
* What the model has done this session, gathered from the transcript already on screen.
|
|
4
|
+
*
|
|
5
|
+
* Asked for because a long run is opaque while it happens and unreadable afterwards: the tool
|
|
6
|
+
* calls are all there in scrollback, hundreds of lines apart, and nobody scrolls back through
|
|
7
|
+
* forty screens to count how many files were written.
|
|
8
|
+
*
|
|
9
|
+
* Built from the rows rather than from a second log kept alongside them. Two records of the same
|
|
10
|
+
* events drift, and the one on screen would be the one that was wrong.
|
|
11
|
+
*/
|
|
12
|
+
export interface ActivityStep {
|
|
13
|
+
kind: 'tool' | 'say';
|
|
14
|
+
name?: string;
|
|
15
|
+
detail?: string;
|
|
16
|
+
ok?: boolean;
|
|
17
|
+
startedAt?: number;
|
|
18
|
+
endedAt?: number;
|
|
19
|
+
}
|
|
20
|
+
export interface ActivityRow {
|
|
21
|
+
role: string;
|
|
22
|
+
steps?: ActivityStep[];
|
|
23
|
+
text?: string;
|
|
24
|
+
}
|
|
25
|
+
export interface ActivityTotals {
|
|
26
|
+
turns: number;
|
|
27
|
+
totalTokens: number;
|
|
28
|
+
}
|
|
29
|
+
export declare function describeActivity(rows: readonly ActivityRow[], plan: Plan | null, totals: ActivityTotals): string;
|
|
30
|
+
//# sourceMappingURL=activity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activity.d.ts","sourceRoot":"","sources":["../src/activity.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC;;;;;;;;;GASG;AAEH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,YAAY,EAAE,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAYD,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,SAAS,WAAW,EAAE,EAC5B,IAAI,EAAE,IAAI,GAAG,IAAI,EACjB,MAAM,EAAE,cAAc,GACrB,MAAM,CAuDR"}
|
package/dist/activity.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { planSummary } from './plan.js';
|
|
2
|
+
/** Files and commands are what people actually want to know about; the rest is counted. */
|
|
3
|
+
const FILE_TOOLS = new Set(['write_file', 'apply_diff', 'search_replace', 'move_file', 'delete_file']);
|
|
4
|
+
export function describeActivity(rows, plan, totals) {
|
|
5
|
+
const byTool = new Map();
|
|
6
|
+
const files = new Set();
|
|
7
|
+
const commands = [];
|
|
8
|
+
for (const row of rows) {
|
|
9
|
+
for (const step of row.steps ?? []) {
|
|
10
|
+
if (step.kind !== 'tool' || !step.name)
|
|
11
|
+
continue;
|
|
12
|
+
const tally = byTool.get(step.name) ?? { calls: 0, failed: 0, ms: 0 };
|
|
13
|
+
tally.calls++;
|
|
14
|
+
if (step.ok === false)
|
|
15
|
+
tally.failed++;
|
|
16
|
+
// Checked for presence, not truthiness: a step that began at timestamp 0 is a real step,
|
|
17
|
+
// and `if (startedAt)` silently drops it along with its timing.
|
|
18
|
+
if (step.startedAt !== undefined && step.endedAt !== undefined) {
|
|
19
|
+
tally.ms += Math.max(0, step.endedAt - step.startedAt);
|
|
20
|
+
}
|
|
21
|
+
byTool.set(step.name, tally);
|
|
22
|
+
if (FILE_TOOLS.has(step.name) && step.detail)
|
|
23
|
+
files.add(step.detail.split(/\s+/)[0] ?? step.detail);
|
|
24
|
+
if (step.name === 'execute_command' && step.detail)
|
|
25
|
+
commands.push(step.detail);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
if (byTool.size === 0) {
|
|
29
|
+
return 'Nothing done yet this session — no tools have run.';
|
|
30
|
+
}
|
|
31
|
+
const lines = [];
|
|
32
|
+
lines.push(`**${totals.turns} turns**, ${totals.totalTokens.toLocaleString()} tokens`);
|
|
33
|
+
if (plan && plan.steps.length > 0)
|
|
34
|
+
lines.push(`**Plan** ${planSummary(plan)}`);
|
|
35
|
+
lines.push('');
|
|
36
|
+
lines.push('**Tools**');
|
|
37
|
+
for (const [name, tally] of [...byTool.entries()].sort((a, b) => b[1].calls - a[1].calls)) {
|
|
38
|
+
const seconds = tally.ms > 0 ? ` ${(tally.ms / 1000).toFixed(1)}s` : '';
|
|
39
|
+
const failed = tally.failed > 0 ? ` ${tally.failed} failed` : '';
|
|
40
|
+
lines.push(` ${name} × ${tally.calls}${seconds}${failed}`);
|
|
41
|
+
}
|
|
42
|
+
if (files.size > 0) {
|
|
43
|
+
lines.push('');
|
|
44
|
+
lines.push(`**Files changed** (${files.size})`);
|
|
45
|
+
for (const file of [...files].slice(0, 20))
|
|
46
|
+
lines.push(` ${file}`);
|
|
47
|
+
if (files.size > 20)
|
|
48
|
+
lines.push(` … and ${files.size - 20} more`);
|
|
49
|
+
}
|
|
50
|
+
if (commands.length > 0) {
|
|
51
|
+
lines.push('');
|
|
52
|
+
lines.push(`**Commands run** (${commands.length})`);
|
|
53
|
+
// The last few, because the recent ones are the ones being asked about.
|
|
54
|
+
for (const command of commands.slice(-8))
|
|
55
|
+
lines.push(` ${command.slice(0, 90)}`);
|
|
56
|
+
}
|
|
57
|
+
return lines.join('\n');
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=activity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activity.js","sourceRoot":"","sources":["../src/activity.ts"],"names":[],"mappings":"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"}
|
package/dist/ink-chat.d.ts
CHANGED
|
@@ -121,6 +121,14 @@ interface AskOption {
|
|
|
121
121
|
* would otherwise renumber the rows beneath it in one of the two paths and not the other.
|
|
122
122
|
*/
|
|
123
123
|
export declare function askOptions(tool: string, prefix: string): AskOption[];
|
|
124
|
+
/**
|
|
125
|
+
* The last few lines of reasoning, wrapped and clipped for a glance.
|
|
126
|
+
*
|
|
127
|
+
* Reasoning arrives as one long stream with few newlines, so it is wrapped to the panel width
|
|
128
|
+
* first and then the tail is taken — clipping the raw text instead would show the last 200
|
|
129
|
+
* characters of one enormous line, which is a fragment of a sentence and tells nobody anything.
|
|
130
|
+
*/
|
|
131
|
+
export declare function thinkingTail(text: string, lines: number, width: number): string[];
|
|
124
132
|
export declare function runInkChatMode(config: AgentConfig): Promise<void>;
|
|
125
133
|
export {};
|
|
126
134
|
//# sourceMappingURL=ink-chat.d.ts.map
|
package/dist/ink-chat.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ink-chat.d.ts","sourceRoot":"","sources":["../src/ink-chat.tsx"],"names":[],"mappings":"AAgDA,OAAO,KAAK,EAAY,SAAS,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"ink-chat.d.ts","sourceRoot":"","sources":["../src/ink-chat.tsx"],"names":[],"mappings":"AAgDA,OAAO,KAAK,EAAY,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAO5D,OAAO,KAAK,EAAE,WAAW,EAAiB,MAAM,YAAY,CAAC;AAoE7D,6FAA6F;AAC7F,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAM7C;AA0BD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CA+BpE;AAED,qFAAqF;AACrF,eAAO,MAAM,cAAc,KAAK,CAAC;AAEjC;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,SAAiB,GAAG,MAAM,CAM9E;AA6CD;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAGnE;AAuBD;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,UAAU,CAAC;AAE3E,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CA2GzE,CAAC;AAEF,0CAA0C;AAC1C,iFAAiF;AACjF,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,8BAA8B;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAItD;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG,QAAQ,CAMpD;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAIpF;AAwDD,UAAU,UAAU;IAAG,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE;AAUtG,qDAAqD;AACrD,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAK7E;AAeD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,UAAU,EAAE,CAWlF;AAGD,iGAAiG;AACjG,UAAU,SAAS;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,SAAS,GAAG,IAAI,CAAC;IACvB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,CAepE;AAQD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAMjF;AA8/FD,wBAAsB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAQvE"}
|
package/dist/ink-chat.js
CHANGED
|
@@ -35,6 +35,7 @@ import { MODES as MODE_SPECS, modeSpec, decide, loadRules, saveRules, addRule, c
|
|
|
35
35
|
import { AskQueue } from './ask-queue.js';
|
|
36
36
|
import { planSummary } from './plan.js';
|
|
37
37
|
import { logoFor } from './logo.js';
|
|
38
|
+
import { describeActivity } from './activity.js';
|
|
38
39
|
import { describeSandbox, resolveSandbox } from './sandbox.js';
|
|
39
40
|
const CYAN = '#54D7E7';
|
|
40
41
|
const GREEN = '#9BCB8F';
|
|
@@ -443,6 +444,8 @@ const COMMANDS = [
|
|
|
443
444
|
{ cmd: '/cost', desc: 'Session cost' },
|
|
444
445
|
{ cmd: '/memory', desc: 'Show project memory (/memory clear wipes it)' },
|
|
445
446
|
{ cmd: '/altscreen', desc: 'Pin the prompt to the last row (own screen, own scrollback)' },
|
|
447
|
+
{ cmd: '/thinking', desc: 'Show or hide the model\'s reasoning as it arrives' },
|
|
448
|
+
{ cmd: '/activity', desc: 'What the model has done this session, and what it is on now' },
|
|
446
449
|
{ cmd: '/name', desc: 'Name this session, so /resume can find it by name' },
|
|
447
450
|
{ cmd: '/fork', desc: 'Copy this session and continue on the copy' },
|
|
448
451
|
{ cmd: '/archive', desc: 'Keep a session but hide it from /resume' },
|
|
@@ -538,6 +541,24 @@ export function askOptions(tool, prefix) {
|
|
|
538
541
|
options.push({ key: 'n', label: 'refuse', rule: null, allow: false });
|
|
539
542
|
return options;
|
|
540
543
|
}
|
|
544
|
+
/** How much of a turn's reasoning to keep for display. Enough to read, not enough to scroll. */
|
|
545
|
+
const THINKING_TAIL_CHARS = 2_000;
|
|
546
|
+
/** Lines of reasoning shown live. More than this and it stops being a glance. */
|
|
547
|
+
const THINKING_LINES = 4;
|
|
548
|
+
/**
|
|
549
|
+
* The last few lines of reasoning, wrapped and clipped for a glance.
|
|
550
|
+
*
|
|
551
|
+
* Reasoning arrives as one long stream with few newlines, so it is wrapped to the panel width
|
|
552
|
+
* first and then the tail is taken — clipping the raw text instead would show the last 200
|
|
553
|
+
* characters of one enormous line, which is a fragment of a sentence and tells nobody anything.
|
|
554
|
+
*/
|
|
555
|
+
export function thinkingTail(text, lines, width) {
|
|
556
|
+
const wrapped = text
|
|
557
|
+
.split('\n')
|
|
558
|
+
.flatMap(paragraph => wrapPreserving(paragraph, Math.max(20, width)))
|
|
559
|
+
.filter(line => line.trim() !== '');
|
|
560
|
+
return wrapped.slice(-lines);
|
|
561
|
+
}
|
|
541
562
|
const MODES = MODE_SPECS.map(m => m.name);
|
|
542
563
|
const HELP_TEXT = `
|
|
543
564
|
Type / on an empty line to browse every command; keep typing to filter.
|
|
@@ -825,8 +846,13 @@ function App({ config: initialConfig }) {
|
|
|
825
846
|
toolsWarnedRef.current = model;
|
|
826
847
|
addSystem(toolsUnsupportedNotice(model));
|
|
827
848
|
},
|
|
828
|
-
onThinking: (
|
|
849
|
+
onThinking: (text, totalChars) => {
|
|
829
850
|
thinkingRef.current = { chars: totalChars, at: Date.now() };
|
|
851
|
+
// The text was discarded before this, so the model's reasoning was never visible — only a
|
|
852
|
+
// count of it. Kept as a rolling tail rather than the whole thing: a reasoning model can
|
|
853
|
+
// produce tens of thousands of characters per turn, and what anyone watching wants is what
|
|
854
|
+
// it is thinking now.
|
|
855
|
+
thinkingTextRef.current = (thinkingTextRef.current + text).slice(-THINKING_TAIL_CHARS);
|
|
830
856
|
lastActivityRef.current = Date.now();
|
|
831
857
|
},
|
|
832
858
|
onAgentProgress: (list) => { agentsRef.current = list; setAgents(list); },
|
|
@@ -855,6 +881,15 @@ function App({ config: initialConfig }) {
|
|
|
855
881
|
const modeRef = useRef('auto');
|
|
856
882
|
/** The run's current plan, so it is visible rather than buried in the transcript. */
|
|
857
883
|
const [plan, setPlan] = useState(null);
|
|
884
|
+
/**
|
|
885
|
+
* The tail of what the model is reasoning about, and whether to show it.
|
|
886
|
+
*
|
|
887
|
+
* A ref rather than state: reasoning arrives in a flood, and setting state per chunk would
|
|
888
|
+
* repaint the screen faster than anyone can read it. The live region already redraws on a
|
|
889
|
+
* timer, which is the right rate for something being read rather than parsed.
|
|
890
|
+
*/
|
|
891
|
+
const thinkingTextRef = useRef('');
|
|
892
|
+
const [showThinking, setShowThinking] = useState(true);
|
|
858
893
|
/**
|
|
859
894
|
* Whether the interface owns the whole screen.
|
|
860
895
|
*
|
|
@@ -1737,6 +1772,20 @@ function App({ config: initialConfig }) {
|
|
|
1737
1772
|
: 'Alt-screen off: back to writing into the terminal\'s own scrollback.');
|
|
1738
1773
|
return;
|
|
1739
1774
|
}
|
|
1775
|
+
case '/thinking': {
|
|
1776
|
+
const next = arg.trim() === 'off' ? false : arg.trim() === 'on' ? true : !showThinking;
|
|
1777
|
+
setShowThinking(next);
|
|
1778
|
+
addSystem(next
|
|
1779
|
+
? 'Showing the model\'s reasoning as it arrives, under the working line.'
|
|
1780
|
+
: 'Hiding the reasoning. The token count stays on the working line.');
|
|
1781
|
+
return;
|
|
1782
|
+
}
|
|
1783
|
+
case '/activity': {
|
|
1784
|
+
// Built from the transcript that is already held rather than a second log kept in
|
|
1785
|
+
// parallel: two records of the same events drift, and the one shown would be the wrong one.
|
|
1786
|
+
addSystem(describeActivity(rows, plan, stats));
|
|
1787
|
+
return;
|
|
1788
|
+
}
|
|
1740
1789
|
case '/memory': {
|
|
1741
1790
|
// Clearable, because these notes are written by the model — including while it is
|
|
1742
1791
|
// failing — and a wrong one is read back as fact by every later session in this folder.
|
|
@@ -2725,6 +2774,7 @@ function App({ config: initialConfig }) {
|
|
|
2725
2774
|
streamedRef.current = '';
|
|
2726
2775
|
replyStartedRef.current = false;
|
|
2727
2776
|
thinkingRef.current = { chars: 0, at: 0 };
|
|
2777
|
+
thinkingTextRef.current = '';
|
|
2728
2778
|
incompleteRef.current = null;
|
|
2729
2779
|
lastActivityRef.current = Date.now();
|
|
2730
2780
|
setProviderFrames(0);
|
|
@@ -2982,7 +3032,7 @@ function App({ config: initialConfig }) {
|
|
|
2982
3032
|
: elapsedMs > 8_000 ? `no response from ${cfg.provider} yet`
|
|
2983
3033
|
: 'starting', thinkingRef.current.chars > 0 && Date.now() - thinkingRef.current.at < 2_000
|
|
2984
3034
|
? ` | thinking, ${fmtTokens(Math.round(thinkingRef.current.chars / 4))} reasoning tokens`
|
|
2985
|
-
: '', ")"] })] }) }), _jsx(Box, { paddingLeft: 2, children: _jsx(Text, { color: DIM, children: "esc to cancel and keep your input \u00B7 ctrl+c to exit" }) })] })) }), usagePane && (() => {
|
|
3035
|
+
: '', ")"] })] }) }), showThinking && thinkingTextRef.current.trim() !== '' && (_jsx(Box, { flexDirection: "column", paddingLeft: 2, children: thinkingTail(thinkingTextRef.current, THINKING_LINES, barWidth - 6).map((line, i) => (_jsx(Text, { color: DIM, italic: true, children: line }, i))) })), _jsx(Box, { paddingLeft: 2, children: _jsx(Text, { color: DIM, children: "esc to cancel and keep your input \u00B7 ctrl+c to exit" }) })] })) }), usagePane && (() => {
|
|
2986
3036
|
const width = Math.min(barWidth, usagePane === 'settings' ? 96 : 66);
|
|
2987
3037
|
const inner = width - 4;
|
|
2988
3038
|
const BAR_W = Math.max(12, inner - 14);
|