cvc-tui 0.4.0 → 0.4.2

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 (133) hide show
  1. package/dist/entry.js +71148 -61
  2. package/package.json +2 -2
  3. package/dist/app/completion.js +0 -102
  4. package/dist/app/createGatewayEventHandler.js +0 -508
  5. package/dist/app/createSlashHandler.js +0 -101
  6. package/dist/app/delegationStore.js +0 -51
  7. package/dist/app/gatewayContext.js +0 -17
  8. package/dist/app/historyStore.js +0 -123
  9. package/dist/app/inputBuffer.js +0 -120
  10. package/dist/app/inputSelectionStore.js +0 -8
  11. package/dist/app/inputStore.js +0 -28
  12. package/dist/app/interfaces.js +0 -6
  13. package/dist/app/overlayStore.js +0 -40
  14. package/dist/app/promptStore.js +0 -44
  15. package/dist/app/queueStore.js +0 -25
  16. package/dist/app/scroll.js +0 -44
  17. package/dist/app/setupHandoff.js +0 -28
  18. package/dist/app/slash/commands/core.js +0 -479
  19. package/dist/app/slash/commands/debug.js +0 -44
  20. package/dist/app/slash/commands/ops.js +0 -498
  21. package/dist/app/slash/commands/session.js +0 -431
  22. package/dist/app/slash/commands/setup.js +0 -20
  23. package/dist/app/slash/commands/toggles.js +0 -40
  24. package/dist/app/slash/registry.js +0 -18
  25. package/dist/app/slash/types.js +0 -1
  26. package/dist/app/spawnHistoryStore.js +0 -105
  27. package/dist/app/turnController.js +0 -650
  28. package/dist/app/turnStore.js +0 -48
  29. package/dist/app/uiStore.js +0 -36
  30. package/dist/app/useComposerState.js +0 -265
  31. package/dist/app/useConfigSync.js +0 -144
  32. package/dist/app/useInputHandlers.js +0 -403
  33. package/dist/app/useLongRunToolCharms.js +0 -50
  34. package/dist/app/useMainApp.js +0 -629
  35. package/dist/app/useSessionLifecycle.js +0 -175
  36. package/dist/app/useSubmission.js +0 -287
  37. package/dist/app.js +0 -15
  38. package/dist/banner.js +0 -57
  39. package/dist/components/agentsOverlay.js +0 -474
  40. package/dist/components/appChrome.js +0 -252
  41. package/dist/components/appLayout.js +0 -121
  42. package/dist/components/appOverlays.js +0 -65
  43. package/dist/components/branding.js +0 -97
  44. package/dist/components/fpsOverlay.js +0 -22
  45. package/dist/components/helpHint.js +0 -21
  46. package/dist/components/markdown.js +0 -501
  47. package/dist/components/maskedPrompt.js +0 -12
  48. package/dist/components/messageLine.js +0 -82
  49. package/dist/components/modelPicker.js +0 -254
  50. package/dist/components/overlayControls.js +0 -30
  51. package/dist/components/overlays/confirmPrompt.js +0 -25
  52. package/dist/components/overlays/helpOverlay.js +0 -76
  53. package/dist/components/overlays/historySearch.js +0 -49
  54. package/dist/components/overlays/modelPicker.js +0 -60
  55. package/dist/components/overlays/overlayUtils.js +0 -19
  56. package/dist/components/overlays/secretPrompt.js +0 -36
  57. package/dist/components/overlays/sessionPicker.js +0 -93
  58. package/dist/components/overlays/skillsHub.js +0 -71
  59. package/dist/components/prompts.js +0 -95
  60. package/dist/components/queuedMessages.js +0 -24
  61. package/dist/components/sessionPicker.js +0 -130
  62. package/dist/components/skillsHub.js +0 -165
  63. package/dist/components/streamingAssistant.js +0 -35
  64. package/dist/components/streamingMarkdown.js +0 -144
  65. package/dist/components/textInput.js +0 -794
  66. package/dist/components/themed.js +0 -12
  67. package/dist/components/thinking.js +0 -496
  68. package/dist/components/todoPanel.js +0 -40
  69. package/dist/components/transcript.js +0 -22
  70. package/dist/config/env.js +0 -18
  71. package/dist/config/limits.js +0 -22
  72. package/dist/config/timing.js +0 -18
  73. package/dist/content/charms.js +0 -5
  74. package/dist/content/faces.js +0 -21
  75. package/dist/content/fortunes.js +0 -29
  76. package/dist/content/hotkeys.js +0 -38
  77. package/dist/content/placeholders.js +0 -15
  78. package/dist/content/setup.js +0 -14
  79. package/dist/content/verbs.js +0 -41
  80. package/dist/domain/details.js +0 -53
  81. package/dist/domain/messages.js +0 -63
  82. package/dist/domain/paths.js +0 -16
  83. package/dist/domain/providers.js +0 -11
  84. package/dist/domain/roles.js +0 -6
  85. package/dist/domain/slash.js +0 -11
  86. package/dist/domain/usage.js +0 -1
  87. package/dist/domain/viewport.js +0 -33
  88. package/dist/gateway/client.js +0 -312
  89. package/dist/gatewayClient.js +0 -574
  90. package/dist/gatewayTypes.js +0 -1
  91. package/dist/hooks/useCompletion.js +0 -86
  92. package/dist/hooks/useGitBranch.js +0 -58
  93. package/dist/hooks/useInputHistory.js +0 -12
  94. package/dist/hooks/useQueue.js +0 -57
  95. package/dist/hooks/useVirtualHistory.js +0 -401
  96. package/dist/lib/circularBuffer.js +0 -43
  97. package/dist/lib/clipboard.js +0 -126
  98. package/dist/lib/editor.js +0 -41
  99. package/dist/lib/editor.test.js +0 -58
  100. package/dist/lib/emoji.js +0 -49
  101. package/dist/lib/externalCli.js +0 -11
  102. package/dist/lib/forceTruecolor.js +0 -26
  103. package/dist/lib/fpsStore.js +0 -36
  104. package/dist/lib/gracefulExit.js +0 -29
  105. package/dist/lib/history.js +0 -69
  106. package/dist/lib/inputMetrics.js +0 -143
  107. package/dist/lib/liveProgress.js +0 -51
  108. package/dist/lib/liveProgress.test.js +0 -89
  109. package/dist/lib/mathUnicode.js +0 -685
  110. package/dist/lib/memory.js +0 -123
  111. package/dist/lib/memoryMonitor.js +0 -76
  112. package/dist/lib/messages.js +0 -3
  113. package/dist/lib/messages.test.js +0 -25
  114. package/dist/lib/osc52.js +0 -53
  115. package/dist/lib/perfPane.js +0 -94
  116. package/dist/lib/platform.js +0 -312
  117. package/dist/lib/precisionWheel.js +0 -25
  118. package/dist/lib/reasoning.js +0 -39
  119. package/dist/lib/rpc.js +0 -26
  120. package/dist/lib/subagentTree.js +0 -287
  121. package/dist/lib/syntax.js +0 -89
  122. package/dist/lib/terminalModes.js +0 -46
  123. package/dist/lib/terminalParity.js +0 -48
  124. package/dist/lib/terminalSetup.js +0 -321
  125. package/dist/lib/text.js +0 -203
  126. package/dist/lib/text.test.js +0 -18
  127. package/dist/lib/todo.js +0 -2
  128. package/dist/lib/todo.test.js +0 -22
  129. package/dist/lib/viewportStore.js +0 -82
  130. package/dist/lib/virtualHeights.js +0 -61
  131. package/dist/lib/wheelAccel.js +0 -143
  132. package/dist/theme.js +0 -398
  133. package/dist/types.js +0 -1
@@ -1,71 +0,0 @@
1
- import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
- // @ts-nocheck
3
- // CVC skillsHub overlay — list skills (via gateway or supplied prop), search/filter,
4
- // arrow-key navigable, Enter triggers an onActivate callback (e.g. to inject the
5
- // skill into the next user message).
6
- import { useEffect, useMemo, useState } from 'react';
7
- import { Box, Text, useInput } from 'ink';
8
- import { CVC_THEME } from '../../types.js';
9
- import { filterRows, windowItems } from './overlayUtils.js';
10
- const VISIBLE = 12;
11
- export const SkillsHub = ({ skills, loadSkills, onActivate, onCancel, }) => {
12
- const [all, setAll] = useState(skills ?? []);
13
- const [loading, setLoading] = useState(!skills && Boolean(loadSkills));
14
- const [query, setQuery] = useState('');
15
- const [idx, setIdx] = useState(0);
16
- useEffect(() => {
17
- if (skills || !loadSkills)
18
- return;
19
- let cancelled = false;
20
- loadSkills()
21
- .then(list => {
22
- if (!cancelled) {
23
- setAll(list);
24
- setLoading(false);
25
- }
26
- })
27
- .catch(() => {
28
- if (!cancelled)
29
- setLoading(false);
30
- });
31
- return () => {
32
- cancelled = true;
33
- };
34
- }, [skills, loadSkills]);
35
- const filtered = useMemo(() => filterRows(all, query, s => `${s.name} ${s.description ?? ''} ${s.category ?? ''}`), [all, query]);
36
- const safeIdx = Math.min(idx, Math.max(0, filtered.length - 1));
37
- useInput((input, key) => {
38
- if (key.escape)
39
- return onCancel();
40
- if (key.upArrow && safeIdx > 0)
41
- return setIdx(safeIdx - 1);
42
- if (key.downArrow && safeIdx < filtered.length - 1)
43
- return setIdx(safeIdx + 1);
44
- if (key.return) {
45
- const s = filtered[safeIdx];
46
- if (s)
47
- onActivate(s);
48
- return;
49
- }
50
- if (key.backspace || key.delete) {
51
- setQuery(q => q.slice(0, -1));
52
- setIdx(0);
53
- return;
54
- }
55
- if (input && !key.ctrl && !key.meta && !key.tab) {
56
- setQuery(q => q + input);
57
- setIdx(0);
58
- }
59
- });
60
- const rows = filtered.map(s => {
61
- const cat = s.category ? `[${s.category}] ` : '';
62
- const desc = s.description ? ` — ${s.description}` : '';
63
- return `${cat}${s.name}${desc}`;
64
- });
65
- const { items, offset } = windowItems(rows, safeIdx, VISIBLE);
66
- return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: CVC_THEME.primary, bold: true, children: ["Skills Hub (", filtered.length, "/", all.length, ")"] }), _jsxs(Text, { dimColor: true, children: ["filter: ", query || '(none)'] }), loading ? (_jsx(Text, { dimColor: true, children: "loading skills\u2026" })) : items.length === 0 ? (_jsx(Text, { dimColor: true, children: "no skills match" })) : (_jsxs(_Fragment, { children: [offset > 0 ? _jsx(Text, { dimColor: true, children: ` ↑ ${offset} more` }) : _jsx(Text, { children: " " }), items.map((row, i) => {
67
- const k = offset + i;
68
- const active = safeIdx === k;
69
- return (_jsxs(Text, { color: active ? CVC_THEME.primary : undefined, inverse: active, bold: active, children: [active ? '▸ ' : ' ', row] }, filtered[k]?.name ?? `sk-${k}`));
70
- }), offset + VISIBLE < rows.length ? (_jsx(Text, { dimColor: true, children: ` ↓ ${rows.length - offset - VISIBLE} more` })) : (_jsx(Text, { children: " " }))] })), _jsx(Text, { dimColor: true, children: "type to filter \u00B7 \u2191/\u2193 select \u00B7 Enter activate \u00B7 Esc cancel" })] }));
71
- };
@@ -1,95 +0,0 @@
1
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
- // @ts-nocheck
3
- // SPDX-License-Identifier: MIT
4
- // Ported from CVC Agent (https://github.com/NousResearch/cvc)
5
- // Original Copyright (c) 2025 Nous Research. CVC adaptations (c) 2026 Jai Kumar Meena.
6
- import { Box, Text, useInput } from '@cvc/ink';
7
- import { useState } from 'react';
8
- import { isMac } from '../lib/platform.js';
9
- import { TextInput } from './textInput.js';
10
- const OPTS = ['once', 'session', 'always', 'deny'];
11
- const LABELS = { always: 'Always allow', deny: 'Deny', once: 'Allow once', session: 'Allow this session' };
12
- const CMD_PREVIEW_LINES = 10;
13
- export function ApprovalPrompt({ onChoice, req, t }) {
14
- const [sel, setSel] = useState(0);
15
- useInput((ch, key) => {
16
- if (key.upArrow && sel > 0) {
17
- setSel(s => s - 1);
18
- }
19
- if (key.downArrow && sel < OPTS.length - 1) {
20
- setSel(s => s + 1);
21
- }
22
- const n = parseInt(ch, 10);
23
- if (n >= 1 && n <= OPTS.length) {
24
- onChoice(OPTS[n - 1]);
25
- return;
26
- }
27
- if (key.return) {
28
- onChoice(OPTS[sel]);
29
- }
30
- });
31
- const rawLines = req.command.split('\n');
32
- const shown = rawLines.slice(0, CMD_PREVIEW_LINES);
33
- const overflow = rawLines.length - shown.length;
34
- return (_jsxs(Box, { borderColor: t.color.warn, borderStyle: "double", flexDirection: "column", paddingX: 1, children: [_jsxs(Text, { bold: true, color: t.color.warn, children: ["\u26A0 approval required \u00B7 ", req.description] }), _jsxs(Box, { flexDirection: "column", paddingLeft: 1, children: [shown.map((line, i) => (_jsx(Text, { color: t.color.text, wrap: "truncate-end", children: line || ' ' }, i))), overflow > 0 ? (_jsxs(Text, { color: t.color.muted, children: ["\u2026 +", overflow, " more line", overflow === 1 ? '' : 's', " (full text above)"] })) : null] }), _jsx(Text, {}), OPTS.map((o, i) => (_jsx(Text, { children: _jsxs(Text, { bold: sel === i, color: sel === i ? t.color.warn : t.color.muted, inverse: sel === i, children: [sel === i ? '▸ ' : ' ', i + 1, ". ", LABELS[o]] }) }, o))), _jsx(Text, { color: t.color.muted, children: "\u2191/\u2193 select \u00B7 Enter confirm \u00B7 1-4 quick pick \u00B7 Ctrl+C deny" })] }));
35
- }
36
- export function ClarifyPrompt({ cols = 80, onAnswer, onCancel, req, t }) {
37
- const [sel, setSel] = useState(0);
38
- const [custom, setCustom] = useState('');
39
- const [typing, setTyping] = useState(false);
40
- const choices = req.choices ?? [];
41
- const heading = (_jsxs(Text, { bold: true, children: [_jsx(Text, { color: t.color.accent, children: "ask" }), _jsxs(Text, { color: t.color.text, children: [" ", req.question] })] }));
42
- useInput((ch, key) => {
43
- if (key.escape) {
44
- typing && choices.length ? setTyping(false) : onCancel();
45
- return;
46
- }
47
- if (typing || !choices.length) {
48
- return;
49
- }
50
- if (key.upArrow && sel > 0) {
51
- setSel(s => s - 1);
52
- }
53
- if (key.downArrow && sel < choices.length) {
54
- setSel(s => s + 1);
55
- }
56
- if (key.return) {
57
- sel === choices.length ? setTyping(true) : choices[sel] && onAnswer(choices[sel]);
58
- }
59
- const n = parseInt(ch);
60
- if (n >= 1 && n <= choices.length) {
61
- onAnswer(choices[n - 1]);
62
- }
63
- });
64
- if (typing || !choices.length) {
65
- return (_jsxs(Box, { flexDirection: "column", children: [heading, _jsxs(Box, { children: [_jsx(Text, { color: t.color.label, children: '> ' }), _jsx(TextInput, { columns: Math.max(20, cols - 6), onChange: setCustom, onSubmit: onAnswer, value: custom })] }), _jsxs(Text, { color: t.color.muted, children: ["Enter send \u00B7 Esc ", choices.length ? 'back' : 'cancel', " \u00B7", ' ', isMac ? 'Cmd+C copy · Cmd+V paste · Ctrl+C cancel' : 'Ctrl+C cancel'] })] }));
66
- }
67
- return (_jsxs(Box, { flexDirection: "column", children: [heading, [...choices, 'Other (type your answer)'].map((c, i) => (_jsx(Text, { children: _jsxs(Text, { bold: sel === i, color: sel === i ? t.color.label : t.color.muted, inverse: sel === i, children: [sel === i ? '▸ ' : ' ', i + 1, ". ", c] }) }, i))), _jsxs(Text, { color: t.color.muted, children: ["\u2191/\u2193 select \u00B7 Enter confirm \u00B7 1-", choices.length, " quick pick \u00B7 Esc/Ctrl+C cancel"] })] }));
68
- }
69
- export function ConfirmPrompt({ onCancel, onConfirm, req, t }) {
70
- const [sel, setSel] = useState(0);
71
- useInput((ch, key) => {
72
- const lower = ch.toLowerCase();
73
- if (key.escape || (key.ctrl && lower === 'c') || lower === 'n') {
74
- return onCancel();
75
- }
76
- if (lower === 'y') {
77
- return onConfirm();
78
- }
79
- if (key.upArrow) {
80
- setSel(0);
81
- }
82
- if (key.downArrow) {
83
- setSel(1);
84
- }
85
- if (key.return) {
86
- sel === 0 ? onCancel() : onConfirm();
87
- }
88
- });
89
- const accent = req.danger ? t.color.error : t.color.warn;
90
- const rows = [
91
- { color: t.color.text, label: req.cancelLabel ?? 'No' },
92
- { color: req.danger ? t.color.error : t.color.text, label: req.confirmLabel ?? 'Yes' }
93
- ];
94
- return (_jsxs(Box, { borderColor: accent, borderStyle: "double", flexDirection: "column", paddingX: 1, children: [_jsxs(Text, { bold: true, color: accent, children: [req.danger ? '⚠' : '?', " ", req.title] }), req.detail ? (_jsx(Box, { paddingLeft: 1, children: _jsx(Text, { color: t.color.text, wrap: "truncate-end", children: req.detail }) })) : null, _jsx(Text, {}), rows.map((row, i) => (_jsxs(Text, { children: [_jsx(Text, { color: sel === i ? accent : t.color.muted, children: sel === i ? '▸ ' : ' ' }), _jsx(Text, { color: sel === i ? row.color : t.color.muted, children: row.label })] }, row.label))), _jsx(Text, { color: t.color.muted, children: "\u2191/\u2193 select \u00B7 Enter confirm \u00B7 Y/N quick \u00B7 Esc cancel" })] }));
95
- }
@@ -1,24 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- // @ts-nocheck
3
- // SPDX-License-Identifier: MIT
4
- // Ported from CVC Agent (https://github.com/NousResearch/cvc)
5
- // Original Copyright (c) 2025 Nous Research. CVC adaptations (c) 2026 Jai Kumar Meena.
6
- import { Box, Text } from '@cvc/ink';
7
- import { compactPreview } from '../lib/text.js';
8
- export const QUEUE_WINDOW = 3;
9
- export function getQueueWindow(queueLen, queueEditIdx) {
10
- const start = queueEditIdx === null ? 0 : Math.max(0, Math.min(queueEditIdx - 1, Math.max(0, queueLen - QUEUE_WINDOW)));
11
- const end = Math.min(queueLen, start + QUEUE_WINDOW);
12
- return { end, showLead: start > 0, showTail: end < queueLen, start };
13
- }
14
- export function QueuedMessages({ cols, queueEditIdx, queued, t }) {
15
- if (!queued.length) {
16
- return null;
17
- }
18
- const q = getQueueWindow(queued.length, queueEditIdx);
19
- return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [_jsx(Text, { color: t.color.muted, dimColor: true, children: `queued (${queued.length})${queueEditIdx !== null ? ` · editing ${queueEditIdx + 1} · Ctrl+X delete · Esc cancel` : ''}` }), q.showLead && (_jsxs(Text, { color: t.color.muted, dimColor: true, children: [' ', "\u2026"] })), queued.slice(q.start, q.end).map((item, i) => {
20
- const idx = q.start + i;
21
- const active = queueEditIdx === idx;
22
- return (_jsxs(Text, { color: active ? t.color.accent : t.color.muted, dimColor: true, children: [active ? '▸' : ' ', " ", idx + 1, ". ", compactPreview(item, Math.max(16, cols - 10))] }, `${idx}-${item.slice(0, 16)}`));
23
- }), q.showTail && (_jsxs(Text, { color: t.color.muted, dimColor: true, children: [' ', "\u2026and ", queued.length - q.end, " more"] }))] }));
24
- }
@@ -1,130 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- // @ts-nocheck
3
- // SPDX-License-Identifier: MIT
4
- // Ported from CVC Agent (https://github.com/NousResearch/cvc)
5
- // Original Copyright (c) 2025 Nous Research. CVC adaptations (c) 2026 Jai Kumar Meena.
6
- import { Box, Text, useInput, useStdout } from '@cvc/ink';
7
- import { useEffect, useState } from 'react';
8
- import { asRpcResult, rpcErrorMessage } from '../lib/rpc.js';
9
- import { OverlayHint, useOverlayKeys, windowOffset } from './overlayControls.js';
10
- const VISIBLE = 15;
11
- const MIN_WIDTH = 60;
12
- const MAX_WIDTH = 120;
13
- const age = (ts) => {
14
- const d = (Date.now() / 1000 - ts) / 86400;
15
- if (d < 1) {
16
- return 'today';
17
- }
18
- if (d < 2) {
19
- return 'yesterday';
20
- }
21
- return `${Math.floor(d)}d ago`;
22
- };
23
- export function SessionPicker({ gw, onCancel, onSelect, t }) {
24
- const [items, setItems] = useState([]);
25
- const [err, setErr] = useState('');
26
- const [sel, setSel] = useState(0);
27
- const [loading, setLoading] = useState(true);
28
- // When non-null, the user pressed `d` on this index and we're waiting for
29
- // a second `d`/`D` to confirm deletion. Any other key cancels the prompt.
30
- const [confirmDelete, setConfirmDelete] = useState(null);
31
- const [deleting, setDeleting] = useState(false);
32
- const { stdout } = useStdout();
33
- const width = Math.max(MIN_WIDTH, Math.min(MAX_WIDTH, (stdout?.columns ?? 80) - 6));
34
- useOverlayKeys({ onClose: onCancel });
35
- useEffect(() => {
36
- gw.request('session.list', { limit: 200 })
37
- .then(raw => {
38
- const r = asRpcResult(raw);
39
- if (!r) {
40
- setErr('invalid response: session.list');
41
- setLoading(false);
42
- return;
43
- }
44
- setItems(r.sessions ?? []);
45
- setErr('');
46
- setLoading(false);
47
- })
48
- .catch((e) => {
49
- setErr(rpcErrorMessage(e));
50
- setLoading(false);
51
- });
52
- }, [gw]);
53
- const performDelete = (index) => {
54
- const target = items[index];
55
- if (!target || deleting) {
56
- return;
57
- }
58
- setDeleting(true);
59
- gw.request('session.delete', { session_id: target.id })
60
- .then(raw => {
61
- const r = asRpcResult(raw);
62
- if (!r || r.deleted !== target.id) {
63
- setErr('invalid response: session.delete');
64
- setDeleting(false);
65
- return;
66
- }
67
- setItems(prev => {
68
- const next = prev.filter((_, i) => i !== index);
69
- setSel(s => Math.max(0, Math.min(s, next.length - 1)));
70
- return next;
71
- });
72
- setErr('');
73
- setDeleting(false);
74
- })
75
- .catch((e) => {
76
- setErr(rpcErrorMessage(e));
77
- setDeleting(false);
78
- });
79
- };
80
- useInput((ch, key) => {
81
- if (deleting) {
82
- return;
83
- }
84
- if (confirmDelete !== null) {
85
- if (ch?.toLowerCase() === 'd') {
86
- const idx = confirmDelete;
87
- setConfirmDelete(null);
88
- performDelete(idx);
89
- }
90
- else {
91
- setConfirmDelete(null);
92
- }
93
- return;
94
- }
95
- if (key.upArrow && sel > 0) {
96
- setSel(s => s - 1);
97
- }
98
- if (key.downArrow && sel < items.length - 1) {
99
- setSel(s => s + 1);
100
- }
101
- if (key.return && items[sel]) {
102
- onSelect(items[sel].id);
103
- return;
104
- }
105
- if (ch?.toLowerCase() === 'd' && items[sel]) {
106
- setConfirmDelete(sel);
107
- return;
108
- }
109
- const n = parseInt(ch);
110
- if (n >= 1 && n <= Math.min(9, items.length)) {
111
- onSelect(items[n - 1].id);
112
- }
113
- });
114
- if (loading) {
115
- return _jsx(Text, { color: t.color.muted, children: "loading sessions\u2026" });
116
- }
117
- if (err && !items.length) {
118
- return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { color: t.color.label, children: ["error: ", err] }), _jsx(OverlayHint, { t: t, children: "Esc/q cancel" })] }));
119
- }
120
- if (!items.length) {
121
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: t.color.muted, children: "no previous sessions" }), _jsx(OverlayHint, { t: t, children: "Esc/q cancel" })] }));
122
- }
123
- const offset = windowOffset(items.length, sel, VISIBLE);
124
- return (_jsxs(Box, { flexDirection: "column", width: width, children: [_jsx(Text, { bold: true, color: t.color.accent, children: "Resume Session" }), offset > 0 && _jsxs(Text, { color: t.color.muted, children: [" \u2191 ", offset, " more"] }), items.slice(offset, offset + VISIBLE).map((s, vi) => {
125
- const i = offset + vi;
126
- const selected = sel === i;
127
- const pendingDelete = confirmDelete === i;
128
- return (_jsxs(Box, { children: [_jsx(Text, { bold: selected, color: selected ? t.color.accent : t.color.muted, inverse: selected, children: selected ? '▸ ' : ' ' }), _jsx(Box, { width: 30, children: _jsxs(Text, { bold: selected, color: selected ? t.color.accent : t.color.muted, inverse: selected, children: [String(i + 1).padStart(2), ". [", s.id, "]"] }) }), _jsx(Box, { width: 30, children: _jsxs(Text, { bold: selected, color: selected ? t.color.accent : t.color.muted, inverse: selected, children: ["(", s.message_count, " msgs, ", age(s.started_at), ", ", s.source || 'tui', ")"] }) }), _jsx(Text, { bold: selected, color: pendingDelete ? t.color.label : selected ? t.color.accent : t.color.muted, inverse: selected, wrap: "truncate-end", children: pendingDelete ? 'press d again to delete' : s.title || s.preview || '(untitled)' })] }, s.id));
129
- }), offset + VISIBLE < items.length && _jsxs(Text, { color: t.color.muted, children: [" \u2193 ", items.length - offset - VISIBLE, " more"] }), err && _jsxs(Text, { color: t.color.label, children: ["error: ", err] }), deleting ? (_jsx(OverlayHint, { t: t, children: "deleting\u2026" })) : (_jsx(OverlayHint, { t: t, children: "\u2191/\u2193 select \u00B7 Enter resume \u00B7 1-9 quick \u00B7 d delete \u00B7 Esc/q cancel" }))] }));
130
- }
@@ -1,165 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- // @ts-nocheck
3
- // SPDX-License-Identifier: MIT
4
- // Ported from CVC Agent (https://github.com/NousResearch/cvc)
5
- // Original Copyright (c) 2025 Nous Research. CVC adaptations (c) 2026 Jai Kumar Meena.
6
- import { Box, Text, useInput, useStdout } from '@cvc/ink';
7
- import { useEffect, useState } from 'react';
8
- import { rpcErrorMessage } from '../lib/rpc.js';
9
- import { OverlayHint, useOverlayKeys, windowItems, windowOffset } from './overlayControls.js';
10
- const VISIBLE = 12;
11
- const MIN_WIDTH = 40;
12
- const MAX_WIDTH = 90;
13
- export function SkillsHub({ gw, onClose, t }) {
14
- const [skillsByCat, setSkillsByCat] = useState({});
15
- const [selectedCat, setSelectedCat] = useState('');
16
- const [catIdx, setCatIdx] = useState(0);
17
- const [skillIdx, setSkillIdx] = useState(0);
18
- const [stage, setStage] = useState('category');
19
- const [info, setInfo] = useState(null);
20
- const [installing, setInstalling] = useState(false);
21
- const [err, setErr] = useState('');
22
- const [loading, setLoading] = useState(true);
23
- const { stdout } = useStdout();
24
- const width = Math.max(MIN_WIDTH, Math.min(MAX_WIDTH, (stdout?.columns ?? 80) - 6));
25
- useEffect(() => {
26
- gw.request('skills.manage', { action: 'list' })
27
- .then(r => {
28
- setSkillsByCat(r?.skills ?? {});
29
- setErr('');
30
- setLoading(false);
31
- })
32
- .catch((e) => {
33
- setErr(rpcErrorMessage(e));
34
- setLoading(false);
35
- });
36
- }, [gw]);
37
- const cats = Object.keys(skillsByCat).sort();
38
- const skills = selectedCat ? (skillsByCat[selectedCat] ?? []) : [];
39
- const skillName = skills[skillIdx] ?? '';
40
- const back = () => {
41
- if (stage === 'actions') {
42
- setStage('skill');
43
- setInfo(null);
44
- setErr('');
45
- return;
46
- }
47
- if (stage === 'skill') {
48
- setStage('category');
49
- setSkillIdx(0);
50
- return;
51
- }
52
- onClose();
53
- };
54
- useOverlayKeys({ disabled: installing, onBack: back, onClose });
55
- const inspect = (name) => {
56
- setInfo(null);
57
- setErr('');
58
- gw.request('skills.manage', { action: 'inspect', query: name })
59
- .then(r => setInfo(r?.info ?? { name }))
60
- .catch((e) => setErr(rpcErrorMessage(e)));
61
- };
62
- const install = (name) => {
63
- setInstalling(true);
64
- setErr('');
65
- gw.request('skills.manage', { action: 'install', query: name })
66
- .then(() => onClose())
67
- .catch((e) => setErr(rpcErrorMessage(e)))
68
- .finally(() => setInstalling(false));
69
- };
70
- useInput((ch, key) => {
71
- if (installing) {
72
- return;
73
- }
74
- if (stage === 'actions') {
75
- if (key.return) {
76
- setStage('skill');
77
- setInfo(null);
78
- setErr('');
79
- return;
80
- }
81
- if (ch.toLowerCase() === 'x' && skillName) {
82
- install(skillName);
83
- return;
84
- }
85
- if (ch.toLowerCase() === 'i' && skillName) {
86
- inspect(skillName);
87
- }
88
- return;
89
- }
90
- const count = stage === 'category' ? cats.length : skills.length;
91
- const sel = stage === 'category' ? catIdx : skillIdx;
92
- const setSel = stage === 'category' ? setCatIdx : setSkillIdx;
93
- if (key.upArrow && sel > 0) {
94
- setSel(v => v - 1);
95
- return;
96
- }
97
- if (key.downArrow && sel < count - 1) {
98
- setSel(v => v + 1);
99
- return;
100
- }
101
- if (key.return) {
102
- if (stage === 'category') {
103
- const cat = cats[catIdx];
104
- if (!cat) {
105
- return;
106
- }
107
- setSelectedCat(cat);
108
- setSkillIdx(0);
109
- setStage('skill');
110
- return;
111
- }
112
- const name = skills[skillIdx];
113
- if (name) {
114
- setStage('actions');
115
- inspect(name);
116
- }
117
- return;
118
- }
119
- const n = ch === '0' ? 10 : parseInt(ch, 10);
120
- if (!Number.isNaN(n) && n >= 1 && n <= Math.min(10, count)) {
121
- const next = windowOffset(count, sel, VISIBLE) + n - 1;
122
- if (stage === 'category') {
123
- const cat = cats[next];
124
- if (cat) {
125
- setSelectedCat(cat);
126
- setCatIdx(next);
127
- setSkillIdx(0);
128
- setStage('skill');
129
- }
130
- return;
131
- }
132
- const name = skills[next];
133
- if (name) {
134
- setSkillIdx(next);
135
- setStage('actions');
136
- inspect(name);
137
- }
138
- }
139
- });
140
- if (loading) {
141
- return _jsx(Text, { color: t.color.muted, children: "loading skills\u2026" });
142
- }
143
- if (err && stage === 'category') {
144
- return (_jsxs(Box, { flexDirection: "column", width: width, children: [_jsxs(Text, { color: t.color.label, children: ["error: ", err] }), _jsx(OverlayHint, { t: t, children: "Esc/q cancel" })] }));
145
- }
146
- if (!cats.length) {
147
- return (_jsxs(Box, { flexDirection: "column", width: width, children: [_jsx(Text, { color: t.color.muted, children: "no skills available" }), _jsx(OverlayHint, { t: t, children: "Esc/q cancel" })] }));
148
- }
149
- if (stage === 'category') {
150
- const rows = cats.map(c => `${c} · ${skillsByCat[c]?.length ?? 0} skills`);
151
- const { items, offset } = windowItems(rows, catIdx, VISIBLE);
152
- return (_jsxs(Box, { flexDirection: "column", width: width, children: [_jsx(Text, { bold: true, color: t.color.accent, children: "Skills Hub" }), _jsx(Text, { color: t.color.muted, children: "select a category" }), offset > 0 && _jsxs(Text, { color: t.color.muted, children: [" \u2191 ", offset, " more"] }), items.map((row, i) => {
153
- const idx = offset + i;
154
- return (_jsxs(Text, { bold: catIdx === idx, color: catIdx === idx ? t.color.accent : t.color.muted, inverse: catIdx === idx, wrap: "truncate-end", children: [catIdx === idx ? '▸ ' : ' ', i + 1, ". ", row] }, row));
155
- }), offset + VISIBLE < rows.length && _jsxs(Text, { color: t.color.muted, children: [" \u2193 ", rows.length - offset - VISIBLE, " more"] }), _jsx(OverlayHint, { t: t, children: "\u2191/\u2193 select \u00B7 Enter open \u00B7 1-9,0 quick \u00B7 Esc/q cancel" })] }));
156
- }
157
- if (stage === 'skill') {
158
- const { items, offset } = windowItems(skills, skillIdx, VISIBLE);
159
- return (_jsxs(Box, { flexDirection: "column", width: width, children: [_jsx(Text, { bold: true, color: t.color.accent, children: selectedCat }), _jsxs(Text, { color: t.color.muted, children: [skills.length, " skill(s)"] }), !skills.length ? _jsx(Text, { color: t.color.muted, children: "no skills in this category" }) : null, offset > 0 && _jsxs(Text, { color: t.color.muted, children: [" \u2191 ", offset, " more"] }), items.map((row, i) => {
160
- const idx = offset + i;
161
- return (_jsxs(Text, { bold: skillIdx === idx, color: skillIdx === idx ? t.color.accent : t.color.muted, inverse: skillIdx === idx, wrap: "truncate-end", children: [skillIdx === idx ? '▸ ' : ' ', i + 1, ". ", row] }, row));
162
- }), offset + VISIBLE < skills.length && (_jsxs(Text, { color: t.color.muted, children: [" \u2193 ", skills.length - offset - VISIBLE, " more"] })), _jsx(OverlayHint, { t: t, children: skills.length ? '↑/↓ select · Enter open · 1-9,0 quick · Esc back · q close' : 'Esc back · q close' })] }));
163
- }
164
- return (_jsxs(Box, { flexDirection: "column", width: width, children: [_jsx(Text, { bold: true, color: t.color.accent, children: info?.name ?? skillName }), _jsx(Text, { color: t.color.muted, children: info?.category ?? selectedCat }), info?.description ? _jsx(Text, { color: t.color.text, children: info.description }) : null, info?.path ? _jsxs(Text, { color: t.color.muted, children: ["path: ", info.path] }) : null, !info && !err ? _jsx(Text, { color: t.color.muted, children: "loading\u2026" }) : null, err ? _jsxs(Text, { color: t.color.label, children: ["error: ", err] }) : null, installing ? _jsx(Text, { color: t.color.accent, children: "installing\u2026" }) : null, _jsx(OverlayHint, { t: t, children: "i reinspect \u00B7 x reinstall \u00B7 Enter/Esc back \u00B7 q close" })] }));
165
- }
@@ -1,35 +0,0 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- // @ts-nocheck
3
- // SPDX-License-Identifier: MIT
4
- // Ported from CVC Agent (https://github.com/NousResearch/cvc)
5
- // Original Copyright (c) 2025 Nous Research. CVC adaptations (c) 2026 Jai Kumar Meena.
6
- import { useStore } from '@nanostores/react';
7
- import { memo } from 'react';
8
- import { toggleTodoCollapsed, useTurnSelector } from '../app/turnStore.js';
9
- import { $uiState } from '../app/uiStore.js';
10
- import { appendToolShelfMessage } from '../lib/liveProgress.js';
11
- import { MessageLine } from './messageLine.js';
12
- import { TodoPanel } from './todoPanel.js';
13
- const groupedSegments = (segments) => segments.reduce((acc, msg) => appendToolShelfMessage(acc, msg), []);
14
- export const StreamingAssistant = memo(function StreamingAssistant({ cols, compact, detailsMode, detailsModeCommandOverride, progress, sections }) {
15
- const ui = useStore($uiState);
16
- const streamSegments = useTurnSelector(state => state.streamSegments);
17
- const streamPendingTools = useTurnSelector(state => state.streamPendingTools);
18
- const streaming = useTurnSelector(state => state.streaming);
19
- const activeTools = useTurnSelector(state => state.tools);
20
- const showStreamingArea = Boolean(streaming);
21
- if (!progress.showProgressArea && !showStreamingArea && !activeTools.length) {
22
- return null;
23
- }
24
- return (_jsxs(_Fragment, { children: [groupedSegments(streamSegments).map((msg, i) => (_jsx(MessageLine, { cols: cols, compact: compact, detailsMode: detailsMode, detailsModeCommandOverride: detailsModeCommandOverride, msg: msg, sections: sections, t: ui.theme }, `seg:${i}`))), !!activeTools.length && (_jsx(MessageLine, { cols: cols, compact: compact, detailsMode: detailsMode, detailsModeCommandOverride: detailsModeCommandOverride, msg: { kind: 'trail', role: 'system', text: '' }, sections: sections, t: ui.theme, tools: activeTools })), showStreamingArea && (_jsx(MessageLine, { cols: cols, compact: compact, detailsMode: detailsMode, detailsModeCommandOverride: detailsModeCommandOverride, isStreaming: true, msg: {
25
- role: 'assistant',
26
- text: streaming,
27
- ...(streamPendingTools.length && { tools: streamPendingTools })
28
- }, sections: sections, t: ui.theme })), !showStreamingArea && !!streamPendingTools.length && (_jsx(MessageLine, { cols: cols, compact: compact, detailsMode: detailsMode, detailsModeCommandOverride: detailsModeCommandOverride, msg: { kind: 'trail', role: 'system', text: '', tools: streamPendingTools }, sections: sections, t: ui.theme }))] }));
29
- });
30
- export const LiveTodoPanel = memo(function LiveTodoPanel() {
31
- const ui = useStore($uiState);
32
- const todos = useTurnSelector(state => state.todos);
33
- const collapsed = useTurnSelector(state => state.todoCollapsed);
34
- return _jsx(TodoPanel, { collapsed: collapsed, onToggle: toggleTodoCollapsed, t: ui.theme, todos: todos });
35
- });