cvc-tui 0.4.4 → 0.4.7

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 (142) hide show
  1. package/NOTICES.md +13 -0
  2. package/dist/app/completion.js +102 -0
  3. package/dist/app/createGatewayEventHandler.js +508 -0
  4. package/dist/app/createSlashHandler.js +101 -0
  5. package/dist/app/delegationStore.js +51 -0
  6. package/dist/app/gatewayContext.js +17 -0
  7. package/dist/app/historyStore.js +123 -0
  8. package/dist/app/inputBuffer.js +120 -0
  9. package/dist/app/inputSelectionStore.js +8 -0
  10. package/dist/app/inputStore.js +28 -0
  11. package/dist/app/interfaces.js +6 -0
  12. package/dist/app/overlayStore.js +40 -0
  13. package/dist/app/promptStore.js +44 -0
  14. package/dist/app/queueStore.js +25 -0
  15. package/dist/app/scroll.js +44 -0
  16. package/dist/app/setupHandoff.js +28 -0
  17. package/dist/app/slash/commands/core.js +479 -0
  18. package/dist/app/slash/commands/debug.js +44 -0
  19. package/dist/app/slash/commands/ops.js +512 -0
  20. package/dist/app/slash/commands/session.js +431 -0
  21. package/dist/app/slash/commands/setup.js +20 -0
  22. package/dist/app/slash/commands/toggles.js +40 -0
  23. package/dist/app/slash/registry.js +18 -0
  24. package/dist/app/slash/types.js +1 -0
  25. package/dist/app/spawnHistoryStore.js +105 -0
  26. package/dist/app/turnController.js +650 -0
  27. package/dist/app/turnStore.js +48 -0
  28. package/dist/app/uiStore.js +36 -0
  29. package/dist/app/useComposerState.js +265 -0
  30. package/dist/app/useConfigSync.js +144 -0
  31. package/dist/app/useInputHandlers.js +403 -0
  32. package/dist/app/useLongRunToolCharms.js +50 -0
  33. package/dist/app/useMainApp.js +638 -0
  34. package/dist/app/useSessionLifecycle.js +175 -0
  35. package/dist/app/useSubmission.js +287 -0
  36. package/dist/app.js +15 -0
  37. package/dist/banner.js +63 -0
  38. package/dist/components/agentsOverlay.js +474 -0
  39. package/dist/components/appChrome.js +252 -0
  40. package/dist/components/appLayout.js +122 -0
  41. package/dist/components/appOverlays.js +65 -0
  42. package/dist/components/branding.js +97 -0
  43. package/dist/components/fpsOverlay.js +22 -0
  44. package/dist/components/helpHint.js +21 -0
  45. package/dist/components/markdown.js +501 -0
  46. package/dist/components/maskedPrompt.js +12 -0
  47. package/dist/components/messageLine.js +82 -0
  48. package/dist/components/modelPicker.js +254 -0
  49. package/dist/components/overlayControls.js +30 -0
  50. package/dist/components/overlays/confirmPrompt.js +25 -0
  51. package/dist/components/overlays/helpOverlay.js +76 -0
  52. package/dist/components/overlays/historySearch.js +49 -0
  53. package/dist/components/overlays/modelPicker.js +60 -0
  54. package/dist/components/overlays/overlayUtils.js +19 -0
  55. package/dist/components/overlays/secretPrompt.js +36 -0
  56. package/dist/components/overlays/sessionPicker.js +93 -0
  57. package/dist/components/overlays/skillsHub.js +71 -0
  58. package/dist/components/prompts.js +95 -0
  59. package/dist/components/queuedMessages.js +24 -0
  60. package/dist/components/sessionPicker.js +130 -0
  61. package/dist/components/skillsHub.js +165 -0
  62. package/dist/components/streamingAssistant.js +35 -0
  63. package/dist/components/streamingMarkdown.js +144 -0
  64. package/dist/components/textInput.js +794 -0
  65. package/dist/components/themed.js +12 -0
  66. package/dist/components/thinking.js +496 -0
  67. package/dist/components/todoPanel.js +40 -0
  68. package/dist/components/transcript.js +22 -0
  69. package/dist/config/env.js +18 -0
  70. package/dist/config/limits.js +22 -0
  71. package/dist/config/timing.js +25 -0
  72. package/dist/content/charms.js +5 -0
  73. package/dist/content/faces.js +21 -0
  74. package/dist/content/fortunes.js +29 -0
  75. package/dist/content/hotkeys.js +38 -0
  76. package/dist/content/placeholders.js +15 -0
  77. package/dist/content/setup.js +14 -0
  78. package/dist/content/verbs.js +41 -0
  79. package/dist/domain/details.js +53 -0
  80. package/dist/domain/messages.js +63 -0
  81. package/dist/domain/paths.js +16 -0
  82. package/dist/domain/providers.js +11 -0
  83. package/dist/domain/roles.js +6 -0
  84. package/dist/domain/slash.js +11 -0
  85. package/dist/domain/usage.js +1 -0
  86. package/dist/domain/viewport.js +33 -0
  87. package/dist/entry.js +64 -70236
  88. package/dist/gateway/client.js +312 -0
  89. package/dist/gatewayClient.js +574 -0
  90. package/dist/gatewayTypes.js +1 -0
  91. package/dist/hooks/useCompletion.js +86 -0
  92. package/dist/hooks/useGitBranch.js +58 -0
  93. package/dist/hooks/useInputHistory.js +12 -0
  94. package/dist/hooks/useQueue.js +57 -0
  95. package/dist/hooks/useVirtualHistory.js +401 -0
  96. package/dist/lib/circularBuffer.js +43 -0
  97. package/dist/lib/clipboard.js +126 -0
  98. package/dist/lib/editor.js +41 -0
  99. package/dist/lib/editor.test.js +58 -0
  100. package/dist/lib/emoji.js +49 -0
  101. package/dist/lib/externalCli.js +11 -0
  102. package/dist/lib/forceTruecolor.js +26 -0
  103. package/dist/lib/fpsStore.js +36 -0
  104. package/dist/lib/gracefulExit.js +29 -0
  105. package/dist/lib/history.js +69 -0
  106. package/dist/lib/inputMetrics.js +143 -0
  107. package/dist/lib/liveProgress.js +51 -0
  108. package/dist/lib/liveProgress.test.js +89 -0
  109. package/dist/lib/localSessionInfo.js +116 -0
  110. package/dist/lib/mathUnicode.js +685 -0
  111. package/dist/lib/memory.js +123 -0
  112. package/dist/lib/memoryMonitor.js +76 -0
  113. package/dist/lib/messages.js +3 -0
  114. package/dist/lib/messages.test.js +25 -0
  115. package/dist/lib/osc52.js +53 -0
  116. package/dist/lib/perfPane.js +94 -0
  117. package/dist/lib/platform.js +312 -0
  118. package/dist/lib/precisionWheel.js +25 -0
  119. package/dist/lib/react-devtools-stub.js +12 -0
  120. package/dist/lib/reasoning.js +39 -0
  121. package/dist/lib/rpc.js +26 -0
  122. package/dist/lib/subagentTree.js +287 -0
  123. package/dist/lib/syntax.js +89 -0
  124. package/dist/lib/terminalModes.js +46 -0
  125. package/dist/lib/terminalParity.js +48 -0
  126. package/dist/lib/terminalSetup.js +321 -0
  127. package/dist/lib/text.js +203 -0
  128. package/dist/lib/text.test.js +18 -0
  129. package/dist/lib/todo.js +2 -0
  130. package/dist/lib/todo.test.js +22 -0
  131. package/dist/lib/viewportStore.js +82 -0
  132. package/dist/lib/virtualHeights.js +61 -0
  133. package/dist/lib/wheelAccel.js +143 -0
  134. package/dist/protocol/interpolation.js +4 -0
  135. package/dist/protocol/paste.js +3 -0
  136. package/dist/theme.js +398 -0
  137. package/dist/types.js +1 -0
  138. package/dist/vendor/cvc-ink/dist/entry-exports.js +52737 -0
  139. package/dist/vendor/cvc-ink/index.js +1 -0
  140. package/dist/vendor/cvc-ink/package.json +9 -0
  141. package/dist/vendor/cvc-ink/text-input.js +1 -0
  142. package/package.json +9 -9
@@ -0,0 +1,89 @@
1
+ // @ts-nocheck
2
+ // SPDX-License-Identifier: MIT
3
+ // Ported from CVC Agent (https://github.com/NousResearch/cvc)
4
+ // Original Copyright (c) 2025 Nous Research. CVC adaptations (c) 2026 Jai Kumar Meena.
5
+ import { describe, expect, it } from 'vitest';
6
+ import { appendToolShelfMessage, canHoldToolShelf, isTodoDone, mergeToolShelfInto } from './liveProgress.js';
7
+ describe('isTodoDone', () => {
8
+ it('only treats non-empty all-completed/cancelled lists as done', () => {
9
+ expect(isTodoDone([])).toBe(false);
10
+ expect(isTodoDone([{ content: 'x', id: 'x', status: 'completed' }])).toBe(true);
11
+ expect(isTodoDone([{ content: 'x', id: 'x', status: 'in_progress' }])).toBe(false);
12
+ expect(isTodoDone([
13
+ { content: 'x', id: 'x', status: 'completed' },
14
+ { content: 'y', id: 'y', status: 'cancelled' }
15
+ ])).toBe(true);
16
+ });
17
+ });
18
+ describe('tool shelf helpers', () => {
19
+ it('recognizes contextual thinking shelves as holders', () => {
20
+ expect(canHoldToolShelf({ kind: 'trail', role: 'system', text: '', thinking: 'plan' })).toBe(true);
21
+ expect(canHoldToolShelf({ kind: 'trail', role: 'system', text: '', tools: ['one ✓'] })).toBe(true);
22
+ expect(canHoldToolShelf({ role: 'assistant', text: 'done' })).toBe(false);
23
+ });
24
+ it('merges source rows into an existing shelf', () => {
25
+ expect(mergeToolShelfInto({ kind: 'trail', role: 'system', text: '', thinking: 'plan', tools: ['one ✓'] }, { kind: 'trail', role: 'system', text: '', tools: ['two ✓'] })).toEqual({ kind: 'trail', role: 'system', text: '', thinking: 'plan', tools: ['one ✓', 'two ✓'] });
26
+ });
27
+ });
28
+ describe('appendToolShelfMessage', () => {
29
+ it('merges adjacent tool shelves into one contextual shelf', () => {
30
+ const merged = appendToolShelfMessage([{ kind: 'trail', role: 'system', text: '', tools: ['one ✓'] }], {
31
+ kind: 'trail',
32
+ role: 'system',
33
+ text: '',
34
+ tools: ['two ✓']
35
+ });
36
+ expect(merged).toEqual([{ kind: 'trail', role: 'system', text: '', tools: ['one ✓', 'two ✓'] }]);
37
+ });
38
+ it('adds tools to the nearest contextual thinking shelf', () => {
39
+ const merged = appendToolShelfMessage([{ kind: 'trail', role: 'system', text: '', thinking: 'plan', tools: ['one ✓'] }], { kind: 'trail', role: 'system', text: '', tools: ['two ✓'] });
40
+ expect(merged).toEqual([{ kind: 'trail', role: 'system', text: '', thinking: 'plan', tools: ['one ✓', 'two ✓'] }]);
41
+ });
42
+ it('merges through intervening thinking-only rows back into the nearest holder', () => {
43
+ const prev = [
44
+ { kind: 'trail', role: 'system', text: '', thinking: 'plan', tools: ['one ✓'] },
45
+ { kind: 'trail', role: 'system', text: '', thinking: 'more plan' }
46
+ ];
47
+ const merged = appendToolShelfMessage(prev, {
48
+ kind: 'trail',
49
+ role: 'system',
50
+ text: '',
51
+ tools: ['two ✓']
52
+ });
53
+ expect(merged).toHaveLength(2);
54
+ expect(merged[0]).toEqual({
55
+ kind: 'trail',
56
+ role: 'system',
57
+ text: '',
58
+ thinking: 'plan',
59
+ tools: ['one ✓', 'two ✓']
60
+ });
61
+ expect(merged[1]).toEqual({ kind: 'trail', role: 'system', text: '', thinking: 'more plan' });
62
+ });
63
+ it('collapses a chronological thinking/tool/thinking/tool stream into one shelf', () => {
64
+ const events = [
65
+ { kind: 'trail', role: 'system', text: '', thinking: 'plan' },
66
+ { kind: 'trail', role: 'system', text: '', tools: ['one ✓'] },
67
+ { kind: 'trail', role: 'system', text: '', thinking: 'more plan' },
68
+ { kind: 'trail', role: 'system', text: '', tools: ['two ✓'] },
69
+ { kind: 'trail', role: 'system', text: '', tools: ['three ✓'] }
70
+ ];
71
+ const reduced = events.reduce((acc, msg) => appendToolShelfMessage(acc, msg), []);
72
+ expect(reduced).toHaveLength(2);
73
+ expect(reduced[0]).toEqual({
74
+ kind: 'trail',
75
+ role: 'system',
76
+ text: '',
77
+ thinking: 'plan',
78
+ tools: ['one ✓', 'two ✓', 'three ✓']
79
+ });
80
+ expect(reduced[1]).toEqual({ kind: 'trail', role: 'system', text: '', thinking: 'more plan' });
81
+ });
82
+ it('starts a new shelf across assistant text boundaries', () => {
83
+ const merged = appendToolShelfMessage([
84
+ { kind: 'trail', role: 'system', text: '', tools: ['one ✓'] },
85
+ { role: 'assistant', text: 'done' }
86
+ ], { kind: 'trail', role: 'system', text: '', tools: ['two ✓'] });
87
+ expect(merged).toHaveLength(3);
88
+ });
89
+ });
@@ -0,0 +1,116 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // Builds an offline SessionInfo from local config + filesystem so the TUI
3
+ // welcome screen renders rich content even when the gateway is down.
4
+ //
5
+ // The gateway's session.info RPC is the ideal source of truth (it knows the
6
+ // active model, full skill registry, MCP statuses, etc.). When it isn't
7
+ // reachable we degrade gracefully instead of showing a wasteland.
8
+ import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
9
+ import { homedir } from 'node:os';
10
+ import { join } from 'node:path';
11
+ const SAFE_TOOL_DIRS = new Set(['__pycache__']);
12
+ function readYamlMinimal(path) {
13
+ // Tiny single-level YAML reader — enough for `key: value` lines.
14
+ // We deliberately avoid pulling in `js-yaml` here; the welcome screen
15
+ // is rendered before any heavy deps load.
16
+ try {
17
+ const raw = readFileSync(path, 'utf-8');
18
+ const out = {};
19
+ for (const line of raw.split('\n')) {
20
+ const m = line.match(/^([a-z_]+):\s*(.+?)\s*$/i);
21
+ if (!m)
22
+ continue;
23
+ const [, k, v] = m;
24
+ const cleaned = v.replace(/^['"]|['"]$/g, '');
25
+ out[k] = cleaned;
26
+ }
27
+ return out;
28
+ }
29
+ catch {
30
+ return {};
31
+ }
32
+ }
33
+ function listDirs(path) {
34
+ try {
35
+ return readdirSync(path)
36
+ .filter(name => !name.startsWith('.') && !SAFE_TOOL_DIRS.has(name))
37
+ .filter(name => {
38
+ try {
39
+ return statSync(join(path, name)).isDirectory();
40
+ }
41
+ catch {
42
+ return false;
43
+ }
44
+ })
45
+ .sort();
46
+ }
47
+ catch {
48
+ return [];
49
+ }
50
+ }
51
+ function listToolFiles(path) {
52
+ try {
53
+ return readdirSync(path)
54
+ .filter(name => name.endsWith('.py') && !name.startsWith('_'))
55
+ .map(name => name.slice(0, -3))
56
+ .sort();
57
+ }
58
+ catch {
59
+ return [];
60
+ }
61
+ }
62
+ function findCvcSitePackages() {
63
+ // Prefer uv-tool install layout, then a couple of common fallbacks.
64
+ const candidates = [
65
+ join(homedir(), '.local/share/uv/tools/tm-ai/lib/python3.12/site-packages/cvc'),
66
+ join(homedir(), '.local/share/uv/tools/tm-ai/lib/python3.13/site-packages/cvc'),
67
+ join(homedir(), '.local/share/uv/tools/tm-ai/lib/python3.11/site-packages/cvc'),
68
+ ];
69
+ for (const c of candidates) {
70
+ if (existsSync(c))
71
+ return c;
72
+ }
73
+ return null;
74
+ }
75
+ function readCvcVersion() {
76
+ // CVC_VERSION is set by the Python launcher (cvc/cli/agent.py).
77
+ const envV = process.env.CVC_VERSION;
78
+ if (envV)
79
+ return envV;
80
+ return '0.0.0+unknown';
81
+ }
82
+ export function buildLocalSessionInfo() {
83
+ const configDir = process.env.CVC_CONFIG_DIR || join(homedir(), '.cvc');
84
+ const cfg = readYamlMinimal(join(configDir, 'config.yaml'));
85
+ const sitePkg = findCvcSitePackages();
86
+ const tools = {};
87
+ const skills = {};
88
+ if (sitePkg) {
89
+ // Top-level tool modules grouped under `core`
90
+ const coreTools = listToolFiles(join(sitePkg, 'tools'));
91
+ if (coreTools.length)
92
+ tools.core = coreTools;
93
+ // Tool subdirectories (browser, file_ops, web, messaging, media, skills)
94
+ for (const sub of listDirs(join(sitePkg, 'tools'))) {
95
+ const items = listToolFiles(join(sitePkg, 'tools', sub));
96
+ if (items.length)
97
+ tools[sub] = items;
98
+ }
99
+ // Bundled skills — each subdir is a skill name; group under `bundled`.
100
+ const bundled = listDirs(join(sitePkg, 'bundled_skills'));
101
+ if (bundled.length)
102
+ skills.bundled = bundled;
103
+ }
104
+ return {
105
+ cwd: process.cwd(),
106
+ lazy: false,
107
+ mcp_servers: [],
108
+ model: cfg.default_model
109
+ ? `${cfg.primary_provider ?? 'local'}/${cfg.default_model}`
110
+ : 'unknown/offline',
111
+ skills,
112
+ tools,
113
+ update_command: 'cvc update',
114
+ version: readCvcVersion(),
115
+ };
116
+ }