cmdr-agent 2.5.0 → 2.5.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.
- package/dist/bin/cmdr.js +117 -27
- package/dist/bin/cmdr.js.map +1 -1
- package/dist/package.json +9 -4
- package/dist/src/cli/ink/App.d.ts +2 -2
- package/dist/src/cli/ink/App.d.ts.map +1 -1
- package/dist/src/cli/ink/App.js +118 -65
- package/dist/src/cli/ink/App.js.map +1 -1
- package/dist/src/cli/ink/PromptInput.d.ts +17 -0
- package/dist/src/cli/ink/PromptInput.d.ts.map +1 -0
- package/dist/src/cli/ink/PromptInput.js +202 -0
- package/dist/src/cli/ink/PromptInput.js.map +1 -0
- package/dist/src/cli/ink/StatusBar.d.ts +1 -1
- package/dist/src/cli/ink/StatusBar.d.ts.map +1 -1
- package/dist/src/cli/ink/StatusBar.js +116 -21
- package/dist/src/cli/ink/StatusBar.js.map +1 -1
- package/dist/src/cli/ink/input-buffer.d.ts +34 -0
- package/dist/src/cli/ink/input-buffer.d.ts.map +1 -0
- package/dist/src/cli/ink/input-buffer.js +152 -0
- package/dist/src/cli/ink/input-buffer.js.map +1 -0
- package/dist/src/cli/progress.d.ts +6 -5
- package/dist/src/cli/progress.d.ts.map +1 -1
- package/dist/src/cli/progress.js +10 -17
- package/dist/src/cli/progress.js.map +1 -1
- package/dist/src/cli/renderer.d.ts +14 -3
- package/dist/src/cli/renderer.d.ts.map +1 -1
- package/dist/src/cli/renderer.js +93 -32
- package/dist/src/cli/renderer.js.map +1 -1
- package/dist/src/cli/repl.d.ts.map +1 -1
- package/dist/src/cli/repl.js +46 -28
- package/dist/src/cli/repl.js.map +1 -1
- package/dist/src/cli/spinner.d.ts +2 -1
- package/dist/src/cli/spinner.d.ts.map +1 -1
- package/dist/src/cli/spinner.js +16 -1
- package/dist/src/cli/spinner.js.map +1 -1
- package/dist/src/cli/theme.d.ts +14 -12
- package/dist/src/cli/theme.d.ts.map +1 -1
- package/dist/src/cli/theme.js +192 -123
- package/dist/src/cli/theme.js.map +1 -1
- package/dist/src/cli/themes.d.ts +17 -1
- package/dist/src/cli/themes.d.ts.map +1 -1
- package/dist/src/cli/themes.js +125 -27
- package/dist/src/cli/themes.js.map +1 -1
- package/dist/src/core/presets.d.ts.map +1 -1
- package/dist/src/core/presets.js +1 -0
- package/dist/src/core/presets.js.map +1 -1
- package/dist/src/tools/built-in/index.d.ts +2 -1
- package/dist/src/tools/built-in/index.d.ts.map +1 -1
- package/dist/src/tools/built-in/index.js +3 -1
- package/dist/src/tools/built-in/index.js.map +1 -1
- package/dist/src/tools/built-in/pdf-report.d.ts +39 -0
- package/dist/src/tools/built-in/pdf-report.d.ts.map +1 -0
- package/dist/src/tools/built-in/pdf-report.js +326 -0
- package/dist/src/tools/built-in/pdf-report.js.map +1 -0
- package/package.json +9 -4
package/dist/bin/cmdr.js
CHANGED
|
@@ -7,43 +7,133 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { parseArgs, printHelp } from '../src/cli/args.js';
|
|
9
9
|
import { startRepl } from '../src/cli/repl.js';
|
|
10
|
-
import { GREEN, PURPLE, DIM, renderError,
|
|
10
|
+
import { GREEN, PURPLE, DIM, renderError, CYAN } from '../src/cli/theme.js';
|
|
11
11
|
import { OllamaAdapter } from '../src/llm/ollama.js';
|
|
12
12
|
import { checkForUpdate } from '../src/cli/update-checker.js';
|
|
13
13
|
import * as readline from 'readline';
|
|
14
|
+
import chalk from 'chalk';
|
|
14
15
|
import { createRequire } from 'module';
|
|
15
16
|
const require = createRequire(import.meta.url);
|
|
16
|
-
const { version: VERSION } = require('
|
|
17
|
+
const { version: VERSION } = require('../../package.json');
|
|
18
|
+
function isRecommendedModel(modelName) {
|
|
19
|
+
const name = modelName.toLowerCase();
|
|
20
|
+
return name.includes('coder') || name.includes('code') || name.includes('deepseek');
|
|
21
|
+
}
|
|
22
|
+
function defaultModelIndex(models) {
|
|
23
|
+
const recommended = models.findIndex(isRecommendedModel);
|
|
24
|
+
return recommended >= 0 ? recommended : 0;
|
|
25
|
+
}
|
|
17
26
|
/** Prompt user to pick a model from the list. */
|
|
18
27
|
function promptModelSelection(models) {
|
|
28
|
+
const fallbackIndex = defaultModelIndex(models);
|
|
29
|
+
if (!process.stdin.isTTY ||
|
|
30
|
+
!process.stdout.isTTY ||
|
|
31
|
+
typeof process.stdin.setRawMode !== 'function') {
|
|
32
|
+
console.log(` ${DIM('Non-interactive terminal detected, using:')} ${GREEN(models[fallbackIndex])}`);
|
|
33
|
+
return Promise.resolve(models[fallbackIndex]);
|
|
34
|
+
}
|
|
19
35
|
return new Promise((resolve) => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
const stdin = process.stdin;
|
|
37
|
+
const stdout = process.stdout;
|
|
38
|
+
const wasRaw = Boolean(stdin.isRaw);
|
|
39
|
+
let selected = fallbackIndex;
|
|
40
|
+
let renderedLines = 0;
|
|
41
|
+
const clearRendered = () => {
|
|
42
|
+
if (renderedLines <= 0)
|
|
43
|
+
return;
|
|
44
|
+
readline.moveCursor(stdout, 0, -renderedLines);
|
|
45
|
+
readline.clearScreenDown(stdout);
|
|
46
|
+
renderedLines = 0;
|
|
47
|
+
};
|
|
48
|
+
const renderMenu = () => {
|
|
49
|
+
clearRendered();
|
|
50
|
+
const menuWidth = process.stdout.columns || 80;
|
|
51
|
+
const maxModelWidth = Math.max(14, menuWidth - 24);
|
|
52
|
+
const compact = (value) => {
|
|
53
|
+
if (value.length <= maxModelWidth)
|
|
54
|
+
return value;
|
|
55
|
+
return `${value.slice(0, Math.max(1, maxModelWidth - 3))}...`;
|
|
56
|
+
};
|
|
57
|
+
const lines = [
|
|
58
|
+
'',
|
|
59
|
+
` ${PURPLE.bold('Model Matrix')}`,
|
|
60
|
+
` ${DIM('Use ↑/↓ to target, Enter to initialize')}`,
|
|
61
|
+
'',
|
|
62
|
+
];
|
|
63
|
+
for (let i = 0; i < models.length; i++) {
|
|
64
|
+
const isActive = i === selected;
|
|
65
|
+
const isRecommended = isRecommendedModel(models[i]);
|
|
66
|
+
const pointer = isActive ? CYAN.bold('▶') : DIM('·');
|
|
67
|
+
const ordinal = DIM(`${String(i + 1).padStart(2, ' ')}.`);
|
|
68
|
+
const modelName = compact(models[i]);
|
|
69
|
+
const modelLabel = isActive
|
|
70
|
+
? chalk.bgHex('#11303A').hex('#B7FFE3').bold(` ${modelName} `)
|
|
71
|
+
: DIM(modelName);
|
|
72
|
+
const recommendation = isRecommended
|
|
73
|
+
? isActive
|
|
74
|
+
? ` ${GREEN('●')} ${DIM('recommended')}`
|
|
75
|
+
: ` ${DIM('· recommended')}`
|
|
76
|
+
: '';
|
|
77
|
+
lines.push(` ${pointer} ${ordinal} ${modelLabel}${recommendation}`);
|
|
40
78
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
79
|
+
lines.push('');
|
|
80
|
+
lines.push(` ${DIM('Esc picks default:')} ${GREEN(models[fallbackIndex])}`);
|
|
81
|
+
stdout.write(lines.join('\n'));
|
|
82
|
+
renderedLines = lines.length;
|
|
83
|
+
};
|
|
84
|
+
const cleanup = () => {
|
|
85
|
+
stdin.off('keypress', onKeypress);
|
|
86
|
+
if (typeof stdin.setRawMode === 'function') {
|
|
87
|
+
stdin.setRawMode(wasRaw);
|
|
45
88
|
}
|
|
46
|
-
|
|
89
|
+
stdin.pause();
|
|
90
|
+
stdout.write('\x1B[?25h');
|
|
91
|
+
};
|
|
92
|
+
const finish = (chosenModel, statusLine) => {
|
|
93
|
+
cleanup();
|
|
94
|
+
clearRendered();
|
|
95
|
+
console.log(statusLine);
|
|
96
|
+
resolve(chosenModel);
|
|
97
|
+
};
|
|
98
|
+
const onKeypress = (input, key) => {
|
|
99
|
+
if (key.ctrl && key.name === 'c') {
|
|
100
|
+
cleanup();
|
|
101
|
+
clearRendered();
|
|
102
|
+
stdout.write('\n');
|
|
103
|
+
process.exit(130);
|
|
104
|
+
}
|
|
105
|
+
if (key.name === 'up') {
|
|
106
|
+
selected = (selected - 1 + models.length) % models.length;
|
|
107
|
+
renderMenu();
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (key.name === 'down') {
|
|
111
|
+
selected = (selected + 1) % models.length;
|
|
112
|
+
renderMenu();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
if (key.name === 'return') {
|
|
116
|
+
finish(models[selected], ` ${DIM('Selected model:')} ${GREEN(models[selected])}`);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (key.name === 'escape') {
|
|
120
|
+
finish(models[fallbackIndex], ` ${DIM('Using default model:')} ${GREEN(models[fallbackIndex])}`);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (input && /^\d$/.test(input)) {
|
|
124
|
+
const idx = parseInt(input, 10) - 1;
|
|
125
|
+
if (idx >= 0 && idx < models.length) {
|
|
126
|
+
selected = idx;
|
|
127
|
+
renderMenu();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
readline.emitKeypressEvents(stdin);
|
|
132
|
+
stdin.setRawMode?.(true);
|
|
133
|
+
stdin.resume();
|
|
134
|
+
stdout.write('\x1B[?25l');
|
|
135
|
+
stdin.on('keypress', onKeypress);
|
|
136
|
+
renderMenu();
|
|
47
137
|
});
|
|
48
138
|
}
|
|
49
139
|
async function main() {
|
package/dist/bin/cmdr.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cmdr.js","sourceRoot":"","sources":["../../bin/cmdr.ts"],"names":[],"mappings":";AAEA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"cmdr.js","sourceRoot":"","sources":["../../bin/cmdr.ts"],"names":[],"mappings":"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"}
|
package/dist/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cmdr-agent",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.2",
|
|
4
4
|
"description": "Open-source multi-agent coding tool for your terminal. Powered by Ollama.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -34,18 +34,23 @@
|
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"chalk": "^5.3.0",
|
|
37
|
-
"
|
|
37
|
+
"highlight.js": "^11.11.1",
|
|
38
|
+
"ink": "npm:@jrichman/ink@6.6.7",
|
|
39
|
+
"ink-spinner": "^5.0.0",
|
|
38
40
|
"ink-text-input": "^6.0.0",
|
|
41
|
+
"lowlight": "^3.3.0",
|
|
39
42
|
"marked": "^14.0.0",
|
|
40
43
|
"marked-terminal": "^7.2.0",
|
|
41
44
|
"ora": "^8.0.0",
|
|
42
|
-
"react": "^
|
|
45
|
+
"react": "^19.2.0",
|
|
43
46
|
"smol-toml": "^1.6.1",
|
|
47
|
+
"string-width": "^8.1.0",
|
|
48
|
+
"strip-ansi": "^7.1.0",
|
|
44
49
|
"zod": "^3.23.0"
|
|
45
50
|
},
|
|
46
51
|
"devDependencies": {
|
|
47
52
|
"@types/node": "^22.0.0",
|
|
48
|
-
"@types/react": "^
|
|
53
|
+
"@types/react": "^19.2.2",
|
|
49
54
|
"tsx": "^4.21.0",
|
|
50
55
|
"typescript": "^5.6.0",
|
|
51
56
|
"vitest": "^2.1.0"
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Ink-based REPL application — replaces raw readline.
|
|
3
3
|
*
|
|
4
4
|
* Architecture:
|
|
5
|
-
* -
|
|
6
|
-
* - Dynamic section: active spinner
|
|
5
|
+
* - Windowed transcript viewport for bounded scrollback rendering
|
|
6
|
+
* - Dynamic section: active spinner, approval prompts, and input composer
|
|
7
7
|
* - State machine: idle | processing | waiting_approval | exiting
|
|
8
8
|
*/
|
|
9
9
|
import React from 'react';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../../../src/cli/ink/App.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../../../src/cli/ink/App.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAA4D,MAAM,OAAO,CAAA;AAGhF,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AACtE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAA;AAClE,OAAO,KAAK,EAAE,UAAU,EAAkE,UAAU,EAAE,MAAM,qBAAqB,CAAA;AACjI,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAI9D,OAAO,EACsD,cAAc,EAC1E,MAAM,sCAAsC,CAAA;AAE7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAChE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iCAAiC,CAAA;AACpE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,6BAA6B,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAA;AAqEvE,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,KAAK,CAAA;IACZ,OAAO,EAAE,cAAc,CAAA;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,iBAAiB,EAAE,iBAAiB,CAAA;IACpC,OAAO,EAAE,UAAU,CAAA;IACnB,YAAY,EAAE,YAAY,CAAA;IAC1B,gBAAgB,CAAC,EAAE,UAAU,CAAA;IAC7B,WAAW,EAAE,WAAW,CAAA;IACxB,WAAW,EAAE,WAAW,CAAA;IACxB,aAAa,EAAE,aAAa,CAAA;IAC5B,SAAS,EAAE,SAAS,CAAA;IACpB,YAAY,EAAE,YAAY,CAAA;IAC1B,aAAa,EAAE,aAAa,CAAA;IAC5B,aAAa,EAAE,aAAa,CAAA;IAC5B,aAAa,EAAE,aAAa,CAAA;IAC5B,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3B,SAAS,EAAE,cAAc,CAAA;IACzB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAoED,MAAM,CAAC,OAAO,UAAU,GAAG,CAAC,KAAK,EAAE,WAAW,GAAG,KAAK,CAAC,YAAY,CAyjClE"}
|
package/dist/src/cli/ink/App.js
CHANGED
|
@@ -3,12 +3,12 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
* Ink-based REPL application — replaces raw readline.
|
|
4
4
|
*
|
|
5
5
|
* Architecture:
|
|
6
|
-
* -
|
|
7
|
-
* - Dynamic section: active spinner
|
|
6
|
+
* - Windowed transcript viewport for bounded scrollback rendering
|
|
7
|
+
* - Dynamic section: active spinner, approval prompts, and input composer
|
|
8
8
|
* - State machine: idle | processing | waiting_approval | exiting
|
|
9
9
|
*/
|
|
10
|
-
import { useState, useCallback, useEffect, useRef } from 'react';
|
|
11
|
-
import { Box, Text,
|
|
10
|
+
import { useState, useCallback, useEffect, useMemo, useRef } from 'react';
|
|
11
|
+
import { Box, Text, useApp, useInput } from 'ink';
|
|
12
12
|
import TextInput from 'ink-text-input';
|
|
13
13
|
import { getDefaultContextLength } from '../../llm/model-registry.js';
|
|
14
14
|
import { isSlashCommand, parseSlashCommand, getCommand } from '../commands.js';
|
|
@@ -16,20 +16,11 @@ import { saveSession, loadSession, } from '../../session/session-persistence.js'
|
|
|
16
16
|
import { getTeamPreset } from '../../core/presets.js';
|
|
17
17
|
import { listAvailableServers, getServerDefinition, toMcpConfig, getMissingEnvVars } from '../../config/mcp-registry.js';
|
|
18
18
|
import StatusBar from './StatusBar.js';
|
|
19
|
-
|
|
20
|
-
import
|
|
21
|
-
|
|
22
|
-
const GREEN_DIM = chalk.hex('#00BB30');
|
|
23
|
-
const PURPLE = chalk.hex('#BF40FF');
|
|
24
|
-
const CYAN = chalk.hex('#00FFFF');
|
|
25
|
-
const DIM = chalk.hex('#555555');
|
|
26
|
-
const WHITE = chalk.hex('#E0E0E0');
|
|
27
|
-
const YELLOW = chalk.hex('#FFD700');
|
|
28
|
-
const RED = chalk.hex('#FF3333');
|
|
19
|
+
import PromptInput from './PromptInput.js';
|
|
20
|
+
import { StreamingMarkdownRenderer } from '../renderer.js';
|
|
21
|
+
import { GREEN, PURPLE, CYAN, DIM, WHITE, YELLOW, RED, SEPARATOR, } from '../theme.js';
|
|
29
22
|
const SUCCESS_SYM = GREEN('✓');
|
|
30
23
|
const ERROR_SYM = RED('✗');
|
|
31
|
-
const TOOL_SYM = CYAN('⚡');
|
|
32
|
-
const SEPARATOR = GREEN_DIM('─'.repeat(60));
|
|
33
24
|
// ---------------------------------------------------------------------------
|
|
34
25
|
// Verb pool for spinner
|
|
35
26
|
// ---------------------------------------------------------------------------
|
|
@@ -57,6 +48,7 @@ function toPastTense(verb) {
|
|
|
57
48
|
}
|
|
58
49
|
return stem + 'ed';
|
|
59
50
|
}
|
|
51
|
+
const MAX_OUTPUT_LINES = 6000;
|
|
60
52
|
// ---------------------------------------------------------------------------
|
|
61
53
|
// Tool result summary
|
|
62
54
|
// ---------------------------------------------------------------------------
|
|
@@ -116,8 +108,8 @@ export default function App(props) {
|
|
|
116
108
|
const { agent, session, permissionManager, adapter, orchestrator, costTracker, undoManager, pluginManager, mcpClient, toolRegistry, agentRegistry, commandLoader, taskScheduler, ollamaUrl, verbose, doSave, autoSaver, } = props;
|
|
117
109
|
const { exit } = useApp();
|
|
118
110
|
const [state, setState] = useState('idle');
|
|
119
|
-
const [inputValue, setInputValue] = useState('');
|
|
120
111
|
const [outputLines, setOutputLines] = useState([]);
|
|
112
|
+
const [historyScrollOffset, setHistoryScrollOffset] = useState(0);
|
|
121
113
|
const [spinnerText, setSpinnerText] = useState('');
|
|
122
114
|
const [approval, setApproval] = useState(null);
|
|
123
115
|
const [approvalInput, setApprovalInput] = useState('');
|
|
@@ -137,42 +129,73 @@ export default function App(props) {
|
|
|
137
129
|
}, [state]);
|
|
138
130
|
// Append output to scrollback
|
|
139
131
|
const appendOutput = useCallback((text) => {
|
|
140
|
-
|
|
132
|
+
setHistoryScrollOffset(0);
|
|
133
|
+
setOutputLines(prev => {
|
|
134
|
+
const next = [...prev, { id: nextId(), text }];
|
|
135
|
+
return next.length > MAX_OUTPUT_LINES ? next.slice(next.length - MAX_OUTPUT_LINES) : next;
|
|
136
|
+
});
|
|
141
137
|
}, []);
|
|
142
138
|
// Append multiple lines at once
|
|
143
139
|
const appendLines = useCallback((lines) => {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
140
|
+
if (lines.length === 0)
|
|
141
|
+
return;
|
|
142
|
+
setHistoryScrollOffset(0);
|
|
143
|
+
setOutputLines(prev => {
|
|
144
|
+
const next = [
|
|
145
|
+
...prev,
|
|
146
|
+
...lines.map(text => ({ id: nextId(), text })),
|
|
147
|
+
];
|
|
148
|
+
return next.length > MAX_OUTPUT_LINES ? next.slice(next.length - MAX_OUTPUT_LINES) : next;
|
|
149
|
+
});
|
|
148
150
|
}, []);
|
|
151
|
+
const appendRenderedMarkdown = useCallback((rendered) => {
|
|
152
|
+
if (!rendered)
|
|
153
|
+
return;
|
|
154
|
+
const prefixed = rendered
|
|
155
|
+
.split('\n')
|
|
156
|
+
.map((line) => ` ${PURPLE('│')} ${line}`);
|
|
157
|
+
appendLines(prefixed);
|
|
158
|
+
}, [appendLines]);
|
|
159
|
+
const terminalRows = process.stdout.rows || 42;
|
|
160
|
+
const reservedRows = state === 'idle' ? 9 : state === 'waiting_approval' ? 13 : 6;
|
|
161
|
+
const historyWindowSize = Math.max(8, terminalRows - reservedRows);
|
|
162
|
+
const visibleOutputLines = useMemo(() => {
|
|
163
|
+
const end = Math.max(0, outputLines.length - historyScrollOffset);
|
|
164
|
+
const start = Math.max(0, end - historyWindowSize);
|
|
165
|
+
return outputLines.slice(start, end);
|
|
166
|
+
}, [outputLines, historyScrollOffset, historyWindowSize]);
|
|
149
167
|
// ---------------------------------------------------------------------------
|
|
150
168
|
// Spinner management
|
|
151
169
|
// ---------------------------------------------------------------------------
|
|
152
170
|
const spinnerRef = useRef(null);
|
|
153
171
|
const verbRef = useRef(pickVerb());
|
|
154
172
|
const spinnerStartRef = useRef(0);
|
|
173
|
+
const turnStartRef = useRef(0);
|
|
174
|
+
const lastVerbRotateSecondRef = useRef(0);
|
|
155
175
|
const spinnerFrameRef = useRef(0);
|
|
156
176
|
const SPINNER_FRAMES = ['◇ ', '◈ ', '◆ ', '◈ '];
|
|
157
177
|
const startSpinner = useCallback((mode, toolName) => {
|
|
158
178
|
stopSpinnerFn();
|
|
159
179
|
spinnerStartRef.current = Date.now();
|
|
160
180
|
verbRef.current = pickVerb();
|
|
181
|
+
lastVerbRotateSecondRef.current = 0;
|
|
161
182
|
spinnerFrameRef.current = 0;
|
|
183
|
+
if (mode === 'tool') {
|
|
184
|
+
setSpinnerText(` ${CYAN('⚡')} ${CYAN(toolName ?? 'tool')} ${DIM('executing...')}`);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
162
187
|
const update = () => {
|
|
163
188
|
spinnerFrameRef.current = (spinnerFrameRef.current + 1) % SPINNER_FRAMES.length;
|
|
164
189
|
const frame = SPINNER_FRAMES[spinnerFrameRef.current];
|
|
165
190
|
const elapsed = Math.round((Date.now() - spinnerStartRef.current) / 1000);
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
}
|
|
173
|
-
else {
|
|
174
|
-
setSpinnerText(` ${CYAN('⚡')} ${CYAN(toolName ?? 'tool')} ${DIM('executing...')}`);
|
|
191
|
+
// Rotate verb every ~3s, once per threshold crossing.
|
|
192
|
+
if (elapsed > 0 &&
|
|
193
|
+
elapsed % 3 === 0 &&
|
|
194
|
+
elapsed !== lastVerbRotateSecondRef.current) {
|
|
195
|
+
verbRef.current = pickVerb();
|
|
196
|
+
lastVerbRotateSecondRef.current = elapsed;
|
|
175
197
|
}
|
|
198
|
+
setSpinnerText(` ${PURPLE(frame)}${PURPLE(verbRef.current + '...')} ${DIM(`(${elapsed}s)`)}`);
|
|
176
199
|
};
|
|
177
200
|
update();
|
|
178
201
|
spinnerRef.current = setInterval(update, 120);
|
|
@@ -185,7 +208,8 @@ export default function App(props) {
|
|
|
185
208
|
setSpinnerText('');
|
|
186
209
|
}, []);
|
|
187
210
|
const getCompletionSummary = useCallback(() => {
|
|
188
|
-
const
|
|
211
|
+
const start = turnStartRef.current || spinnerStartRef.current;
|
|
212
|
+
const elapsed = Math.round((Date.now() - start) / 1000);
|
|
189
213
|
return `${toPastTense(verbRef.current)} for ${elapsed}s`;
|
|
190
214
|
}, []);
|
|
191
215
|
// ---------------------------------------------------------------------------
|
|
@@ -228,10 +252,14 @@ export default function App(props) {
|
|
|
228
252
|
// Handle user message (streaming)
|
|
229
253
|
// ---------------------------------------------------------------------------
|
|
230
254
|
const handleUserMessage = useCallback(async (message) => {
|
|
255
|
+
turnStartRef.current = Date.now();
|
|
231
256
|
appendOutput('');
|
|
232
257
|
startSpinner('thinking');
|
|
233
|
-
|
|
258
|
+
const streamRenderer = new StreamingMarkdownRenderer({
|
|
259
|
+
width: Math.max(60, (process.stdout.columns || 96) - 8),
|
|
260
|
+
});
|
|
234
261
|
let firstText = true;
|
|
262
|
+
let hadTextOutput = false;
|
|
235
263
|
let currentTool = '';
|
|
236
264
|
let currentToolInput = {};
|
|
237
265
|
let toolCallCount = 0;
|
|
@@ -275,27 +303,22 @@ export default function App(props) {
|
|
|
275
303
|
firstText = false;
|
|
276
304
|
}
|
|
277
305
|
const chunk = event.data;
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
306
|
+
const rendered = streamRenderer.push(chunk);
|
|
307
|
+
if (rendered) {
|
|
308
|
+
hadTextOutput = true;
|
|
309
|
+
appendRenderedMarkdown(rendered);
|
|
310
|
+
}
|
|
281
311
|
break;
|
|
282
312
|
}
|
|
283
313
|
case 'tool_use': {
|
|
284
314
|
stopSpinnerFn();
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
displayText = displayText.replace(/```thought[\s\S]*?```/g, '').trim();
|
|
291
|
-
if (displayText) {
|
|
292
|
-
const formatted = displayText.split('\n').map(l => ` ${PURPLE('│')} ${l}`).join('\n');
|
|
293
|
-
appendOutput(formatted);
|
|
294
|
-
}
|
|
295
|
-
fullOutput = '';
|
|
296
|
-
}
|
|
297
|
-
firstText = true;
|
|
315
|
+
const rendered = streamRenderer.flush();
|
|
316
|
+
if (rendered) {
|
|
317
|
+
hadTextOutput = true;
|
|
318
|
+
appendRenderedMarkdown(rendered);
|
|
319
|
+
appendOutput('');
|
|
298
320
|
}
|
|
321
|
+
firstText = true;
|
|
299
322
|
const block = event.data;
|
|
300
323
|
currentTool = block.name;
|
|
301
324
|
currentToolInput = block.input;
|
|
@@ -337,6 +360,11 @@ export default function App(props) {
|
|
|
337
360
|
break;
|
|
338
361
|
}
|
|
339
362
|
case 'done': {
|
|
363
|
+
const rendered = streamRenderer.flush();
|
|
364
|
+
if (rendered) {
|
|
365
|
+
hadTextOutput = true;
|
|
366
|
+
appendRenderedMarkdown(rendered);
|
|
367
|
+
}
|
|
340
368
|
stopSpinnerFn();
|
|
341
369
|
break;
|
|
342
370
|
}
|
|
@@ -364,8 +392,9 @@ export default function App(props) {
|
|
|
364
392
|
// Retry once with compacted context
|
|
365
393
|
try {
|
|
366
394
|
startSpinner('thinking');
|
|
367
|
-
|
|
395
|
+
streamRenderer.reset();
|
|
368
396
|
firstText = true;
|
|
397
|
+
hadTextOutput = false;
|
|
369
398
|
for await (const event of agent.stream('', callbacks, abortController.signal)) {
|
|
370
399
|
switch (event.type) {
|
|
371
400
|
case 'text': {
|
|
@@ -373,11 +402,21 @@ export default function App(props) {
|
|
|
373
402
|
stopSpinnerFn();
|
|
374
403
|
firstText = false;
|
|
375
404
|
}
|
|
376
|
-
|
|
405
|
+
const rendered = streamRenderer.push(event.data);
|
|
406
|
+
if (rendered) {
|
|
407
|
+
hadTextOutput = true;
|
|
408
|
+
appendRenderedMarkdown(rendered);
|
|
409
|
+
}
|
|
377
410
|
break;
|
|
378
411
|
}
|
|
379
412
|
case 'tool_use': {
|
|
380
413
|
stopSpinnerFn();
|
|
414
|
+
const rendered = streamRenderer.flush();
|
|
415
|
+
if (rendered) {
|
|
416
|
+
hadTextOutput = true;
|
|
417
|
+
appendRenderedMarkdown(rendered);
|
|
418
|
+
appendOutput('');
|
|
419
|
+
}
|
|
381
420
|
const block = event.data;
|
|
382
421
|
currentTool = block.name;
|
|
383
422
|
currentToolInput = block.input;
|
|
@@ -412,6 +451,11 @@ export default function App(props) {
|
|
|
412
451
|
}
|
|
413
452
|
}
|
|
414
453
|
}
|
|
454
|
+
const retryRemainder = streamRenderer.flush();
|
|
455
|
+
if (retryRemainder) {
|
|
456
|
+
hadTextOutput = true;
|
|
457
|
+
appendRenderedMarkdown(retryRemainder);
|
|
458
|
+
}
|
|
415
459
|
}
|
|
416
460
|
catch (retryErr) {
|
|
417
461
|
stopSpinnerFn();
|
|
@@ -426,17 +470,12 @@ export default function App(props) {
|
|
|
426
470
|
appendOutput(`\n ${ERROR_SYM} ${RED.bold(msg)}\n`);
|
|
427
471
|
}
|
|
428
472
|
}
|
|
429
|
-
|
|
430
|
-
if (
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
displayText = displayText.replace(/```thought[\s\S]*?```/g, '').trim();
|
|
434
|
-
if (displayText) {
|
|
435
|
-
const formatted = displayText.split('\n').map(l => ` ${PURPLE('│')} ${l}`).join('\n');
|
|
436
|
-
appendOutput(formatted);
|
|
437
|
-
}
|
|
473
|
+
const remainder = streamRenderer.flush();
|
|
474
|
+
if (remainder) {
|
|
475
|
+
hadTextOutput = true;
|
|
476
|
+
appendRenderedMarkdown(remainder);
|
|
438
477
|
}
|
|
439
|
-
if (
|
|
478
|
+
if (hadTextOutput || !firstText) {
|
|
440
479
|
appendOutput('');
|
|
441
480
|
}
|
|
442
481
|
// Turn summary
|
|
@@ -467,11 +506,12 @@ export default function App(props) {
|
|
|
467
506
|
appendOutput(SEPARATOR);
|
|
468
507
|
appendOutput('');
|
|
469
508
|
}, [agent, session, adapter, costTracker, undoManager, verbose, autoSaver, doSave,
|
|
470
|
-
appendOutput, startSpinner, stopSpinnerFn, getCompletionSummary]);
|
|
509
|
+
appendOutput, appendRenderedMarkdown, startSpinner, stopSpinnerFn, getCompletionSummary]);
|
|
471
510
|
// ---------------------------------------------------------------------------
|
|
472
511
|
// Handle team message
|
|
473
512
|
// ---------------------------------------------------------------------------
|
|
474
513
|
const handleTeamMessage = useCallback(async (goal, teamConfig) => {
|
|
514
|
+
turnStartRef.current = Date.now();
|
|
475
515
|
appendOutput('');
|
|
476
516
|
appendOutput(` ${PURPLE('◈')} Running team ${PURPLE.bold(teamConfig.name)} with ${teamConfig.agents.length} agents...`);
|
|
477
517
|
appendOutput('');
|
|
@@ -872,7 +912,6 @@ export default function App(props) {
|
|
|
872
912
|
// ---------------------------------------------------------------------------
|
|
873
913
|
const handleSubmit = useCallback(async (value) => {
|
|
874
914
|
const input = value.trim();
|
|
875
|
-
setInputValue('');
|
|
876
915
|
if (!input)
|
|
877
916
|
return;
|
|
878
917
|
if (stateRef.current !== 'idle')
|
|
@@ -946,6 +985,20 @@ export default function App(props) {
|
|
|
946
985
|
// Keyboard input handling (Ctrl+C, Ctrl+D)
|
|
947
986
|
// ---------------------------------------------------------------------------
|
|
948
987
|
useInput((input, key) => {
|
|
988
|
+
const maxScrollOffset = Math.max(0, outputLines.length - historyWindowSize);
|
|
989
|
+
const pageStep = Math.max(1, Math.floor(historyWindowSize * 0.7));
|
|
990
|
+
if (key.pageUp) {
|
|
991
|
+
setHistoryScrollOffset((prev) => Math.min(maxScrollOffset, prev + pageStep));
|
|
992
|
+
return;
|
|
993
|
+
}
|
|
994
|
+
if (key.pageDown) {
|
|
995
|
+
setHistoryScrollOffset((prev) => Math.max(0, prev - pageStep));
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
if (key.escape && historyScrollOffset > 0) {
|
|
999
|
+
setHistoryScrollOffset(0);
|
|
1000
|
+
return;
|
|
1001
|
+
}
|
|
949
1002
|
// Ctrl+C handling
|
|
950
1003
|
if (key.ctrl && input === 'c') {
|
|
951
1004
|
const now = Date.now();
|
|
@@ -1015,11 +1068,11 @@ export default function App(props) {
|
|
|
1015
1068
|
// ---------------------------------------------------------------------------
|
|
1016
1069
|
// Render
|
|
1017
1070
|
// ---------------------------------------------------------------------------
|
|
1018
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(
|
|
1071
|
+
return (_jsxs(Box, { flexDirection: "column", height: terminalRows, children: [_jsx(Box, { flexDirection: "column", flexGrow: 1, overflow: "hidden", children: visibleOutputLines.map((line) => (_jsx(Text, { children: line.text }, line.id))) }), historyScrollOffset > 0 && (_jsx(Text, { children: ` ${DIM('Scrollback')} ${WHITE(String(historyScrollOffset))} ${DIM('(PgUp/PgDn, Esc to jump to live)')}` })), state === 'processing' && spinnerText && (_jsx(Text, { children: spinnerText })), state === 'waiting_approval' && approval && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: '' }), _jsx(Text, { children: ` ${YELLOW('⚠')} ${WHITE('Tool approval required')} ${DIM('[')}${approval.riskLevel === 'dangerous' ? RED(approval.riskLevel.toUpperCase()) : YELLOW(approval.riskLevel.toUpperCase())}${DIM(']')}` }), _jsx(Text, { children: ` ${DIM('Tool:')} ${CYAN(approval.toolName)}` }), Object.entries(approval.input).map(([key, val]) => {
|
|
1019
1072
|
const display = typeof val === 'string'
|
|
1020
1073
|
? val.length > 120 ? val.slice(0, 120) + DIM('...') : val
|
|
1021
1074
|
: JSON.stringify(val).slice(0, 120);
|
|
1022
1075
|
return _jsx(Text, { children: ` ${DIM(key + ':')} ${WHITE(display)}` }, key);
|
|
1023
|
-
}), _jsx(Text, { children: '' }), _jsx(Text, { children: ` ${GREEN('y')}${DIM('es')} ${DIM('/')} ${RED('n')}${DIM('o')} ${DIM('/')} ${PURPLE('a')}${DIM('lways allow this tool')}` }), _jsxs(Box, { children: [_jsx(Text, { children: ` ${YELLOW('?')} ` }), _jsx(TextInput, { value: approvalInput, onChange: setApprovalInput, onSubmit: handleApprovalSubmit })] })] })),
|
|
1076
|
+
}), _jsx(Text, { children: '' }), _jsx(Text, { children: ` ${GREEN('y')}${DIM('es')} ${DIM('/')} ${RED('n')}${DIM('o')} ${DIM('/')} ${PURPLE('a')}${DIM('lways allow this tool')}` }), _jsxs(Box, { children: [_jsx(Text, { children: ` ${YELLOW('?')} ` }), _jsx(TextInput, { value: approvalInput, onChange: setApprovalInput, onSubmit: handleApprovalSubmit })] })] })), _jsx(StatusBar, { model: currentModelRef.current, tokensIn: tokensIn, tokensOut: tokensOut, turns: turnCount, agentCount: agentRegistry.list().length, permissionMode: permissionManager.getMode(), cwd: process.cwd(), gitBranch: props.gitBranch, contextPct: session.maxContextTokens ? Math.round((session.tokenCount / session.maxContextTokens) * 100) : 0, version: props.version }), state === 'idle' && (_jsx(PromptInput, { onSubmit: handleSubmit, placeholder: "Ask anything, @file to include, /help for commands" }))] }));
|
|
1024
1077
|
}
|
|
1025
1078
|
//# sourceMappingURL=App.js.map
|