thatgfsj-code 0.2.1
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/.patches/0001-fix-repl-replace-readline-with-inquirer-input-for-ke.patch +279 -0
- package/.patches/0002-fix-repl-stream-AI-output-directly-to-stdout-so-term.patch +564 -0
- package/.patches/0003-fix-session-break-the-hallucination-loop-in-assistan.patch +194 -0
- package/.patches/0004-chore-release-bump-version-to-0.2.1.patch +24 -0
- package/LICENSE +21 -0
- package/README.md +100 -0
- package/ROADMAP.md +107 -0
- package/dist/agent/core.d.ts +56 -0
- package/dist/agent/core.d.ts.map +1 -0
- package/dist/agent/core.js +142 -0
- package/dist/agent/core.js.map +1 -0
- package/dist/agent/index.d.ts +8 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +8 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/intent.d.ts +36 -0
- package/dist/agent/intent.d.ts.map +1 -0
- package/dist/agent/intent.js +146 -0
- package/dist/agent/intent.js.map +1 -0
- package/dist/agent/streaming.d.ts +50 -0
- package/dist/agent/streaming.d.ts.map +1 -0
- package/dist/agent/streaming.js +110 -0
- package/dist/agent/streaming.js.map +1 -0
- package/dist/core/ai-engine.d.ts +59 -0
- package/dist/core/ai-engine.d.ts.map +1 -0
- package/dist/core/ai-engine.js +378 -0
- package/dist/core/ai-engine.js.map +1 -0
- package/dist/core/cli.d.ts +21 -0
- package/dist/core/cli.d.ts.map +1 -0
- package/dist/core/cli.js +143 -0
- package/dist/core/cli.js.map +1 -0
- package/dist/core/config.d.ts +38 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +129 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/context-compactor.d.ts +54 -0
- package/dist/core/context-compactor.d.ts.map +1 -0
- package/dist/core/context-compactor.js +197 -0
- package/dist/core/context-compactor.js.map +1 -0
- package/dist/core/hooks.d.ts +75 -0
- package/dist/core/hooks.d.ts.map +1 -0
- package/dist/core/hooks.js +146 -0
- package/dist/core/hooks.js.map +1 -0
- package/dist/core/permissions.d.ts +52 -0
- package/dist/core/permissions.d.ts.map +1 -0
- package/dist/core/permissions.js +237 -0
- package/dist/core/permissions.js.map +1 -0
- package/dist/core/session.d.ts +54 -0
- package/dist/core/session.d.ts.map +1 -0
- package/dist/core/session.js +147 -0
- package/dist/core/session.js.map +1 -0
- package/dist/core/skills.d.ts +60 -0
- package/dist/core/skills.d.ts.map +1 -0
- package/dist/core/skills.js +175 -0
- package/dist/core/skills.js.map +1 -0
- package/dist/core/state.d.ts +60 -0
- package/dist/core/state.d.ts.map +1 -0
- package/dist/core/state.js +106 -0
- package/dist/core/state.js.map +1 -0
- package/dist/core/subagent.d.ts +68 -0
- package/dist/core/subagent.d.ts.map +1 -0
- package/dist/core/subagent.js +142 -0
- package/dist/core/subagent.js.map +1 -0
- package/dist/core/system-prompt.d.ts +40 -0
- package/dist/core/system-prompt.d.ts.map +1 -0
- package/dist/core/system-prompt.js +138 -0
- package/dist/core/system-prompt.js.map +1 -0
- package/dist/core/tool-registry.d.ts +53 -0
- package/dist/core/tool-registry.d.ts.map +1 -0
- package/dist/core/tool-registry.js +138 -0
- package/dist/core/tool-registry.js.map +1 -0
- package/dist/core/types.d.ts +206 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +127 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +481 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/client.d.ts +83 -0
- package/dist/mcp/client.d.ts.map +1 -0
- package/dist/mcp/client.js +267 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/repl/index.d.ts +8 -0
- package/dist/repl/index.d.ts.map +1 -0
- package/dist/repl/index.js +8 -0
- package/dist/repl/index.js.map +1 -0
- package/dist/repl/input.d.ts +61 -0
- package/dist/repl/input.d.ts.map +1 -0
- package/dist/repl/input.js +127 -0
- package/dist/repl/input.js.map +1 -0
- package/dist/repl/loop.d.ts +53 -0
- package/dist/repl/loop.d.ts.map +1 -0
- package/dist/repl/loop.js +241 -0
- package/dist/repl/loop.js.map +1 -0
- package/dist/repl/output.d.ts +105 -0
- package/dist/repl/output.d.ts.map +1 -0
- package/dist/repl/output.js +197 -0
- package/dist/repl/output.js.map +1 -0
- package/dist/repl/welcome.d.ts +68 -0
- package/dist/repl/welcome.d.ts.map +1 -0
- package/dist/repl/welcome.js +249 -0
- package/dist/repl/welcome.js.map +1 -0
- package/dist/tools/file.d.ts +46 -0
- package/dist/tools/file.d.ts.map +1 -0
- package/dist/tools/file.js +100 -0
- package/dist/tools/file.js.map +1 -0
- package/dist/tools/git.d.ts +52 -0
- package/dist/tools/git.d.ts.map +1 -0
- package/dist/tools/git.js +112 -0
- package/dist/tools/git.js.map +1 -0
- package/dist/tools/index.d.ts +22 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +43 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/search.d.ts +36 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +223 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/shell.d.ts +57 -0
- package/dist/tools/shell.d.ts.map +1 -0
- package/dist/tools/shell.js +153 -0
- package/dist/tools/shell.js.map +1 -0
- package/dist/utils/diff-preview.d.ts +42 -0
- package/dist/utils/diff-preview.d.ts.map +1 -0
- package/dist/utils/diff-preview.js +174 -0
- package/dist/utils/diff-preview.js.map +1 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +8 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/memory.d.ts +81 -0
- package/dist/utils/memory.d.ts.map +1 -0
- package/dist/utils/memory.js +186 -0
- package/dist/utils/memory.js.map +1 -0
- package/dist/utils/project-context.d.ts +62 -0
- package/dist/utils/project-context.d.ts.map +1 -0
- package/dist/utils/project-context.js +197 -0
- package/dist/utils/project-context.js.map +1 -0
- package/docs/API_KEY_GUIDE.md +236 -0
- package/docs/FAQ.md +182 -0
- package/install.bat +63 -0
- package/install.ps1 +238 -0
- package/install.sh +113 -0
- package/package.json +36 -0
- package/src/agent/core.ts +179 -0
- package/src/agent/index.ts +8 -0
- package/src/agent/intent.ts +181 -0
- package/src/agent/streaming.ts +132 -0
- package/src/core/ai-engine.ts +437 -0
- package/src/core/cli.ts +171 -0
- package/src/core/config.ts +147 -0
- package/src/core/context-compactor.ts +245 -0
- package/src/core/hooks.ts +196 -0
- package/src/core/permissions.ts +308 -0
- package/src/core/session.ts +165 -0
- package/src/core/skills.ts +208 -0
- package/src/core/state.ts +120 -0
- package/src/core/subagent.ts +195 -0
- package/src/core/system-prompt.ts +163 -0
- package/src/core/tool-registry.ts +157 -0
- package/src/core/types.ts +280 -0
- package/src/index.ts +544 -0
- package/src/mcp/client.ts +330 -0
- package/src/repl/index.ts +8 -0
- package/src/repl/input.ts +139 -0
- package/src/repl/loop.ts +280 -0
- package/src/repl/output.ts +222 -0
- package/src/repl/welcome.ts +296 -0
- package/src/tools/file.ts +117 -0
- package/src/tools/git.ts +132 -0
- package/src/tools/index.ts +48 -0
- package/src/tools/search.ts +263 -0
- package/src/tools/shell.ts +181 -0
- package/src/utils/diff-preview.ts +202 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/memory.ts +223 -0
- package/src/utils/project-context.ts +207 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S07: MCP Client (Model Context Protocol)
|
|
3
|
+
* Connect to MCP servers and expose their tools as agent tools
|
|
4
|
+
*
|
|
5
|
+
* MCP turns the agent from a closed system into an open platform.
|
|
6
|
+
* Any server can expose tools via the MCP JSON-RPC 2.0 protocol.
|
|
7
|
+
*/
|
|
8
|
+
import { Tool, ToolResult } from '../core/types.js';
|
|
9
|
+
export declare class MCPClient {
|
|
10
|
+
private process;
|
|
11
|
+
private tools;
|
|
12
|
+
private requestId;
|
|
13
|
+
private pendingRequests;
|
|
14
|
+
private name;
|
|
15
|
+
private connected;
|
|
16
|
+
constructor(name: string);
|
|
17
|
+
/**
|
|
18
|
+
* S07: Connect to an MCP server
|
|
19
|
+
* @param command Command to run (e.g., 'npx', 'node')
|
|
20
|
+
* @param args Arguments (e.g., ['-y', '@modelcontextprotocol/server-filesystem', '/path/to/dir'])
|
|
21
|
+
*/
|
|
22
|
+
connect(command: string, args: string[]): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* S07: Handle incoming JSON-RPC message
|
|
25
|
+
*/
|
|
26
|
+
private handleMessage;
|
|
27
|
+
/**
|
|
28
|
+
* S07: Send a JSON-RPC request
|
|
29
|
+
*/
|
|
30
|
+
private sendRequest;
|
|
31
|
+
/**
|
|
32
|
+
* S07: Send a notification (no response expected)
|
|
33
|
+
*/
|
|
34
|
+
private sendNotification;
|
|
35
|
+
/**
|
|
36
|
+
* S07: Call an MCP tool
|
|
37
|
+
*/
|
|
38
|
+
callTool(name: string, arguments_: Record<string, any>): Promise<ToolResult>;
|
|
39
|
+
/**
|
|
40
|
+
* S07: List tools from MCP server
|
|
41
|
+
*/
|
|
42
|
+
private listTools;
|
|
43
|
+
/**
|
|
44
|
+
* S07: Get registered tools as agent Tool[]
|
|
45
|
+
*/
|
|
46
|
+
getTools(): Tool[];
|
|
47
|
+
/**
|
|
48
|
+
* S07: Get tool names
|
|
49
|
+
*/
|
|
50
|
+
getToolNames(): string[];
|
|
51
|
+
/**
|
|
52
|
+
* S07: Check if connected
|
|
53
|
+
*/
|
|
54
|
+
isConnected(): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* S07: Disconnect from MCP server
|
|
57
|
+
*/
|
|
58
|
+
disconnect(): void;
|
|
59
|
+
}
|
|
60
|
+
export declare class MCPServerManager {
|
|
61
|
+
private clients;
|
|
62
|
+
/**
|
|
63
|
+
* S07: Add and connect an MCP server
|
|
64
|
+
*/
|
|
65
|
+
addServer(name: string, command: string, args: string[]): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* S07: Get all tools from all servers
|
|
68
|
+
*/
|
|
69
|
+
getAllTools(): Tool[];
|
|
70
|
+
/**
|
|
71
|
+
* S07: Get tool names from all servers
|
|
72
|
+
*/
|
|
73
|
+
getAllToolNames(): string[];
|
|
74
|
+
/**
|
|
75
|
+
* S07: Disconnect a server
|
|
76
|
+
*/
|
|
77
|
+
removeServer(name: string): void;
|
|
78
|
+
/**
|
|
79
|
+
* S07: Get server status
|
|
80
|
+
*/
|
|
81
|
+
getStatus(): Record<string, boolean>;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/mcp/client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AA8BpD,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,KAAK,CAAmC;IAChD,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,eAAe,CAGR;IACf,OAAO,CAAC,IAAI,CAAS;IACrB,OAAO,CAAC,SAAS,CAAS;gBAEd,IAAI,EAAE,MAAM;IAIxB;;;;OAIG;IACG,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAqD7D;;OAEG;IACH,OAAO,CAAC,aAAa;IAoBrB;;OAEG;IACH,OAAO,CAAC,WAAW;IA6BnB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAYxB;;OAEG;IACG,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC;IAmBlF;;OAEG;YACW,SAAS;IAgBvB;;OAEG;IACH,QAAQ,IAAI,IAAI,EAAE;IAgBlB;;OAEG;IACH,YAAY,IAAI,MAAM,EAAE;IAIxB;;OAEG;IACH,WAAW,IAAI,OAAO;IAItB;;OAEG;IACH,UAAU,IAAI,IAAI;CASnB;AAID,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,OAAO,CAAqC;IAEpD;;OAEG;IACG,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAM7E;;OAEG;IACH,WAAW,IAAI,IAAI,EAAE;IAQrB;;OAEG;IACH,eAAe,IAAI,MAAM,EAAE;IAU3B;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAQhC;;OAEG;IACH,SAAS,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAOrC"}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S07: MCP Client (Model Context Protocol)
|
|
3
|
+
* Connect to MCP servers and expose their tools as agent tools
|
|
4
|
+
*
|
|
5
|
+
* MCP turns the agent from a closed system into an open platform.
|
|
6
|
+
* Any server can expose tools via the MCP JSON-RPC 2.0 protocol.
|
|
7
|
+
*/
|
|
8
|
+
import { spawn } from 'child_process';
|
|
9
|
+
// ==================== MCP Client ====================
|
|
10
|
+
export class MCPClient {
|
|
11
|
+
process = null;
|
|
12
|
+
tools = new Map();
|
|
13
|
+
requestId = 0;
|
|
14
|
+
pendingRequests = new Map();
|
|
15
|
+
name;
|
|
16
|
+
connected = false;
|
|
17
|
+
constructor(name) {
|
|
18
|
+
this.name = name;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* S07: Connect to an MCP server
|
|
22
|
+
* @param command Command to run (e.g., 'npx', 'node')
|
|
23
|
+
* @param args Arguments (e.g., ['-y', '@modelcontextprotocol/server-filesystem', '/path/to/dir'])
|
|
24
|
+
*/
|
|
25
|
+
async connect(command, args) {
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
this.process = spawn(command, args, {
|
|
28
|
+
stdio: ['pipe', 'pipe', 'pipe']
|
|
29
|
+
});
|
|
30
|
+
let buffer = '';
|
|
31
|
+
this.process.stdout?.on('data', (data) => {
|
|
32
|
+
buffer += data.toString();
|
|
33
|
+
const lines = buffer.split('\n');
|
|
34
|
+
buffer = lines.pop() || '';
|
|
35
|
+
for (const line of lines) {
|
|
36
|
+
if (line.trim()) {
|
|
37
|
+
this.handleMessage(line);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
this.process.stderr?.on('data', (data) => {
|
|
42
|
+
console.error(`[MCP ${this.name}] stderr:`, data.toString().trim());
|
|
43
|
+
});
|
|
44
|
+
this.process.on('error', (err) => {
|
|
45
|
+
reject(err);
|
|
46
|
+
});
|
|
47
|
+
this.process.on('close', (code) => {
|
|
48
|
+
this.connected = false;
|
|
49
|
+
console.log(`[MCP ${this.name}] exited with code ${code}`);
|
|
50
|
+
});
|
|
51
|
+
// Initialize MCP connection
|
|
52
|
+
this.sendRequest('initialize', {
|
|
53
|
+
protocolVersion: '2024-11-05',
|
|
54
|
+
capabilities: { tools: {} },
|
|
55
|
+
clientInfo: { name: 'thatgfsj-code', version: '1.0.0' }
|
|
56
|
+
}).then(() => {
|
|
57
|
+
this.connected = true;
|
|
58
|
+
// Send initialized notification
|
|
59
|
+
this.sendNotification('initialized', {});
|
|
60
|
+
// List available tools
|
|
61
|
+
return this.listTools();
|
|
62
|
+
}).then(() => {
|
|
63
|
+
resolve();
|
|
64
|
+
}).catch(reject);
|
|
65
|
+
// Timeout
|
|
66
|
+
setTimeout(() => reject(new Error('MCP connection timeout')), 30000);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* S07: Handle incoming JSON-RPC message
|
|
71
|
+
*/
|
|
72
|
+
handleMessage(raw) {
|
|
73
|
+
try {
|
|
74
|
+
const msg = JSON.parse(raw);
|
|
75
|
+
// Handle response
|
|
76
|
+
const pending = this.pendingRequests.get(msg.id);
|
|
77
|
+
if (pending) {
|
|
78
|
+
this.pendingRequests.delete(msg.id);
|
|
79
|
+
if (msg.error) {
|
|
80
|
+
pending.reject(new Error(msg.error.message));
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
pending.resolve(msg.result);
|
|
84
|
+
}
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
// Not JSON, ignore
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* S07: Send a JSON-RPC request
|
|
94
|
+
*/
|
|
95
|
+
sendRequest(method, params) {
|
|
96
|
+
return new Promise((resolve, reject) => {
|
|
97
|
+
if (!this.process?.connected) {
|
|
98
|
+
reject(new Error('MCP process not connected'));
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const id = ++this.requestId;
|
|
102
|
+
this.pendingRequests.set(id, { resolve, reject });
|
|
103
|
+
const request = {
|
|
104
|
+
jsonrpc: '2.0',
|
|
105
|
+
id,
|
|
106
|
+
method,
|
|
107
|
+
params
|
|
108
|
+
};
|
|
109
|
+
this.process.stdin?.write(JSON.stringify(request) + '\n');
|
|
110
|
+
// Timeout
|
|
111
|
+
setTimeout(() => {
|
|
112
|
+
if (this.pendingRequests.has(id)) {
|
|
113
|
+
this.pendingRequests.delete(id);
|
|
114
|
+
reject(new Error('MCP request timeout: ' + method));
|
|
115
|
+
}
|
|
116
|
+
}, 30000);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* S07: Send a notification (no response expected)
|
|
121
|
+
*/
|
|
122
|
+
sendNotification(method, params) {
|
|
123
|
+
if (!this.process?.connected)
|
|
124
|
+
return;
|
|
125
|
+
const notification = {
|
|
126
|
+
jsonrpc: '2.0',
|
|
127
|
+
method,
|
|
128
|
+
params
|
|
129
|
+
};
|
|
130
|
+
this.process.stdin?.write(JSON.stringify(notification) + '\n');
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* S07: Call an MCP tool
|
|
134
|
+
*/
|
|
135
|
+
async callTool(name, arguments_) {
|
|
136
|
+
try {
|
|
137
|
+
const result = await this.sendRequest('tools/call', {
|
|
138
|
+
name,
|
|
139
|
+
arguments: arguments_
|
|
140
|
+
});
|
|
141
|
+
return {
|
|
142
|
+
success: true,
|
|
143
|
+
output: typeof result === 'string' ? result : JSON.stringify(result)
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
return {
|
|
148
|
+
success: false,
|
|
149
|
+
error: error.message
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* S07: List tools from MCP server
|
|
155
|
+
*/
|
|
156
|
+
async listTools() {
|
|
157
|
+
try {
|
|
158
|
+
const result = await this.sendRequest('tools/list', {});
|
|
159
|
+
const tools = result.tools || [];
|
|
160
|
+
this.tools.clear();
|
|
161
|
+
for (const tool of tools) {
|
|
162
|
+
this.tools.set(tool.name, tool);
|
|
163
|
+
}
|
|
164
|
+
console.log(`[MCP ${this.name}] Loaded ${tools.length} tools:`, [...this.tools.keys()].join(', '));
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
console.error(`[MCP ${this.name}] Failed to list tools:`, error.message);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* S07: Get registered tools as agent Tool[]
|
|
172
|
+
*/
|
|
173
|
+
getTools() {
|
|
174
|
+
return [...this.tools.values()].map(mcpTool => ({
|
|
175
|
+
name: this.name + ':' + mcpTool.name,
|
|
176
|
+
description: mcpTool.description,
|
|
177
|
+
parameters: Object.entries(mcpTool.inputSchema.properties || {}).map(([name, schema]) => ({
|
|
178
|
+
name,
|
|
179
|
+
type: schema.type || 'string',
|
|
180
|
+
description: schema.description || '',
|
|
181
|
+
required: (mcpTool.inputSchema.required || []).includes(name)
|
|
182
|
+
})),
|
|
183
|
+
execute: async (params) => {
|
|
184
|
+
return this.callTool(mcpTool.name, params);
|
|
185
|
+
}
|
|
186
|
+
}));
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* S07: Get tool names
|
|
190
|
+
*/
|
|
191
|
+
getToolNames() {
|
|
192
|
+
return [...this.tools.keys()];
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* S07: Check if connected
|
|
196
|
+
*/
|
|
197
|
+
isConnected() {
|
|
198
|
+
return this.connected;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* S07: Disconnect from MCP server
|
|
202
|
+
*/
|
|
203
|
+
disconnect() {
|
|
204
|
+
if (this.process) {
|
|
205
|
+
this.process.kill();
|
|
206
|
+
this.process = null;
|
|
207
|
+
}
|
|
208
|
+
this.connected = false;
|
|
209
|
+
this.tools.clear();
|
|
210
|
+
this.pendingRequests.clear();
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
// ==================== MCP Server Manager ====================
|
|
214
|
+
export class MCPServerManager {
|
|
215
|
+
clients = new Map();
|
|
216
|
+
/**
|
|
217
|
+
* S07: Add and connect an MCP server
|
|
218
|
+
*/
|
|
219
|
+
async addServer(name, command, args) {
|
|
220
|
+
const client = new MCPClient(name);
|
|
221
|
+
await client.connect(command, args);
|
|
222
|
+
this.clients.set(name, client);
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* S07: Get all tools from all servers
|
|
226
|
+
*/
|
|
227
|
+
getAllTools() {
|
|
228
|
+
const allTools = [];
|
|
229
|
+
for (const client of this.clients.values()) {
|
|
230
|
+
allTools.push(...client.getTools());
|
|
231
|
+
}
|
|
232
|
+
return allTools;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* S07: Get tool names from all servers
|
|
236
|
+
*/
|
|
237
|
+
getAllToolNames() {
|
|
238
|
+
const names = [];
|
|
239
|
+
for (const [serverName, client] of this.clients) {
|
|
240
|
+
for (const toolName of client.getToolNames()) {
|
|
241
|
+
names.push(serverName + ':' + toolName);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return names;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* S07: Disconnect a server
|
|
248
|
+
*/
|
|
249
|
+
removeServer(name) {
|
|
250
|
+
const client = this.clients.get(name);
|
|
251
|
+
if (client) {
|
|
252
|
+
client.disconnect();
|
|
253
|
+
this.clients.delete(name);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* S07: Get server status
|
|
258
|
+
*/
|
|
259
|
+
getStatus() {
|
|
260
|
+
const status = {};
|
|
261
|
+
for (const [name, client] of this.clients) {
|
|
262
|
+
status[name] = client.isConnected();
|
|
263
|
+
}
|
|
264
|
+
return status;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/mcp/client.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,KAAK,EAAgB,MAAM,eAAe,CAAC;AA6BpD,uDAAuD;AAEvD,MAAM,OAAO,SAAS;IACZ,OAAO,GAAwB,IAAI,CAAC;IACpC,KAAK,GAAyB,IAAI,GAAG,EAAE,CAAC;IACxC,SAAS,GAAG,CAAC,CAAC;IACd,eAAe,GAGlB,IAAI,GAAG,EAAE,CAAC;IACP,IAAI,CAAS;IACb,SAAS,GAAG,KAAK,CAAC;IAE1B,YAAY,IAAY;QACtB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,OAAO,CAAC,OAAe,EAAE,IAAc;QAC3C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE;gBAClC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;aAChC,CAAC,CAAC;YAEH,IAAI,MAAM,GAAG,EAAE,CAAC;YAEhB,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;gBAC/C,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAC1B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACjC,MAAM,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;gBAE3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;oBACzB,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;wBAChB,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;oBAC3B,CAAC;gBACH,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;gBAC/C,OAAO,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,IAAI,WAAW,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;YACtE,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBAC/B,MAAM,CAAC,GAAG,CAAC,CAAC;YACd,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;gBAChC,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;gBACvB,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,IAAI,sBAAsB,IAAI,EAAE,CAAC,CAAC;YAC7D,CAAC,CAAC,CAAC;YAEH,4BAA4B;YAC5B,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE;gBAC7B,eAAe,EAAE,YAAY;gBAC7B,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;gBAC3B,UAAU,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,OAAO,EAAE;aACxD,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;gBACX,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;gBACtB,gCAAgC;gBAChC,IAAI,CAAC,gBAAgB,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;gBACzC,uBAAuB;gBACvB,OAAO,IAAI,CAAC,SAAS,EAAE,CAAC;YAC1B,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;gBACX,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;YAEjB,UAAU;YACV,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QACvE,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,aAAa,CAAC,GAAW;QAC/B,IAAI,CAAC;YACH,MAAM,GAAG,GAAuB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAEhD,kBAAkB;YAClB,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACjD,IAAI,OAAO,EAAE,CAAC;gBACZ,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACpC,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;oBACd,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;gBAC/C,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBAC9B,CAAC;gBACD,OAAO;YACT,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,mBAAmB;QACrB,CAAC;IACH,CAAC;IAED;;OAEG;IACK,WAAW,CAAC,MAAc,EAAE,MAAW;QAC7C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC;gBAC7B,MAAM,CAAC,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC,CAAC;gBAC/C,OAAO;YACT,CAAC;YAED,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC;YAC5B,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;YAElD,MAAM,OAAO,GAAsB;gBACjC,OAAO,EAAE,KAAK;gBACd,EAAE;gBACF,MAAM;gBACN,MAAM;aACP,CAAC;YAEF,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;YAE1D,UAAU;YACV,UAAU,CAAC,GAAG,EAAE;gBACd,IAAI,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;oBACjC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;oBAChC,MAAM,CAAC,IAAI,KAAK,CAAC,uBAAuB,GAAG,MAAM,CAAC,CAAC,CAAC;gBACtD,CAAC;YACH,CAAC,EAAE,KAAK,CAAC,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,gBAAgB,CAAC,MAAc,EAAE,MAAW;QAClD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS;YAAE,OAAO;QAErC,MAAM,YAAY,GAAG;YACnB,OAAO,EAAE,KAAK;YACd,MAAM;YACN,MAAM;SACP,CAAC;QAEF,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC,CAAC;IACjE,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,QAAQ,CAAC,IAAY,EAAE,UAA+B;QAC1D,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE;gBAClD,IAAI;gBACJ,SAAS,EAAE,UAAU;aACtB,CAAC,CAAC;YAEH,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,MAAM,EAAE,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;aACrE,CAAC;QACJ,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,KAAK,CAAC,OAAO;aACrB,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,SAAS;QACrB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;YACxD,MAAM,KAAK,GAAc,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;YAE5C,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACnB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;gBACzB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;YAClC,CAAC;YAED,OAAO,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,IAAI,YAAY,KAAK,CAAC,MAAM,SAAS,EAAE,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACrG,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,IAAI,yBAAyB,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC;IAED;;OAEG;IACH,QAAQ;QACN,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAC9C,IAAI,EAAE,IAAI,CAAC,IAAI,GAAG,GAAG,GAAG,OAAO,CAAC,IAAI;YACpC,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,UAAU,EAAE,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAgB,EAAE,EAAE,CAAC,CAAC;gBACvG,IAAI;gBACJ,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,QAAQ;gBAC7B,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,EAAE;gBACrC,QAAQ,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;aAC9D,CAAC,CAAC;YACH,OAAO,EAAE,KAAK,EAAE,MAA2B,EAAuB,EAAE;gBAClE,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;YAC7C,CAAC;SACF,CAAC,CAAC,CAAC;IACN,CAAC;IAED;;OAEG;IACH,YAAY;QACV,OAAO,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAChC,CAAC;IAED;;OAEG;IACH,WAAW;QACT,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED;;OAEG;IACH,UAAU;QACR,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YACpB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACtB,CAAC;QACD,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC;QACvB,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnB,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;IAC/B,CAAC;CACF;AAED,+DAA+D;AAE/D,MAAM,OAAO,gBAAgB;IACnB,OAAO,GAA2B,IAAI,GAAG,EAAE,CAAC;IAEpD;;OAEG;IACH,KAAK,CAAC,SAAS,CAAC,IAAY,EAAE,OAAe,EAAE,IAAc;QAC3D,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC;QACnC,MAAM,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACjC,CAAC;IAED;;OAEG;IACH,WAAW;QACT,MAAM,QAAQ,GAAW,EAAE,CAAC;QAC5B,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;YAC3C,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QACtC,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED;;OAEG;IACH,eAAe;QACb,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAChD,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,YAAY,EAAE,EAAE,CAAC;gBAC7C,KAAK,CAAC,IAAI,CAAC,UAAU,GAAG,GAAG,GAAG,QAAQ,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,IAAY;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,CAAC,UAAU,EAAE,CAAC;YACpB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC;IAED;;OAEG;IACH,SAAS;QACP,MAAM,MAAM,GAA4B,EAAE,CAAC;QAC3C,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC1C,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;QACtC,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/repl/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/repl/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* REPL Input Handler
|
|
3
|
+
*
|
|
4
|
+
* 基于 @inquirer/input 实现,支持:
|
|
5
|
+
* - 方向键(含数字小键盘方向键)行内移动 / 跳转词首尾
|
|
6
|
+
* - Home / End / Backspace / Delete 行内编辑
|
|
7
|
+
* - Ctrl+A / Ctrl+E 跳到行首/行尾(emacs 风格)
|
|
8
|
+
* - Ctrl+C 中断当前输入(不清空整个会话),连续按两次空输入退出
|
|
9
|
+
* - 命令历史:本地维护 history 数组,通过 default 预填上一条
|
|
10
|
+
*
|
|
11
|
+
* 不再使用 Node 内置 readline 的 rl.question()——它在 Windows 终端下
|
|
12
|
+
* 对小键盘方向键的 ANSI 转义序列不友好,会导致光标无法移动 (Bug #1)。
|
|
13
|
+
*/
|
|
14
|
+
export type PromptResult = {
|
|
15
|
+
kind: 'value';
|
|
16
|
+
value: string;
|
|
17
|
+
} | {
|
|
18
|
+
kind: 'cancelled';
|
|
19
|
+
};
|
|
20
|
+
export declare class REPLInput {
|
|
21
|
+
private history;
|
|
22
|
+
private historyIndex;
|
|
23
|
+
private currentDraft;
|
|
24
|
+
private defaultPrefix;
|
|
25
|
+
private consecutiveCancels;
|
|
26
|
+
/**
|
|
27
|
+
* Ask the user for input. Returns either a value or 'cancelled'.
|
|
28
|
+
* Loop decides what to do with cancellation (usually: continue session,
|
|
29
|
+
* unless user has cancelled an already-empty input twice in a row).
|
|
30
|
+
*/
|
|
31
|
+
prompt(prefix?: string, abortSignal?: AbortSignal): Promise<PromptResult>;
|
|
32
|
+
/**
|
|
33
|
+
* Should we ask the loop to exit? Two consecutive Ctrl+C on empty input => exit.
|
|
34
|
+
*/
|
|
35
|
+
shouldExitOnCancel(): boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Reset consecutive-cancel counter when the loop has decided to keep running.
|
|
38
|
+
*/
|
|
39
|
+
resetCancelCounter(): void;
|
|
40
|
+
/**
|
|
41
|
+
* Decide what to prefill. Two modes:
|
|
42
|
+
* - 'history': when user is navigating up/down with arrows
|
|
43
|
+
* - 'draft': when user has cleared the input — preserve their draft
|
|
44
|
+
*/
|
|
45
|
+
private computePrefill;
|
|
46
|
+
/**
|
|
47
|
+
* Save the user's in-progress draft so ↑↓ preserves their unsent typing.
|
|
48
|
+
*/
|
|
49
|
+
saveDraft(text: string): void;
|
|
50
|
+
/**
|
|
51
|
+
* Navigate up in history (called from a global key listener, if needed).
|
|
52
|
+
*/
|
|
53
|
+
historyUp(): string;
|
|
54
|
+
/**
|
|
55
|
+
* Navigate down in history.
|
|
56
|
+
*/
|
|
57
|
+
historyDown(): string;
|
|
58
|
+
getHistory(): readonly string[];
|
|
59
|
+
clearHistory(): void;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=input.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input.d.ts","sourceRoot":"","sources":["../../src/repl/input.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAOH,MAAM,MAAM,YAAY,GACpB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,CAAC;AAE1B,qBAAa,SAAS;IACpB,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,kBAAkB,CAAa;IAEvC;;;;OAIG;IACG,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAqC/E;;OAEG;IACH,kBAAkB,IAAI,OAAO;IAI7B;;OAEG;IACH,kBAAkB,IAAI,IAAI;IAI1B;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAQtB;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI7B;;OAEG;IACH,SAAS,IAAI,MAAM;IAOnB;;OAEG;IACH,WAAW,IAAI,MAAM;IAWrB,UAAU,IAAI,SAAS,MAAM,EAAE;IAI/B,YAAY,IAAI,IAAI;CAIrB"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* REPL Input Handler
|
|
3
|
+
*
|
|
4
|
+
* 基于 @inquirer/input 实现,支持:
|
|
5
|
+
* - 方向键(含数字小键盘方向键)行内移动 / 跳转词首尾
|
|
6
|
+
* - Home / End / Backspace / Delete 行内编辑
|
|
7
|
+
* - Ctrl+A / Ctrl+E 跳到行首/行尾(emacs 风格)
|
|
8
|
+
* - Ctrl+C 中断当前输入(不清空整个会话),连续按两次空输入退出
|
|
9
|
+
* - 命令历史:本地维护 history 数组,通过 default 预填上一条
|
|
10
|
+
*
|
|
11
|
+
* 不再使用 Node 内置 readline 的 rl.question()——它在 Windows 终端下
|
|
12
|
+
* 对小键盘方向键的 ANSI 转义序列不友好,会导致光标无法移动 (Bug #1)。
|
|
13
|
+
*/
|
|
14
|
+
import input from '@inquirer/input';
|
|
15
|
+
import chalk from 'chalk';
|
|
16
|
+
const MAX_HISTORY = 200;
|
|
17
|
+
export class REPLInput {
|
|
18
|
+
history = [];
|
|
19
|
+
historyIndex = -1; // -1 表示"未在历史中浏览"
|
|
20
|
+
currentDraft = ''; // 离开历史时保留用户原始草稿
|
|
21
|
+
defaultPrefix = chalk.green('\n> ');
|
|
22
|
+
consecutiveCancels = 0; // 连续空输入 + Ctrl+C 计数,达到阈值退出
|
|
23
|
+
/**
|
|
24
|
+
* Ask the user for input. Returns either a value or 'cancelled'.
|
|
25
|
+
* Loop decides what to do with cancellation (usually: continue session,
|
|
26
|
+
* unless user has cancelled an already-empty input twice in a row).
|
|
27
|
+
*/
|
|
28
|
+
async prompt(prefix, abortSignal) {
|
|
29
|
+
const prefill = this.computePrefill();
|
|
30
|
+
const previousDraft = prefill.kind === 'history' ? prefill.value : '';
|
|
31
|
+
// 用 abortSignal 绑到 inquirer:外面 Ctrl+C / 主进程事件可以取消
|
|
32
|
+
const value = await input({
|
|
33
|
+
message: prefix ?? this.defaultPrefix,
|
|
34
|
+
prefill: 'editable', // 关键:启用方向键 + 行内编辑,包括小键盘
|
|
35
|
+
default: previousDraft, // 历史预填
|
|
36
|
+
// Ctrl+C 由 @inquirer/input 抛出一个 symbol-like 错误,我们捕获为 cancelled
|
|
37
|
+
validate: () => true,
|
|
38
|
+
}, abortSignal ? { signal: abortSignal } : undefined).catch((err) => {
|
|
39
|
+
// 区分真实错误与用户取消;inquirer 用 ExitPromptError (name: 'ExitPromptError')
|
|
40
|
+
if (err && (err.name === 'ExitPromptError' || err.message?.includes('User force closed'))) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
throw err;
|
|
44
|
+
});
|
|
45
|
+
if (value === null || value === undefined) {
|
|
46
|
+
this.consecutiveCancels++;
|
|
47
|
+
return { kind: 'cancelled' };
|
|
48
|
+
}
|
|
49
|
+
const trimmed = value.trim();
|
|
50
|
+
if (trimmed.length > 0) {
|
|
51
|
+
// 避免把连续重复的内容都压入历史
|
|
52
|
+
if (this.history[this.history.length - 1] !== trimmed) {
|
|
53
|
+
this.history.push(trimmed);
|
|
54
|
+
if (this.history.length > MAX_HISTORY)
|
|
55
|
+
this.history.shift();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
this.consecutiveCancels = 0;
|
|
59
|
+
return { kind: 'value', value: trimmed };
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Should we ask the loop to exit? Two consecutive Ctrl+C on empty input => exit.
|
|
63
|
+
*/
|
|
64
|
+
shouldExitOnCancel() {
|
|
65
|
+
return this.consecutiveCancels >= 2;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Reset consecutive-cancel counter when the loop has decided to keep running.
|
|
69
|
+
*/
|
|
70
|
+
resetCancelCounter() {
|
|
71
|
+
this.consecutiveCancels = 0;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Decide what to prefill. Two modes:
|
|
75
|
+
* - 'history': when user is navigating up/down with arrows
|
|
76
|
+
* - 'draft': when user has cleared the input — preserve their draft
|
|
77
|
+
*/
|
|
78
|
+
computePrefill() {
|
|
79
|
+
if (this.historyIndex >= 0 && this.historyIndex < this.history.length) {
|
|
80
|
+
return { kind: 'history', value: this.history[this.historyIndex] };
|
|
81
|
+
}
|
|
82
|
+
if (this.currentDraft)
|
|
83
|
+
return { kind: 'draft', value: this.currentDraft };
|
|
84
|
+
return { kind: 'none', value: '' };
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Save the user's in-progress draft so ↑↓ preserves their unsent typing.
|
|
88
|
+
*/
|
|
89
|
+
saveDraft(text) {
|
|
90
|
+
this.currentDraft = text;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Navigate up in history (called from a global key listener, if needed).
|
|
94
|
+
*/
|
|
95
|
+
historyUp() {
|
|
96
|
+
if (this.history.length === 0)
|
|
97
|
+
return this.currentDraft;
|
|
98
|
+
if (this.historyIndex < 0)
|
|
99
|
+
this.historyIndex = this.history.length;
|
|
100
|
+
if (this.historyIndex > 0)
|
|
101
|
+
this.historyIndex--;
|
|
102
|
+
return this.history[this.historyIndex] ?? '';
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Navigate down in history.
|
|
106
|
+
*/
|
|
107
|
+
historyDown() {
|
|
108
|
+
if (this.history.length === 0)
|
|
109
|
+
return this.currentDraft;
|
|
110
|
+
if (this.historyIndex >= this.history.length)
|
|
111
|
+
return this.currentDraft;
|
|
112
|
+
this.historyIndex++;
|
|
113
|
+
if (this.historyIndex >= this.history.length) {
|
|
114
|
+
this.historyIndex = this.history.length;
|
|
115
|
+
return this.currentDraft;
|
|
116
|
+
}
|
|
117
|
+
return this.history[this.historyIndex] ?? '';
|
|
118
|
+
}
|
|
119
|
+
getHistory() {
|
|
120
|
+
return this.history;
|
|
121
|
+
}
|
|
122
|
+
clearHistory() {
|
|
123
|
+
this.history = [];
|
|
124
|
+
this.historyIndex = -1;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=input.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input.js","sourceRoot":"","sources":["../../src/repl/input.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* REPL Loop
|
|
3
|
+
* Main interactive loop with streaming support
|
|
4
|
+
*
|
|
5
|
+
* S07-fix:
|
|
6
|
+
* - 输入端换用 REPLInput (基于 @inquirer/input),支持方向键/小键盘
|
|
7
|
+
* - 流式输出保留完整内容(用户可滚动终端查看历史),不跳顶不刷屏
|
|
8
|
+
* - Ctrl+C 行为:有未提交内容=>清空当前输入;空输入两次=>退出
|
|
9
|
+
*/
|
|
10
|
+
export declare class REPLLoop {
|
|
11
|
+
private input;
|
|
12
|
+
private output;
|
|
13
|
+
private ai;
|
|
14
|
+
private session;
|
|
15
|
+
private running;
|
|
16
|
+
private streamAbort;
|
|
17
|
+
constructor();
|
|
18
|
+
/**
|
|
19
|
+
* Initialize the REPL
|
|
20
|
+
* S04: Use SystemPromptBuilder for dynamic prompt construction
|
|
21
|
+
*/
|
|
22
|
+
init(): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* Start the REPL loop
|
|
25
|
+
*/
|
|
26
|
+
start(): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Handle built-in commands
|
|
29
|
+
*/
|
|
30
|
+
private handleCommand;
|
|
31
|
+
/**
|
|
32
|
+
* Process user input with AI (S01: streaming, no prompt reset)
|
|
33
|
+
*
|
|
34
|
+
* 关键修复:
|
|
35
|
+
* - 不再调用 rl.question,所以不会 reset 终端
|
|
36
|
+
* - chunk 直接 process.stdout.write,完整保留所有输出,用户可滚动查看
|
|
37
|
+
* - spinner 在第一个 chunk 到达时停止,然后正常流式
|
|
38
|
+
*/
|
|
39
|
+
private processInput;
|
|
40
|
+
private showContext;
|
|
41
|
+
private showHistory;
|
|
42
|
+
private showTools;
|
|
43
|
+
private showProviders;
|
|
44
|
+
/**
|
|
45
|
+
* Stop the REPL
|
|
46
|
+
*/
|
|
47
|
+
stop(): void;
|
|
48
|
+
/**
|
|
49
|
+
* Handle interrupt (Ctrl+C) while streaming
|
|
50
|
+
*/
|
|
51
|
+
interrupt(): void;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=loop.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../src/repl/loop.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAWH,qBAAa,QAAQ;IACnB,OAAO,CAAC,KAAK,CAAY;IACzB,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,EAAE,CAAyB;IACnC,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,OAAO,CAAkB;IAEjC,OAAO,CAAC,WAAW,CAAgC;;IAOnD;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAqC3B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA0C5B;;OAEG;YACW,aAAa;IA0C3B;;;;;;;OAOG;YACW,YAAY;IAsD1B,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,WAAW;IAUnB,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,aAAa;IAQrB;;OAEG;IACH,IAAI,IAAI,IAAI;IASZ;;OAEG;IACH,SAAS,IAAI,IAAI;CAOlB"}
|