@horneross/cli 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 +222 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +532 -0
- package/dist/index.js.map +1 -0
- package/package.json +66 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Horneross
|
|
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,222 @@
|
|
|
1
|
+
# @horneross/cli
|
|
2
|
+
|
|
3
|
+
Terminal interface for Horneross AI agents - interact with your agents directly from the command line.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
### Development (from monorepo)
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
cd packages/cli
|
|
11
|
+
pnpm install
|
|
12
|
+
pnpm build
|
|
13
|
+
|
|
14
|
+
# Test locally
|
|
15
|
+
node dist/index.js --help
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Global Installation (Future)
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g @horneross/cli
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
### 1. Initialize Configuration
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
horneross config init
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
You'll be prompted for:
|
|
33
|
+
- **Agent name**: A friendly name (e.g., "adam")
|
|
34
|
+
- **Agent ID**: Your agent's ID (e.g., `clrz0tn6h000108kxfyomdzxg`)
|
|
35
|
+
- **API Key**: Your agent's API key
|
|
36
|
+
- **Base URL**: API endpoint (default: `http://localhost:3000`)
|
|
37
|
+
|
|
38
|
+
Configuration is saved to `~/.horneross/config.yaml`.
|
|
39
|
+
|
|
40
|
+
### 2. Send a Message
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
horneross chat "Hello, how are you?"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 3. Interactive Mode
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
horneross interactive
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Start a continuous conversation. Type `exit` to quit.
|
|
53
|
+
|
|
54
|
+
## Commands
|
|
55
|
+
|
|
56
|
+
### `horneross chat <message>`
|
|
57
|
+
|
|
58
|
+
Send a one-shot message to your agent.
|
|
59
|
+
|
|
60
|
+
**Options:**
|
|
61
|
+
- `-a, --agent <name>` - Use a specific agent (default: configured default agent)
|
|
62
|
+
- `--conversation-id <id>` - Continue an existing conversation
|
|
63
|
+
|
|
64
|
+
**Examples:**
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
# Basic chat
|
|
68
|
+
horneross chat "What is TypeScript?"
|
|
69
|
+
|
|
70
|
+
# Use specific agent
|
|
71
|
+
horneross chat "Generate a PDF report" --agent adam
|
|
72
|
+
|
|
73
|
+
# Continue conversation
|
|
74
|
+
horneross chat "Tell me more" --conversation-id abc123
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### `horneross interactive`
|
|
78
|
+
|
|
79
|
+
Start an interactive chat session (REPL mode).
|
|
80
|
+
|
|
81
|
+
**Options:**
|
|
82
|
+
- `-a, --agent <name>` - Use a specific agent
|
|
83
|
+
|
|
84
|
+
**Examples:**
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Interactive session with default agent
|
|
88
|
+
horneross interactive
|
|
89
|
+
|
|
90
|
+
# Interactive session with specific agent
|
|
91
|
+
horneross interactive --agent adam
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
In interactive mode:
|
|
95
|
+
- Type messages and press Enter
|
|
96
|
+
- Conversation persists across messages
|
|
97
|
+
- Type `exit` or press Ctrl+C to quit
|
|
98
|
+
|
|
99
|
+
### `horneross config init`
|
|
100
|
+
|
|
101
|
+
Initialize or update CLI configuration.
|
|
102
|
+
|
|
103
|
+
### `horneross config show`
|
|
104
|
+
|
|
105
|
+
Display current configuration.
|
|
106
|
+
|
|
107
|
+
## Configuration File
|
|
108
|
+
|
|
109
|
+
Configuration is stored at `~/.horneross/config.yaml`:
|
|
110
|
+
|
|
111
|
+
```yaml
|
|
112
|
+
default_agent: adam
|
|
113
|
+
base_url: http://localhost:3000
|
|
114
|
+
|
|
115
|
+
agents:
|
|
116
|
+
adam:
|
|
117
|
+
id: clrz0tn6h000108kxfyomdzxg
|
|
118
|
+
api_key: f7d3174f-4335-4a2b-bb02-416453ea2099
|
|
119
|
+
name: Adam
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Multiple Agents
|
|
123
|
+
|
|
124
|
+
You can configure multiple agents and switch between them:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
# Add second agent
|
|
128
|
+
horneross config init
|
|
129
|
+
# Enter "maria" as name, then her ID and API key
|
|
130
|
+
|
|
131
|
+
# Use specific agent
|
|
132
|
+
horneross chat "Hello" --agent maria
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Features
|
|
136
|
+
|
|
137
|
+
### ✅ Phase 1 MVP (Complete)
|
|
138
|
+
|
|
139
|
+
- ✅ One-shot chat command
|
|
140
|
+
- ✅ Configuration management
|
|
141
|
+
- ✅ SSE streaming support
|
|
142
|
+
- ✅ Tool execution visualization (spinners)
|
|
143
|
+
- ✅ Interactive REPL mode
|
|
144
|
+
- ✅ Bearer token authentication
|
|
145
|
+
|
|
146
|
+
### 🚧 Future Phases
|
|
147
|
+
|
|
148
|
+
- File attachments (`--attach`)
|
|
149
|
+
- Markdown rendering with syntax highlighting
|
|
150
|
+
- Conversation history management
|
|
151
|
+
- Tab completion
|
|
152
|
+
- Multi-agent switching improvements
|
|
153
|
+
|
|
154
|
+
## Architecture
|
|
155
|
+
|
|
156
|
+
The CLI is a **pure HTTP client** that consumes the existing Horneross API:
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
Terminal → CLI → HTTP POST /api/v2/agent/{agentId}/chat → ChatService → Agent
|
|
160
|
+
↓
|
|
161
|
+
SSE Response
|
|
162
|
+
↓
|
|
163
|
+
Stream Adapter
|
|
164
|
+
↓
|
|
165
|
+
stdout
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Key Components
|
|
169
|
+
|
|
170
|
+
- **ConfigManager** (`src/config/config-manager.ts`) - YAML config handling
|
|
171
|
+
- **StreamAdapter** (`src/adapters/stream-adapter.ts`) - SSE → terminal output
|
|
172
|
+
- **AuthManager** (`src/auth/auth-manager.ts`) - API key validation
|
|
173
|
+
- **Commands** (`src/commands/`) - CLI command implementations
|
|
174
|
+
|
|
175
|
+
## Development
|
|
176
|
+
|
|
177
|
+
### Build
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
pnpm build
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Watch Mode
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
pnpm dev
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Type Check
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
pnpm typecheck
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Troubleshooting
|
|
196
|
+
|
|
197
|
+
### "No default agent configured"
|
|
198
|
+
|
|
199
|
+
Run `horneross config init` to set up your configuration.
|
|
200
|
+
|
|
201
|
+
### "Authentication failed"
|
|
202
|
+
|
|
203
|
+
Verify your API key and agent ID are correct:
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
horneross config show
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Re-run `horneross config init` if needed.
|
|
210
|
+
|
|
211
|
+
### "Connection failed"
|
|
212
|
+
|
|
213
|
+
Ensure the Horneross API server is running:
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
# In the main project
|
|
217
|
+
pnpm dev # Should run on http://localhost:3000
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## License
|
|
221
|
+
|
|
222
|
+
MIT
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Command as Command4 } from "commander";
|
|
5
|
+
import chalk6 from "chalk";
|
|
6
|
+
|
|
7
|
+
// src/commands/chat.ts
|
|
8
|
+
import { Command } from "commander";
|
|
9
|
+
import chalk2 from "chalk";
|
|
10
|
+
|
|
11
|
+
// src/config/config-manager.ts
|
|
12
|
+
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
13
|
+
import { homedir } from "os";
|
|
14
|
+
import { join } from "path";
|
|
15
|
+
import { parse, stringify } from "yaml";
|
|
16
|
+
var CONFIG_DIR = join(homedir(), ".horneross");
|
|
17
|
+
var CONFIG_PATH = join(CONFIG_DIR, "config.yaml");
|
|
18
|
+
var DEFAULT_CONFIG = {
|
|
19
|
+
default_agent: "",
|
|
20
|
+
base_url: "http://localhost:3000",
|
|
21
|
+
agents: {}
|
|
22
|
+
};
|
|
23
|
+
var ConfigManager = class {
|
|
24
|
+
static async load() {
|
|
25
|
+
try {
|
|
26
|
+
const content = await readFile(CONFIG_PATH, "utf-8");
|
|
27
|
+
const config = parse(content);
|
|
28
|
+
return { ...DEFAULT_CONFIG, ...config };
|
|
29
|
+
} catch (error) {
|
|
30
|
+
if (error.code === "ENOENT") {
|
|
31
|
+
return DEFAULT_CONFIG;
|
|
32
|
+
}
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
static async save(config) {
|
|
37
|
+
await mkdir(CONFIG_DIR, { recursive: true });
|
|
38
|
+
const content = stringify(config);
|
|
39
|
+
await writeFile(CONFIG_PATH, content, { mode: 384 });
|
|
40
|
+
}
|
|
41
|
+
static async addAgent(name, agentConfig) {
|
|
42
|
+
const config = await this.load();
|
|
43
|
+
config.agents[name] = agentConfig;
|
|
44
|
+
if (!config.default_agent) {
|
|
45
|
+
config.default_agent = name;
|
|
46
|
+
}
|
|
47
|
+
await this.save(config);
|
|
48
|
+
}
|
|
49
|
+
static async getAgent(name) {
|
|
50
|
+
const config = await this.load();
|
|
51
|
+
const agentName = name || config.default_agent;
|
|
52
|
+
if (!agentName) {
|
|
53
|
+
throw new Error("No default agent configured. Run: horneross config init");
|
|
54
|
+
}
|
|
55
|
+
const agent = config.agents[agentName];
|
|
56
|
+
if (!agent) {
|
|
57
|
+
throw new Error(`Agent "${agentName}" not found in configuration`);
|
|
58
|
+
}
|
|
59
|
+
return agent;
|
|
60
|
+
}
|
|
61
|
+
static async validateAuth(agentConfig, baseUrl) {
|
|
62
|
+
try {
|
|
63
|
+
const response = await fetch(`${baseUrl}/api/v2/agent/${agentConfig.id}/config`, {
|
|
64
|
+
headers: {
|
|
65
|
+
Authorization: `Bearer ${agentConfig.api_key}`
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
return response.ok;
|
|
69
|
+
} catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
static getConfigPath() {
|
|
74
|
+
return CONFIG_PATH;
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// src/adapters/stream-adapter.ts
|
|
79
|
+
import { createParser } from "eventsource-parser";
|
|
80
|
+
import ora from "ora";
|
|
81
|
+
import chalk from "chalk";
|
|
82
|
+
var StreamAdapter = class {
|
|
83
|
+
activeSpinner = null;
|
|
84
|
+
toolCallStack = /* @__PURE__ */ new Map();
|
|
85
|
+
metadata = null;
|
|
86
|
+
async processStream(response) {
|
|
87
|
+
if (!response.body) {
|
|
88
|
+
throw new Error("Response body is null");
|
|
89
|
+
}
|
|
90
|
+
const reader = response.body.getReader();
|
|
91
|
+
const decoder = new TextDecoder();
|
|
92
|
+
return new Promise((resolve, reject) => {
|
|
93
|
+
const parser = createParser((event) => {
|
|
94
|
+
if (event.type === "event") {
|
|
95
|
+
try {
|
|
96
|
+
const data = JSON.parse(event.data);
|
|
97
|
+
this.handleEvent(data);
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.error(chalk.red("Failed to parse SSE event:"), error);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
const processChunk = async () => {
|
|
104
|
+
try {
|
|
105
|
+
const { done, value } = await reader.read();
|
|
106
|
+
if (done) {
|
|
107
|
+
this.cleanup();
|
|
108
|
+
resolve(this.metadata);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
112
|
+
parser.feed(chunk);
|
|
113
|
+
await processChunk();
|
|
114
|
+
} catch (error) {
|
|
115
|
+
this.cleanup();
|
|
116
|
+
reject(error);
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
processChunk();
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
handleEvent(event) {
|
|
123
|
+
switch (event.type) {
|
|
124
|
+
case "text-delta":
|
|
125
|
+
this.handleTextDelta(event);
|
|
126
|
+
break;
|
|
127
|
+
case "tool-call":
|
|
128
|
+
this.handleToolCall(event);
|
|
129
|
+
break;
|
|
130
|
+
case "tool-result":
|
|
131
|
+
this.handleToolResult(event);
|
|
132
|
+
break;
|
|
133
|
+
case "data-message-ids":
|
|
134
|
+
this.handleMetadata(event);
|
|
135
|
+
break;
|
|
136
|
+
case "error":
|
|
137
|
+
this.handleError(event);
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
handleTextDelta(event) {
|
|
142
|
+
if (this.activeSpinner) {
|
|
143
|
+
this.activeSpinner.stop();
|
|
144
|
+
this.activeSpinner = null;
|
|
145
|
+
}
|
|
146
|
+
if (event.content) {
|
|
147
|
+
process.stdout.write(event.content);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
handleToolCall(event) {
|
|
151
|
+
const { toolName, args } = event;
|
|
152
|
+
const toolCallId = `${toolName}-${Date.now()}`;
|
|
153
|
+
this.toolCallStack.set(toolCallId, {
|
|
154
|
+
name: toolName || "unknown",
|
|
155
|
+
startTime: Date.now()
|
|
156
|
+
});
|
|
157
|
+
if (this.activeSpinner) {
|
|
158
|
+
this.activeSpinner.stop();
|
|
159
|
+
}
|
|
160
|
+
const argsPreview = this.formatArgs(args);
|
|
161
|
+
this.activeSpinner = ora({
|
|
162
|
+
text: chalk.cyan(`${toolName}${argsPreview}`),
|
|
163
|
+
prefixText: "\n"
|
|
164
|
+
}).start();
|
|
165
|
+
}
|
|
166
|
+
handleToolResult(event) {
|
|
167
|
+
if (this.activeSpinner) {
|
|
168
|
+
const { toolName } = event;
|
|
169
|
+
const elapsed = this.getElapsedTime();
|
|
170
|
+
this.activeSpinner.succeed(
|
|
171
|
+
chalk.green(`${toolName} ${chalk.gray(`(${elapsed})`)}`)
|
|
172
|
+
);
|
|
173
|
+
this.activeSpinner = null;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
handleMetadata(event) {
|
|
177
|
+
if (event.data && typeof event.data === "object" && "conversationId" in event.data) {
|
|
178
|
+
this.metadata = event.data;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
handleError(event) {
|
|
182
|
+
this.cleanup();
|
|
183
|
+
console.error(chalk.red("\n\u2716 Error:"), event.content || "Unknown error");
|
|
184
|
+
}
|
|
185
|
+
formatArgs(args) {
|
|
186
|
+
if (!args || typeof args !== "object") {
|
|
187
|
+
return "";
|
|
188
|
+
}
|
|
189
|
+
const entries = Object.entries(args);
|
|
190
|
+
if (entries.length === 0) {
|
|
191
|
+
return "";
|
|
192
|
+
}
|
|
193
|
+
const preview = entries.slice(0, 2).map(([key, value]) => {
|
|
194
|
+
const valueStr = typeof value === "string" ? value : JSON.stringify(value);
|
|
195
|
+
const truncated = valueStr.length > 30 ? valueStr.slice(0, 30) + "..." : valueStr;
|
|
196
|
+
return `${key}: ${truncated}`;
|
|
197
|
+
}).join(", ");
|
|
198
|
+
return ` ${chalk.gray(`(${preview})`)}`;
|
|
199
|
+
}
|
|
200
|
+
getElapsedTime() {
|
|
201
|
+
const lastTool = Array.from(this.toolCallStack.values()).pop();
|
|
202
|
+
if (!lastTool) {
|
|
203
|
+
return "0s";
|
|
204
|
+
}
|
|
205
|
+
const elapsed = Date.now() - lastTool.startTime;
|
|
206
|
+
return elapsed < 1e3 ? `${elapsed}ms` : `${(elapsed / 1e3).toFixed(1)}s`;
|
|
207
|
+
}
|
|
208
|
+
cleanup() {
|
|
209
|
+
if (this.activeSpinner) {
|
|
210
|
+
this.activeSpinner.stop();
|
|
211
|
+
this.activeSpinner = null;
|
|
212
|
+
}
|
|
213
|
+
this.toolCallStack.clear();
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
// src/commands/chat.ts
|
|
218
|
+
function createChatCommand() {
|
|
219
|
+
const chat = new Command("chat");
|
|
220
|
+
chat.description("Send a one-shot message to your agent").argument("<message>", "Message to send to the agent").option("-a, --agent <name>", "Agent to use (defaults to configured default)").option("--conversation-id <id>", "Continue an existing conversation").action(async (message, options) => {
|
|
221
|
+
try {
|
|
222
|
+
const config = await ConfigManager.load();
|
|
223
|
+
const agentName = options.agent || config.default_agent;
|
|
224
|
+
if (!agentName) {
|
|
225
|
+
console.error(chalk2.red("\n\u2716 No default agent configured"));
|
|
226
|
+
console.error(chalk2.yellow("Run: horneross config init\n"));
|
|
227
|
+
process.exit(1);
|
|
228
|
+
}
|
|
229
|
+
const agent = config.agents[agentName];
|
|
230
|
+
if (!agent) {
|
|
231
|
+
console.error(chalk2.red(`
|
|
232
|
+
\u2716 Agent "${agentName}" not found`));
|
|
233
|
+
console.error(chalk2.yellow("Available agents:"));
|
|
234
|
+
for (const name of Object.keys(config.agents)) {
|
|
235
|
+
console.error(chalk2.gray(` - ${name}`));
|
|
236
|
+
}
|
|
237
|
+
console.error();
|
|
238
|
+
process.exit(1);
|
|
239
|
+
}
|
|
240
|
+
const requestBody = {
|
|
241
|
+
query: message,
|
|
242
|
+
streaming: true,
|
|
243
|
+
executionMode: "chat",
|
|
244
|
+
...options.conversationId && { conversationId: options.conversationId }
|
|
245
|
+
};
|
|
246
|
+
const response = await fetch(
|
|
247
|
+
`${config.base_url}/api/v2/agent/${agent.id}/chat`,
|
|
248
|
+
{
|
|
249
|
+
method: "POST",
|
|
250
|
+
headers: {
|
|
251
|
+
"Content-Type": "application/json",
|
|
252
|
+
Authorization: `Bearer ${agent.api_key}`
|
|
253
|
+
},
|
|
254
|
+
body: JSON.stringify(requestBody)
|
|
255
|
+
}
|
|
256
|
+
);
|
|
257
|
+
if (!response.ok) {
|
|
258
|
+
const errorText = await response.text();
|
|
259
|
+
console.error(chalk2.red(`
|
|
260
|
+
\u2716 Request failed (${response.status}):`), errorText);
|
|
261
|
+
process.exit(1);
|
|
262
|
+
}
|
|
263
|
+
const adapter = new StreamAdapter();
|
|
264
|
+
const metadata = await adapter.processStream(response);
|
|
265
|
+
if (metadata) {
|
|
266
|
+
console.log(
|
|
267
|
+
chalk2.gray(
|
|
268
|
+
`
|
|
269
|
+
|
|
270
|
+
Conversation ID: ${metadata.conversationId}`
|
|
271
|
+
)
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
console.log();
|
|
275
|
+
} catch (error) {
|
|
276
|
+
const message2 = error instanceof Error ? error.message : "Unknown error";
|
|
277
|
+
console.error(chalk2.red("\n\u2716 Chat failed:"), message2);
|
|
278
|
+
process.exit(1);
|
|
279
|
+
}
|
|
280
|
+
});
|
|
281
|
+
return chat;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// src/commands/config.ts
|
|
285
|
+
import { Command as Command2 } from "commander";
|
|
286
|
+
import chalk4 from "chalk";
|
|
287
|
+
import * as readline from "readline/promises";
|
|
288
|
+
|
|
289
|
+
// src/auth/auth-manager.ts
|
|
290
|
+
import chalk3 from "chalk";
|
|
291
|
+
var AuthManager = class {
|
|
292
|
+
static async validateConnection(agentConfig, baseUrl) {
|
|
293
|
+
try {
|
|
294
|
+
const response = await fetch(`${baseUrl}/api/v2/agent/${agentConfig.id}/config`, {
|
|
295
|
+
headers: {
|
|
296
|
+
Authorization: `Bearer ${agentConfig.api_key}`
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
if (response.ok) {
|
|
300
|
+
return { valid: true };
|
|
301
|
+
}
|
|
302
|
+
if (response.status === 401) {
|
|
303
|
+
return { valid: false, error: "Invalid API key" };
|
|
304
|
+
}
|
|
305
|
+
if (response.status === 404) {
|
|
306
|
+
return { valid: false, error: "Agent not found" };
|
|
307
|
+
}
|
|
308
|
+
return { valid: false, error: `HTTP ${response.status}: ${response.statusText}` };
|
|
309
|
+
} catch (error) {
|
|
310
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
311
|
+
return { valid: false, error: `Connection failed: ${message}` };
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
static displayAuthError(error) {
|
|
315
|
+
console.error(chalk3.red("\n\u2716 Authentication failed:"), error);
|
|
316
|
+
console.error(chalk3.yellow("\nTroubleshooting:"));
|
|
317
|
+
console.error(chalk3.gray(" 1. Check your API key is correct"));
|
|
318
|
+
console.error(chalk3.gray(" 2. Verify the agent ID exists"));
|
|
319
|
+
console.error(chalk3.gray(" 3. Ensure the base URL is accessible"));
|
|
320
|
+
console.error(chalk3.gray("\nRun: horneross config init"));
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
// src/commands/config.ts
|
|
325
|
+
function createConfigCommand() {
|
|
326
|
+
const config = new Command2("config");
|
|
327
|
+
config.command("init").description("Initialize Horneross CLI configuration").action(async () => {
|
|
328
|
+
console.log(chalk4.bold.cyan("\n\u{1F916} Horneross CLI Setup\n"));
|
|
329
|
+
const rl = readline.createInterface({
|
|
330
|
+
input: process.stdin,
|
|
331
|
+
output: process.stdout
|
|
332
|
+
});
|
|
333
|
+
try {
|
|
334
|
+
const agentName = await rl.question(
|
|
335
|
+
chalk4.yellow('Agent name (e.g., "adam"): ')
|
|
336
|
+
);
|
|
337
|
+
if (!agentName.trim()) {
|
|
338
|
+
console.error(chalk4.red("\n\u2716 Agent name is required"));
|
|
339
|
+
process.exit(1);
|
|
340
|
+
}
|
|
341
|
+
const agentId = await rl.question(
|
|
342
|
+
chalk4.yellow("Agent ID: ")
|
|
343
|
+
);
|
|
344
|
+
if (!agentId.trim()) {
|
|
345
|
+
console.error(chalk4.red("\n\u2716 Agent ID is required"));
|
|
346
|
+
process.exit(1);
|
|
347
|
+
}
|
|
348
|
+
const apiKey = await rl.question(
|
|
349
|
+
chalk4.yellow("API Key: ")
|
|
350
|
+
);
|
|
351
|
+
if (!apiKey.trim()) {
|
|
352
|
+
console.error(chalk4.red("\n\u2716 API Key is required"));
|
|
353
|
+
process.exit(1);
|
|
354
|
+
}
|
|
355
|
+
const baseUrl = await rl.question(
|
|
356
|
+
chalk4.yellow("Base URL [http://localhost:3000]: ")
|
|
357
|
+
);
|
|
358
|
+
const finalBaseUrl = baseUrl.trim() || "http://localhost:3000";
|
|
359
|
+
rl.close();
|
|
360
|
+
const agentConfig = {
|
|
361
|
+
id: agentId.trim(),
|
|
362
|
+
api_key: apiKey.trim(),
|
|
363
|
+
name: agentName.trim()
|
|
364
|
+
};
|
|
365
|
+
console.log(chalk4.gray("\n\u23F3 Validating connection..."));
|
|
366
|
+
const { valid, error } = await AuthManager.validateConnection(
|
|
367
|
+
agentConfig,
|
|
368
|
+
finalBaseUrl
|
|
369
|
+
);
|
|
370
|
+
if (!valid) {
|
|
371
|
+
AuthManager.displayAuthError(error || "Unknown error");
|
|
372
|
+
process.exit(1);
|
|
373
|
+
}
|
|
374
|
+
await ConfigManager.addAgent(agentName.trim(), agentConfig);
|
|
375
|
+
const currentConfig = await ConfigManager.load();
|
|
376
|
+
currentConfig.base_url = finalBaseUrl;
|
|
377
|
+
await ConfigManager.save(currentConfig);
|
|
378
|
+
console.log(chalk4.green("\n\u2713 Configuration saved successfully!"));
|
|
379
|
+
console.log(chalk4.gray(`
|
|
380
|
+
Config file: ${ConfigManager.getConfigPath()}`));
|
|
381
|
+
console.log(chalk4.gray(`Default agent: ${agentName.trim()}`));
|
|
382
|
+
console.log(chalk4.cyan('\nYou can now run: horneross chat "Hello"\n'));
|
|
383
|
+
} catch (error) {
|
|
384
|
+
rl.close();
|
|
385
|
+
console.error(chalk4.red("\n\u2716 Setup failed:"), error);
|
|
386
|
+
process.exit(1);
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
config.command("show").description("Show current configuration").action(async () => {
|
|
390
|
+
try {
|
|
391
|
+
const config2 = await ConfigManager.load();
|
|
392
|
+
console.log(chalk4.bold.cyan("\n\u{1F527} Current Configuration\n"));
|
|
393
|
+
console.log(chalk4.yellow("Base URL:"), config2.base_url);
|
|
394
|
+
console.log(chalk4.yellow("Default Agent:"), config2.default_agent || chalk4.gray("(not set)"));
|
|
395
|
+
console.log(chalk4.yellow("\nConfigured Agents:"));
|
|
396
|
+
if (Object.keys(config2.agents).length === 0) {
|
|
397
|
+
console.log(chalk4.gray(" No agents configured"));
|
|
398
|
+
} else {
|
|
399
|
+
for (const [name, agent] of Object.entries(config2.agents)) {
|
|
400
|
+
const isDefault = name === config2.default_agent;
|
|
401
|
+
const marker = isDefault ? chalk4.green("\u2713") : " ";
|
|
402
|
+
console.log(` ${marker} ${chalk4.cyan(name)} (${agent.id})`);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
console.log(chalk4.gray(`
|
|
406
|
+
Config file: ${ConfigManager.getConfigPath()}
|
|
407
|
+
`));
|
|
408
|
+
} catch (error) {
|
|
409
|
+
console.error(chalk4.red("Failed to load configuration:"), error);
|
|
410
|
+
process.exit(1);
|
|
411
|
+
}
|
|
412
|
+
});
|
|
413
|
+
return config;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// src/commands/interactive.ts
|
|
417
|
+
import { Command as Command3 } from "commander";
|
|
418
|
+
import chalk5 from "chalk";
|
|
419
|
+
import * as readline2 from "readline";
|
|
420
|
+
import { createId } from "@paralleldrive/cuid2";
|
|
421
|
+
function createInteractiveCommand() {
|
|
422
|
+
const interactive = new Command3("interactive");
|
|
423
|
+
interactive.description("Start an interactive chat session").option("-a, --agent <name>", "Agent to use (defaults to configured default)").action(async (options) => {
|
|
424
|
+
try {
|
|
425
|
+
const config = await ConfigManager.load();
|
|
426
|
+
const agentName = options.agent || config.default_agent;
|
|
427
|
+
if (!agentName) {
|
|
428
|
+
console.error(chalk5.red("\n\u2716 No default agent configured"));
|
|
429
|
+
console.error(chalk5.yellow("Run: horneross config init\n"));
|
|
430
|
+
process.exit(1);
|
|
431
|
+
}
|
|
432
|
+
const agent = config.agents[agentName];
|
|
433
|
+
if (!agent) {
|
|
434
|
+
console.error(chalk5.red(`
|
|
435
|
+
\u2716 Agent "${agentName}" not found`));
|
|
436
|
+
process.exit(1);
|
|
437
|
+
}
|
|
438
|
+
console.log(chalk5.bold.cyan(`
|
|
439
|
+
\u{1F916} Interactive mode with ${agent.name}`));
|
|
440
|
+
console.log(chalk5.gray('Type "exit" or press Ctrl+C to quit\n'));
|
|
441
|
+
const conversationId = createId();
|
|
442
|
+
let messageCount = 0;
|
|
443
|
+
const rl = readline2.createInterface({
|
|
444
|
+
input: process.stdin,
|
|
445
|
+
output: process.stdout,
|
|
446
|
+
prompt: chalk5.green("> ")
|
|
447
|
+
});
|
|
448
|
+
rl.prompt();
|
|
449
|
+
rl.on("line", async (input) => {
|
|
450
|
+
const trimmed = input.trim();
|
|
451
|
+
if (trimmed === "exit" || trimmed === "quit") {
|
|
452
|
+
console.log(chalk5.gray("\nGoodbye! \u{1F44B}\n"));
|
|
453
|
+
rl.close();
|
|
454
|
+
process.exit(0);
|
|
455
|
+
}
|
|
456
|
+
if (!trimmed) {
|
|
457
|
+
rl.prompt();
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
460
|
+
try {
|
|
461
|
+
messageCount++;
|
|
462
|
+
const response = await fetch(
|
|
463
|
+
`${config.base_url}/api/v2/agent/${agent.id}/chat`,
|
|
464
|
+
{
|
|
465
|
+
method: "POST",
|
|
466
|
+
headers: {
|
|
467
|
+
"Content-Type": "application/json",
|
|
468
|
+
Authorization: `Bearer ${agent.api_key}`
|
|
469
|
+
},
|
|
470
|
+
body: JSON.stringify({
|
|
471
|
+
query: trimmed,
|
|
472
|
+
streaming: true,
|
|
473
|
+
executionMode: "chat",
|
|
474
|
+
conversationId
|
|
475
|
+
})
|
|
476
|
+
}
|
|
477
|
+
);
|
|
478
|
+
if (!response.ok) {
|
|
479
|
+
const errorText = await response.text();
|
|
480
|
+
console.error(chalk5.red(`
|
|
481
|
+
\u2716 Request failed (${response.status}):`), errorText);
|
|
482
|
+
rl.prompt();
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
const adapter = new StreamAdapter();
|
|
486
|
+
await adapter.processStream(response);
|
|
487
|
+
console.log("\n");
|
|
488
|
+
rl.prompt();
|
|
489
|
+
} catch (error) {
|
|
490
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
491
|
+
console.error(chalk5.red("\n\u2716 Error:"), message);
|
|
492
|
+
rl.prompt();
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
rl.on("close", () => {
|
|
496
|
+
console.log(
|
|
497
|
+
chalk5.gray(`
|
|
498
|
+
Session ended. ${messageCount} messages exchanged.
|
|
499
|
+
`)
|
|
500
|
+
);
|
|
501
|
+
process.exit(0);
|
|
502
|
+
});
|
|
503
|
+
} catch (error) {
|
|
504
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
505
|
+
console.error(chalk5.red("\n\u2716 Interactive mode failed:"), message);
|
|
506
|
+
process.exit(1);
|
|
507
|
+
}
|
|
508
|
+
});
|
|
509
|
+
return interactive;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// src/index.ts
|
|
513
|
+
var program = new Command4();
|
|
514
|
+
program.name("horneross").description("Terminal interface for Horneross AI agents").version("0.1.0");
|
|
515
|
+
program.addCommand(createChatCommand());
|
|
516
|
+
program.addCommand(createConfigCommand());
|
|
517
|
+
program.addCommand(createInteractiveCommand());
|
|
518
|
+
program.on("command:*", () => {
|
|
519
|
+
console.error(chalk6.red("\n\u2716 Invalid command"));
|
|
520
|
+
console.log(chalk6.yellow("\nAvailable commands:"));
|
|
521
|
+
console.log(chalk6.gray(" horneross chat <message> Send a one-shot message"));
|
|
522
|
+
console.log(chalk6.gray(" horneross interactive Start interactive session"));
|
|
523
|
+
console.log(chalk6.gray(" horneross config init Initialize configuration"));
|
|
524
|
+
console.log(chalk6.gray(" horneross config show Show current configuration"));
|
|
525
|
+
console.log(chalk6.gray('\nRun "horneross --help" for more details\n'));
|
|
526
|
+
process.exit(1);
|
|
527
|
+
});
|
|
528
|
+
program.parse(process.argv);
|
|
529
|
+
if (!process.argv.slice(2).length) {
|
|
530
|
+
program.outputHelp();
|
|
531
|
+
}
|
|
532
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/chat.ts","../src/config/config-manager.ts","../src/adapters/stream-adapter.ts","../src/commands/config.ts","../src/auth/auth-manager.ts","../src/commands/interactive.ts"],"sourcesContent":["import { Command } from 'commander';\nimport chalk from 'chalk';\nimport { createChatCommand } from './commands/chat.js';\nimport { createConfigCommand } from './commands/config.js';\nimport { createInteractiveCommand } from './commands/interactive.js';\n\nconst program = new Command();\n\nprogram\n .name('horneross')\n .description('Terminal interface for Horneross AI agents')\n .version('0.1.0');\n\nprogram.addCommand(createChatCommand());\nprogram.addCommand(createConfigCommand());\nprogram.addCommand(createInteractiveCommand());\n\nprogram.on('command:*', () => {\n console.error(chalk.red('\\n✖ Invalid command'));\n console.log(chalk.yellow('\\nAvailable commands:'));\n console.log(chalk.gray(' horneross chat <message> Send a one-shot message'));\n console.log(chalk.gray(' horneross interactive Start interactive session'));\n console.log(chalk.gray(' horneross config init Initialize configuration'));\n console.log(chalk.gray(' horneross config show Show current configuration'));\n console.log(chalk.gray('\\nRun \"horneross --help\" for more details\\n'));\n process.exit(1);\n});\n\nprogram.parse(process.argv);\n\nif (!process.argv.slice(2).length) {\n program.outputHelp();\n}\n","import { Command } from 'commander';\nimport chalk from 'chalk';\nimport { ConfigManager } from '../config/config-manager.js';\nimport { StreamAdapter } from '../adapters/stream-adapter.js';\nimport type { ChatOptions } from '../types.js';\n\nexport function createChatCommand(): Command {\n const chat = new Command('chat');\n\n chat\n .description('Send a one-shot message to your agent')\n .argument('<message>', 'Message to send to the agent')\n .option('-a, --agent <name>', 'Agent to use (defaults to configured default)')\n .option('--conversation-id <id>', 'Continue an existing conversation')\n .action(async (message: string, options: ChatOptions) => {\n try {\n const config = await ConfigManager.load();\n const agentName = options.agent || config.default_agent;\n\n if (!agentName) {\n console.error(chalk.red('\\n✖ No default agent configured'));\n console.error(chalk.yellow('Run: horneross config init\\n'));\n process.exit(1);\n }\n\n const agent = config.agents[agentName];\n if (!agent) {\n console.error(chalk.red(`\\n✖ Agent \"${agentName}\" not found`));\n console.error(chalk.yellow('Available agents:'));\n for (const name of Object.keys(config.agents)) {\n console.error(chalk.gray(` - ${name}`));\n }\n console.error();\n process.exit(1);\n }\n\n const requestBody = {\n query: message,\n streaming: true,\n executionMode: 'chat' as const,\n ...(options.conversationId && { conversationId: options.conversationId }),\n };\n\n const response = await fetch(\n `${config.base_url}/api/v2/agent/${agent.id}/chat`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${agent.api_key}`,\n },\n body: JSON.stringify(requestBody),\n }\n );\n\n if (!response.ok) {\n const errorText = await response.text();\n console.error(chalk.red(`\\n✖ Request failed (${response.status}):`), errorText);\n process.exit(1);\n }\n\n const adapter = new StreamAdapter();\n const metadata = await adapter.processStream(response);\n\n if (metadata) {\n console.log(\n chalk.gray(\n `\\n\\nConversation ID: ${metadata.conversationId}`\n )\n );\n }\n\n console.log();\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n console.error(chalk.red('\\n✖ Chat failed:'), message);\n process.exit(1);\n }\n });\n\n return chat;\n}\n","import { readFile, writeFile, mkdir } from 'fs/promises';\nimport { homedir } from 'os';\nimport { join } from 'path';\nimport { parse, stringify } from 'yaml';\nimport type { CLIConfig, AgentConfig } from '../types.js';\n\nconst CONFIG_DIR = join(homedir(), '.horneross');\nconst CONFIG_PATH = join(CONFIG_DIR, 'config.yaml');\n\nconst DEFAULT_CONFIG: CLIConfig = {\n default_agent: '',\n base_url: 'http://localhost:3000',\n agents: {},\n};\n\nexport class ConfigManager {\n static async load(): Promise<CLIConfig> {\n try {\n const content = await readFile(CONFIG_PATH, 'utf-8');\n const config = parse(content) as CLIConfig;\n return { ...DEFAULT_CONFIG, ...config };\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return DEFAULT_CONFIG;\n }\n throw error;\n }\n }\n\n static async save(config: CLIConfig): Promise<void> {\n await mkdir(CONFIG_DIR, { recursive: true });\n const content = stringify(config);\n await writeFile(CONFIG_PATH, content, { mode: 0o600 });\n }\n\n static async addAgent(\n name: string,\n agentConfig: AgentConfig\n ): Promise<void> {\n const config = await this.load();\n config.agents[name] = agentConfig;\n\n if (!config.default_agent) {\n config.default_agent = name;\n }\n\n await this.save(config);\n }\n\n static async getAgent(name?: string): Promise<AgentConfig> {\n const config = await this.load();\n const agentName = name || config.default_agent;\n\n if (!agentName) {\n throw new Error('No default agent configured. Run: horneross config init');\n }\n\n const agent = config.agents[agentName];\n if (!agent) {\n throw new Error(`Agent \"${agentName}\" not found in configuration`);\n }\n\n return agent;\n }\n\n static async validateAuth(\n agentConfig: AgentConfig,\n baseUrl: string\n ): Promise<boolean> {\n try {\n const response = await fetch(`${baseUrl}/api/v2/agent/${agentConfig.id}/config`, {\n headers: {\n Authorization: `Bearer ${agentConfig.api_key}`,\n },\n });\n\n return response.ok;\n } catch {\n return false;\n }\n }\n\n static getConfigPath(): string {\n return CONFIG_PATH;\n }\n}\n","import { createParser } from 'eventsource-parser';\nimport ora, { type Ora } from 'ora';\nimport chalk from 'chalk';\nimport type { SSEEvent, StreamMetadata } from '../types.js';\n\nexport class StreamAdapter {\n private activeSpinner: Ora | null = null;\n private toolCallStack: Map<string, { name: string; startTime: number }> =\n new Map();\n private metadata: StreamMetadata | null = null;\n\n async processStream(response: Response): Promise<StreamMetadata | null> {\n if (!response.body) {\n throw new Error('Response body is null');\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n\n return new Promise((resolve, reject) => {\n const parser = createParser((event) => {\n if (event.type === 'event') {\n try {\n const data = JSON.parse(event.data);\n this.handleEvent(data);\n } catch (error) {\n console.error(chalk.red('Failed to parse SSE event:'), error);\n }\n }\n });\n\n const processChunk = async (): Promise<void> => {\n try {\n const { done, value } = await reader.read();\n\n if (done) {\n this.cleanup();\n resolve(this.metadata);\n return;\n }\n\n const chunk = decoder.decode(value, { stream: true });\n parser.feed(chunk);\n\n await processChunk();\n } catch (error) {\n this.cleanup();\n reject(error);\n }\n };\n\n processChunk();\n });\n }\n\n private handleEvent(event: SSEEvent): void {\n switch (event.type) {\n case 'text-delta':\n this.handleTextDelta(event);\n break;\n case 'tool-call':\n this.handleToolCall(event);\n break;\n case 'tool-result':\n this.handleToolResult(event);\n break;\n case 'data-message-ids':\n this.handleMetadata(event);\n break;\n case 'error':\n this.handleError(event);\n break;\n }\n }\n\n private handleTextDelta(event: SSEEvent): void {\n if (this.activeSpinner) {\n this.activeSpinner.stop();\n this.activeSpinner = null;\n }\n\n if (event.content) {\n process.stdout.write(event.content);\n }\n }\n\n private handleToolCall(event: SSEEvent): void {\n const { toolName, args } = event;\n const toolCallId = `${toolName}-${Date.now()}`;\n\n this.toolCallStack.set(toolCallId, {\n name: toolName || 'unknown',\n startTime: Date.now(),\n });\n\n if (this.activeSpinner) {\n this.activeSpinner.stop();\n }\n\n const argsPreview = this.formatArgs(args);\n this.activeSpinner = ora({\n text: chalk.cyan(`${toolName}${argsPreview}`),\n prefixText: '\\n',\n }).start();\n }\n\n private handleToolResult(event: SSEEvent): void {\n if (this.activeSpinner) {\n const { toolName } = event;\n const elapsed = this.getElapsedTime();\n\n this.activeSpinner.succeed(\n chalk.green(`${toolName} ${chalk.gray(`(${elapsed})`)}`)\n );\n this.activeSpinner = null;\n }\n }\n\n private handleMetadata(event: SSEEvent): void {\n if (event.data && typeof event.data === 'object' && 'conversationId' in event.data) {\n this.metadata = event.data as StreamMetadata;\n }\n }\n\n private handleError(event: SSEEvent): void {\n this.cleanup();\n console.error(chalk.red('\\n✖ Error:'), event.content || 'Unknown error');\n }\n\n private formatArgs(args: unknown): string {\n if (!args || typeof args !== 'object') {\n return '';\n }\n\n const entries = Object.entries(args as Record<string, unknown>);\n if (entries.length === 0) {\n return '';\n }\n\n const preview = entries\n .slice(0, 2)\n .map(([key, value]) => {\n const valueStr = typeof value === 'string' ? value : JSON.stringify(value);\n const truncated = valueStr.length > 30 ? valueStr.slice(0, 30) + '...' : valueStr;\n return `${key}: ${truncated}`;\n })\n .join(', ');\n\n return ` ${chalk.gray(`(${preview})`)}`;\n }\n\n private getElapsedTime(): string {\n const lastTool = Array.from(this.toolCallStack.values()).pop();\n if (!lastTool) {\n return '0s';\n }\n\n const elapsed = Date.now() - lastTool.startTime;\n return elapsed < 1000 ? `${elapsed}ms` : `${(elapsed / 1000).toFixed(1)}s`;\n }\n\n private cleanup(): void {\n if (this.activeSpinner) {\n this.activeSpinner.stop();\n this.activeSpinner = null;\n }\n this.toolCallStack.clear();\n }\n}\n","import { Command } from 'commander';\nimport chalk from 'chalk';\nimport * as readline from 'readline/promises';\nimport { ConfigManager } from '../config/config-manager.js';\nimport { AuthManager } from '../auth/auth-manager.js';\n\nexport function createConfigCommand(): Command {\n const config = new Command('config');\n\n config\n .command('init')\n .description('Initialize Horneross CLI configuration')\n .action(async () => {\n console.log(chalk.bold.cyan('\\n🤖 Horneross CLI Setup\\n'));\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n try {\n const agentName = await rl.question(\n chalk.yellow('Agent name (e.g., \"adam\"): ')\n );\n\n if (!agentName.trim()) {\n console.error(chalk.red('\\n✖ Agent name is required'));\n process.exit(1);\n }\n\n const agentId = await rl.question(\n chalk.yellow('Agent ID: ')\n );\n\n if (!agentId.trim()) {\n console.error(chalk.red('\\n✖ Agent ID is required'));\n process.exit(1);\n }\n\n const apiKey = await rl.question(\n chalk.yellow('API Key: ')\n );\n\n if (!apiKey.trim()) {\n console.error(chalk.red('\\n✖ API Key is required'));\n process.exit(1);\n }\n\n const baseUrl = await rl.question(\n chalk.yellow('Base URL [http://localhost:3000]: ')\n );\n\n const finalBaseUrl = baseUrl.trim() || 'http://localhost:3000';\n\n rl.close();\n\n const agentConfig = {\n id: agentId.trim(),\n api_key: apiKey.trim(),\n name: agentName.trim(),\n };\n\n console.log(chalk.gray('\\n⏳ Validating connection...'));\n\n const { valid, error } = await AuthManager.validateConnection(\n agentConfig,\n finalBaseUrl\n );\n\n if (!valid) {\n AuthManager.displayAuthError(error || 'Unknown error');\n process.exit(1);\n }\n\n await ConfigManager.addAgent(agentName.trim(), agentConfig);\n\n const currentConfig = await ConfigManager.load();\n currentConfig.base_url = finalBaseUrl;\n await ConfigManager.save(currentConfig);\n\n console.log(chalk.green('\\n✓ Configuration saved successfully!'));\n console.log(chalk.gray(`\\nConfig file: ${ConfigManager.getConfigPath()}`));\n console.log(chalk.gray(`Default agent: ${agentName.trim()}`));\n console.log(chalk.cyan('\\nYou can now run: horneross chat \"Hello\"\\n'));\n } catch (error) {\n rl.close();\n console.error(chalk.red('\\n✖ Setup failed:'), error);\n process.exit(1);\n }\n });\n\n config\n .command('show')\n .description('Show current configuration')\n .action(async () => {\n try {\n const config = await ConfigManager.load();\n\n console.log(chalk.bold.cyan('\\n🔧 Current Configuration\\n'));\n console.log(chalk.yellow('Base URL:'), config.base_url);\n console.log(chalk.yellow('Default Agent:'), config.default_agent || chalk.gray('(not set)'));\n console.log(chalk.yellow('\\nConfigured Agents:'));\n\n if (Object.keys(config.agents).length === 0) {\n console.log(chalk.gray(' No agents configured'));\n } else {\n for (const [name, agent] of Object.entries(config.agents)) {\n const isDefault = name === config.default_agent;\n const marker = isDefault ? chalk.green('✓') : ' ';\n console.log(` ${marker} ${chalk.cyan(name)} (${agent.id})`);\n }\n }\n\n console.log(chalk.gray(`\\nConfig file: ${ConfigManager.getConfigPath()}\\n`));\n } catch (error) {\n console.error(chalk.red('Failed to load configuration:'), error);\n process.exit(1);\n }\n });\n\n return config;\n}\n","import chalk from 'chalk';\nimport type { AgentConfig } from '../types.js';\n\nexport class AuthManager {\n static async validateConnection(\n agentConfig: AgentConfig,\n baseUrl: string\n ): Promise<{ valid: boolean; error?: string }> {\n try {\n const response = await fetch(`${baseUrl}/api/v2/agent/${agentConfig.id}/config`, {\n headers: {\n Authorization: `Bearer ${agentConfig.api_key}`,\n },\n });\n\n if (response.ok) {\n return { valid: true };\n }\n\n if (response.status === 401) {\n return { valid: false, error: 'Invalid API key' };\n }\n\n if (response.status === 404) {\n return { valid: false, error: 'Agent not found' };\n }\n\n return { valid: false, error: `HTTP ${response.status}: ${response.statusText}` };\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n return { valid: false, error: `Connection failed: ${message}` };\n }\n }\n\n static displayAuthError(error: string): void {\n console.error(chalk.red('\\n✖ Authentication failed:'), error);\n console.error(chalk.yellow('\\nTroubleshooting:'));\n console.error(chalk.gray(' 1. Check your API key is correct'));\n console.error(chalk.gray(' 2. Verify the agent ID exists'));\n console.error(chalk.gray(' 3. Ensure the base URL is accessible'));\n console.error(chalk.gray('\\nRun: horneross config init'));\n }\n}\n","import { Command } from 'commander';\nimport chalk from 'chalk';\nimport * as readline from 'readline';\nimport { createId } from '@paralleldrive/cuid2';\nimport { ConfigManager } from '../config/config-manager.js';\nimport { StreamAdapter } from '../adapters/stream-adapter.js';\n\nexport function createInteractiveCommand(): Command {\n const interactive = new Command('interactive');\n\n interactive\n .description('Start an interactive chat session')\n .option('-a, --agent <name>', 'Agent to use (defaults to configured default)')\n .action(async (options: { agent?: string }) => {\n try {\n const config = await ConfigManager.load();\n const agentName = options.agent || config.default_agent;\n\n if (!agentName) {\n console.error(chalk.red('\\n✖ No default agent configured'));\n console.error(chalk.yellow('Run: horneross config init\\n'));\n process.exit(1);\n }\n\n const agent = config.agents[agentName];\n if (!agent) {\n console.error(chalk.red(`\\n✖ Agent \"${agentName}\" not found`));\n process.exit(1);\n }\n\n console.log(chalk.bold.cyan(`\\n🤖 Interactive mode with ${agent.name}`));\n console.log(chalk.gray('Type \"exit\" or press Ctrl+C to quit\\n'));\n\n const conversationId = createId();\n let messageCount = 0;\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n prompt: chalk.green('> '),\n });\n\n rl.prompt();\n\n rl.on('line', async (input) => {\n const trimmed = input.trim();\n\n if (trimmed === 'exit' || trimmed === 'quit') {\n console.log(chalk.gray('\\nGoodbye! 👋\\n'));\n rl.close();\n process.exit(0);\n }\n\n if (!trimmed) {\n rl.prompt();\n return;\n }\n\n try {\n messageCount++;\n\n const response = await fetch(\n `${config.base_url}/api/v2/agent/${agent.id}/chat`,\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${agent.api_key}`,\n },\n body: JSON.stringify({\n query: trimmed,\n streaming: true,\n executionMode: 'chat',\n conversationId,\n }),\n }\n );\n\n if (!response.ok) {\n const errorText = await response.text();\n console.error(chalk.red(`\\n✖ Request failed (${response.status}):`), errorText);\n rl.prompt();\n return;\n }\n\n const adapter = new StreamAdapter();\n await adapter.processStream(response);\n\n console.log('\\n');\n rl.prompt();\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n console.error(chalk.red('\\n✖ Error:'), message);\n rl.prompt();\n }\n });\n\n rl.on('close', () => {\n console.log(\n chalk.gray(`\\nSession ended. ${messageCount} messages exchanged.\\n`)\n );\n process.exit(0);\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Unknown error';\n console.error(chalk.red('\\n✖ Interactive mode failed:'), message);\n process.exit(1);\n }\n });\n\n return interactive;\n}\n"],"mappings":"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","names":["Command","chalk","chalk","chalk","message","Command","chalk","chalk","Command","chalk","config","Command","chalk","readline","Command","chalk","Command","chalk"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@horneross/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Terminal interface for Horneross AI agents",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"horneross": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"keywords": [
|
|
16
|
+
"cli",
|
|
17
|
+
"horneross",
|
|
18
|
+
"ai",
|
|
19
|
+
"agent",
|
|
20
|
+
"terminal",
|
|
21
|
+
"chat",
|
|
22
|
+
"llm",
|
|
23
|
+
"conversational-ai"
|
|
24
|
+
],
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "https://github.com/horneross/horneross-agents.git",
|
|
28
|
+
"directory": "packages/cli"
|
|
29
|
+
},
|
|
30
|
+
"homepage": "https://horneross.com",
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/horneross/horneross-agents/issues"
|
|
33
|
+
},
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"author": "Horneross Team",
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsup",
|
|
38
|
+
"dev": "tsup --watch",
|
|
39
|
+
"typecheck": "tsc --noEmit",
|
|
40
|
+
"clean": "rm -rf dist",
|
|
41
|
+
"test": "jest",
|
|
42
|
+
"test:watch": "jest --watch"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"commander": "^11.1.0",
|
|
46
|
+
"chalk": "^5.3.0",
|
|
47
|
+
"ora": "^8.0.1",
|
|
48
|
+
"marked": "^11.1.1",
|
|
49
|
+
"marked-terminal": "^7.0.0",
|
|
50
|
+
"highlight.js": "^11.9.0",
|
|
51
|
+
"yaml": "^2.3.4",
|
|
52
|
+
"@paralleldrive/cuid2": "^2.2.2",
|
|
53
|
+
"eventsource-parser": "^1.1.2"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@types/node": "^20.10.0",
|
|
57
|
+
"@types/jest": "^29.5.0",
|
|
58
|
+
"jest": "^29.7.0",
|
|
59
|
+
"ts-jest": "^29.1.0",
|
|
60
|
+
"typescript": "^5.3.0",
|
|
61
|
+
"tsup": "^8.0.0"
|
|
62
|
+
},
|
|
63
|
+
"engines": {
|
|
64
|
+
"node": ">=18.0.0"
|
|
65
|
+
}
|
|
66
|
+
}
|