158 lines
3.7 KiB
JavaScript
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');
|
|
}
|