koneck 2.25.54 → 2.25.56

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/ink-chat.js CHANGED
@@ -36,6 +36,7 @@ import { AskQueue } from './ask-queue.js';
36
36
  import { planSummary } from './plan.js';
37
37
  import { logoFor } from './logo.js';
38
38
  import { describeActivity } from './activity.js';
39
+ import { renderTrajectory } from './trajectory.js';
39
40
  import { describeSandbox, resolveSandbox } from './sandbox.js';
40
41
  const CYAN = '#54D7E7';
41
42
  const GREEN = '#9BCB8F';
@@ -446,6 +447,8 @@ const COMMANDS = [
446
447
  { cmd: '/altscreen', desc: 'Pin the prompt to the last row (own screen, own scrollback)' },
447
448
  { cmd: '/thinking', desc: 'Show or hide the model\'s reasoning as it arrives' },
448
449
  { cmd: '/activity', desc: 'What the model has done this session, and what it is on now' },
450
+ { cmd: '/trajectory', desc: 'Where the time went: per-request timings, tool durations, waits' },
451
+ { cmd: '/update', desc: 'Check for a new version and update' },
449
452
  { cmd: '/name', desc: 'Name this session, so /resume can find it by name' },
450
453
  { cmd: '/fork', desc: 'Copy this session and continue on the copy' },
451
454
  { cmd: '/archive', desc: 'Keep a session but hide it from /resume' },
@@ -559,13 +562,22 @@ export function thinkingTail(text, lines, width) {
559
562
  .filter(line => line.trim() !== '');
560
563
  return wrapped.slice(-lines);
561
564
  }
565
+ export function pasteTarget(open) {
566
+ if (open.keyPrompt)
567
+ return 'key-prompt';
568
+ // A picker and a permission question both take single keys. A pasted blob is not an answer to
569
+ // either, and answering something nobody chose is worse than ignoring it.
570
+ if (open.picker || open.ask)
571
+ return 'drop';
572
+ return 'composer';
573
+ }
562
574
  const MODES = MODE_SPECS.map(m => m.name);
563
575
  const HELP_TEXT = `
564
576
  Type / on an empty line to browse every command; keep typing to filter.
565
577
 
566
578
  Slash commands:
567
579
  /help Show this help
568
- (shift+u) Updates and a key guide, in a side panel
580
+ /update Updates and a key guide, in a side panel
569
581
  /models [filter] Browse models from the connected provider and switch
570
582
  /connect [provider] Connect a provider (picker when no name given)
571
583
  /connect <name> <url> Declare a provider KONECK does not ship with, e.g.
@@ -1780,6 +1792,17 @@ function App({ config: initialConfig }) {
1780
1792
  : 'Hiding the reasoning. The token count stays on the working line.');
1781
1793
  return;
1782
1794
  }
1795
+ case '/update': {
1796
+ void openUpdatePane();
1797
+ return;
1798
+ }
1799
+ case '/trajectory': {
1800
+ // The timings the transcript cannot answer for: where the time went, which tool was slow,
1801
+ // how much of a long turn was spent waiting for a first token rather than generating.
1802
+ const s = await activeSession.p.catch(() => null);
1803
+ addSystem(renderTrajectory(s?.trajectory ?? []));
1804
+ return;
1805
+ }
1783
1806
  case '/activity': {
1784
1807
  // Built from the transcript that is already held rather than a second log kept in
1785
1808
  // parallel: two records of the same events drift, and the one shown would be the wrong one.
@@ -2244,6 +2267,15 @@ function App({ config: initialConfig }) {
2244
2267
  function filePaste(text) {
2245
2268
  const clean = text.replace(/\r\n?/g, '\n');
2246
2269
  const lines = clean.split('\n').length;
2270
+ // Whatever owns the keyboard gets the paste.
2271
+ const target = pasteTarget({ keyPrompt: Boolean(keyPrompt), picker: Boolean(picker), ask: Boolean(ask) });
2272
+ if (target === 'drop')
2273
+ return;
2274
+ if (target === 'key-prompt') {
2275
+ // A key pasted from a manager often carries a trailing newline; it is not part of the key.
2276
+ setKeyPrompt(p => (p ? { ...p, value: p.value + clean.replace(/\s+$/, '') } : p));
2277
+ return;
2278
+ }
2247
2279
  if (!clean.includes('\n') && clean.length <= 200) {
2248
2280
  setDraft(d => d.slice(0, caret) + clean + d.slice(caret));
2249
2281
  setCaret(c => c + clean.length);
@@ -2567,15 +2599,11 @@ function App({ config: initialConfig }) {
2567
2599
  }
2568
2600
  }
2569
2601
  // Shift+U → the update and guide panel.
2570
- if (key.shift && (input === 'U' || input === 'u')) {
2571
- if (updatePane) {
2572
- setUpdatePane(null);
2573
- setUpdating('idle');
2574
- }
2575
- else
2576
- void openUpdatePane();
2577
- return;
2578
- }
2602
+ // There is deliberately no shortcut to open this any more. It was shift+u, which is exactly
2603
+ // how a capital U is typed: the pane opened instead of the letter appearing, and there was no
2604
+ // way to write one at all. /update opens it, which is discoverable from /help and the palette
2605
+ // rather than from a habit, and cannot collide with anything anyone types.
2606
+ //
2579
2607
  // Inside the panel: u applies the update, esc closes it.
2580
2608
  if (updatePane) {
2581
2609
  if (key.escape) {
@@ -3222,7 +3250,7 @@ function App({ config: initialConfig }) {
3222
3250
  }
3223
3251
  lines.push('');
3224
3252
  lines.push('---');
3225
- lines.push('**Keys** shift+u update · tab analytics · shift+tab mode · ctrl+c exit');
3253
+ lines.push('**Keys** tab analytics · shift+tab mode · ctrl+c exit · /update for this panel');
3226
3254
  lines.push('**Editing** arrows move · ctrl+a/e ends · ctrl+w word · ctrl+u/k cut');
3227
3255
  lines.push('**Sessions** /sessions · /send <repo> <task> · /ask <repo> <q> · /resume');
3228
3256
  lines.push('**Changelog** github.com/Gubevu/konech/commits/main');