godspeed-agent 0.1.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/LICENSE +21 -0
- package/README.md +99 -0
- package/bin/godspeed +2 -0
- package/package.json +32 -0
- package/src/cli.ts +25 -0
- package/src/commands/agent.ts +81 -0
- package/src/commands/chat.ts +65 -0
- package/src/commands/models.ts +49 -0
- package/src/commands/providers.ts +83 -0
- package/src/commands/tools.ts +40 -0
- package/src/commands/tui.tsx +24 -0
- package/src/lib/agent.ts +183 -0
- package/src/lib/agentMemory.ts +69 -0
- package/src/lib/config.ts +55 -0
- package/src/lib/history.ts +50 -0
- package/src/lib/llm.ts +86 -0
- package/src/lib/providers.ts +45 -0
- package/src/providers/gemini.ts +91 -0
- package/src/providers/index.ts +24 -0
- package/src/providers/ollama.ts +84 -0
- package/src/providers/openrouter.ts +97 -0
- package/src/providers/types.ts +18 -0
- package/src/tools/labels.ts +38 -0
- package/src/tools/metadata.ts +102 -0
- package/src/tools/prompt.ts +37 -0
- package/src/tools/registry.ts +63 -0
- package/src/tools/tools.ts +179 -0
- package/src/tools/workspace.ts +22 -0
- package/src/tui/App.tsx +377 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Bhupesh
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
## GodSpeed Agent
|
|
2
|
+
A lightweight AI coding agent built with Bun, TypeScript, Ink, and Gemini/Ollama.
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
## feature (v1) :-
|
|
7
|
+
- Providers
|
|
8
|
+
- Models
|
|
9
|
+
- Agent loop
|
|
10
|
+
- Tool registry
|
|
11
|
+
- Workspace sandbox
|
|
12
|
+
- READ_FILE
|
|
13
|
+
- WRITE_FILE
|
|
14
|
+
- EDIT_FILE
|
|
15
|
+
- DELETE_FILE
|
|
16
|
+
- CREATE_DIRECTORY
|
|
17
|
+
- MOVE_FILE
|
|
18
|
+
- COPY_FILE
|
|
19
|
+
- RUN_COMMAND
|
|
20
|
+
- GLOB_FILES
|
|
21
|
+
- SEARCH_FILES
|
|
22
|
+
- Tool approvals
|
|
23
|
+
- Agent memory
|
|
24
|
+
- CLI agent
|
|
25
|
+
- TUI agent
|
|
26
|
+
- Direct streaming chat
|
|
27
|
+
---------
|
|
28
|
+
inshort -
|
|
29
|
+
* Interactive TUI
|
|
30
|
+
* Agent mode
|
|
31
|
+
* Tool calling
|
|
32
|
+
* File editing
|
|
33
|
+
* Workspace sandboxing
|
|
34
|
+
* Gemini support
|
|
35
|
+
* Ollama support
|
|
36
|
+
* Persistent memory
|
|
37
|
+
* Multi-provider architecture
|
|
38
|
+
|
|
39
|
+
currently supporting these features (v0.1.0)
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
Installation
|
|
43
|
+
```
|
|
44
|
+
bun add -g godspeed-agent
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Usage
|
|
48
|
+
```
|
|
49
|
+
godspeed tui
|
|
50
|
+
```
|
|
51
|
+
```
|
|
52
|
+
godspeed agent -p "create a hello world express server"
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
----
|
|
56
|
+
|
|
57
|
+
# Configure Provider
|
|
58
|
+
## gemini
|
|
59
|
+
```
|
|
60
|
+
godspeed providers login -p gemini -k YOUR_API_KEY
|
|
61
|
+
godspeed providers set gemini
|
|
62
|
+
godspeed models set gemini-2.5-flash
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## ollama
|
|
66
|
+
```
|
|
67
|
+
godspeed providers login -p ollama -k local
|
|
68
|
+
godspeed providers set ollama
|
|
69
|
+
godspeed models set qwen2.5-coder:3b-instruct-q4_K_M
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## openrouter
|
|
73
|
+
```
|
|
74
|
+
godspeed providers login -p openrouter -k YOUR_API_KEY
|
|
75
|
+
godspeed providers set openrouter
|
|
76
|
+
godspeed models set openrouter/free
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Requirements
|
|
80
|
+
- Bun >= 1.0
|
|
81
|
+
|
|
82
|
+
# Disclaimer
|
|
83
|
+
GodSpeed Agent is an experimental AI-powered coding assistant. While it can generate code, edit files, execute commands, and automate development workflows, it may occasionally produce incorrect, incomplete, insecure, or unexpected results.
|
|
84
|
+
|
|
85
|
+
Users are responsible for:
|
|
86
|
+
|
|
87
|
+
* Reviewing all generated code before use.
|
|
88
|
+
* Verifying file modifications and command executions.
|
|
89
|
+
* Testing applications before deploying to production environments.
|
|
90
|
+
* Protecting sensitive information, credentials, and proprietary data.
|
|
91
|
+
|
|
92
|
+
The authors and contributors of GodSpeed Agent are not responsible for any data loss, security vulnerabilities, system damage, financial loss, or other consequences resulting from the use of this software.
|
|
93
|
+
|
|
94
|
+
Use GodSpeed Agent at your own risk. It is recommended to use workspace sandboxing, version control, and regular backups when working with important projects.
|
|
95
|
+
|
|
96
|
+
By installing or using GodSpeed Agent, you acknowledge and accept these limitations and responsibilities.
|
|
97
|
+
|
|
98
|
+
## License
|
|
99
|
+
This project is licensed under the MIT License. See the [LICENSE](./LICENSE) file for details.
|
package/bin/godspeed
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "godspeed-agent",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"godspeed": "bin/godspeed"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin",
|
|
11
|
+
"src",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE",
|
|
14
|
+
"package.json"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"dev": "bun run src/cli.ts"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"chalk": "^5.6.2",
|
|
21
|
+
"commander": "^14.0.2",
|
|
22
|
+
"fast-glob": "^3.3.3",
|
|
23
|
+
"ink": "^7.0.5",
|
|
24
|
+
"ora": "^9.4.0",
|
|
25
|
+
"react": "^19.2.7"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/bun": "latest",
|
|
29
|
+
"@types/react": "^19.2.16",
|
|
30
|
+
"typescript": "latest"
|
|
31
|
+
}
|
|
32
|
+
}
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import { providersCommand } from "./commands/providers.js";
|
|
5
|
+
import { modelsCommand } from "./commands/models.js";
|
|
6
|
+
import { agentCommand } from "./commands/agent.js";
|
|
7
|
+
import { chatCommand } from "./commands/chat.js";
|
|
8
|
+
import { toolsCommand } from "./commands/tools.js";
|
|
9
|
+
import { tuiCommand } from "./commands/tui.js";
|
|
10
|
+
|
|
11
|
+
const program = new Command();
|
|
12
|
+
|
|
13
|
+
program
|
|
14
|
+
.name("tuistarter")
|
|
15
|
+
.description("Minimal agent CLI from scratch")
|
|
16
|
+
.version("0.1.0");
|
|
17
|
+
|
|
18
|
+
program.addCommand(providersCommand);
|
|
19
|
+
program.addCommand(modelsCommand);
|
|
20
|
+
program.addCommand(agentCommand);
|
|
21
|
+
program.addCommand(chatCommand);
|
|
22
|
+
program.addCommand(toolsCommand);
|
|
23
|
+
program.addCommand(tuiCommand);
|
|
24
|
+
|
|
25
|
+
program.parse();
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { runAgent } from "../lib/agent.js";
|
|
4
|
+
import { streamLLM } from "../lib/llm.js";
|
|
5
|
+
import { setWorkspace, getWorkspace } from "../tools/workspace.js";
|
|
6
|
+
import readline from "readline/promises";
|
|
7
|
+
import { stdin, stdout } from "process";
|
|
8
|
+
import { getToolLabel } from "../tools/labels.js";
|
|
9
|
+
|
|
10
|
+
export const agentCommand = new Command("agent")
|
|
11
|
+
.description("Run coding agent")
|
|
12
|
+
.option("-p, --prompt <prompt>", "Prompt to send")
|
|
13
|
+
.option("-s, --stream", "Stream direct LLM response")
|
|
14
|
+
.option("-w, --workspace <workspace>", "Workspace path", process.cwd())
|
|
15
|
+
.action(async (options) => {
|
|
16
|
+
try {
|
|
17
|
+
setWorkspace(options.workspace);
|
|
18
|
+
|
|
19
|
+
console.log(chalk.gray(`Workspace: ${getWorkspace()}`));
|
|
20
|
+
|
|
21
|
+
if (!options.prompt) {
|
|
22
|
+
console.log(chalk.red("Prompt is required. Use -p or --prompt."));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (options.stream) {
|
|
27
|
+
await streamLLM(options.prompt);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const answer = await runAgent(options.prompt, {
|
|
32
|
+
showSpinner: true,
|
|
33
|
+
|
|
34
|
+
async confirmTool(action) {
|
|
35
|
+
const rl = readline.createInterface({
|
|
36
|
+
input: stdin,
|
|
37
|
+
output: stdout,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const label = getToolLabel(action);
|
|
41
|
+
|
|
42
|
+
const answer = await rl.question(
|
|
43
|
+
chalk.yellow(`Approve ${label}? (y/n): `),
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
rl.close();
|
|
47
|
+
|
|
48
|
+
return answer.trim().toLowerCase() === "y";
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
onStep(step) {
|
|
52
|
+
const statusIcon =
|
|
53
|
+
step.status === "completed"
|
|
54
|
+
? "✅"
|
|
55
|
+
: step.status === "failed"
|
|
56
|
+
? "❌"
|
|
57
|
+
: "⏳";
|
|
58
|
+
|
|
59
|
+
console.log(
|
|
60
|
+
chalk.gray(
|
|
61
|
+
`${statusIcon} Step ${step.step}: ${step.action} ${step.status}`,
|
|
62
|
+
),
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
if (step.path) console.log(chalk.gray(` path: ${step.path}`));
|
|
66
|
+
if (step.command)
|
|
67
|
+
console.log(chalk.gray(` command: ${step.command}`));
|
|
68
|
+
if (step.pattern)
|
|
69
|
+
console.log(chalk.gray(` pattern: ${step.pattern}`));
|
|
70
|
+
if (step.query) console.log(chalk.gray(` query: ${step.query}`));
|
|
71
|
+
if (step.error) console.log(chalk.red(` error: ${step.error}`));
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
if (answer) {
|
|
76
|
+
console.log(answer);
|
|
77
|
+
}
|
|
78
|
+
} catch (err) {
|
|
79
|
+
console.log(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
80
|
+
}
|
|
81
|
+
});
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import readline from "readline/promises";
|
|
3
|
+
import { stdin, stdout } from "process";
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import { askLLMWithMessages, type ChatMessage } from "../lib/llm.js";
|
|
6
|
+
import { loadHistory, saveHistory, clearHistory } from "../lib/history.js";
|
|
7
|
+
|
|
8
|
+
export const chatCommand = new Command("chat")
|
|
9
|
+
.description("Start interactive chat with persistent memory")
|
|
10
|
+
.option("--session <name>", "Chat session name", "default")
|
|
11
|
+
.option("--clear", "Clear chat history before starting")
|
|
12
|
+
.action(async (options) => {
|
|
13
|
+
const rl = readline.createInterface({
|
|
14
|
+
input: stdin,
|
|
15
|
+
output: stdout,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
if (options.clear) {
|
|
19
|
+
clearHistory(options.session);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const messages: ChatMessage[] = loadHistory(options.session);
|
|
23
|
+
|
|
24
|
+
console.log(chalk.green("TUI Starter Chat"));
|
|
25
|
+
console.log(chalk.gray(`Session: ${options.session}`));
|
|
26
|
+
console.log(chalk.gray("Type exit or quit to stop.\n"));
|
|
27
|
+
|
|
28
|
+
while (true) {
|
|
29
|
+
const prompt = await rl.question(chalk.cyan("You> "));
|
|
30
|
+
const cleanedPrompt = prompt.trim();
|
|
31
|
+
|
|
32
|
+
if (!cleanedPrompt) continue;
|
|
33
|
+
|
|
34
|
+
if (
|
|
35
|
+
cleanedPrompt.toLowerCase() === "exit" ||
|
|
36
|
+
cleanedPrompt.toLowerCase() === "quit"
|
|
37
|
+
) {
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
messages.push({
|
|
42
|
+
role: "user",
|
|
43
|
+
text: cleanedPrompt,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const answer = await askLLMWithMessages(messages);
|
|
48
|
+
|
|
49
|
+
messages.push({
|
|
50
|
+
role: "model",
|
|
51
|
+
text: answer,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
saveHistory(options.session, messages);
|
|
55
|
+
|
|
56
|
+
console.log(chalk.yellow("\nAI>"));
|
|
57
|
+
console.log(answer);
|
|
58
|
+
console.log();
|
|
59
|
+
} catch (err) {
|
|
60
|
+
console.log(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
rl.close();
|
|
65
|
+
});
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { loadConfig, saveConfig } from "../lib/config.js";
|
|
4
|
+
import { SUPPORTED_PROVIDERS } from "../lib/providers.js";
|
|
5
|
+
|
|
6
|
+
export const modelsCommand = new Command("models");
|
|
7
|
+
|
|
8
|
+
modelsCommand
|
|
9
|
+
.command("list")
|
|
10
|
+
.description("List models")
|
|
11
|
+
.action(() => {
|
|
12
|
+
const config = loadConfig();
|
|
13
|
+
|
|
14
|
+
if (!config.activeProvider) {
|
|
15
|
+
console.log(chalk.red("No active provider selected"));
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const provider = SUPPORTED_PROVIDERS.find(
|
|
20
|
+
p => p.name === config.activeProvider
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
if (!provider) return;
|
|
24
|
+
|
|
25
|
+
for (const model of provider.models) {
|
|
26
|
+
const active =
|
|
27
|
+
config.activeModel === model
|
|
28
|
+
? chalk.green(" (active)")
|
|
29
|
+
: "";
|
|
30
|
+
|
|
31
|
+
console.log(`- ${model}${active}`);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
modelsCommand
|
|
36
|
+
.command("set")
|
|
37
|
+
.argument("<model>")
|
|
38
|
+
.description("Set active model")
|
|
39
|
+
.action((model) => {
|
|
40
|
+
const config = loadConfig();
|
|
41
|
+
|
|
42
|
+
config.activeModel = model;
|
|
43
|
+
|
|
44
|
+
saveConfig(config);
|
|
45
|
+
|
|
46
|
+
console.log(
|
|
47
|
+
chalk.green(`Active model set to ${model}`)
|
|
48
|
+
);
|
|
49
|
+
});
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { getConfigPath, loadConfig, saveConfig } from "../lib/config.js";
|
|
4
|
+
|
|
5
|
+
export const providersCommand = new Command("providers")
|
|
6
|
+
.description("Manage API providers");
|
|
7
|
+
|
|
8
|
+
providersCommand
|
|
9
|
+
.command("list")
|
|
10
|
+
.description("List configured providers")
|
|
11
|
+
.action(() => {
|
|
12
|
+
const config = loadConfig();
|
|
13
|
+
const names = Object.keys(config.providers);
|
|
14
|
+
|
|
15
|
+
console.log(chalk.gray(`Config: ${getConfigPath()}`));
|
|
16
|
+
|
|
17
|
+
if (names.length === 0) {
|
|
18
|
+
console.log(chalk.yellow("No providers configured yet."));
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
for (const name of names) {
|
|
23
|
+
const active = config.activeProvider === name ? chalk.green(" active") : "";
|
|
24
|
+
console.log(`- ${name}${active}`);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
providersCommand
|
|
29
|
+
.command("login")
|
|
30
|
+
.description("Save provider API key")
|
|
31
|
+
.requiredOption("-p, --provider <provider>", "Provider name")
|
|
32
|
+
.requiredOption("-k, --api-key <apiKey>", "API key")
|
|
33
|
+
.action((options) => {
|
|
34
|
+
const config = loadConfig();
|
|
35
|
+
|
|
36
|
+
config.providers[options.provider] = {
|
|
37
|
+
apiKey: options.apiKey,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
if (!config.activeProvider) {
|
|
41
|
+
config.activeProvider = options.provider;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
saveConfig(config);
|
|
45
|
+
|
|
46
|
+
console.log(chalk.green(`Logged in provider: ${options.provider}`));
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
providersCommand
|
|
50
|
+
.command("set")
|
|
51
|
+
.description("Set active provider")
|
|
52
|
+
.argument("<provider>", "Provider name")
|
|
53
|
+
.action((provider) => {
|
|
54
|
+
const config = loadConfig();
|
|
55
|
+
|
|
56
|
+
if (!config.providers[provider]) {
|
|
57
|
+
console.log(chalk.red(`Provider not found: ${provider}`));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
config.activeProvider = provider;
|
|
62
|
+
saveConfig(config);
|
|
63
|
+
|
|
64
|
+
console.log(chalk.green(`Active provider set to: ${provider}`));
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
providersCommand
|
|
68
|
+
.command("logout")
|
|
69
|
+
.description("Remove provider")
|
|
70
|
+
.requiredOption("-p, --provider <provider>", "Provider name")
|
|
71
|
+
.action((options) => {
|
|
72
|
+
const config = loadConfig();
|
|
73
|
+
|
|
74
|
+
delete config.providers[options.provider];
|
|
75
|
+
|
|
76
|
+
if (config.activeProvider === options.provider) {
|
|
77
|
+
config.activeProvider = Object.keys(config.providers)[0];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
saveConfig(config);
|
|
81
|
+
|
|
82
|
+
console.log(chalk.green(`Logged out provider: ${options.provider}`));
|
|
83
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { listFiles, readFile, writeFile } from "../tools/tools.js";
|
|
4
|
+
|
|
5
|
+
export const toolsCommand = new Command("tools")
|
|
6
|
+
.description("Test local tools");
|
|
7
|
+
|
|
8
|
+
toolsCommand
|
|
9
|
+
.command("list")
|
|
10
|
+
.argument("[dir]", "Directory", ".")
|
|
11
|
+
.action((dir) => {
|
|
12
|
+
try {
|
|
13
|
+
console.log(listFiles(dir));
|
|
14
|
+
} catch (err) {
|
|
15
|
+
console.log(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
toolsCommand
|
|
20
|
+
.command("read")
|
|
21
|
+
.argument("<file>", "File path")
|
|
22
|
+
.action((file) => {
|
|
23
|
+
try {
|
|
24
|
+
console.log(readFile(file));
|
|
25
|
+
} catch (err) {
|
|
26
|
+
console.log(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
toolsCommand
|
|
31
|
+
.command("write")
|
|
32
|
+
.argument("<file>", "File path")
|
|
33
|
+
.argument("<content>", "File content")
|
|
34
|
+
.action((file, content) => {
|
|
35
|
+
try {
|
|
36
|
+
console.log(writeFile(file, content));
|
|
37
|
+
} catch (err) {
|
|
38
|
+
console.log(chalk.red(err instanceof Error ? err.message : String(err)));
|
|
39
|
+
}
|
|
40
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { render } from "ink";
|
|
4
|
+
import { App } from "../tui/App.js";
|
|
5
|
+
import { clearHistory } from "../lib/history.js";
|
|
6
|
+
import { setWorkspace } from "../tools/workspace.js";
|
|
7
|
+
import { clearAgentMemory } from "../lib/agentMemory.js";
|
|
8
|
+
|
|
9
|
+
export const tuiCommand = new Command("tui")
|
|
10
|
+
.description("Start TUI mode")
|
|
11
|
+
.option("--session <name>", "TUI session name", "tui")
|
|
12
|
+
.option("--clear", "Clear TUI history before starting")
|
|
13
|
+
.option("-w, --workspace <workspace>", "Workspace path", process.cwd())
|
|
14
|
+
.option("--direct", "Use direct streaming chat mode by default")
|
|
15
|
+
.action((options) => {
|
|
16
|
+
setWorkspace(options.workspace);
|
|
17
|
+
|
|
18
|
+
if (options.clear) {
|
|
19
|
+
clearHistory(options.session);
|
|
20
|
+
clearAgentMemory(options.session);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
render(<App sessionName={options.session} direct={options.direct}/>);
|
|
24
|
+
});
|