swiftroutercli 3.0.0 → 4.0.0
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/README.md +5 -5
- package/dist/api/client.js +37 -1
- package/dist/index.js +16 -4
- package/dist/ui/Chat.js +63 -4
- package/package.json +3 -2
- package/src/api/client.ts +44 -1
- package/src/index.ts +17 -4
- package/src/ui/Chat.tsx +74 -4
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ Upon first launch, the CLI asks for configuration parameters. You can also confi
|
|
|
23
23
|
## Usage
|
|
24
24
|
Simply run the CLI anywhere on your system:
|
|
25
25
|
```bash
|
|
26
|
-
|
|
26
|
+
swiftroutercli chat
|
|
27
27
|
```
|
|
28
28
|
|
|
29
29
|
- Type `/models` to select models interactively.
|
|
@@ -31,10 +31,10 @@ swiftrouter chat
|
|
|
31
31
|
- Type `/exit` to quit.
|
|
32
32
|
|
|
33
33
|
### Additional Commands
|
|
34
|
-
- `
|
|
35
|
-
- `
|
|
36
|
-
- `
|
|
37
|
-
- `
|
|
34
|
+
- `swiftroutercli config --set-api-key <KEY> --set-base-url <URL>`: Manually configure CLI
|
|
35
|
+
- `swiftroutercli models`: List available models natively
|
|
36
|
+
- `swiftroutercli status`: Check authentication and connection status
|
|
37
|
+
- `swiftroutercli logout`: Clear local configuration securely
|
|
38
38
|
|
|
39
39
|
## Built With
|
|
40
40
|
- `ink`
|
package/dist/api/client.js
CHANGED
|
@@ -1,10 +1,44 @@
|
|
|
1
1
|
import { createParser } from "eventsource-parser";
|
|
2
2
|
import fs from "fs";
|
|
3
3
|
import path from "path";
|
|
4
|
+
import os from "os";
|
|
5
|
+
function getHierarchicalAgentsContext() {
|
|
6
|
+
const cwd = process.cwd();
|
|
7
|
+
const pathsToRead = [];
|
|
8
|
+
// 1. Global
|
|
9
|
+
pathsToRead.push(path.join(os.homedir(), ".swiftrouter-cli", "AGENTS.md"));
|
|
10
|
+
// 2. Repo Root
|
|
11
|
+
let currentDir = cwd;
|
|
12
|
+
let repoRoot = null;
|
|
13
|
+
while (currentDir !== path.parse(currentDir).root) {
|
|
14
|
+
if (fs.existsSync(path.join(currentDir, ".git"))) {
|
|
15
|
+
repoRoot = currentDir;
|
|
16
|
+
break;
|
|
17
|
+
}
|
|
18
|
+
currentDir = path.dirname(currentDir);
|
|
19
|
+
}
|
|
20
|
+
if (repoRoot) {
|
|
21
|
+
pathsToRead.push(path.join(repoRoot, "AGENTS.md"));
|
|
22
|
+
}
|
|
23
|
+
// 3. Local CWD
|
|
24
|
+
pathsToRead.push(path.join(cwd, "AGENTS.md"));
|
|
25
|
+
// Deduplicate
|
|
26
|
+
const uniquePaths = [...new Set(pathsToRead)];
|
|
27
|
+
let agentsContent = "";
|
|
28
|
+
for (const p of uniquePaths) {
|
|
29
|
+
if (fs.existsSync(p)) {
|
|
30
|
+
try {
|
|
31
|
+
agentsContent += `\n--- Context from ${p} ---\n` + fs.readFileSync(p, "utf-8") + "\n";
|
|
32
|
+
}
|
|
33
|
+
catch (e) { }
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return agentsContent;
|
|
37
|
+
}
|
|
4
38
|
function getWorkspaceContext() {
|
|
5
39
|
const cwd = process.cwd();
|
|
6
40
|
let context = `Current Workspace: ${cwd}\n`;
|
|
7
|
-
const filesToRead = ["README.md", "
|
|
41
|
+
const filesToRead = ["README.md", "package.json"];
|
|
8
42
|
for (const file of filesToRead) {
|
|
9
43
|
const filePath = path.join(cwd, file);
|
|
10
44
|
if (fs.existsSync(filePath)) {
|
|
@@ -15,6 +49,8 @@ function getWorkspaceContext() {
|
|
|
15
49
|
catch (e) { }
|
|
16
50
|
}
|
|
17
51
|
}
|
|
52
|
+
// Append Hierarchical AGENTS.md
|
|
53
|
+
context += getHierarchicalAgentsContext();
|
|
18
54
|
return context;
|
|
19
55
|
}
|
|
20
56
|
export async function fetchModels(config) {
|
package/dist/index.js
CHANGED
|
@@ -46,9 +46,9 @@ async function ensureConfig() {
|
|
|
46
46
|
return config;
|
|
47
47
|
}
|
|
48
48
|
program
|
|
49
|
-
.name("
|
|
49
|
+
.name("swiftroutercli")
|
|
50
50
|
.description("CLI for SwiftRouter AI Gateway")
|
|
51
|
-
.version("
|
|
51
|
+
.version("4.0.0");
|
|
52
52
|
program
|
|
53
53
|
.command("config")
|
|
54
54
|
.description("Manually configure the CLI with your SwiftRouter API Key and Base URL")
|
|
@@ -96,13 +96,15 @@ program
|
|
|
96
96
|
.description("Start an interactive chat session")
|
|
97
97
|
.argument("[prompt]", "Initial prompt to start the chat")
|
|
98
98
|
.option("-m, --model <model>", "Model to use", DEFAULT_MODEL)
|
|
99
|
+
.option("-a, --approval-mode <mode>", "AI assistant's permission mode (suggest, auto-edit, full-auto)", "suggest")
|
|
100
|
+
.option("-q, --quiet", "Run in headless CI/CD mode without interactive TUI rendering", false)
|
|
99
101
|
.action(async (prompt, options) => {
|
|
100
102
|
const config = await ensureConfig();
|
|
101
103
|
if (!prompt) {
|
|
102
|
-
startChat(config, options.model, "");
|
|
104
|
+
startChat(config, options.model, "", options.approvalMode, options.quiet);
|
|
103
105
|
}
|
|
104
106
|
else {
|
|
105
|
-
startChat(config, options.model, prompt);
|
|
107
|
+
startChat(config, options.model, prompt, options.approvalMode, options.quiet);
|
|
106
108
|
}
|
|
107
109
|
});
|
|
108
110
|
program
|
|
@@ -140,4 +142,14 @@ program
|
|
|
140
142
|
console.log(chalk.gray("You were not logged in."));
|
|
141
143
|
}
|
|
142
144
|
});
|
|
145
|
+
// Default action: if no subcommand is given, launch chat (just like `codex`)
|
|
146
|
+
program
|
|
147
|
+
.argument("[prompt]", "Initial prompt to start chat directly")
|
|
148
|
+
.option("-m, --model <model>", "Model to use", DEFAULT_MODEL)
|
|
149
|
+
.option("-a, --approval-mode <mode>", "AI assistant's permission mode (suggest, auto-edit, full-auto)", "suggest")
|
|
150
|
+
.option("-q, --quiet", "Run in headless CI/CD mode without interactive TUI rendering", false)
|
|
151
|
+
.action(async (prompt, options) => {
|
|
152
|
+
const config = await ensureConfig();
|
|
153
|
+
startChat(config, options.model, prompt || "", options.approvalMode, options.quiet);
|
|
154
|
+
});
|
|
143
155
|
program.parse();
|
package/dist/ui/Chat.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { useState, useEffect } from "react";
|
|
2
2
|
import { render, Box, Text, useInput, Static } from "ink";
|
|
3
3
|
import { streamChatCompletion, fetchModels } from "../api/client.js";
|
|
4
|
+
import chalk from "chalk";
|
|
4
5
|
import { loadHistory, saveHistory } from "../config.js";
|
|
5
6
|
import { marked } from "marked";
|
|
6
7
|
import TerminalRenderer from "marked-terminal";
|
|
@@ -10,7 +11,7 @@ marked.setOptions({
|
|
|
10
11
|
// @ts-ignore
|
|
11
12
|
renderer: new TerminalRenderer()
|
|
12
13
|
});
|
|
13
|
-
const Chat = ({ config, model, initialPrompt }) => {
|
|
14
|
+
const Chat = ({ config, model, initialPrompt, approvalMode }) => {
|
|
14
15
|
const [messages, setMessages] = useState([
|
|
15
16
|
{ id: 0, role: "user", content: initialPrompt },
|
|
16
17
|
]);
|
|
@@ -40,7 +41,27 @@ const Chat = ({ config, model, initialPrompt }) => {
|
|
|
40
41
|
]);
|
|
41
42
|
const bashMatch = streamingContent.match(/```(?:bash|sh)\n([\s\S]*?)\n```/);
|
|
42
43
|
if (bashMatch) {
|
|
43
|
-
|
|
44
|
+
const command = bashMatch[1].trim();
|
|
45
|
+
if (approvalMode === "full-auto") {
|
|
46
|
+
setIsExecuting(true);
|
|
47
|
+
const dockerCmd = `docker run --rm -v "${process.cwd()}":/workspace -w /workspace node:20 bash -c "${command.replace(/"/g, '\\"')}"`;
|
|
48
|
+
setMessages((prev) => [
|
|
49
|
+
...prev,
|
|
50
|
+
{ id: prev.length, role: "system", content: `[Full-Auto Sandboxed] Executing: ${command}` }
|
|
51
|
+
]);
|
|
52
|
+
exec(dockerCmd, (err, stdout, stderr) => {
|
|
53
|
+
const output = err ? stderr : stdout;
|
|
54
|
+
setMessages((prev) => [
|
|
55
|
+
...prev,
|
|
56
|
+
{ id: prev.length, role: "system", content: `Sandbox Output:\n${output || "Done"}` }
|
|
57
|
+
]);
|
|
58
|
+
setIsExecuting(false);
|
|
59
|
+
// Recursive automation could go here in V5
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
setPendingCommand(command);
|
|
64
|
+
}
|
|
44
65
|
}
|
|
45
66
|
setStreamingContent("");
|
|
46
67
|
setIsStreaming(false);
|
|
@@ -182,6 +203,44 @@ const Chat = ({ config, model, initialPrompt }) => {
|
|
|
182
203
|
history.length,
|
|
183
204
|
" Prompts Saved"))))));
|
|
184
205
|
};
|
|
185
|
-
export function startChat(config, model, prompt) {
|
|
186
|
-
|
|
206
|
+
export function startChat(config, model, prompt, approvalMode = "suggest", quiet = false) {
|
|
207
|
+
if (quiet) {
|
|
208
|
+
if (!prompt) {
|
|
209
|
+
console.error(chalk.red("Error: --quiet requires an initial prompt to be passed (e.g. swiftroutercli chat -q \"hello\")"));
|
|
210
|
+
process.exit(1);
|
|
211
|
+
}
|
|
212
|
+
let fullResponse = "";
|
|
213
|
+
streamChatCompletion(config, model, [{ role: "user", content: prompt }], (text) => {
|
|
214
|
+
process.stdout.write(text);
|
|
215
|
+
fullResponse += text;
|
|
216
|
+
}, () => {
|
|
217
|
+
console.log("\n");
|
|
218
|
+
// If full-auto is requested in quiet mode, we would parse bash blocks and execute them here.
|
|
219
|
+
// For now, headless simply streams the raw text response for CI pipelines.
|
|
220
|
+
if (approvalMode === "full-auto") {
|
|
221
|
+
const bashMatch = fullResponse.match(/```(?:bash|sh)\n([\s\S]*?)\n```/);
|
|
222
|
+
if (bashMatch) {
|
|
223
|
+
const command = bashMatch[1].trim();
|
|
224
|
+
console.log(chalk.yellow(`\n[Full-Auto] Executing headless command: ${command}`));
|
|
225
|
+
exec(command, { cwd: process.cwd() }, (err, stdout, stderr) => {
|
|
226
|
+
if (err) {
|
|
227
|
+
console.error(chalk.red(`Error: ${stderr}`));
|
|
228
|
+
process.exit(1);
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
console.log(stdout);
|
|
232
|
+
process.exit(0);
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
process.exit(0);
|
|
239
|
+
}, (err) => {
|
|
240
|
+
console.error(chalk.red(`\nError: ${err.message}`));
|
|
241
|
+
process.exit(1);
|
|
242
|
+
});
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
render(React.createElement(Chat, { config: config, model: model, initialPrompt: prompt, approvalMode: approvalMode }));
|
|
187
246
|
}
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "swiftroutercli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "The official SwiftRouter Command Line Interface using React Ink Components",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"bin": {
|
|
8
|
-
"swiftrouter": "./dist/index.js"
|
|
8
|
+
"swiftrouter": "./dist/index.js",
|
|
9
|
+
"swiftroutercli": "./dist/index.js"
|
|
9
10
|
},
|
|
10
11
|
"scripts": {
|
|
11
12
|
"build": "tsc",
|
package/src/api/client.ts
CHANGED
|
@@ -2,11 +2,50 @@ import { Config, loadConfig } from "../config.js";
|
|
|
2
2
|
import { createParser } from "eventsource-parser";
|
|
3
3
|
import fs from "fs";
|
|
4
4
|
import path from "path";
|
|
5
|
+
import os from "os";
|
|
6
|
+
|
|
7
|
+
function getHierarchicalAgentsContext(): string {
|
|
8
|
+
const cwd = process.cwd();
|
|
9
|
+
const pathsToRead: string[] = [];
|
|
10
|
+
|
|
11
|
+
// 1. Global
|
|
12
|
+
pathsToRead.push(path.join(os.homedir(), ".swiftrouter-cli", "AGENTS.md"));
|
|
13
|
+
|
|
14
|
+
// 2. Repo Root
|
|
15
|
+
let currentDir = cwd;
|
|
16
|
+
let repoRoot: string | null = null;
|
|
17
|
+
while (currentDir !== path.parse(currentDir).root) {
|
|
18
|
+
if (fs.existsSync(path.join(currentDir, ".git"))) {
|
|
19
|
+
repoRoot = currentDir;
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
currentDir = path.dirname(currentDir);
|
|
23
|
+
}
|
|
24
|
+
if (repoRoot) {
|
|
25
|
+
pathsToRead.push(path.join(repoRoot, "AGENTS.md"));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// 3. Local CWD
|
|
29
|
+
pathsToRead.push(path.join(cwd, "AGENTS.md"));
|
|
30
|
+
|
|
31
|
+
// Deduplicate
|
|
32
|
+
const uniquePaths = [...new Set(pathsToRead)];
|
|
33
|
+
|
|
34
|
+
let agentsContent = "";
|
|
35
|
+
for (const p of uniquePaths) {
|
|
36
|
+
if (fs.existsSync(p)) {
|
|
37
|
+
try {
|
|
38
|
+
agentsContent += `\n--- Context from ${p} ---\n` + fs.readFileSync(p, "utf-8") + "\n";
|
|
39
|
+
} catch (e) { }
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return agentsContent;
|
|
43
|
+
}
|
|
5
44
|
|
|
6
45
|
function getWorkspaceContext(): string {
|
|
7
46
|
const cwd = process.cwd();
|
|
8
47
|
let context = `Current Workspace: ${cwd}\n`;
|
|
9
|
-
const filesToRead = ["README.md", "
|
|
48
|
+
const filesToRead = ["README.md", "package.json"];
|
|
10
49
|
for (const file of filesToRead) {
|
|
11
50
|
const filePath = path.join(cwd, file);
|
|
12
51
|
if (fs.existsSync(filePath)) {
|
|
@@ -16,6 +55,10 @@ function getWorkspaceContext(): string {
|
|
|
16
55
|
} catch (e) { }
|
|
17
56
|
}
|
|
18
57
|
}
|
|
58
|
+
|
|
59
|
+
// Append Hierarchical AGENTS.md
|
|
60
|
+
context += getHierarchicalAgentsContext();
|
|
61
|
+
|
|
19
62
|
return context;
|
|
20
63
|
}
|
|
21
64
|
|
package/src/index.ts
CHANGED
|
@@ -59,9 +59,9 @@ async function ensureConfig(): Promise<Config> {
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
program
|
|
62
|
-
.name("
|
|
62
|
+
.name("swiftroutercli")
|
|
63
63
|
.description("CLI for SwiftRouter AI Gateway")
|
|
64
|
-
.version("
|
|
64
|
+
.version("4.0.0");
|
|
65
65
|
|
|
66
66
|
program
|
|
67
67
|
.command("config")
|
|
@@ -112,13 +112,15 @@ program
|
|
|
112
112
|
.description("Start an interactive chat session")
|
|
113
113
|
.argument("[prompt]", "Initial prompt to start the chat")
|
|
114
114
|
.option("-m, --model <model>", "Model to use", DEFAULT_MODEL)
|
|
115
|
+
.option("-a, --approval-mode <mode>", "AI assistant's permission mode (suggest, auto-edit, full-auto)", "suggest")
|
|
116
|
+
.option("-q, --quiet", "Run in headless CI/CD mode without interactive TUI rendering", false)
|
|
115
117
|
.action(async (prompt, options) => {
|
|
116
118
|
const config = await ensureConfig();
|
|
117
119
|
|
|
118
120
|
if (!prompt) {
|
|
119
|
-
startChat(config, options.model, "");
|
|
121
|
+
startChat(config, options.model, "", options.approvalMode, options.quiet);
|
|
120
122
|
} else {
|
|
121
|
-
startChat(config, options.model, prompt);
|
|
123
|
+
startChat(config, options.model, prompt, options.approvalMode, options.quiet);
|
|
122
124
|
}
|
|
123
125
|
});
|
|
124
126
|
|
|
@@ -159,4 +161,15 @@ program
|
|
|
159
161
|
}
|
|
160
162
|
});
|
|
161
163
|
|
|
164
|
+
// Default action: if no subcommand is given, launch chat (just like `codex`)
|
|
165
|
+
program
|
|
166
|
+
.argument("[prompt]", "Initial prompt to start chat directly")
|
|
167
|
+
.option("-m, --model <model>", "Model to use", DEFAULT_MODEL)
|
|
168
|
+
.option("-a, --approval-mode <mode>", "AI assistant's permission mode (suggest, auto-edit, full-auto)", "suggest")
|
|
169
|
+
.option("-q, --quiet", "Run in headless CI/CD mode without interactive TUI rendering", false)
|
|
170
|
+
.action(async (prompt, options) => {
|
|
171
|
+
const config = await ensureConfig();
|
|
172
|
+
startChat(config, options.model, prompt || "", options.approvalMode, options.quiet);
|
|
173
|
+
});
|
|
174
|
+
|
|
162
175
|
program.parse();
|
package/src/ui/Chat.tsx
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, { useState, useEffect } from "react";
|
|
2
2
|
import { render, Box, Text, useInput, Static } from "ink";
|
|
3
3
|
import { streamChatCompletion, fetchModels } from "../api/client.js";
|
|
4
|
+
import chalk from "chalk";
|
|
4
5
|
import { Config, loadHistory, saveHistory } from "../config.js";
|
|
5
6
|
import { marked } from "marked";
|
|
6
7
|
import TerminalRenderer from "marked-terminal";
|
|
@@ -21,9 +22,10 @@ interface ChatProps {
|
|
|
21
22
|
config: Config;
|
|
22
23
|
model: string;
|
|
23
24
|
initialPrompt: string;
|
|
25
|
+
approvalMode: string;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
const Chat: React.FC<ChatProps> = ({ config, model, initialPrompt }) => {
|
|
28
|
+
const Chat: React.FC<ChatProps> = ({ config, model, initialPrompt, approvalMode }) => {
|
|
27
29
|
const [messages, setMessages] = useState<{ id: number; role: string; content: string }[]>([
|
|
28
30
|
{ id: 0, role: "user", content: initialPrompt },
|
|
29
31
|
]);
|
|
@@ -63,7 +65,28 @@ const Chat: React.FC<ChatProps> = ({ config, model, initialPrompt }) => {
|
|
|
63
65
|
|
|
64
66
|
const bashMatch = streamingContent.match(/```(?:bash|sh)\n([\s\S]*?)\n```/);
|
|
65
67
|
if (bashMatch) {
|
|
66
|
-
|
|
68
|
+
const command = bashMatch[1].trim();
|
|
69
|
+
if (approvalMode === "full-auto") {
|
|
70
|
+
setIsExecuting(true);
|
|
71
|
+
const dockerCmd = `docker run --rm -v "${process.cwd()}":/workspace -w /workspace node:20 bash -c "${command.replace(/"/g, '\\"')}"`;
|
|
72
|
+
|
|
73
|
+
setMessages((prev) => [
|
|
74
|
+
...prev,
|
|
75
|
+
{ id: prev.length, role: "system", content: `[Full-Auto Sandboxed] Executing: ${command}` }
|
|
76
|
+
]);
|
|
77
|
+
|
|
78
|
+
exec(dockerCmd, (err, stdout, stderr) => {
|
|
79
|
+
const output = err ? stderr : stdout;
|
|
80
|
+
setMessages((prev) => [
|
|
81
|
+
...prev,
|
|
82
|
+
{ id: prev.length, role: "system", content: `Sandbox Output:\n${output || "Done"}` }
|
|
83
|
+
]);
|
|
84
|
+
setIsExecuting(false);
|
|
85
|
+
// Recursive automation could go here in V5
|
|
86
|
+
});
|
|
87
|
+
} else {
|
|
88
|
+
setPendingCommand(command);
|
|
89
|
+
}
|
|
67
90
|
}
|
|
68
91
|
|
|
69
92
|
setStreamingContent("");
|
|
@@ -251,6 +274,53 @@ const Chat: React.FC<ChatProps> = ({ config, model, initialPrompt }) => {
|
|
|
251
274
|
);
|
|
252
275
|
};
|
|
253
276
|
|
|
254
|
-
export function startChat(config: Config, model: string, prompt: string) {
|
|
255
|
-
|
|
277
|
+
export function startChat(config: Config, model: string, prompt: string, approvalMode: string = "suggest", quiet: boolean = false) {
|
|
278
|
+
if (quiet) {
|
|
279
|
+
if (!prompt) {
|
|
280
|
+
console.error(chalk.red("Error: --quiet requires an initial prompt to be passed (e.g. swiftroutercli chat -q \"hello\")"));
|
|
281
|
+
process.exit(1);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
let fullResponse = "";
|
|
285
|
+
streamChatCompletion(
|
|
286
|
+
config,
|
|
287
|
+
model,
|
|
288
|
+
[{ role: "user", content: prompt }],
|
|
289
|
+
(text) => {
|
|
290
|
+
process.stdout.write(text);
|
|
291
|
+
fullResponse += text;
|
|
292
|
+
},
|
|
293
|
+
() => {
|
|
294
|
+
console.log("\n");
|
|
295
|
+
|
|
296
|
+
// If full-auto is requested in quiet mode, we would parse bash blocks and execute them here.
|
|
297
|
+
// For now, headless simply streams the raw text response for CI pipelines.
|
|
298
|
+
if (approvalMode === "full-auto") {
|
|
299
|
+
const bashMatch = fullResponse.match(/```(?:bash|sh)\n([\s\S]*?)\n```/);
|
|
300
|
+
if (bashMatch) {
|
|
301
|
+
const command = bashMatch[1].trim();
|
|
302
|
+
console.log(chalk.yellow(`\n[Full-Auto] Executing headless command: ${command}`));
|
|
303
|
+
exec(command, { cwd: process.cwd() }, (err, stdout, stderr) => {
|
|
304
|
+
if (err) {
|
|
305
|
+
console.error(chalk.red(`Error: ${stderr}`));
|
|
306
|
+
process.exit(1);
|
|
307
|
+
} else {
|
|
308
|
+
console.log(stdout);
|
|
309
|
+
process.exit(0);
|
|
310
|
+
}
|
|
311
|
+
});
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
process.exit(0);
|
|
316
|
+
},
|
|
317
|
+
(err) => {
|
|
318
|
+
console.error(chalk.red(`\nError: ${err.message}`));
|
|
319
|
+
process.exit(1);
|
|
320
|
+
}
|
|
321
|
+
);
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
render(<Chat config={config} model={model} initialPrompt={prompt} approvalMode={approvalMode} />);
|
|
256
326
|
}
|