EasyAgent/demo/cli_demo.js
2026-02-28 03:00:08 +08:00

158 lines
3.7 KiB
JavaScript

#!/usr/bin/env node
'use strict';
const readline = require('readline');
const { WORKSPACE, WORKSPACE_NAME, PROMPT, COLOR_ENABLED, RESET } = require('./lib/env');
const { loadSystemPrompt } = require('./lib/system_prompt');
const { createState } = require('./lib/state');
const { handleCommand } = require('./lib/commands');
const { createAssistantSimulator } = require('./lib/assistant_sim');
const { openCommandMenu } = require('./lib/ui/command_menu');
const SHOW_REASONING = process.env.EA_REASONING !== '0';
const SYSTEM_PROMPT = loadSystemPrompt();
void SYSTEM_PROMPT; // demo only
const state = createState();
const simulateAssistantReply = createAssistantSimulator(state, {
showReasoning: SHOW_REASONING,
});
console.log('');
console.log('eagent demo');
console.log(`model: kimi | allow: full_access | cwd: ${WORKSPACE_NAME}`);
console.log('');
let rl = null;
let commandMenuActive = false;
let closingExplicit = false;
let menuSearchTerm = '';
let menuJustClosedAt = 0;
let menuInjectedCommand = null;
readline.emitKeypressEvents(process.stdin);
if (process.stdin.isTTY) process.stdin.setRawMode(true);
initReadline();
process.stdin.on('keypress', (str) => {
if (commandMenuActive) return;
if (str === '/' && (rl.line === '' || rl.line === '/')) {
commandMenuActive = true;
menuSearchTerm = '';
void openCommandMenu({
rl,
prompt: PROMPT,
pageSize: 6,
colorEnabled: COLOR_ENABLED,
resetAnsi: RESET,
onInput: (input) => {
menuSearchTerm = input || '';
},
})
.then((result) => {
if (result && result.chosen) {
menuInjectedCommand = result.chosen;
menuSearchTerm = '';
}
})
.finally(() => {
commandMenuActive = false;
menuJustClosedAt = Date.now();
drainStdin();
rl.line = '';
rl.cursor = 0;
rl.prompt();
if (menuInjectedCommand) {
const injected = menuInjectedCommand;
menuInjectedCommand = null;
setImmediate(() => injectLine(injected));
}
});
}
});
function initReadline() {
if (rl) {
try {
rl.removeAllListeners();
} catch (_) {}
}
rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: true,
});
process.stdin.resume();
rl.setPrompt(PROMPT);
rl.prompt();
rl.on('line', async (line) => {
if (commandMenuActive) {
rl.prompt();
return;
}
const input = line.trim();
if (menuJustClosedAt) {
const tooOld = Date.now() - menuJustClosedAt > 800;
const normalizedMenu = String(menuSearchTerm).trim().replace(/^\/+/, '');
const normalizedInput = input.replace(/^\/+/, '');
if (!tooOld && (!normalizedMenu ? input === '' : normalizedInput === normalizedMenu)) {
menuJustClosedAt = 0;
rl.prompt();
return;
}
menuJustClosedAt = 0;
}
if (!input) {
rl.prompt();
return;
}
if (input.startsWith('/')) {
await handleCommand(input, state, {
rl,
workspacePath: WORKSPACE,
markClosing: () => {
closingExplicit = true;
},
});
rl.prompt();
return;
}
console.log(`用户:${line}`);
console.log('');
await simulateAssistantReply(input);
rl.prompt();
});
rl.on('close', () => {
process.stdout.write('\n');
if (closingExplicit) {
process.exit(0);
}
closingExplicit = false;
initReadline();
});
}
function drainStdin() {
if (!process.stdin.isTTY) return;
process.stdin.pause();
// Drain any buffered input from the command menu.
while (process.stdin.read() !== null) {}
process.stdin.resume();
}
function injectLine(text) {
if (!rl) return;
rl.write(text);
rl.write('\n');
}