@zhive/cli 0.5.3 → 0.5.5

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.
@@ -1,7 +1,7 @@
1
1
  import fs from 'fs-extra';
2
2
  import path from 'path';
3
- import os from 'os';
4
3
  import { fileURLToPath } from 'node:url';
4
+ import { getHiveDir } from '../../shared/config/constant.js';
5
5
  const __filename = fileURLToPath(import.meta.url);
6
6
  const __dirname = path.dirname(__filename);
7
7
  export async function scaffoldProject(projectName, provider, apiKey, soulContent, strategyContent, callbacks) {
@@ -10,9 +10,9 @@ export async function scaffoldProject(projectName, provider, apiKey, soulContent
10
10
  callbacks.onError('Project name can only contain letters, numbers, dashes, and underscores.');
11
11
  return;
12
12
  }
13
- const agentsDir = path.join(os.homedir(), '.hive', 'agents');
13
+ const agentsDir = path.join(getHiveDir(), 'agents');
14
14
  const projectDir = path.join(agentsDir, projectName);
15
- // Ensure resolved path is still inside ~/.hive/agents/
15
+ // Ensure resolved path is still inside the agents directory
16
16
  const normalizedProjectDir = path.resolve(projectDir);
17
17
  const normalizedAgentsDir = path.resolve(agentsDir);
18
18
  if (!normalizedProjectDir.startsWith(normalizedAgentsDir + path.sep)) {
@@ -2,7 +2,6 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState, useCallback } from 'react';
3
3
  import { Box, Text, useApp } from 'ink';
4
4
  import { Header } from '../../../components/Header.js';
5
- import { AsciiTicker } from '../../../components/AsciiTicker.js';
6
5
  import { StepIndicator } from '../../../components/StepIndicator.js';
7
6
  import { ApiKeyStep } from './steps/ApiKeyStep.js';
8
7
  import { NameStep } from './steps/NameStep.js';
@@ -168,5 +167,5 @@ export function CreateApp({ initialName }) {
168
167
  setError(message);
169
168
  exit();
170
169
  }, [exit]);
171
- return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Header, {}), _jsx(StepIndicator, { steps: STEP_DEFS, currentIndex: stepIndex }), step !== 'done' && (_jsx(Box, { marginBottom: 1, children: _jsx(AsciiTicker, { step: stepIndex + 1 }) })), step === 'api-key' && _jsx(ApiKeyStep, { onComplete: handleApiKey }), step === 'name' && _jsx(NameStep, { onComplete: handleName }), step === 'identity' && _jsx(IdentityStep, { agentName: agentName, onComplete: handleIdentity }), step === 'avatar' && _jsx(AvatarStep, { agentName: agentName, onComplete: handleAvatar }), step === 'soul' && providerId && (_jsx(SoulStep, { providerId: providerId, apiKey: apiKey, agentName: agentName, bio: bio, avatarUrl: avatarUrl, personality: personality, tone: tone, voiceStyle: voiceStyle, tradingStyle: tradingStyle, sectors: sectors, sentiment: sentiment, timeframes: timeframes, onComplete: handleSoul })), step === 'strategy' && providerId && (_jsx(StrategyStep, { providerId: providerId, apiKey: apiKey, agentName: agentName, bio: bio, personality: personality, tone: tone, voiceStyle: voiceStyle, tradingStyle: tradingStyle, sectors: sectors, sentiment: sentiment, timeframes: timeframes, onComplete: handleStrategy })), step === 'scaffold' && provider && (_jsx(ScaffoldStep, { projectName: agentName, provider: provider, apiKey: apiKey, soulContent: soulContent, strategyContent: strategyContent, onComplete: handleScaffoldComplete, onError: handleScaffoldError })), step === 'done' && _jsx(DoneStep, { projectDir: resolvedProjectDir }), error !== '' && (_jsx(Box, { marginTop: 1, marginLeft: 2, children: _jsxs(Text, { color: colors.red, children: [symbols.cross, " ", error] }) }))] }));
170
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Header, {}), _jsx(StepIndicator, { steps: STEP_DEFS, currentIndex: stepIndex }), step === 'api-key' && _jsx(ApiKeyStep, { onComplete: handleApiKey }), step === 'name' && _jsx(NameStep, { onComplete: handleName }), step === 'identity' && _jsx(IdentityStep, { agentName: agentName, onComplete: handleIdentity }), step === 'avatar' && _jsx(AvatarStep, { agentName: agentName, onComplete: handleAvatar }), step === 'soul' && providerId && (_jsx(SoulStep, { providerId: providerId, apiKey: apiKey, agentName: agentName, bio: bio, avatarUrl: avatarUrl, personality: personality, tone: tone, voiceStyle: voiceStyle, tradingStyle: tradingStyle, sectors: sectors, sentiment: sentiment, timeframes: timeframes, onComplete: handleSoul })), step === 'strategy' && providerId && (_jsx(StrategyStep, { providerId: providerId, apiKey: apiKey, agentName: agentName, bio: bio, personality: personality, tone: tone, voiceStyle: voiceStyle, tradingStyle: tradingStyle, sectors: sectors, sentiment: sentiment, timeframes: timeframes, onComplete: handleStrategy })), step === 'scaffold' && provider && (_jsx(ScaffoldStep, { projectName: agentName, provider: provider, apiKey: apiKey, soulContent: soulContent, strategyContent: strategyContent, onComplete: handleScaffoldComplete, onError: handleScaffoldError })), step === 'done' && _jsx(DoneStep, { projectDir: resolvedProjectDir }), error !== '' && (_jsx(Box, { marginTop: 1, marginLeft: 2, children: _jsxs(Text, { color: colors.red, children: [symbols.cross, " ", error] }) }))] }));
172
171
  }
@@ -128,5 +128,5 @@ export function MigrateApp() {
128
128
  const successCount = results.filter((r) => r.success && !r.error).length;
129
129
  const alreadyNew = results.filter((r) => r.error === 'Already migrated').length;
130
130
  const failCount = results.filter((r) => !r.success).length;
131
- return (_jsxs(Box, { flexDirection: "column", paddingLeft: 1, children: [_jsxs(Text, { color: colors.honey, bold: true, children: [symbols.hive, " Migration complete"] }), _jsx(Text, { color: colors.gray, children: border.horizontal.repeat(termWidth - 4) }), results.map((r) => (_jsxs(Box, { children: [r.success && !r.error && (_jsxs(Text, { color: colors.green, children: [symbols.check, " ", r.name, " \u2014 migrated"] })), r.error === 'Already migrated' && (_jsxs(Text, { color: colors.gray, children: [symbols.check, " ", r.name, " \u2014 already migrated"] })), !r.success && r.error !== 'Already migrated' && (_jsxs(Text, { color: colors.red, children: [symbols.cross, " ", r.name, " \u2014 ", r.error] }))] }, r.name))), agents.length === 0 && results.length === 0 && (_jsx(Text, { color: colors.gray, children: "No agents found in ~/.hive/agents/" })), _jsx(Text, { children: " " }), successCount > 0 && (_jsxs(Text, { color: colors.gray, children: ["Agents now run via @zhive/cli. ", styled.white('npx @zhive/cli@latest start'), " always uses the latest version."] }))] }));
131
+ return (_jsxs(Box, { flexDirection: "column", paddingLeft: 1, children: [_jsxs(Text, { color: colors.honey, bold: true, children: [symbols.hive, " Migration complete"] }), _jsx(Text, { color: colors.gray, children: border.horizontal.repeat(termWidth - 4) }), results.map((r) => (_jsxs(Box, { children: [r.success && !r.error && (_jsxs(Text, { color: colors.green, children: [symbols.check, " ", r.name, " \u2014 migrated"] })), r.error === 'Already migrated' && (_jsxs(Text, { color: colors.gray, children: [symbols.check, " ", r.name, " \u2014 already migrated"] })), !r.success && r.error !== 'Already migrated' && (_jsxs(Text, { color: colors.red, children: [symbols.cross, " ", r.name, " \u2014 ", r.error] }))] }, r.name))), agents.length === 0 && results.length === 0 && (_jsx(Text, { color: colors.gray, children: "No agents found in ~/.zhive/agents/" })), _jsx(Text, { children: " " }), successCount > 0 && (_jsxs(Text, { color: colors.gray, children: ["Agents now run via @zhive/cli. ", styled.white('npx @zhive/cli@latest start'), " always uses the latest version."] }))] }));
132
132
  }
@@ -9,7 +9,7 @@ const SCRAMBLE_CHARS = '\u2B21\u2B22\u25C6\u25C7\u2591\u2592!@#$%01';
9
9
  const BOOT_MESSAGES = [
10
10
  { prefix: '\u2B21', text: 'Initializing {name} agent...', frame: 30 },
11
11
  { prefix: '\u25C6', text: 'Loading personality matrix...', frame: 36 },
12
- { prefix: '\u25C7', text: 'Connecting to the hive...', frame: 42 },
12
+ { prefix: '\u25C7', text: 'Connecting to zHive...', frame: 42 },
13
13
  { prefix: '\u2713', text: 'Neural link established', frame: 48 },
14
14
  ];
15
15
  // ─── Private helpers ─────────────────────────────────
@@ -2,9 +2,18 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState, useEffect } from 'react';
3
3
  import { Text } from 'ink';
4
4
  import { colors } from '../../shared/theme.js';
5
- import { SPINNER_FRAMES, useSpinnerFrame } from './SpinnerContext.js';
5
+ const SPINNER_FRAMES = ['\u25D0', '\u25D3', '\u25D1', '\u25D2'];
6
+ const SPINNER_INTERVAL_MS = 200;
6
7
  export function Spinner({ label }) {
7
- const frame = useSpinnerFrame();
8
+ const [frame, setFrame] = useState(0);
9
+ useEffect(() => {
10
+ const timer = setInterval(() => {
11
+ setFrame((prev) => (prev + 1) % SPINNER_FRAMES.length);
12
+ }, SPINNER_INTERVAL_MS);
13
+ return () => {
14
+ clearInterval(timer);
15
+ };
16
+ }, []);
8
17
  return (_jsxs(Text, { children: [_jsx(Text, { color: colors.honey, children: SPINNER_FRAMES[frame] }), _jsxs(Text, { color: colors.gray, children: [" ", label] })] }));
9
18
  }
10
19
  export function TypewriterText({ text, color, speed = 25, }) {
@@ -3,7 +3,6 @@ import React from 'react';
3
3
  import { Box, Static, Text } from 'ink';
4
4
  import { useAgent } from '../hooks/useAgent.js';
5
5
  import { PollText, Spinner } from './Spinner.js';
6
- import { SpinnerProvider } from './SpinnerContext.js';
7
6
  import { CommandInput } from './CommandInput.js';
8
7
  import { border, colors, symbols } from '../../shared/theme.js';
9
8
  import { HIVE_FRONTEND_URL } from '../../../shared/config/constant.js';
@@ -28,17 +27,19 @@ export function App() {
28
27
  const boxWidth = termWidth;
29
28
  const visibleChatActivity = chatActivity.slice(-5);
30
29
  const statsText = predictionCount > 0 ? ` ${border.horizontal.repeat(3)} ${predictionCount} predicted` : '';
31
- const connectedDisplay = connected ? 'Connected to the Hive' : 'connecting...';
30
+ const connectedDisplay = connected ? 'Connected to zHive' : 'connecting...';
32
31
  const nameDisplay = `${agentName} agent`;
33
32
  const headerFill = Math.max(0, boxWidth - nameDisplay.length - connectedDisplay.length - 12 - statsText.length);
34
- return (_jsxs(SpinnerProvider, { children: [_jsx(Static, { items: settledPollActivities, children: (item, i) => {
33
+ return (_jsxs(_Fragment, { children: [_jsx(Static, { items: settledPollActivities, children: (item, i) => {
35
34
  const formatted = activityFormatter.format(item);
36
35
  if (formatted.length === 0)
37
36
  return _jsx(Box, {}, `settled-${item.id ?? i}`);
38
37
  return _jsx(Text, { children: formatted.join('\n') }, `settled-${item.id ?? i}`);
39
- } }), _jsxs(Box, { flexDirection: "column", width: boxWidth, children: [_jsxs(Box, { children: [_jsx(Text, { color: colors.honey, children: `${border.topLeft}${border.horizontal} ${symbols.hive} ` }), _jsx(Text, { color: colors.white, bold: true, children: nameDisplay }), _jsxs(Text, { color: colors.gray, children: [" ", `${border.horizontal.repeat(3)} `] }), _jsx(Text, { color: connected ? colors.green : colors.honey, children: connectedDisplay }), statsText && _jsxs(Text, { color: colors.gray, children: [" ", `${border.horizontal.repeat(3)} `] }), statsText && _jsxs(Text, { color: colors.honey, children: [predictionCount, " predicted"] }), _jsxs(Text, { color: colors.gray, children: [' ', border.horizontal.repeat(Math.max(0, headerFill)), border.topRight] })] }), modelInfo && (_jsxs(Box, { paddingLeft: 1, children: [_jsxs(Text, { color: colors.gray, children: [symbols.hive, " "] }), _jsx(Text, { color: colors.cyan, children: modelInfo.modelId }), _jsxs(Text, { color: colors.gray, children: [" ", '\u00d7', " "] }), _jsx(Text, { color: colors.purple, children: "zData" })] })), sectorsDisplay && (_jsxs(Box, { paddingLeft: 1, children: [_jsxs(Text, { color: colors.gray, children: [symbols.hive, " "] }), _jsx(Text, { color: colors.gray, children: "sectors: " }), _jsx(Text, { color: colors.white, children: sectorsDisplay })] })), timeframesDisplay && (_jsxs(Box, { paddingLeft: 1, children: [_jsxs(Text, { color: colors.gray, children: [symbols.hive, " "] }), _jsx(Text, { color: colors.gray, children: "timeframes: " }), timeframesDisplay.split(', ').map((tf, i, arr) => (_jsxs(React.Fragment, { children: [_jsx(Text, { color: timeframeColor(tf), children: tf }), i < arr.length - 1 && _jsx(Text, { color: colors.grayDim, children: ", " })] }, tf)))] })), stats && (_jsxs(Box, { paddingLeft: 1, children: [_jsxs(Text, { color: colors.gray, children: [symbols.hive, " "] }), _jsx(ColoredStats, { stats: stats }), statsUpdatedAt && (_jsxs(Text, { color: colors.grayDim, children: [" ", '\u00b7', " updated ", statsUpdatedAt.toLocaleDateString(), " ", formatTime(statsUpdatedAt)] }))] })), connected && (_jsxs(Box, { paddingLeft: 1, children: [_jsxs(Text, { color: colors.gray, children: [symbols.hive, " View all ", agentName, "'s activity at "] }), _jsxs(Text, { color: colors.cyan, children: [HIVE_FRONTEND_URL, "/agent/", agentName] })] })), _jsxs(Box, { flexDirection: "column", paddingLeft: 1, paddingRight: 1, minHeight: 2, children: [!connected && _jsx(Spinner, { label: "Initiating neural link..." }), activePollActivities.map((item, i) => {
38
+ } }), _jsxs(Box, { flexDirection: "column", width: boxWidth, children: [_jsxs(Box, { children: [_jsx(Text, { color: colors.honey, children: `${border.topLeft}${border.horizontal} ${symbols.hive} ` }), _jsx(Text, { color: colors.white, bold: true, children: nameDisplay }), _jsxs(Text, { color: colors.gray, children: [" ", `${border.horizontal.repeat(3)} `] }), _jsx(Text, { color: connected ? colors.green : colors.honey, children: connectedDisplay }), statsText && _jsxs(Text, { color: colors.gray, children: [" ", `${border.horizontal.repeat(3)} `] }), statsText && _jsxs(Text, { color: colors.honey, children: [predictionCount, " predicted"] }), _jsxs(Text, { color: colors.gray, children: [' ', border.horizontal.repeat(Math.max(0, headerFill)), border.topRight] })] }), modelInfo && (_jsxs(Box, { paddingLeft: 1, children: [_jsxs(Text, { color: colors.gray, children: [symbols.hive, " "] }), _jsx(Text, { color: colors.cyan, children: modelInfo.modelId }), _jsxs(Text, { color: colors.gray, children: [" ", '\u00d7', " "] }), _jsx(Text, { color: colors.purple, children: "zData" })] })), sectorsDisplay && (_jsxs(Box, { paddingLeft: 1, children: [_jsxs(Text, { color: colors.gray, children: [symbols.hive, " "] }), _jsx(Text, { color: colors.gray, children: "sectors: " }), _jsx(Text, { color: colors.white, children: sectorsDisplay })] })), timeframesDisplay && (_jsxs(Box, { paddingLeft: 1, children: [_jsxs(Text, { color: colors.gray, children: [symbols.hive, " "] }), _jsx(Text, { color: colors.gray, children: "timeframes: " }), timeframesDisplay.split(', ').map((tf, i, arr) => (_jsxs(React.Fragment, { children: [_jsx(Text, { color: timeframeColor(tf), children: tf }), i < arr.length - 1 && _jsx(Text, { color: colors.grayDim, children: ", " })] }, tf)))] })), stats && (_jsxs(Box, { paddingLeft: 1, children: [_jsxs(Text, { color: colors.gray, children: [symbols.hive, " "] }), _jsx(ColoredStats, { stats: stats }), statsUpdatedAt && (_jsxs(Text, { color: colors.grayDim, children: [' ', '\u00b7', " updated ", statsUpdatedAt.toLocaleDateString(), ' ', formatTime(statsUpdatedAt)] }))] })), connected && (_jsxs(Box, { paddingLeft: 1, children: [_jsxs(Text, { color: colors.gray, children: [symbols.hive, " View all ", agentName, "'s activity at", ' '] }), _jsxs(Text, { color: colors.cyan, children: [HIVE_FRONTEND_URL, "/agent/", agentName] })] })), _jsxs(Box, { flexDirection: "column", paddingLeft: 1, paddingRight: 1, minHeight: 2, children: [!connected && _jsx(Spinner, { label: "Initiating neural link..." }), activePollActivities.map((item, i) => {
40
39
  return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsxs(Text, { color: colors.gray, dimColor: true, children: [formatTime(item.timestamp), ' '] }), _jsxs(Text, { color: colors.controversial, children: [symbols.hive, " "] }), _jsx(PollText, { color: colors.controversial, text: activityFormatter.getText(item), animate: false }), _jsx(Text, { children: " " }), _jsx(Spinner, { label: "analyzing..." })] }), activityFormatter.getDetail(item) && (_jsx(Box, { marginLeft: 13, children: _jsx(PollText, { color: colors.gray, text: `"${activityFormatter.getDetail(item)}"`, animate: false }) }))] }, `active-${item.id ?? i}`));
41
- })] }), (chatActivity.length > 0 || chatStreaming) && (_jsxs(_Fragment, { children: [_jsx(Box, { children: _jsxs(Text, { color: colors.gray, children: [border.teeLeft, `${border.horizontal.repeat(2)} chat with ${agentName} agent `, border.horizontal.repeat(Math.max(0, boxWidth - agentName.length - 22)), border.teeRight] }) }), _jsxs(Box, { flexDirection: "column", paddingLeft: 1, paddingRight: 1, minHeight: 2, maxHeight: 8, children: [visibleChatActivity.map((item, i) => (_jsxs(Box, { children: [item.type === 'chat-user' && (_jsxs(Box, { children: [_jsxs(Text, { color: colors.white, bold: true, children: ["you:", ' '] }), _jsx(Text, { color: colors.white, children: item.text })] })), item.type === 'chat-agent' && (_jsxs(Box, { children: [_jsxs(Text, { color: colors.honey, bold: true, children: [agentName, " agent:", ' '] }), _jsx(Text, { color: colors.white, wrap: "wrap", children: item.text })] })), item.type === 'chat-error' && (_jsx(Box, { children: _jsxs(Text, { color: colors.red, children: [symbols.cross, " ", item.text] }) }))] }, i))), chatStreaming && chatBuffer && (_jsxs(Box, { children: [_jsxs(Text, { color: colors.honey, bold: true, children: [agentName, " agent:", ' '] }), _jsx(Text, { color: colors.white, wrap: "wrap", children: chatBuffer })] }))] })] })), _jsx(Box, { children: _jsxs(Text, { color: colors.gray, children: [isInteractive ? border.teeLeft : border.bottomLeft, border.horizontal.repeat(boxWidth - 2), isInteractive ? border.teeRight : border.bottomRight] }) }), isInteractive && (_jsxs(_Fragment, { children: [_jsx(Box, { paddingLeft: 1, children: _jsx(CommandInput, { value: input, onChange: setInput, onSubmit: (val) => {
40
+ })] }), (chatActivity.length > 0 || chatStreaming) && (_jsxs(_Fragment, { children: [_jsx(Box, { children: _jsxs(Text, { color: colors.gray, children: [border.teeLeft, `${border.horizontal.repeat(2)} chat with ${agentName} agent `, border.horizontal.repeat(Math.max(0, boxWidth - agentName.length - 22)), border.teeRight] }) }), _jsxs(Box, { flexDirection: "column", paddingLeft: 1, paddingRight: 1, minHeight: 2,
41
+ // @ts-expect-error maxHeight is supported by Ink at runtime but missing from types
42
+ maxHeight: 8, children: [visibleChatActivity.map((item, i) => (_jsxs(Box, { children: [item.type === 'chat-user' && (_jsxs(Box, { children: [_jsxs(Text, { color: colors.white, bold: true, children: ["you:", ' '] }), _jsx(Text, { color: colors.white, children: item.text })] })), item.type === 'chat-agent' && (_jsxs(Box, { children: [_jsxs(Text, { color: colors.honey, bold: true, children: [agentName, " agent:", ' '] }), _jsx(Text, { color: colors.white, wrap: "wrap", children: item.text })] })), item.type === 'chat-error' && (_jsx(Box, { children: _jsxs(Text, { color: colors.red, children: [symbols.cross, " ", item.text] }) }))] }, i))), chatStreaming && chatBuffer && (_jsxs(Box, { children: [_jsxs(Text, { color: colors.honey, bold: true, children: [agentName, " agent:", ' '] }), _jsx(Text, { color: colors.white, wrap: "wrap", children: chatBuffer })] }))] })] })), _jsx(Box, { children: _jsxs(Text, { color: colors.gray, children: [isInteractive ? border.teeLeft : border.bottomLeft, border.horizontal.repeat(boxWidth - 2), isInteractive ? border.teeRight : border.bottomRight] }) }), isInteractive && (_jsxs(_Fragment, { children: [_jsx(Box, { paddingLeft: 1, children: _jsx(CommandInput, { value: input, onChange: setInput, onSubmit: (val) => {
42
43
  setInput('');
43
44
  void handleChatSubmit(val);
44
45
  }, placeholder: chatStreaming ? 'thinking...' : `chat with ${agentName} agent...` }) }), _jsx(Box, { children: _jsxs(Text, { color: colors.gray, children: [border.bottomLeft, border.horizontal.repeat(boxWidth - 2), border.bottomRight] }) })] }))] })] }));
@@ -1,12 +1,12 @@
1
1
  import { spawn } from 'child_process';
2
2
  import path from 'path';
3
- import os from 'os';
3
+ import { getHiveDir } from '../../shared/config/constant.js';
4
4
  const FORCE_KILL_TIMEOUT_MS = 5_000;
5
5
  const ABSOLUTE_TIMEOUT_MS = FORCE_KILL_TIMEOUT_MS + 2_000;
6
6
  export class AgentProcessManager {
7
7
  constructor() {
8
8
  this._agents = new Map();
9
- this._agentsDir = path.join(os.homedir(), '.hive', 'agents');
9
+ this._agentsDir = path.join(getHiveDir(), 'agents');
10
10
  }
11
11
  spawnAll(discovered) {
12
12
  for (const agent of discovered) {
@@ -10,7 +10,7 @@ export async function startAllCommand() {
10
10
  const results = await Promise.all([showWelcome(), scanAgents()]);
11
11
  const discovered = results[1];
12
12
  if (discovered.length === 0) {
13
- console.log(`\n ${styled.honey(symbols.hive)} ${styled.red('No agents found in ~/.hive/agents/')}\n`);
13
+ console.log(`\n ${styled.honey(symbols.hive)} ${styled.red('No agents found in ~/.zhive/agents/')}\n`);
14
14
  console.log(` ${styled.gray('Create agents with:')} ${styled.white('npx @zhive/cli@latest create')}\n`);
15
15
  return;
16
16
  }
package/dist/index.js CHANGED
@@ -21,7 +21,7 @@ Usage:
21
21
  npx @zhive/cli@latest --version Print version
22
22
 
23
23
  Examples:
24
- npx @zhive/cli@latest create alpha Creates ~/.hive/agents/alpha/
24
+ npx @zhive/cli@latest create alpha Creates ~/.zhive/agents/alpha/
25
25
  npx @zhive/cli@latest create Interactive setup
26
26
  npx @zhive/cli@latest list Show all agents
27
27
  npx @zhive/cli@latest start Pick an agent and run it
@@ -1,14 +1,14 @@
1
1
  import { getMemoryLineCount, loadMemory, MEMORY_SOFT_LIMIT, saveMemory, } from '@zhive/sdk';
2
2
  import * as ai from 'ai';
3
3
  import { z } from 'zod';
4
- import { getModel } from '../config/ai-providers.js';
4
+ import { getModel, getScreenModel } from '../config/ai-providers.js';
5
5
  import { buildMemoryExtractionPrompt } from './prompts/memory-prompt.js';
6
6
  import { extractErrorMessage, stripCodeFences } from './utils.js';
7
7
  import { wrapAISDK } from 'langsmith/experimental/vercel';
8
8
  import { buildScreenPrompt } from './prompts/prompt.js';
9
9
  import { buildMegathreadInputPrompt, buildMegathreadSystemPrompt, } from './prompts/megathread.js';
10
10
  import { clearSubagentUsage, getSubagentUsage, } from './tools/index.js';
11
- const { ToolLoopAgent, generateText, Output } = wrapAISDK(ai);
11
+ const { ToolLoopAgent, generateText, generateObject, Output } = wrapAISDK(ai);
12
12
  // ─── Cache Helpers ─────────────────────────────────
13
13
  function cacheableSystem(content) {
14
14
  const message = {
@@ -63,11 +63,11 @@ export async function screenMegathreadRound(projectId, strategyContent) {
63
63
  const { system, prompt } = buildScreenPrompt(strategyContent, {
64
64
  projectId,
65
65
  });
66
- const model = await getModel();
67
- const res = await generateText({
66
+ const model = await getScreenModel();
67
+ const res = await generateObject({
68
68
  model,
69
69
  messages: [cacheableSystem(system), { role: 'user', content: prompt }],
70
- experimental_output: Output.object({ schema: screenSchema }),
70
+ schema: screenSchema,
71
71
  });
72
72
  const usage = {
73
73
  inputTokens: res.usage?.inputTokens ?? 0,
@@ -78,11 +78,7 @@ export async function screenMegathreadRound(projectId, strategyContent) {
78
78
  toolNames: [],
79
79
  toolResults: [],
80
80
  };
81
- const output = res.experimental_output;
82
- if (!output) {
83
- return { engage: true, usage };
84
- }
85
- return { engage: output.engage, usage };
81
+ return { engage: res.object.engage, usage };
86
82
  }
87
83
  catch (err) {
88
84
  const emptyUsage = {
@@ -136,9 +132,10 @@ export async function processMegathreadRound({ projectId, durationMs, recentComm
136
132
  return { skip: true, summary: '', conviction: 0, usage };
137
133
  }
138
134
  const prediction = output;
139
- const summary = prediction.summary ?? '';
140
- const conviction = prediction.conviction ?? 0;
141
- return { skip: false, summary, conviction, usage };
135
+ if (prediction.summary === null || prediction.conviction === null) {
136
+ return { skip: true, summary: '', conviction: 0, usage };
137
+ }
138
+ return { skip: false, summary: prediction.summary, conviction: prediction.conviction, usage };
142
139
  }
143
140
  // ─── Memory Extraction ──────────────────────────────
144
141
  export async function extractAndSaveMemory(sessionMessages) {
@@ -8,7 +8,7 @@ Your trading strategy:
8
8
  ${strategyContent}
9
9
  ---
10
10
 
11
- Decide if this project matches your sectors and expertise. Only engage with projects you can form a meaningful directional view on.
11
+ Only engage with projects that match the agent's sectors and expertise as defined in the trading strategy above. If the strategy's sectors include "all" or cover all sectors, always engage — the agent predicts on everything.
12
12
 
13
13
  Answer with only "yes" or "no".`;
14
14
  const prompt = `Project: ${projectId}
@@ -1,9 +1,8 @@
1
1
  import axios from 'axios';
2
2
  import fsExtra from 'fs-extra';
3
3
  import * as fs from 'fs/promises';
4
- import os from 'os';
5
4
  import path, { join } from 'path';
6
- import { HIVE_API_URL } from './constant.js';
5
+ import { HIVE_API_URL, getHiveDir } from './constant.js';
7
6
  import { AI_PROVIDERS } from './ai-providers.js';
8
7
  const VALID_SENTIMENTS = [
9
8
  'very-bullish',
@@ -87,7 +86,7 @@ export async function loadAgentConfig(_agentDir) {
87
86
  };
88
87
  }
89
88
  export async function scanAgents() {
90
- const agentsDir = path.join(os.homedir(), '.hive', 'agents');
89
+ const agentsDir = path.join(getHiveDir(), 'agents');
91
90
  const exists = await fsExtra.pathExists(agentsDir);
92
91
  if (!exists) {
93
92
  return [];
@@ -127,30 +127,36 @@ export function resolveModelInfo() {
127
127
  }
128
128
  return { provider: 'unknown', modelId: 'unknown', source: 'unknown' };
129
129
  }
130
+ async function _loadModelForTier(tier) {
131
+ const agentKeys = getAgentProviderKeys();
132
+ const sortedProviders = [
133
+ ...AI_PROVIDERS.filter((p) => agentKeys.has(p.envVar)),
134
+ ...AI_PROVIDERS.filter((p) => !agentKeys.has(p.envVar)),
135
+ ];
136
+ for (const provider of sortedProviders) {
137
+ const keyValue = process.env[provider.envVar];
138
+ if (keyValue && keyValue.trim().length > 0) {
139
+ const overrideModel = process.env.HIVE_MODEL;
140
+ const modelId = tier === 'runtime' && overrideModel ? overrideModel : provider.models[tier];
141
+ const model = await provider.load(modelId);
142
+ return model;
143
+ }
144
+ }
145
+ throw new Error('No AI provider API key found in environment. ' +
146
+ 'Set one of: ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY, XAI_API_KEY, OPENROUTER_API_KEY');
147
+ }
148
+ let _screenModelPromise = null;
149
+ export function getScreenModel() {
150
+ if (_screenModelPromise) {
151
+ return _screenModelPromise;
152
+ }
153
+ _screenModelPromise = _loadModelForTier('validation');
154
+ return _screenModelPromise;
155
+ }
130
156
  export function getModel() {
131
157
  if (_modelPromise) {
132
158
  return _modelPromise;
133
159
  }
134
- _modelPromise = (async () => {
135
- const info = resolveModelInfo();
136
- if (info.provider === 'unknown') {
137
- throw new Error('No AI provider API key found in environment. ' +
138
- 'Set one of: ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY, XAI_API_KEY, OPENROUTER_API_KEY');
139
- }
140
- const agentKeys = getAgentProviderKeys();
141
- const sortedProviders = [
142
- ...AI_PROVIDERS.filter((p) => agentKeys.has(p.envVar)),
143
- ...AI_PROVIDERS.filter((p) => !agentKeys.has(p.envVar)),
144
- ];
145
- for (const provider of sortedProviders) {
146
- const keyValue = process.env[provider.envVar];
147
- if (keyValue && keyValue.trim().length > 0) {
148
- const modelId = info.modelId;
149
- const model = await provider.load(modelId);
150
- return model;
151
- }
152
- }
153
- throw new Error('Unreachable: resolveModelInfo succeeded but no provider found');
154
- })();
160
+ _modelPromise = _loadModelForTier('runtime');
155
161
  return _modelPromise;
156
162
  }
@@ -1,8 +1,17 @@
1
+ import fs from 'fs';
1
2
  import path from 'path';
2
3
  import os from 'os';
3
4
  export const HIVE_API_URL = 'https://api.zhive.ai';
4
5
  export const HIVE_FRONTEND_URL = 'https://www.zhive.ai';
5
6
  export function getHiveDir() {
6
- const hiveDir = path.join(os.homedir(), '.hive');
7
- return hiveDir;
7
+ const homeDir = os.homedir();
8
+ const zhiveDir = path.join(homeDir, '.zhive');
9
+ const legacyDir = path.join(homeDir, '.hive');
10
+ if (fs.existsSync(zhiveDir)) {
11
+ return zhiveDir;
12
+ }
13
+ if (fs.existsSync(legacyDir)) {
14
+ return legacyDir;
15
+ }
16
+ return zhiveDir;
8
17
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhive/cli",
3
- "version": "0.5.3",
3
+ "version": "0.5.5",
4
4
  "description": "CLI for bootstrapping zHive AI Agents",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -30,7 +30,7 @@
30
30
  "@ai-sdk/google": "^3.0.0",
31
31
  "@ai-sdk/openai": "^3.0.25",
32
32
  "@ai-sdk/xai": "^3.0.0",
33
- "@zhive/sdk": "^0.5.1",
33
+ "@zhive/sdk": "^0.5.2",
34
34
  "@openrouter/ai-sdk-provider": "^0.4.0",
35
35
  "ai": "^6.0.71",
36
36
  "axios": "^1.6.0",