genesis-ai-cli 7.4.5
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/.env.example +78 -0
- package/README.md +282 -0
- package/dist/src/active-inference/actions.d.ts +75 -0
- package/dist/src/active-inference/actions.js +250 -0
- package/dist/src/active-inference/autonomous-loop.d.ts +103 -0
- package/dist/src/active-inference/autonomous-loop.js +289 -0
- package/dist/src/active-inference/core.d.ts +85 -0
- package/dist/src/active-inference/core.js +555 -0
- package/dist/src/active-inference/demo-autonomous-loop.d.ts +8 -0
- package/dist/src/active-inference/demo-autonomous-loop.js +338 -0
- package/dist/src/active-inference/demo-value-integration.d.ts +8 -0
- package/dist/src/active-inference/demo-value-integration.js +174 -0
- package/dist/src/active-inference/index.d.ts +32 -0
- package/dist/src/active-inference/index.js +88 -0
- package/dist/src/active-inference/integration.d.ts +114 -0
- package/dist/src/active-inference/integration.js +698 -0
- package/dist/src/active-inference/memory-integration.d.ts +51 -0
- package/dist/src/active-inference/memory-integration.js +232 -0
- package/dist/src/active-inference/observations.d.ts +67 -0
- package/dist/src/active-inference/observations.js +147 -0
- package/dist/src/active-inference/test-active-inference.d.ts +8 -0
- package/dist/src/active-inference/test-active-inference.js +320 -0
- package/dist/src/active-inference/test-value-integration.d.ts +6 -0
- package/dist/src/active-inference/test-value-integration.js +168 -0
- package/dist/src/active-inference/types.d.ts +150 -0
- package/dist/src/active-inference/types.js +59 -0
- package/dist/src/active-inference/value-integration.d.ts +164 -0
- package/dist/src/active-inference/value-integration.js +459 -0
- package/dist/src/agents/base-agent.d.ts +53 -0
- package/dist/src/agents/base-agent.js +178 -0
- package/dist/src/agents/builder.d.ts +67 -0
- package/dist/src/agents/builder.js +537 -0
- package/dist/src/agents/critic.d.ts +35 -0
- package/dist/src/agents/critic.js +322 -0
- package/dist/src/agents/ethicist.d.ts +54 -0
- package/dist/src/agents/ethicist.js +393 -0
- package/dist/src/agents/explorer.d.ts +26 -0
- package/dist/src/agents/explorer.js +216 -0
- package/dist/src/agents/feeling.d.ts +41 -0
- package/dist/src/agents/feeling.js +320 -0
- package/dist/src/agents/index.d.ts +111 -0
- package/dist/src/agents/index.js +222 -0
- package/dist/src/agents/memory.d.ts +69 -0
- package/dist/src/agents/memory.js +404 -0
- package/dist/src/agents/message-bus.d.ts +88 -0
- package/dist/src/agents/message-bus.js +267 -0
- package/dist/src/agents/narrator.d.ts +90 -0
- package/dist/src/agents/narrator.js +473 -0
- package/dist/src/agents/planner.d.ts +38 -0
- package/dist/src/agents/planner.js +341 -0
- package/dist/src/agents/predictor.d.ts +73 -0
- package/dist/src/agents/predictor.js +506 -0
- package/dist/src/agents/sensor.d.ts +88 -0
- package/dist/src/agents/sensor.js +377 -0
- package/dist/src/agents/test-agents.d.ts +6 -0
- package/dist/src/agents/test-agents.js +73 -0
- package/dist/src/agents/types.d.ts +194 -0
- package/dist/src/agents/types.js +7 -0
- package/dist/src/brain/index.d.ts +185 -0
- package/dist/src/brain/index.js +843 -0
- package/dist/src/brain/trace.d.ts +91 -0
- package/dist/src/brain/trace.js +327 -0
- package/dist/src/brain/types.d.ts +165 -0
- package/dist/src/brain/types.js +51 -0
- package/dist/src/cli/chat.d.ts +237 -0
- package/dist/src/cli/chat.js +1959 -0
- package/dist/src/cli/dispatcher.d.ts +182 -0
- package/dist/src/cli/dispatcher.js +718 -0
- package/dist/src/cli/human-loop.d.ts +170 -0
- package/dist/src/cli/human-loop.js +543 -0
- package/dist/src/cli/index.d.ts +12 -0
- package/dist/src/cli/index.js +28 -0
- package/dist/src/cli/interactive.d.ts +141 -0
- package/dist/src/cli/interactive.js +757 -0
- package/dist/src/cli/ui.d.ts +205 -0
- package/dist/src/cli/ui.js +632 -0
- package/dist/src/consciousness/attention-schema.d.ts +154 -0
- package/dist/src/consciousness/attention-schema.js +432 -0
- package/dist/src/consciousness/global-workspace.d.ts +149 -0
- package/dist/src/consciousness/global-workspace.js +422 -0
- package/dist/src/consciousness/index.d.ts +186 -0
- package/dist/src/consciousness/index.js +476 -0
- package/dist/src/consciousness/phi-calculator.d.ts +119 -0
- package/dist/src/consciousness/phi-calculator.js +445 -0
- package/dist/src/consciousness/phi-decisions.d.ts +169 -0
- package/dist/src/consciousness/phi-decisions.js +383 -0
- package/dist/src/consciousness/phi-monitor.d.ts +153 -0
- package/dist/src/consciousness/phi-monitor.js +465 -0
- package/dist/src/consciousness/types.d.ts +260 -0
- package/dist/src/consciousness/types.js +44 -0
- package/dist/src/daemon/dream-mode.d.ts +115 -0
- package/dist/src/daemon/dream-mode.js +470 -0
- package/dist/src/daemon/index.d.ts +162 -0
- package/dist/src/daemon/index.js +542 -0
- package/dist/src/daemon/maintenance.d.ts +139 -0
- package/dist/src/daemon/maintenance.js +549 -0
- package/dist/src/daemon/process.d.ts +82 -0
- package/dist/src/daemon/process.js +442 -0
- package/dist/src/daemon/scheduler.d.ts +90 -0
- package/dist/src/daemon/scheduler.js +494 -0
- package/dist/src/daemon/types.d.ts +213 -0
- package/dist/src/daemon/types.js +50 -0
- package/dist/src/epistemic/index.d.ts +74 -0
- package/dist/src/epistemic/index.js +225 -0
- package/dist/src/grounding/epistemic-stack.d.ts +100 -0
- package/dist/src/grounding/epistemic-stack.js +408 -0
- package/dist/src/grounding/feedback.d.ts +98 -0
- package/dist/src/grounding/feedback.js +276 -0
- package/dist/src/grounding/index.d.ts +123 -0
- package/dist/src/grounding/index.js +224 -0
- package/dist/src/grounding/verifier.d.ts +149 -0
- package/dist/src/grounding/verifier.js +484 -0
- package/dist/src/healing/detector.d.ts +110 -0
- package/dist/src/healing/detector.js +436 -0
- package/dist/src/healing/fixer.d.ts +138 -0
- package/dist/src/healing/fixer.js +572 -0
- package/dist/src/healing/index.d.ts +23 -0
- package/dist/src/healing/index.js +43 -0
- package/dist/src/hooks/index.d.ts +135 -0
- package/dist/src/hooks/index.js +317 -0
- package/dist/src/index.d.ts +23 -0
- package/dist/src/index.js +1266 -0
- package/dist/src/kernel/index.d.ts +155 -0
- package/dist/src/kernel/index.js +795 -0
- package/dist/src/kernel/invariants.d.ts +153 -0
- package/dist/src/kernel/invariants.js +355 -0
- package/dist/src/kernel/test-kernel.d.ts +6 -0
- package/dist/src/kernel/test-kernel.js +108 -0
- package/dist/src/kernel/test-real-mcp.d.ts +10 -0
- package/dist/src/kernel/test-real-mcp.js +295 -0
- package/dist/src/llm/index.d.ts +146 -0
- package/dist/src/llm/index.js +428 -0
- package/dist/src/llm/router.d.ts +136 -0
- package/dist/src/llm/router.js +510 -0
- package/dist/src/mcp/index.d.ts +85 -0
- package/dist/src/mcp/index.js +657 -0
- package/dist/src/mcp/resilient.d.ts +139 -0
- package/dist/src/mcp/resilient.js +417 -0
- package/dist/src/memory/cache.d.ts +118 -0
- package/dist/src/memory/cache.js +356 -0
- package/dist/src/memory/cognitive-workspace.d.ts +231 -0
- package/dist/src/memory/cognitive-workspace.js +521 -0
- package/dist/src/memory/consolidation.d.ts +99 -0
- package/dist/src/memory/consolidation.js +443 -0
- package/dist/src/memory/episodic.d.ts +114 -0
- package/dist/src/memory/episodic.js +394 -0
- package/dist/src/memory/forgetting.d.ts +134 -0
- package/dist/src/memory/forgetting.js +324 -0
- package/dist/src/memory/index.d.ts +211 -0
- package/dist/src/memory/index.js +367 -0
- package/dist/src/memory/indexer.d.ts +123 -0
- package/dist/src/memory/indexer.js +479 -0
- package/dist/src/memory/procedural.d.ts +136 -0
- package/dist/src/memory/procedural.js +479 -0
- package/dist/src/memory/semantic.d.ts +132 -0
- package/dist/src/memory/semantic.js +497 -0
- package/dist/src/memory/types.d.ts +193 -0
- package/dist/src/memory/types.js +15 -0
- package/dist/src/orchestrator.d.ts +65 -0
- package/dist/src/orchestrator.js +317 -0
- package/dist/src/persistence/index.d.ts +257 -0
- package/dist/src/persistence/index.js +763 -0
- package/dist/src/pipeline/executor.d.ts +51 -0
- package/dist/src/pipeline/executor.js +695 -0
- package/dist/src/pipeline/index.d.ts +7 -0
- package/dist/src/pipeline/index.js +11 -0
- package/dist/src/self-production.d.ts +67 -0
- package/dist/src/self-production.js +205 -0
- package/dist/src/subagents/executor.d.ts +58 -0
- package/dist/src/subagents/executor.js +283 -0
- package/dist/src/subagents/index.d.ts +37 -0
- package/dist/src/subagents/index.js +53 -0
- package/dist/src/subagents/registry.d.ts +23 -0
- package/dist/src/subagents/registry.js +167 -0
- package/dist/src/subagents/types.d.ts +79 -0
- package/dist/src/subagents/types.js +14 -0
- package/dist/src/tools/bash.d.ts +139 -0
- package/dist/src/tools/bash.js +583 -0
- package/dist/src/tools/edit.d.ts +125 -0
- package/dist/src/tools/edit.js +424 -0
- package/dist/src/tools/git.d.ts +179 -0
- package/dist/src/tools/git.js +504 -0
- package/dist/src/tools/index.d.ts +21 -0
- package/dist/src/tools/index.js +163 -0
- package/dist/src/types.d.ts +145 -0
- package/dist/src/types.js +7 -0
- package/dist/src/world-model/decoder.d.ts +163 -0
- package/dist/src/world-model/decoder.js +517 -0
- package/dist/src/world-model/digital-twin.d.ts +219 -0
- package/dist/src/world-model/digital-twin.js +695 -0
- package/dist/src/world-model/encoder.d.ts +141 -0
- package/dist/src/world-model/encoder.js +564 -0
- package/dist/src/world-model/index.d.ts +221 -0
- package/dist/src/world-model/index.js +772 -0
- package/dist/src/world-model/predictor.d.ts +161 -0
- package/dist/src/world-model/predictor.js +681 -0
- package/dist/src/world-model/test-value-jepa.d.ts +8 -0
- package/dist/src/world-model/test-value-jepa.js +430 -0
- package/dist/src/world-model/types.d.ts +341 -0
- package/dist/src/world-model/types.js +69 -0
- package/dist/src/world-model/value-jepa.d.ts +247 -0
- package/dist/src/world-model/value-jepa.js +622 -0
- package/dist/test/brain.test.d.ts +11 -0
- package/dist/test/brain.test.js +358 -0
- package/dist/test/cli/dispatcher.test.d.ts +4 -0
- package/dist/test/cli/dispatcher.test.js +332 -0
- package/dist/test/cli/human-loop.test.d.ts +4 -0
- package/dist/test/cli/human-loop.test.js +270 -0
- package/dist/test/grounding/feedback.test.d.ts +4 -0
- package/dist/test/grounding/feedback.test.js +462 -0
- package/dist/test/grounding/verifier.test.d.ts +4 -0
- package/dist/test/grounding/verifier.test.js +442 -0
- package/dist/test/grounding.test.d.ts +6 -0
- package/dist/test/grounding.test.js +246 -0
- package/dist/test/healing/detector.test.d.ts +4 -0
- package/dist/test/healing/detector.test.js +266 -0
- package/dist/test/healing/fixer.test.d.ts +4 -0
- package/dist/test/healing/fixer.test.js +369 -0
- package/dist/test/integration.test.d.ts +5 -0
- package/dist/test/integration.test.js +290 -0
- package/dist/test/tools/bash.test.d.ts +4 -0
- package/dist/test/tools/bash.test.js +348 -0
- package/dist/test/tools/edit.test.d.ts +4 -0
- package/dist/test/tools/edit.test.js +350 -0
- package/dist/test/tools/git.test.d.ts +4 -0
- package/dist/test/tools/git.test.js +350 -0
- package/package.json +60 -0
|
@@ -0,0 +1,757 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Genesis 6.0 - Interactive REPL
|
|
4
|
+
*
|
|
5
|
+
* Full-featured REPL with:
|
|
6
|
+
* - Tool dispatching and execution
|
|
7
|
+
* - History persistence
|
|
8
|
+
* - Progress indicators
|
|
9
|
+
* - Syntax highlighting
|
|
10
|
+
* - Tab completion
|
|
11
|
+
*/
|
|
12
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
15
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
16
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
17
|
+
}
|
|
18
|
+
Object.defineProperty(o, k2, desc);
|
|
19
|
+
}) : (function(o, m, k, k2) {
|
|
20
|
+
if (k2 === undefined) k2 = k;
|
|
21
|
+
o[k2] = m[k];
|
|
22
|
+
}));
|
|
23
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
24
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
25
|
+
}) : function(o, v) {
|
|
26
|
+
o["default"] = v;
|
|
27
|
+
});
|
|
28
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
29
|
+
var ownKeys = function(o) {
|
|
30
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
31
|
+
var ar = [];
|
|
32
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
33
|
+
return ar;
|
|
34
|
+
};
|
|
35
|
+
return ownKeys(o);
|
|
36
|
+
};
|
|
37
|
+
return function (mod) {
|
|
38
|
+
if (mod && mod.__esModule) return mod;
|
|
39
|
+
var result = {};
|
|
40
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
41
|
+
__setModuleDefault(result, mod);
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
44
|
+
})();
|
|
45
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
+
exports.InteractiveSession = void 0;
|
|
47
|
+
exports.createInteractiveSession = createInteractiveSession;
|
|
48
|
+
exports.startInteractive = startInteractive;
|
|
49
|
+
const readline = __importStar(require("readline"));
|
|
50
|
+
const fs = __importStar(require("fs"));
|
|
51
|
+
const path = __importStar(require("path"));
|
|
52
|
+
const index_js_1 = require("../llm/index.js");
|
|
53
|
+
const index_js_2 = require("../persistence/index.js");
|
|
54
|
+
const dispatcher_js_1 = require("./dispatcher.js");
|
|
55
|
+
const index_js_3 = require("../tools/index.js");
|
|
56
|
+
// ============================================================================
|
|
57
|
+
// Colors & Formatting
|
|
58
|
+
// ============================================================================
|
|
59
|
+
const colors = {
|
|
60
|
+
reset: '\x1b[0m',
|
|
61
|
+
bold: '\x1b[1m',
|
|
62
|
+
dim: '\x1b[2m',
|
|
63
|
+
italic: '\x1b[3m',
|
|
64
|
+
underline: '\x1b[4m',
|
|
65
|
+
cyan: '\x1b[36m',
|
|
66
|
+
green: '\x1b[32m',
|
|
67
|
+
yellow: '\x1b[33m',
|
|
68
|
+
red: '\x1b[31m',
|
|
69
|
+
magenta: '\x1b[35m',
|
|
70
|
+
blue: '\x1b[34m',
|
|
71
|
+
white: '\x1b[37m',
|
|
72
|
+
gray: '\x1b[90m',
|
|
73
|
+
bgBlue: '\x1b[44m',
|
|
74
|
+
bgGreen: '\x1b[42m',
|
|
75
|
+
bgRed: '\x1b[41m',
|
|
76
|
+
bgYellow: '\x1b[43m',
|
|
77
|
+
};
|
|
78
|
+
function c(text, ...styles) {
|
|
79
|
+
const codes = styles.map(s => colors[s]).join('');
|
|
80
|
+
return `${codes}${text}${colors.reset}`;
|
|
81
|
+
}
|
|
82
|
+
// Spinner frames
|
|
83
|
+
const SPINNER = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
84
|
+
const DEFAULT_CONFIG = {
|
|
85
|
+
verbose: false,
|
|
86
|
+
workingDirectory: process.cwd(),
|
|
87
|
+
historyFile: path.join(process.env.HOME || '/tmp', '.genesis_history'),
|
|
88
|
+
maxHistorySize: 1000,
|
|
89
|
+
enableTools: true,
|
|
90
|
+
autoExecuteTools: true,
|
|
91
|
+
};
|
|
92
|
+
// ============================================================================
|
|
93
|
+
// Interactive Session
|
|
94
|
+
// ============================================================================
|
|
95
|
+
class InteractiveSession {
|
|
96
|
+
config;
|
|
97
|
+
llm;
|
|
98
|
+
store;
|
|
99
|
+
dispatcher;
|
|
100
|
+
rl = null;
|
|
101
|
+
running = false;
|
|
102
|
+
inputHistory = [];
|
|
103
|
+
historyIndex = -1;
|
|
104
|
+
spinnerInterval = null;
|
|
105
|
+
currentSpinnerFrame = 0;
|
|
106
|
+
constructor(config) {
|
|
107
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
108
|
+
this.llm = (0, index_js_1.getLLMBridge)({
|
|
109
|
+
provider: this.config.provider,
|
|
110
|
+
model: this.config.model,
|
|
111
|
+
});
|
|
112
|
+
this.store = (0, index_js_2.getStateStore)({
|
|
113
|
+
autoSave: true,
|
|
114
|
+
autoSaveIntervalMs: 60000,
|
|
115
|
+
});
|
|
116
|
+
this.dispatcher = (0, dispatcher_js_1.getDispatcher)({
|
|
117
|
+
verbose: this.config.verbose,
|
|
118
|
+
onProgress: (status) => this.showProgress(status),
|
|
119
|
+
});
|
|
120
|
+
// Load input history
|
|
121
|
+
this.loadInputHistory();
|
|
122
|
+
// Restore conversation
|
|
123
|
+
const state = this.store.getState();
|
|
124
|
+
if (state.conversation.history.length > 0) {
|
|
125
|
+
for (const msg of state.conversation.history) {
|
|
126
|
+
this.llm.getHistory().push(msg);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Start interactive session
|
|
132
|
+
*/
|
|
133
|
+
async start() {
|
|
134
|
+
this.printBanner();
|
|
135
|
+
this.printStatus();
|
|
136
|
+
this.printHelp();
|
|
137
|
+
this.rl = readline.createInterface({
|
|
138
|
+
input: process.stdin,
|
|
139
|
+
output: process.stdout,
|
|
140
|
+
terminal: true,
|
|
141
|
+
completer: (line) => this.completer(line),
|
|
142
|
+
});
|
|
143
|
+
// Handle special keys
|
|
144
|
+
if (process.stdin.isTTY) {
|
|
145
|
+
readline.emitKeypressEvents(process.stdin);
|
|
146
|
+
process.stdin.setRawMode(true);
|
|
147
|
+
}
|
|
148
|
+
this.running = true;
|
|
149
|
+
await this.mainLoop();
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Main REPL loop
|
|
153
|
+
*/
|
|
154
|
+
async mainLoop() {
|
|
155
|
+
while (this.running && this.rl) {
|
|
156
|
+
try {
|
|
157
|
+
const input = await this.prompt();
|
|
158
|
+
if (!input)
|
|
159
|
+
continue;
|
|
160
|
+
// Save to history
|
|
161
|
+
this.addToHistory(input);
|
|
162
|
+
// Handle commands
|
|
163
|
+
if (input.startsWith('/')) {
|
|
164
|
+
await this.handleCommand(input);
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
// Process input
|
|
168
|
+
await this.processInput(input);
|
|
169
|
+
}
|
|
170
|
+
catch (error) {
|
|
171
|
+
if (error.code === 'ERR_USE_AFTER_CLOSE') {
|
|
172
|
+
break; // readline closed
|
|
173
|
+
}
|
|
174
|
+
console.error(c(`Error: ${error}`, 'red'));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Prompt for input
|
|
180
|
+
*/
|
|
181
|
+
prompt() {
|
|
182
|
+
return new Promise((resolve, reject) => {
|
|
183
|
+
const promptStr = c('genesis', 'cyan') + c('> ', 'bold');
|
|
184
|
+
this.rl?.question(promptStr, (answer) => {
|
|
185
|
+
resolve(answer?.trim() || '');
|
|
186
|
+
});
|
|
187
|
+
this.rl?.on('close', () => reject(new Error('readline closed')));
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Process user input
|
|
192
|
+
*/
|
|
193
|
+
async processInput(input) {
|
|
194
|
+
// Check LLM status
|
|
195
|
+
if (!this.llm.isConfigured()) {
|
|
196
|
+
console.log(c('Error: LLM not configured. Set API key first.', 'red'));
|
|
197
|
+
console.log(c(' export OPENAI_API_KEY=sk-...', 'dim'));
|
|
198
|
+
console.log();
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
// Start thinking spinner
|
|
202
|
+
this.startSpinner('Thinking');
|
|
203
|
+
try {
|
|
204
|
+
// Send to LLM
|
|
205
|
+
const response = await this.llm.chat(input);
|
|
206
|
+
this.stopSpinner();
|
|
207
|
+
// Check for tool calls
|
|
208
|
+
if (this.config.enableTools) {
|
|
209
|
+
const toolCalls = this.dispatcher.parseToolCalls(response.content);
|
|
210
|
+
if (toolCalls.length > 0) {
|
|
211
|
+
console.log(c(`\n📦 ${toolCalls.length} tool call(s) detected`, 'yellow'));
|
|
212
|
+
if (this.config.autoExecuteTools) {
|
|
213
|
+
const dispatchResult = await this.executeTools(toolCalls);
|
|
214
|
+
await this.handleToolResults(dispatchResult, input);
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
// Ask for confirmation
|
|
218
|
+
console.log(c('Tools:', 'dim'));
|
|
219
|
+
for (const call of toolCalls) {
|
|
220
|
+
console.log(c(` - ${call.name}`, 'cyan'));
|
|
221
|
+
}
|
|
222
|
+
const confirm = await this.confirm('Execute these tools?');
|
|
223
|
+
if (confirm) {
|
|
224
|
+
const dispatchResult = await this.executeTools(toolCalls);
|
|
225
|
+
await this.handleToolResults(dispatchResult, input);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
// Print response
|
|
232
|
+
this.printResponse(response.content);
|
|
233
|
+
if (this.config.verbose) {
|
|
234
|
+
console.log(c(` [${response.latency}ms, ${response.usage?.outputTokens || '?'} tokens]`, 'dim'));
|
|
235
|
+
}
|
|
236
|
+
// Persist
|
|
237
|
+
this.store.updateConversation(this.llm.getHistory(), response.usage?.outputTokens);
|
|
238
|
+
this.store.recordInteraction();
|
|
239
|
+
}
|
|
240
|
+
catch (error) {
|
|
241
|
+
this.stopSpinner();
|
|
242
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
243
|
+
console.log(c(`\nError: ${msg}`, 'red'));
|
|
244
|
+
}
|
|
245
|
+
console.log();
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Execute tool calls
|
|
249
|
+
*/
|
|
250
|
+
async executeTools(toolCalls) {
|
|
251
|
+
this.startSpinner('Executing tools');
|
|
252
|
+
const result = await this.dispatcher.dispatch(toolCalls);
|
|
253
|
+
this.stopSpinner();
|
|
254
|
+
return result;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Handle tool results
|
|
258
|
+
*/
|
|
259
|
+
async handleToolResults(result, originalInput) {
|
|
260
|
+
// Print results
|
|
261
|
+
console.log();
|
|
262
|
+
console.log(c('Tool Results:', 'bold'));
|
|
263
|
+
for (const r of result.results) {
|
|
264
|
+
const status = r.success ? c('✓', 'green') : c('✗', 'red');
|
|
265
|
+
console.log(` ${status} ${c(r.name, 'cyan')} (${r.duration}ms)`);
|
|
266
|
+
if (!r.success && r.error) {
|
|
267
|
+
console.log(c(` Error: ${r.error}`, 'red'));
|
|
268
|
+
}
|
|
269
|
+
else if (this.config.verbose && r.data) {
|
|
270
|
+
const preview = this.formatDataPreview(r.data);
|
|
271
|
+
console.log(c(` ${preview}`, 'dim'));
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
console.log(c(`\nTotal: ${result.totalDuration}ms`, 'dim'));
|
|
275
|
+
// Feed results back to LLM for summary
|
|
276
|
+
const resultsContext = this.dispatcher.formatResultsForLLM(result.results);
|
|
277
|
+
this.startSpinner('Summarizing results');
|
|
278
|
+
try {
|
|
279
|
+
const summary = await this.llm.chat(`Based on these tool results, provide a brief summary for the user:\n\n${resultsContext}\n\nOriginal request: ${originalInput}`);
|
|
280
|
+
this.stopSpinner();
|
|
281
|
+
console.log();
|
|
282
|
+
this.printResponse(summary.content);
|
|
283
|
+
// Persist
|
|
284
|
+
this.store.updateConversation(this.llm.getHistory(), summary.usage?.outputTokens);
|
|
285
|
+
}
|
|
286
|
+
catch (error) {
|
|
287
|
+
this.stopSpinner();
|
|
288
|
+
console.log(c('\nCould not summarize results.', 'yellow'));
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Format data preview
|
|
293
|
+
*/
|
|
294
|
+
formatDataPreview(data, maxLength = 100) {
|
|
295
|
+
if (typeof data === 'string') {
|
|
296
|
+
return data.length > maxLength ? data.substring(0, maxLength) + '...' : data;
|
|
297
|
+
}
|
|
298
|
+
const json = JSON.stringify(data);
|
|
299
|
+
return json.length > maxLength ? json.substring(0, maxLength) + '...' : json;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Handle slash commands
|
|
303
|
+
*/
|
|
304
|
+
async handleCommand(input) {
|
|
305
|
+
const [cmd, ...args] = input.slice(1).split(' ');
|
|
306
|
+
const arg = args.join(' ');
|
|
307
|
+
switch (cmd.toLowerCase()) {
|
|
308
|
+
case 'help':
|
|
309
|
+
case 'h':
|
|
310
|
+
this.printHelp();
|
|
311
|
+
break;
|
|
312
|
+
case 'clear':
|
|
313
|
+
case 'c':
|
|
314
|
+
this.llm.clearHistory();
|
|
315
|
+
console.log(c('Conversation cleared.', 'yellow'));
|
|
316
|
+
break;
|
|
317
|
+
case 'status':
|
|
318
|
+
case 's':
|
|
319
|
+
this.printStatus();
|
|
320
|
+
break;
|
|
321
|
+
case 'tools':
|
|
322
|
+
case 't':
|
|
323
|
+
this.printTools();
|
|
324
|
+
break;
|
|
325
|
+
case 'run':
|
|
326
|
+
case 'r':
|
|
327
|
+
if (!arg) {
|
|
328
|
+
console.log(c('Usage: /run <tool_name> <params...>', 'yellow'));
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
await this.runToolDirect(arg);
|
|
332
|
+
}
|
|
333
|
+
break;
|
|
334
|
+
case 'bash':
|
|
335
|
+
case '!':
|
|
336
|
+
if (!arg) {
|
|
337
|
+
console.log(c('Usage: /bash <command> or !<command>', 'yellow'));
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
await this.runBash(arg);
|
|
341
|
+
}
|
|
342
|
+
break;
|
|
343
|
+
case 'edit':
|
|
344
|
+
if (!arg) {
|
|
345
|
+
console.log(c('Usage: /edit <file>', 'yellow'));
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
await this.editFile(arg);
|
|
349
|
+
}
|
|
350
|
+
break;
|
|
351
|
+
case 'cd':
|
|
352
|
+
this.changeDirectory(arg);
|
|
353
|
+
break;
|
|
354
|
+
case 'pwd':
|
|
355
|
+
console.log(c(this.config.workingDirectory || process.cwd(), 'cyan'));
|
|
356
|
+
break;
|
|
357
|
+
case 'ls':
|
|
358
|
+
await this.listFiles(arg);
|
|
359
|
+
break;
|
|
360
|
+
case 'verbose':
|
|
361
|
+
case 'v':
|
|
362
|
+
this.config.verbose = !this.config.verbose;
|
|
363
|
+
console.log(c(`Verbose: ${this.config.verbose ? 'ON' : 'OFF'}`, 'yellow'));
|
|
364
|
+
break;
|
|
365
|
+
case 'history':
|
|
366
|
+
this.printInputHistory();
|
|
367
|
+
break;
|
|
368
|
+
case 'save':
|
|
369
|
+
await this.store.save();
|
|
370
|
+
this.saveInputHistory();
|
|
371
|
+
console.log(c('State saved.', 'green'));
|
|
372
|
+
break;
|
|
373
|
+
case 'quit':
|
|
374
|
+
case 'exit':
|
|
375
|
+
case 'q':
|
|
376
|
+
this.stop();
|
|
377
|
+
break;
|
|
378
|
+
default:
|
|
379
|
+
// Check if it's a shorthand bash command
|
|
380
|
+
if (cmd.startsWith('!')) {
|
|
381
|
+
await this.runBash(cmd.slice(1) + ' ' + arg);
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
console.log(c(`Unknown command: /${cmd}`, 'red'));
|
|
385
|
+
console.log('Type /help for available commands.');
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
console.log();
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Run a tool directly
|
|
392
|
+
*/
|
|
393
|
+
async runToolDirect(input) {
|
|
394
|
+
const parts = input.split(' ');
|
|
395
|
+
const toolName = parts[0];
|
|
396
|
+
const paramsStr = parts.slice(1).join(' ');
|
|
397
|
+
let params = {};
|
|
398
|
+
try {
|
|
399
|
+
if (paramsStr.startsWith('{')) {
|
|
400
|
+
params = JSON.parse(paramsStr);
|
|
401
|
+
}
|
|
402
|
+
else if (paramsStr) {
|
|
403
|
+
// Simple key=value parsing
|
|
404
|
+
for (const part of paramsStr.split(' ')) {
|
|
405
|
+
const [key, ...vals] = part.split('=');
|
|
406
|
+
if (key && vals.length) {
|
|
407
|
+
params[key] = vals.join('=');
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
catch {
|
|
413
|
+
// Use as single 'input' param
|
|
414
|
+
if (paramsStr) {
|
|
415
|
+
params.input = paramsStr;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
const tool = index_js_3.toolRegistry.get(toolName);
|
|
419
|
+
if (!tool) {
|
|
420
|
+
console.log(c(`Tool not found: ${toolName}`, 'red'));
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
this.startSpinner(`Running ${toolName}`);
|
|
424
|
+
try {
|
|
425
|
+
const result = await tool.execute(params);
|
|
426
|
+
this.stopSpinner();
|
|
427
|
+
console.log(c(`✓ ${toolName} completed`, 'green'));
|
|
428
|
+
console.log(JSON.stringify(result, null, 2));
|
|
429
|
+
}
|
|
430
|
+
catch (error) {
|
|
431
|
+
this.stopSpinner();
|
|
432
|
+
console.log(c(`✗ ${toolName} failed: ${error}`, 'red'));
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Run bash command
|
|
437
|
+
*/
|
|
438
|
+
async runBash(command) {
|
|
439
|
+
const bashTool = index_js_3.toolRegistry.get('bash');
|
|
440
|
+
if (!bashTool) {
|
|
441
|
+
console.log(c('Bash tool not available.', 'red'));
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
this.startSpinner('Running');
|
|
445
|
+
try {
|
|
446
|
+
const result = await bashTool.execute({
|
|
447
|
+
command,
|
|
448
|
+
cwd: this.config.workingDirectory,
|
|
449
|
+
});
|
|
450
|
+
this.stopSpinner();
|
|
451
|
+
if (result.stdout) {
|
|
452
|
+
console.log(result.stdout);
|
|
453
|
+
}
|
|
454
|
+
if (result.stderr) {
|
|
455
|
+
console.log(c(result.stderr, 'yellow'));
|
|
456
|
+
}
|
|
457
|
+
if (!result.success) {
|
|
458
|
+
console.log(c(`Exit with error: ${result.error}`, 'red'));
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
catch (error) {
|
|
462
|
+
this.stopSpinner();
|
|
463
|
+
console.log(c(`Error: ${error}`, 'red'));
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Edit file (open in $EDITOR or print content)
|
|
468
|
+
*/
|
|
469
|
+
async editFile(filePath) {
|
|
470
|
+
const fullPath = path.isAbsolute(filePath)
|
|
471
|
+
? filePath
|
|
472
|
+
: path.join(this.config.workingDirectory || process.cwd(), filePath);
|
|
473
|
+
if (!fs.existsSync(fullPath)) {
|
|
474
|
+
console.log(c(`File not found: ${fullPath}`, 'red'));
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
478
|
+
const lines = content.split('\n');
|
|
479
|
+
console.log(c(`File: ${fullPath} (${lines.length} lines)`, 'cyan'));
|
|
480
|
+
console.log(c('─'.repeat(60), 'dim'));
|
|
481
|
+
// Print with line numbers
|
|
482
|
+
for (let i = 0; i < Math.min(lines.length, 50); i++) {
|
|
483
|
+
const lineNum = String(i + 1).padStart(4, ' ');
|
|
484
|
+
console.log(c(lineNum, 'dim') + ' ' + lines[i]);
|
|
485
|
+
}
|
|
486
|
+
if (lines.length > 50) {
|
|
487
|
+
console.log(c(`... and ${lines.length - 50} more lines`, 'dim'));
|
|
488
|
+
}
|
|
489
|
+
console.log(c('─'.repeat(60), 'dim'));
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Change directory
|
|
493
|
+
*/
|
|
494
|
+
changeDirectory(dir) {
|
|
495
|
+
if (!dir) {
|
|
496
|
+
console.log(c(this.config.workingDirectory || process.cwd(), 'cyan'));
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
const newDir = path.isAbsolute(dir)
|
|
500
|
+
? dir
|
|
501
|
+
: path.join(this.config.workingDirectory || process.cwd(), dir);
|
|
502
|
+
if (!fs.existsSync(newDir)) {
|
|
503
|
+
console.log(c(`Directory not found: ${newDir}`, 'red'));
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
this.config.workingDirectory = newDir;
|
|
507
|
+
console.log(c(`Changed to: ${newDir}`, 'green'));
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* List files
|
|
511
|
+
*/
|
|
512
|
+
async listFiles(dir) {
|
|
513
|
+
const targetDir = dir
|
|
514
|
+
? path.isAbsolute(dir)
|
|
515
|
+
? dir
|
|
516
|
+
: path.join(this.config.workingDirectory || process.cwd(), dir)
|
|
517
|
+
: this.config.workingDirectory || process.cwd();
|
|
518
|
+
if (!fs.existsSync(targetDir)) {
|
|
519
|
+
console.log(c(`Directory not found: ${targetDir}`, 'red'));
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
const entries = fs.readdirSync(targetDir, { withFileTypes: true });
|
|
523
|
+
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
524
|
+
if (entry.isDirectory()) {
|
|
525
|
+
console.log(c(entry.name + '/', 'blue', 'bold'));
|
|
526
|
+
}
|
|
527
|
+
else {
|
|
528
|
+
console.log(entry.name);
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Tab completion
|
|
534
|
+
*/
|
|
535
|
+
completer(line) {
|
|
536
|
+
const completions = [];
|
|
537
|
+
// Command completion
|
|
538
|
+
if (line.startsWith('/')) {
|
|
539
|
+
const commands = [
|
|
540
|
+
'/help', '/clear', '/status', '/tools', '/run', '/bash',
|
|
541
|
+
'/edit', '/cd', '/pwd', '/ls', '/verbose', '/history',
|
|
542
|
+
'/save', '/quit'
|
|
543
|
+
];
|
|
544
|
+
const matches = commands.filter(c => c.startsWith(line));
|
|
545
|
+
return [matches, line];
|
|
546
|
+
}
|
|
547
|
+
// File path completion
|
|
548
|
+
if (line.includes('/') || line.includes('.')) {
|
|
549
|
+
try {
|
|
550
|
+
const dir = path.dirname(line) || '.';
|
|
551
|
+
const prefix = path.basename(line);
|
|
552
|
+
const basePath = path.isAbsolute(dir)
|
|
553
|
+
? dir
|
|
554
|
+
: path.join(this.config.workingDirectory || process.cwd(), dir);
|
|
555
|
+
if (fs.existsSync(basePath)) {
|
|
556
|
+
const entries = fs.readdirSync(basePath);
|
|
557
|
+
const matches = entries
|
|
558
|
+
.filter(e => e.startsWith(prefix))
|
|
559
|
+
.map(e => path.join(dir, e));
|
|
560
|
+
return [matches, line];
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
catch {
|
|
564
|
+
// Ignore errors
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
return [completions, line];
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* Confirm prompt
|
|
571
|
+
*/
|
|
572
|
+
confirm(question) {
|
|
573
|
+
return new Promise((resolve) => {
|
|
574
|
+
this.rl?.question(c(`${question} [y/N] `, 'yellow'), (answer) => {
|
|
575
|
+
resolve(answer.toLowerCase() === 'y' || answer.toLowerCase() === 'yes');
|
|
576
|
+
});
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Start spinner
|
|
581
|
+
*/
|
|
582
|
+
startSpinner(message) {
|
|
583
|
+
this.currentSpinnerFrame = 0;
|
|
584
|
+
process.stdout.write(`${SPINNER[0]} ${c(message + '...', 'dim')}`);
|
|
585
|
+
this.spinnerInterval = setInterval(() => {
|
|
586
|
+
this.currentSpinnerFrame = (this.currentSpinnerFrame + 1) % SPINNER.length;
|
|
587
|
+
process.stdout.write(`\r${SPINNER[this.currentSpinnerFrame]} ${c(message + '...', 'dim')}`);
|
|
588
|
+
}, 80);
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* Stop spinner
|
|
592
|
+
*/
|
|
593
|
+
stopSpinner() {
|
|
594
|
+
if (this.spinnerInterval) {
|
|
595
|
+
clearInterval(this.spinnerInterval);
|
|
596
|
+
this.spinnerInterval = null;
|
|
597
|
+
}
|
|
598
|
+
process.stdout.write('\r\x1b[K'); // Clear line
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* Show progress
|
|
602
|
+
*/
|
|
603
|
+
showProgress(status) {
|
|
604
|
+
if (!this.config.verbose)
|
|
605
|
+
return;
|
|
606
|
+
const pct = Math.round((status.current / status.total) * 100);
|
|
607
|
+
const bar = '█'.repeat(Math.floor(pct / 5)) + '░'.repeat(20 - Math.floor(pct / 5));
|
|
608
|
+
process.stdout.write(`\r [${bar}] ${pct}% ${status.message || ''}`);
|
|
609
|
+
if (status.phase === 'complete') {
|
|
610
|
+
console.log();
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* Print response with formatting
|
|
615
|
+
*/
|
|
616
|
+
printResponse(content) {
|
|
617
|
+
// Basic syntax highlighting for code blocks
|
|
618
|
+
const formatted = content.replace(/```(\w+)?\n([\s\S]*?)```/g, (_, lang, code) => {
|
|
619
|
+
return c(`\`\`\`${lang || ''}\n`, 'dim') +
|
|
620
|
+
c(code, 'cyan') +
|
|
621
|
+
c('```', 'dim');
|
|
622
|
+
});
|
|
623
|
+
console.log(c('Genesis: ', 'green', 'bold') + formatted);
|
|
624
|
+
}
|
|
625
|
+
/**
|
|
626
|
+
* Print banner
|
|
627
|
+
*/
|
|
628
|
+
printBanner() {
|
|
629
|
+
console.log(`
|
|
630
|
+
${c('╔════════════════════════════════════════════════════════════════╗', 'cyan')}
|
|
631
|
+
${c('║', 'cyan')} ${c('GENESIS', 'bold', 'white')} ${c('Interactive Shell', 'dim')} ${c('║', 'cyan')}
|
|
632
|
+
${c('║', 'cyan')} ${c('Tools: bash, edit, git, mcp | Type /help for commands', 'dim')} ${c('║', 'cyan')}
|
|
633
|
+
${c('╚════════════════════════════════════════════════════════════════╝', 'cyan')}
|
|
634
|
+
`);
|
|
635
|
+
}
|
|
636
|
+
/**
|
|
637
|
+
* Print status
|
|
638
|
+
*/
|
|
639
|
+
printStatus() {
|
|
640
|
+
const llmStatus = this.llm.status();
|
|
641
|
+
const tools = this.dispatcher.listTools();
|
|
642
|
+
console.log(c('Status:', 'bold'));
|
|
643
|
+
console.log(` LLM: ${llmStatus.configured ? c(llmStatus.provider, 'green') : c('Not configured', 'red')}`);
|
|
644
|
+
console.log(` Model: ${c(llmStatus.model, 'dim')}`);
|
|
645
|
+
console.log(` Tools: ${c(String(tools.local.length), 'cyan')} local, ${c(String(Object.keys(tools.mcp).length), 'cyan')} MCP servers`);
|
|
646
|
+
console.log(` Dir: ${c(this.config.workingDirectory || process.cwd(), 'dim')}`);
|
|
647
|
+
console.log();
|
|
648
|
+
}
|
|
649
|
+
/**
|
|
650
|
+
* Print help
|
|
651
|
+
*/
|
|
652
|
+
printHelp() {
|
|
653
|
+
console.log(c('Commands:', 'bold'));
|
|
654
|
+
console.log(' /help, /h Show this help');
|
|
655
|
+
console.log(' /status, /s Show status');
|
|
656
|
+
console.log(' /tools, /t List available tools');
|
|
657
|
+
console.log(' /run <tool> Run a tool directly');
|
|
658
|
+
console.log(' /bash <cmd> Run bash command');
|
|
659
|
+
console.log(' /edit <file> View file');
|
|
660
|
+
console.log(' /cd <dir> Change directory');
|
|
661
|
+
console.log(' /ls [dir] List files');
|
|
662
|
+
console.log(' /clear, /c Clear conversation');
|
|
663
|
+
console.log(' /verbose, /v Toggle verbose mode');
|
|
664
|
+
console.log(' /save Save state');
|
|
665
|
+
console.log(' /quit, /q Exit');
|
|
666
|
+
console.log();
|
|
667
|
+
console.log(c('Tips:', 'dim'));
|
|
668
|
+
console.log(c(' - Just type naturally to chat with Genesis', 'dim'));
|
|
669
|
+
console.log(c(' - Genesis will automatically use tools when needed', 'dim'));
|
|
670
|
+
console.log(c(' - Use !<command> as shorthand for /bash <command>', 'dim'));
|
|
671
|
+
console.log();
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* Print tools
|
|
675
|
+
*/
|
|
676
|
+
printTools() {
|
|
677
|
+
const tools = this.dispatcher.listTools();
|
|
678
|
+
console.log(c('Local Tools:', 'bold'));
|
|
679
|
+
for (const name of tools.local) {
|
|
680
|
+
console.log(` ${c(name, 'cyan')}`);
|
|
681
|
+
}
|
|
682
|
+
console.log();
|
|
683
|
+
console.log(c('MCP Tools:', 'bold'));
|
|
684
|
+
for (const [server, serverTools] of Object.entries(tools.mcp)) {
|
|
685
|
+
console.log(` ${c(server, 'magenta')}: ${serverTools.join(', ')}`);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
/**
|
|
689
|
+
* Input history management
|
|
690
|
+
*/
|
|
691
|
+
loadInputHistory() {
|
|
692
|
+
if (!this.config.historyFile)
|
|
693
|
+
return;
|
|
694
|
+
try {
|
|
695
|
+
if (fs.existsSync(this.config.historyFile)) {
|
|
696
|
+
const content = fs.readFileSync(this.config.historyFile, 'utf-8');
|
|
697
|
+
this.inputHistory = content.split('\n').filter(l => l.trim());
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
catch {
|
|
701
|
+
// Ignore errors
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
saveInputHistory() {
|
|
705
|
+
if (!this.config.historyFile)
|
|
706
|
+
return;
|
|
707
|
+
try {
|
|
708
|
+
const content = this.inputHistory.slice(-this.config.maxHistorySize).join('\n');
|
|
709
|
+
fs.writeFileSync(this.config.historyFile, content);
|
|
710
|
+
}
|
|
711
|
+
catch {
|
|
712
|
+
// Ignore errors
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
addToHistory(input) {
|
|
716
|
+
if (input && input !== this.inputHistory[this.inputHistory.length - 1]) {
|
|
717
|
+
this.inputHistory.push(input);
|
|
718
|
+
}
|
|
719
|
+
this.historyIndex = -1;
|
|
720
|
+
}
|
|
721
|
+
printInputHistory() {
|
|
722
|
+
console.log(c('Input History:', 'bold'));
|
|
723
|
+
const recent = this.inputHistory.slice(-20);
|
|
724
|
+
for (let i = 0; i < recent.length; i++) {
|
|
725
|
+
console.log(c(` ${i + 1}. `, 'dim') + recent[i]);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
/**
|
|
729
|
+
* Stop session
|
|
730
|
+
*/
|
|
731
|
+
stop() {
|
|
732
|
+
this.running = false;
|
|
733
|
+
this.stopSpinner();
|
|
734
|
+
// Save state
|
|
735
|
+
console.log(c('\nSaving...', 'dim'));
|
|
736
|
+
this.store.updateConversation(this.llm.getHistory());
|
|
737
|
+
this.store.close();
|
|
738
|
+
this.saveInputHistory();
|
|
739
|
+
console.log(c('Goodbye!\n', 'cyan'));
|
|
740
|
+
this.rl?.close();
|
|
741
|
+
process.exit(0);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
exports.InteractiveSession = InteractiveSession;
|
|
745
|
+
// ============================================================================
|
|
746
|
+
// Factory
|
|
747
|
+
// ============================================================================
|
|
748
|
+
function createInteractiveSession(config) {
|
|
749
|
+
return new InteractiveSession(config);
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* Start interactive session (convenience function)
|
|
753
|
+
*/
|
|
754
|
+
async function startInteractive(config) {
|
|
755
|
+
const session = createInteractiveSession(config);
|
|
756
|
+
await session.start();
|
|
757
|
+
}
|