@imisbahk/hive 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/publish.yml +31 -0
- package/.rocket/README.md +8 -8
- package/.rocket/SYMBOLS.md +260 -117
- package/CONTRIBUTING.md +2 -1
- package/FEATURES.md +55 -0
- package/README.md +13 -11
- package/dist/agent/agent.d.ts +10 -1
- package/dist/agent/agent.d.ts.map +1 -1
- package/dist/agent/agent.js +351 -1
- package/dist/agent/agent.js.map +1 -1
- package/dist/browser/browser.d.ts +9 -0
- package/dist/browser/browser.d.ts.map +1 -0
- package/dist/browser/browser.js +338 -0
- package/dist/browser/browser.js.map +1 -0
- package/dist/cli/commands/chat.d.ts +5 -1
- package/dist/cli/commands/chat.d.ts.map +1 -1
- package/dist/cli/commands/chat.js +560 -38
- package/dist/cli/commands/chat.js.map +1 -1
- package/dist/cli/commands/config.d.ts +11 -0
- package/dist/cli/commands/config.d.ts.map +1 -1
- package/dist/cli/commands/config.js +50 -15
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +39 -14
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/nuke.d.ts.map +1 -1
- package/dist/cli/commands/nuke.js +5 -4
- package/dist/cli/commands/nuke.js.map +1 -1
- package/dist/cli/commands/status.d.ts +5 -0
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +15 -5
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/index.js +34 -12
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/ui.d.ts +7 -0
- package/dist/cli/ui.d.ts.map +1 -0
- package/dist/cli/ui.js +96 -0
- package/dist/cli/ui.js.map +1 -0
- package/dist/providers/base.d.ts +37 -1
- package/dist/providers/base.d.ts.map +1 -1
- package/dist/providers/base.js +104 -0
- package/dist/providers/base.js.map +1 -1
- package/dist/providers/openai-compatible.d.ts +2 -1
- package/dist/providers/openai-compatible.d.ts.map +1 -1
- package/dist/providers/openai-compatible.js +18 -1
- package/dist/providers/openai-compatible.js.map +1 -1
- package/package.json +9 -1
- package/prompts/Browser.md +13 -0
- package/prompts/Debugging.md +15 -0
- package/prompts/Execution.md +13 -0
- package/prompts/Planning.md +13 -0
- package/prompts/Product.md +14 -0
- package/prompts/Review.md +15 -0
- package/prompts/Safety.md +12 -0
- package/prompts/Search.md +14 -0
- package/prompts/Tools.md +14 -0
- package/prompts/Writing.md +13 -0
- package/releases/v1/v0.1/RELEASE-NOTES.md +46 -0
- package/src/agent/agent.ts +442 -2
- package/src/browser/browser.ts +410 -0
- package/src/cli/commands/chat.ts +705 -34
- package/src/cli/commands/config.ts +78 -15
- package/src/cli/commands/init.ts +60 -14
- package/src/cli/commands/nuke.ts +11 -7
- package/src/cli/commands/status.ts +28 -5
- package/src/cli/index.ts +37 -9
- package/src/cli/ui.ts +120 -0
- package/src/providers/base.ts +176 -1
- package/src/providers/openai-compatible.ts +24 -0
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import process from "node:process";
|
|
2
2
|
|
|
3
|
-
import chalk from "chalk";
|
|
4
3
|
import { Command } from "commander";
|
|
5
4
|
import inquirer from "inquirer";
|
|
6
5
|
import keytar from "keytar";
|
|
@@ -9,6 +8,13 @@ import ora from "ora";
|
|
|
9
8
|
import { resolveProviderApiKey } from "../../providers/api-key.js";
|
|
10
9
|
import { normalizeProviderName, type ProviderName } from "../../providers/base.js";
|
|
11
10
|
import { promptForModel, promptForProvider } from "../helpers/providerPrompts.js";
|
|
11
|
+
import {
|
|
12
|
+
renderError,
|
|
13
|
+
renderHiveHeader,
|
|
14
|
+
renderInfo,
|
|
15
|
+
renderStep,
|
|
16
|
+
renderSuccess,
|
|
17
|
+
} from "../ui.js";
|
|
12
18
|
import {
|
|
13
19
|
closeHiveDatabase,
|
|
14
20
|
getPrimaryAgent,
|
|
@@ -20,6 +26,14 @@ import {
|
|
|
20
26
|
|
|
21
27
|
const KEYCHAIN_SERVICE = "hive";
|
|
22
28
|
|
|
29
|
+
interface ConfigShowRenderOptions {
|
|
30
|
+
showHeader?: boolean;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
interface ConfigInteractiveRenderOptions {
|
|
34
|
+
showHeader?: boolean;
|
|
35
|
+
}
|
|
36
|
+
|
|
23
37
|
export function registerConfigCommand(program: Command): void {
|
|
24
38
|
const configCommand = program
|
|
25
39
|
.command("config")
|
|
@@ -52,9 +66,24 @@ export function registerConfigCommand(program: Command): void {
|
|
|
52
66
|
.action(async () => {
|
|
53
67
|
await runConfigShowCommand();
|
|
54
68
|
});
|
|
69
|
+
|
|
70
|
+
configCommand.action(() => {
|
|
71
|
+
renderHiveHeader("Config");
|
|
72
|
+
configCommand.outputHelp();
|
|
73
|
+
});
|
|
55
74
|
}
|
|
56
75
|
|
|
57
76
|
export async function runConfigProviderCommand(): Promise<void> {
|
|
77
|
+
await runConfigProviderCommandWithOptions();
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export async function runConfigProviderCommandWithOptions(
|
|
81
|
+
options: ConfigInteractiveRenderOptions = {},
|
|
82
|
+
): Promise<void> {
|
|
83
|
+
const showHeader = options.showHeader ?? true;
|
|
84
|
+
if (showHeader) {
|
|
85
|
+
renderHiveHeader("Config · Provider");
|
|
86
|
+
}
|
|
58
87
|
const spinner = ora("Loading configuration...").start();
|
|
59
88
|
const db = openHiveDatabase();
|
|
60
89
|
|
|
@@ -64,7 +93,7 @@ export async function runConfigProviderCommand(): Promise<void> {
|
|
|
64
93
|
const agent = getPrimaryAgent(db);
|
|
65
94
|
if (!agent) {
|
|
66
95
|
spinner.stop();
|
|
67
|
-
|
|
96
|
+
renderError("Hive is not initialized. Run `hive init` first.");
|
|
68
97
|
return;
|
|
69
98
|
}
|
|
70
99
|
|
|
@@ -110,7 +139,8 @@ export async function runConfigProviderCommand(): Promise<void> {
|
|
|
110
139
|
}
|
|
111
140
|
|
|
112
141
|
spinner.succeed("Configuration saved.");
|
|
113
|
-
|
|
142
|
+
renderSuccess("Provider updated.");
|
|
143
|
+
renderStep("Run `hive` to use it.");
|
|
114
144
|
} catch (error) {
|
|
115
145
|
if (spinner.isSpinning) {
|
|
116
146
|
spinner.fail("Failed to update provider configuration.");
|
|
@@ -122,6 +152,16 @@ export async function runConfigProviderCommand(): Promise<void> {
|
|
|
122
152
|
}
|
|
123
153
|
|
|
124
154
|
export async function runConfigModelCommand(): Promise<void> {
|
|
155
|
+
await runConfigModelCommandWithOptions();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export async function runConfigModelCommandWithOptions(
|
|
159
|
+
options: ConfigInteractiveRenderOptions = {},
|
|
160
|
+
): Promise<void> {
|
|
161
|
+
const showHeader = options.showHeader ?? true;
|
|
162
|
+
if (showHeader) {
|
|
163
|
+
renderHiveHeader("Config · Model");
|
|
164
|
+
}
|
|
125
165
|
const spinner = ora("Loading configuration...").start();
|
|
126
166
|
const db = openHiveDatabase();
|
|
127
167
|
|
|
@@ -131,7 +171,7 @@ export async function runConfigModelCommand(): Promise<void> {
|
|
|
131
171
|
const agent = getPrimaryAgent(db);
|
|
132
172
|
if (!agent) {
|
|
133
173
|
spinner.stop();
|
|
134
|
-
|
|
174
|
+
renderError("Hive is not initialized. Run `hive init` first.");
|
|
135
175
|
return;
|
|
136
176
|
}
|
|
137
177
|
|
|
@@ -151,7 +191,8 @@ export async function runConfigModelCommand(): Promise<void> {
|
|
|
151
191
|
setMetaValue(db, "model", updatedAgent.model);
|
|
152
192
|
|
|
153
193
|
spinner.succeed("Configuration saved.");
|
|
154
|
-
|
|
194
|
+
renderSuccess("Model updated.");
|
|
195
|
+
renderStep("Run `hive` to use it.");
|
|
155
196
|
} catch (error) {
|
|
156
197
|
if (spinner.isSpinning) {
|
|
157
198
|
spinner.fail("Failed to update model configuration.");
|
|
@@ -163,6 +204,16 @@ export async function runConfigModelCommand(): Promise<void> {
|
|
|
163
204
|
}
|
|
164
205
|
|
|
165
206
|
export async function runConfigKeyCommand(): Promise<void> {
|
|
207
|
+
await runConfigKeyCommandWithOptions();
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export async function runConfigKeyCommandWithOptions(
|
|
211
|
+
options: ConfigInteractiveRenderOptions = {},
|
|
212
|
+
): Promise<void> {
|
|
213
|
+
const showHeader = options.showHeader ?? true;
|
|
214
|
+
if (showHeader) {
|
|
215
|
+
renderHiveHeader("Config · Key");
|
|
216
|
+
}
|
|
166
217
|
const spinner = ora("Loading configuration...").start();
|
|
167
218
|
const db = openHiveDatabase();
|
|
168
219
|
|
|
@@ -172,14 +223,14 @@ export async function runConfigKeyCommand(): Promise<void> {
|
|
|
172
223
|
const agent = getPrimaryAgent(db);
|
|
173
224
|
if (!agent) {
|
|
174
225
|
spinner.stop();
|
|
175
|
-
|
|
226
|
+
renderError("Hive is not initialized. Run `hive init` first.");
|
|
176
227
|
return;
|
|
177
228
|
}
|
|
178
229
|
|
|
179
230
|
const provider = normalizeProviderName(agent.provider);
|
|
180
231
|
|
|
181
232
|
spinner.stop();
|
|
182
|
-
|
|
233
|
+
renderInfo(`Current provider: ${provider}`);
|
|
183
234
|
|
|
184
235
|
const answer = (await inquirer.prompt([
|
|
185
236
|
{
|
|
@@ -195,7 +246,8 @@ export async function runConfigKeyCommand(): Promise<void> {
|
|
|
195
246
|
await keytar.setPassword(KEYCHAIN_SERVICE, provider, answer.apiKey.trim());
|
|
196
247
|
|
|
197
248
|
spinner.succeed("Configuration saved.");
|
|
198
|
-
|
|
249
|
+
renderSuccess("API key updated.");
|
|
250
|
+
renderStep("Run `hive` to use it.");
|
|
199
251
|
} catch (error) {
|
|
200
252
|
if (spinner.isSpinning) {
|
|
201
253
|
spinner.fail("Failed to update API key.");
|
|
@@ -207,22 +259,33 @@ export async function runConfigKeyCommand(): Promise<void> {
|
|
|
207
259
|
}
|
|
208
260
|
|
|
209
261
|
export async function runConfigShowCommand(): Promise<void> {
|
|
262
|
+
await runConfigShowCommandWithOptions();
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export async function runConfigShowCommandWithOptions(
|
|
266
|
+
options: ConfigShowRenderOptions = {},
|
|
267
|
+
): Promise<void> {
|
|
268
|
+
const showHeader = options.showHeader ?? true;
|
|
269
|
+
if (showHeader) {
|
|
270
|
+
renderHiveHeader("Config · Show");
|
|
271
|
+
}
|
|
272
|
+
|
|
210
273
|
const db = openHiveDatabase();
|
|
211
274
|
|
|
212
275
|
try {
|
|
213
276
|
const agent = getPrimaryAgent(db);
|
|
214
277
|
if (!agent) {
|
|
215
|
-
|
|
278
|
+
renderError("Hive is not initialized. Run `hive init` first.");
|
|
216
279
|
return;
|
|
217
280
|
}
|
|
218
281
|
|
|
219
282
|
const provider = normalizeProviderName(agent.provider);
|
|
220
283
|
const keyStatus = await getKeyStatus(provider);
|
|
221
284
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
285
|
+
renderStep(`Provider: ${provider}`);
|
|
286
|
+
renderStep(`Model: ${agent.model}`);
|
|
287
|
+
renderStep(`Agent name: ${agent.agent_name ?? "not set"}`);
|
|
288
|
+
renderStep(`API key: ${keyStatus}`);
|
|
226
289
|
} finally {
|
|
227
290
|
closeHiveDatabase(db);
|
|
228
291
|
}
|
|
@@ -235,8 +298,8 @@ function ensureInteractiveTerminal(errorMessage: string): void {
|
|
|
235
298
|
}
|
|
236
299
|
|
|
237
300
|
function printCurrentProviderAndModel(provider: ProviderName, model: string): void {
|
|
238
|
-
|
|
239
|
-
|
|
301
|
+
renderInfo(`Current provider: ${provider}`);
|
|
302
|
+
renderInfo(`Current model: ${model}`);
|
|
240
303
|
}
|
|
241
304
|
|
|
242
305
|
async function getKeyStatus(provider: ProviderName): Promise<"set" | "not set"> {
|
package/src/cli/commands/init.ts
CHANGED
|
@@ -2,7 +2,6 @@ import process from "node:process";
|
|
|
2
2
|
import * as fs from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
|
|
5
|
-
import chalk from "chalk";
|
|
6
5
|
import { Command } from "commander";
|
|
7
6
|
import inquirer from "inquirer";
|
|
8
7
|
import keytar from "keytar";
|
|
@@ -10,6 +9,12 @@ import ora from "ora";
|
|
|
10
9
|
|
|
11
10
|
import { buildDefaultPersona } from "../../agent/agent.js";
|
|
12
11
|
import { promptForModel, promptForProvider } from "../helpers/providerPrompts.js";
|
|
12
|
+
import {
|
|
13
|
+
renderHiveHeader,
|
|
14
|
+
renderInfo,
|
|
15
|
+
renderStep,
|
|
16
|
+
renderSuccess,
|
|
17
|
+
} from "../ui.js";
|
|
13
18
|
import {
|
|
14
19
|
closeHiveDatabase,
|
|
15
20
|
getHiveHomeDir,
|
|
@@ -49,6 +54,7 @@ export function registerInitCommand(program: Command): void {
|
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
export async function runInitCommand(options: InitCommandOptions = {}): Promise<void> {
|
|
57
|
+
renderHiveHeader("Init");
|
|
52
58
|
const spinner = ora("Preparing init...").start();
|
|
53
59
|
const db = openHiveDatabase();
|
|
54
60
|
|
|
@@ -71,7 +77,7 @@ export async function runInitCommand(options: InitCommandOptions = {}): Promise<
|
|
|
71
77
|
])) as { reinitialize: boolean };
|
|
72
78
|
|
|
73
79
|
if (!reinitialize) {
|
|
74
|
-
|
|
80
|
+
renderInfo("Initialization cancelled.");
|
|
75
81
|
return;
|
|
76
82
|
}
|
|
77
83
|
}
|
|
@@ -101,13 +107,13 @@ export async function runInitCommand(options: InitCommandOptions = {}): Promise<
|
|
|
101
107
|
copyPromptsDirectory(options.force ?? false);
|
|
102
108
|
|
|
103
109
|
spinner.succeed("Initialization complete.");
|
|
104
|
-
|
|
110
|
+
renderSuccess(`HIVE-ID: ${agent.id}`);
|
|
105
111
|
if (agent.agent_name) {
|
|
106
|
-
|
|
112
|
+
renderSuccess(`Agent name: ${agent.agent_name}`);
|
|
107
113
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
114
|
+
renderSuccess(`Provider: ${agent.provider}`);
|
|
115
|
+
renderSuccess(`Model: ${agent.model}`);
|
|
116
|
+
renderStep("Run `hive` to start talking.");
|
|
111
117
|
} catch (error) {
|
|
112
118
|
if (spinner.isSpinning) {
|
|
113
119
|
spinner.fail("Hive initialization failed.");
|
|
@@ -225,18 +231,58 @@ function copyPromptsDirectory(force: boolean): void {
|
|
|
225
231
|
const destinationPath = join(getHiveHomeDir(), "prompts");
|
|
226
232
|
|
|
227
233
|
if (!fs.existsSync(sourcePath)) {
|
|
228
|
-
|
|
234
|
+
renderInfo("Warning: prompts/ folder not found. Skipping prompts load.");
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (force && fs.existsSync(destinationPath)) {
|
|
239
|
+
fs.rmSync(destinationPath, { recursive: true, force: true });
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
fs.mkdirSync(destinationPath, { recursive: true });
|
|
243
|
+
const copiedFiles = syncPromptFiles(sourcePath, destinationPath, force);
|
|
244
|
+
|
|
245
|
+
if (copiedFiles === 0) {
|
|
246
|
+
renderStep("Prompts already up to date -> ~/.hive/prompts/");
|
|
229
247
|
return;
|
|
230
248
|
}
|
|
231
249
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
250
|
+
renderStep(`Prompts loaded -> ~/.hive/prompts/ (${copiedFiles} files)`);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function syncPromptFiles(
|
|
254
|
+
sourceDirectory: string,
|
|
255
|
+
destinationDirectory: string,
|
|
256
|
+
overwriteExisting: boolean,
|
|
257
|
+
): number {
|
|
258
|
+
let copiedCount = 0;
|
|
259
|
+
const entries = fs.readdirSync(sourceDirectory, { withFileTypes: true });
|
|
260
|
+
|
|
261
|
+
for (const entry of entries) {
|
|
262
|
+
const sourceEntryPath = join(sourceDirectory, entry.name);
|
|
263
|
+
const destinationEntryPath = join(destinationDirectory, entry.name);
|
|
264
|
+
|
|
265
|
+
if (entry.isDirectory()) {
|
|
266
|
+
fs.mkdirSync(destinationEntryPath, { recursive: true });
|
|
267
|
+
copiedCount += syncPromptFiles(
|
|
268
|
+
sourceEntryPath,
|
|
269
|
+
destinationEntryPath,
|
|
270
|
+
overwriteExisting,
|
|
271
|
+
);
|
|
272
|
+
continue;
|
|
235
273
|
}
|
|
236
274
|
|
|
237
|
-
|
|
275
|
+
if (!entry.isFile()) {
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (!overwriteExisting && fs.existsSync(destinationEntryPath)) {
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
fs.copyFileSync(sourceEntryPath, destinationEntryPath);
|
|
284
|
+
copiedCount += 1;
|
|
238
285
|
}
|
|
239
286
|
|
|
240
|
-
|
|
241
|
-
console.log("Prompts loaded → ~/.hive/prompts/");
|
|
287
|
+
return copiedCount;
|
|
242
288
|
}
|
package/src/cli/commands/nuke.ts
CHANGED
|
@@ -2,12 +2,17 @@ import * as fs from "node:fs";
|
|
|
2
2
|
import { stdin, stdout } from "node:process";
|
|
3
3
|
import { createInterface } from "node:readline/promises";
|
|
4
4
|
|
|
5
|
-
import chalk from "chalk";
|
|
6
5
|
import { Command } from "commander";
|
|
7
6
|
import keytar from "keytar";
|
|
8
7
|
|
|
9
8
|
import { SUPPORTED_PROVIDER_NAMES } from "../../providers/base.js";
|
|
10
9
|
import { getHiveHomeDir } from "../../storage/db.js";
|
|
10
|
+
import {
|
|
11
|
+
renderError,
|
|
12
|
+
renderHiveHeader,
|
|
13
|
+
renderInfo,
|
|
14
|
+
renderSuccess,
|
|
15
|
+
} from "../ui.js";
|
|
11
16
|
|
|
12
17
|
const KEYCHAIN_SERVICE = "hive";
|
|
13
18
|
const NUKE_CONFIRMATION = "nuke";
|
|
@@ -22,10 +27,9 @@ export function registerNukeCommand(program: Command): void {
|
|
|
22
27
|
}
|
|
23
28
|
|
|
24
29
|
export async function runNukeCommand(): Promise<void> {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
),
|
|
30
|
+
renderHiveHeader("Nuke");
|
|
31
|
+
renderError(
|
|
32
|
+
"This will permanently delete your agent, all memory, all conversations, and all keys. This cannot be undone.",
|
|
29
33
|
);
|
|
30
34
|
|
|
31
35
|
const rl = createInterface({
|
|
@@ -42,7 +46,7 @@ export async function runNukeCommand(): Promise<void> {
|
|
|
42
46
|
}
|
|
43
47
|
|
|
44
48
|
if (confirmation !== NUKE_CONFIRMATION) {
|
|
45
|
-
|
|
49
|
+
renderInfo("Aborted.");
|
|
46
50
|
return;
|
|
47
51
|
}
|
|
48
52
|
|
|
@@ -56,5 +60,5 @@ export async function runNukeCommand(): Promise<void> {
|
|
|
56
60
|
}
|
|
57
61
|
}
|
|
58
62
|
|
|
59
|
-
|
|
63
|
+
renderSuccess("The Hive has been nuked. Gone.");
|
|
60
64
|
}
|
|
@@ -5,6 +5,12 @@ import { join } from "node:path";
|
|
|
5
5
|
import chalk from "chalk";
|
|
6
6
|
import { Command } from "commander";
|
|
7
7
|
import keytar from "keytar";
|
|
8
|
+
import {
|
|
9
|
+
renderHiveHeader,
|
|
10
|
+
renderInfo,
|
|
11
|
+
renderSeparator,
|
|
12
|
+
renderStep,
|
|
13
|
+
} from "../ui.js";
|
|
8
14
|
|
|
9
15
|
import {
|
|
10
16
|
closeHiveDatabase,
|
|
@@ -18,6 +24,10 @@ import {
|
|
|
18
24
|
const KEYCHAIN_SERVICE = "hive";
|
|
19
25
|
const PROMPTS_DIRECTORY = "prompts";
|
|
20
26
|
|
|
27
|
+
interface StatusCommandRenderOptions {
|
|
28
|
+
showHeader?: boolean;
|
|
29
|
+
}
|
|
30
|
+
|
|
21
31
|
export function registerStatusCommand(program: Command): void {
|
|
22
32
|
program
|
|
23
33
|
.command("status")
|
|
@@ -28,12 +38,23 @@ export function registerStatusCommand(program: Command): void {
|
|
|
28
38
|
}
|
|
29
39
|
|
|
30
40
|
export async function runStatusCommand(): Promise<void> {
|
|
41
|
+
await runStatusCommandWithOptions();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export async function runStatusCommandWithOptions(
|
|
45
|
+
options: StatusCommandRenderOptions = {},
|
|
46
|
+
): Promise<void> {
|
|
47
|
+
const showHeader = options.showHeader ?? true;
|
|
48
|
+
if (showHeader) {
|
|
49
|
+
renderHiveHeader("Status");
|
|
50
|
+
}
|
|
51
|
+
|
|
31
52
|
const db = openHiveDatabase();
|
|
32
53
|
|
|
33
54
|
try {
|
|
34
55
|
const agent = getPrimaryAgent(db);
|
|
35
56
|
if (!agent) {
|
|
36
|
-
|
|
57
|
+
renderInfo("Hive is not initialized. Run `hive init` to get started.");
|
|
37
58
|
return;
|
|
38
59
|
}
|
|
39
60
|
|
|
@@ -45,14 +66,16 @@ export async function runStatusCommand(): Promise<void> {
|
|
|
45
66
|
const promptFiles = countFiles(promptsPath);
|
|
46
67
|
const initializedRaw = getMetaValue(db, "initialized_at") ?? agent.created_at;
|
|
47
68
|
|
|
48
|
-
|
|
49
|
-
|
|
69
|
+
if (showHeader) {
|
|
70
|
+
renderStep("Status");
|
|
71
|
+
}
|
|
72
|
+
renderSeparator();
|
|
50
73
|
printStatusLine("Agent", agent.agent_name ?? "not set");
|
|
51
74
|
printStatusLine("Owner", agent.name);
|
|
52
75
|
printStatusLine("Provider", provider);
|
|
53
76
|
printStatusLine("Model", agent.model);
|
|
54
77
|
printStatusLine("API Key", keyStatus);
|
|
55
|
-
|
|
78
|
+
renderSeparator();
|
|
56
79
|
printStatusLine(
|
|
57
80
|
"Database",
|
|
58
81
|
`${displayPath(dbPath)} (${formatBytes(dbSizeBytes)})`,
|
|
@@ -61,7 +84,7 @@ export async function runStatusCommand(): Promise<void> {
|
|
|
61
84
|
"Prompts",
|
|
62
85
|
`${ensureTrailingSlash(displayPath(promptsPath))} (${promptFiles} files)`,
|
|
63
86
|
);
|
|
64
|
-
|
|
87
|
+
renderSeparator();
|
|
65
88
|
printStatusLine("Initialized", formatDate(initializedRaw));
|
|
66
89
|
} finally {
|
|
67
90
|
closeHiveDatabase(db);
|
package/src/cli/index.ts
CHANGED
|
@@ -2,21 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
import "dotenv/config";
|
|
4
4
|
|
|
5
|
-
import chalk from "chalk";
|
|
6
5
|
import { Command } from "commander";
|
|
7
6
|
|
|
8
|
-
import { registerChatCommand } from "./commands/chat.js";
|
|
7
|
+
import { registerChatCommand, runChatCommand } from "./commands/chat.js";
|
|
9
8
|
import { registerConfigCommand } from "./commands/config.js";
|
|
10
9
|
import { registerInitCommand } from "./commands/init.js";
|
|
11
10
|
import { registerNukeCommand } from "./commands/nuke.js";
|
|
12
11
|
import { registerStatusCommand } from "./commands/status.js";
|
|
12
|
+
import { renderError, renderHiveHeader } from "./ui.js";
|
|
13
13
|
|
|
14
14
|
const program = new Command();
|
|
15
15
|
|
|
16
16
|
program
|
|
17
17
|
.name("hive")
|
|
18
18
|
.description("Your agent. Always running. Always learning. Always working.")
|
|
19
|
-
.version("0.1.
|
|
19
|
+
.version("0.1.1");
|
|
20
20
|
|
|
21
21
|
registerInitCommand(program);
|
|
22
22
|
registerChatCommand(program);
|
|
@@ -24,15 +24,43 @@ registerConfigCommand(program);
|
|
|
24
24
|
registerStatusCommand(program);
|
|
25
25
|
registerNukeCommand(program);
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
const argv = process.argv.slice(2);
|
|
28
|
+
|
|
29
|
+
void main();
|
|
30
|
+
|
|
31
|
+
async function main(): Promise<void> {
|
|
32
|
+
try {
|
|
33
|
+
if (argv.length === 0) {
|
|
34
|
+
await runChatCommand({}, { entrypoint: "default" });
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (shouldRenderHelpHeader(argv)) {
|
|
39
|
+
renderHiveHeader(resolveHelpTitle(argv));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
await program.parseAsync(process.argv);
|
|
43
|
+
} catch (error) {
|
|
30
44
|
if (error instanceof Error) {
|
|
31
|
-
|
|
45
|
+
renderError(error.message);
|
|
32
46
|
process.exitCode = 1;
|
|
33
47
|
return;
|
|
34
48
|
}
|
|
35
49
|
|
|
36
|
-
|
|
50
|
+
renderError(String(error));
|
|
37
51
|
process.exitCode = 1;
|
|
38
|
-
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function shouldRenderHelpHeader(args: string[]): boolean {
|
|
56
|
+
return args[0] === "help" || args.includes("-h") || args.includes("--help");
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function resolveHelpTitle(args: string[]): string {
|
|
60
|
+
if (args[0] === "help") {
|
|
61
|
+
return args[1] ?? "Help";
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const commandName = args.find((arg) => !arg.startsWith("-"));
|
|
65
|
+
return commandName ?? "Help";
|
|
66
|
+
}
|
package/src/cli/ui.ts
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import process from "node:process";
|
|
3
|
+
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
|
|
6
|
+
const WORDMARK_LINES = [
|
|
7
|
+
" ██╗ ██╗██╗██╗ ██╗███████╗",
|
|
8
|
+
" ██║ ██║██║██║ ██║██╔════╝",
|
|
9
|
+
" ███████║██║██║ ██║█████╗ ",
|
|
10
|
+
" ██╔══██║██║╚██╗ ██╔╝██╔══╝ ",
|
|
11
|
+
" ██║ ██║██║ ╚████╔╝ ███████╗",
|
|
12
|
+
" ╚═╝ ╚═╝╚═╝ ╚═══╝ ╚══════╝",
|
|
13
|
+
] as const;
|
|
14
|
+
|
|
15
|
+
const COMMAND_CENTRE_LABEL = "COMMAND CENTRE";
|
|
16
|
+
const MAX_SEPARATOR_WIDTH = 72;
|
|
17
|
+
const MIN_SEPARATOR_WIDTH = 24;
|
|
18
|
+
|
|
19
|
+
let cachedVersion: string | null = null;
|
|
20
|
+
|
|
21
|
+
export function renderHiveHeader(pageTitle?: string): void {
|
|
22
|
+
const terminalWidth = getTerminalWidth();
|
|
23
|
+
const separator = "─".repeat(getSeparatorWidth(terminalWidth));
|
|
24
|
+
|
|
25
|
+
for (const line of WORDMARK_LINES) {
|
|
26
|
+
console.log(chalk.bold.whiteBright(centerText(line, terminalWidth)));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
console.log("");
|
|
30
|
+
console.log(chalk.dim(centerText(`v${getCliVersion()}`, terminalWidth)));
|
|
31
|
+
|
|
32
|
+
const normalizedTitle = normalizePageTitle(pageTitle);
|
|
33
|
+
const commandCentreTitle = normalizedTitle
|
|
34
|
+
? `${COMMAND_CENTRE_LABEL} · ${normalizedTitle}`
|
|
35
|
+
: COMMAND_CENTRE_LABEL;
|
|
36
|
+
|
|
37
|
+
console.log(chalk.whiteBright(centerText(commandCentreTitle, terminalWidth)));
|
|
38
|
+
console.log(chalk.dim(centerText(separator, terminalWidth)));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function renderSuccess(message: string): void {
|
|
42
|
+
console.log(chalk.green(message));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function renderError(message: string): void {
|
|
46
|
+
console.error(chalk.red(message));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function renderStep(message: string): void {
|
|
50
|
+
console.log(chalk.whiteBright(message));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function renderInfo(message: string): void {
|
|
54
|
+
console.log(chalk.dim(message));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function renderSeparator(text?: string): void {
|
|
58
|
+
if (text) {
|
|
59
|
+
console.log(chalk.dim(text));
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
console.log(chalk.dim("─".repeat(getSeparatorWidth(getTerminalWidth()))));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function getCliVersion(): string {
|
|
67
|
+
if (cachedVersion) {
|
|
68
|
+
return cachedVersion;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
const raw = readFileSync(new URL("../../package.json", import.meta.url), "utf8");
|
|
73
|
+
const parsed = JSON.parse(raw) as { version?: unknown };
|
|
74
|
+
if (typeof parsed.version === "string" && parsed.version.trim().length > 0) {
|
|
75
|
+
cachedVersion = parsed.version.trim();
|
|
76
|
+
return cachedVersion;
|
|
77
|
+
}
|
|
78
|
+
} catch {
|
|
79
|
+
// Fall through to default when package metadata cannot be read.
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
cachedVersion = "0.0.0";
|
|
83
|
+
return cachedVersion;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function normalizePageTitle(pageTitle?: string): string {
|
|
87
|
+
const trimmed = pageTitle?.trim() ?? "";
|
|
88
|
+
if (trimmed.length === 0) {
|
|
89
|
+
return "";
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return trimmed.toUpperCase();
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function getTerminalWidth(): number {
|
|
96
|
+
if (!process.stdout.isTTY) {
|
|
97
|
+
return 80;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const columns = process.stdout.columns;
|
|
101
|
+
if (typeof columns !== "number" || columns < 20) {
|
|
102
|
+
return 80;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return columns;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function centerText(value: string, totalWidth: number): string {
|
|
109
|
+
if (value.length >= totalWidth) {
|
|
110
|
+
return value;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const leftPadding = Math.floor((totalWidth - value.length) / 2);
|
|
114
|
+
return `${" ".repeat(leftPadding)}${value}`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function getSeparatorWidth(terminalWidth: number): number {
|
|
118
|
+
const usableWidth = Math.max(MIN_SEPARATOR_WIDTH, terminalWidth - 8);
|
|
119
|
+
return Math.min(MAX_SEPARATOR_WIDTH, usableWidth);
|
|
120
|
+
}
|