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 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
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env bun
2
+ import "../src/cli.ts";
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
+ });