@zhive/cli 0.6.5 → 0.6.7
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/dist/commands/agent/commands/profile.js +0 -6
- package/dist/commands/agent/commands/profile.test.js +2 -23
- package/dist/commands/create/presets/index.js +1 -1
- package/dist/commands/create/presets/options.js +18 -15
- package/dist/commands/create/ui/steps/IdentityStep.js +3 -2
- package/dist/commands/doctor/commands/index.js +5 -11
- package/dist/commands/megathread/commands/create-comment.js +2 -7
- package/dist/commands/megathread/commands/create-comment.test.js +3 -30
- package/dist/commands/megathread/commands/create-comments.js +2 -7
- package/dist/commands/megathread/commands/list.js +5 -10
- package/dist/commands/megathread/commands/list.test.js +3 -21
- package/dist/commands/migrate-templates/ui/MigrateApp.js +1 -1
- package/dist/commands/start/commands/prediction.js +1 -1
- package/dist/commands/start/commands/skills.test.js +1 -2
- package/dist/components/MultiSelectPrompt.js +3 -3
- package/dist/shared/config/agent.js +12 -6
- package/dist/shared/config/agent.test.js +0 -5
- package/package.json +2 -2
- package/dist/CLAUDE.md +0 -7
- package/dist/backtest/CLAUDE.md +0 -7
- package/dist/cli.js +0 -20
- package/dist/commands/create/presets.js +0 -613
- package/dist/commands/start/ui/AsciiTicker.js +0 -81
- package/dist/services/agent/analysis.js +0 -160
- package/dist/services/agent/config.js +0 -75
- package/dist/services/agent/env.js +0 -30
- package/dist/services/agent/helpers/model.js +0 -92
- package/dist/services/agent/helpers.js +0 -22
- package/dist/services/agent/prompts/chat-prompt.js +0 -65
- package/dist/services/agent/prompts/memory-prompt.js +0 -45
- package/dist/services/agent/prompts/prompt.js +0 -379
- package/dist/services/agent/skills/index.js +0 -2
- package/dist/services/agent/skills/skill-parser.js +0 -149
- package/dist/services/agent/skills/types.js +0 -1
- package/dist/services/agent/tools/edit-section.js +0 -59
- package/dist/services/agent/tools/fetch-rules.js +0 -21
- package/dist/services/agent/tools/index.js +0 -76
- package/dist/services/agent/tools/market/client.js +0 -41
- package/dist/services/agent/tools/market/index.js +0 -3
- package/dist/services/agent/tools/market/tools.js +0 -518
- package/dist/services/agent/tools/mindshare/client.js +0 -124
- package/dist/services/agent/tools/mindshare/index.js +0 -3
- package/dist/services/agent/tools/mindshare/tools.js +0 -563
- package/dist/services/agent/tools/read-skill-tool.js +0 -30
- package/dist/services/agent/tools/ta/index.js +0 -1
- package/dist/services/agent/tools/ta/indicators.js +0 -201
- package/dist/services/agent/types.js +0 -1
- package/dist/services/ai-providers.js +0 -66
- package/dist/services/config/agent.js +0 -110
- package/dist/services/config/config.js +0 -22
- package/dist/services/config/constant.js +0 -8
- package/dist/shared/agent/agent-runtime.js +0 -144
- package/dist/shared/agent/config.js +0 -75
- package/dist/shared/agent/env.js +0 -30
- package/dist/shared/agent/helpers/model.js +0 -92
- package/dist/shared/agent/types.js +0 -1
- package/dist/shared/ai-providers.js +0 -66
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import { findAgentByName, scanAgents } from '../../../shared/config/agent.js';
|
|
3
3
|
import { styled, symbols } from '../../shared/theme.js';
|
|
4
|
-
import { loadConfig } from '@zhive/sdk';
|
|
5
4
|
export const createAgentProfileCommand = () => {
|
|
6
5
|
return new Command('profile')
|
|
7
6
|
.description('Display agent profile information')
|
|
@@ -19,11 +18,6 @@ export const createAgentProfileCommand = () => {
|
|
|
19
18
|
}
|
|
20
19
|
process.exit(1);
|
|
21
20
|
}
|
|
22
|
-
const credentials = await loadConfig(agentConfig.dir);
|
|
23
|
-
if (!credentials?.apiKey) {
|
|
24
|
-
console.error(styled.red(`${symbols.cross} No credentials found for agent "${agentName}". The agent may need to be registered first.`));
|
|
25
|
-
process.exit(1);
|
|
26
|
-
}
|
|
27
21
|
console.log('');
|
|
28
22
|
console.log(styled.honeyBold(`${symbols.hive} Agent Profile: ${agentConfig.name}`));
|
|
29
23
|
console.log('');
|
|
@@ -10,13 +10,6 @@ vi.mock('../../../shared/config/constant.js', () => ({
|
|
|
10
10
|
vi.mock('../../../shared/config/ai-providers.js', () => ({
|
|
11
11
|
AI_PROVIDERS: [{ label: 'OpenAI', package: '@ai-sdk/openai', envVar: 'OPENAI_API_KEY' }],
|
|
12
12
|
}));
|
|
13
|
-
vi.mock('@zhive/sdk', async () => {
|
|
14
|
-
const actual = await vi.importActual('@zhive/sdk');
|
|
15
|
-
return {
|
|
16
|
-
...actual,
|
|
17
|
-
loadConfig: vi.fn(),
|
|
18
|
-
};
|
|
19
|
-
});
|
|
20
13
|
vi.mock('../../shared/theme.js', () => ({
|
|
21
14
|
styled: {
|
|
22
15
|
red: (text) => text,
|
|
@@ -32,9 +25,7 @@ vi.mock('../../shared/theme.js', () => ({
|
|
|
32
25
|
hive: '⬡',
|
|
33
26
|
},
|
|
34
27
|
}));
|
|
35
|
-
import { loadConfig } from '@zhive/sdk';
|
|
36
28
|
import { createAgentProfileCommand } from './profile.js';
|
|
37
|
-
const mockLoadConfig = loadConfig;
|
|
38
29
|
describe('createAgentProfileCommand', () => {
|
|
39
30
|
let consoleLogSpy;
|
|
40
31
|
let consoleErrorSpy;
|
|
@@ -72,20 +63,11 @@ describe('createAgentProfileCommand', () => {
|
|
|
72
63
|
expect(consoleErrorOutput.join('\n')).toContain('agent-no-skills');
|
|
73
64
|
});
|
|
74
65
|
it('shows error when credentials are missing', async () => {
|
|
75
|
-
mockLoadConfig.mockResolvedValue(null);
|
|
76
|
-
const command = createAgentProfileCommand();
|
|
77
|
-
await expect(command.parseAsync(['test-agent'], { from: 'user' })).rejects.toThrow('process.exit(1)');
|
|
78
|
-
expect(consoleErrorOutput.join('\n')).toContain('No credentials found for agent "test-agent"');
|
|
79
|
-
expect(consoleErrorOutput.join('\n')).toContain('may need to be registered first');
|
|
80
|
-
});
|
|
81
|
-
it('shows error when credentials have no API key', async () => {
|
|
82
|
-
mockLoadConfig.mockResolvedValue({ apiKey: null });
|
|
83
66
|
const command = createAgentProfileCommand();
|
|
84
|
-
await expect(command.parseAsync(['
|
|
85
|
-
expect(consoleErrorOutput.join('\n')).toContain('
|
|
67
|
+
await expect(command.parseAsync(['no-cred'], { from: 'user' })).rejects.toThrow('process.exit(1)');
|
|
68
|
+
expect(consoleErrorOutput.join('\n')).toContain('Agent "no-cred" not found');
|
|
86
69
|
});
|
|
87
70
|
it('displays profile from local config', async () => {
|
|
88
|
-
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
89
71
|
const command = createAgentProfileCommand();
|
|
90
72
|
await command.parseAsync(['test-agent'], { from: 'user' });
|
|
91
73
|
const output = consoleOutput.join('\n');
|
|
@@ -98,7 +80,6 @@ describe('createAgentProfileCommand', () => {
|
|
|
98
80
|
expect(output).toContain('https://example.com/avatar.png');
|
|
99
81
|
});
|
|
100
82
|
it('displays profile settings section', async () => {
|
|
101
|
-
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
102
83
|
const command = createAgentProfileCommand();
|
|
103
84
|
await command.parseAsync(['test-agent'], { from: 'user' });
|
|
104
85
|
const output = consoleOutput.join('\n');
|
|
@@ -111,7 +92,6 @@ describe('createAgentProfileCommand', () => {
|
|
|
111
92
|
expect(output).toContain('defi, gaming');
|
|
112
93
|
});
|
|
113
94
|
it('handles agent with empty sectors', async () => {
|
|
114
|
-
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
115
95
|
const command = createAgentProfileCommand();
|
|
116
96
|
await command.parseAsync(['empty-agent'], { from: 'user' });
|
|
117
97
|
const output = consoleOutput.join('\n');
|
|
@@ -124,7 +104,6 @@ describe('createAgentProfileCommand', () => {
|
|
|
124
104
|
expect(sectorsLine).toContain('-');
|
|
125
105
|
});
|
|
126
106
|
it('works with different fixture agents', async () => {
|
|
127
|
-
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
128
107
|
const command = createAgentProfileCommand();
|
|
129
108
|
await command.parseAsync(['agent-no-skills'], { from: 'user' });
|
|
130
109
|
const output = consoleOutput.join('\n');
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { SOUL_PRESETS, STRATEGY_PRESETS } from './data.js';
|
|
2
|
-
export { PERSONALITY_OPTIONS, VOICE_OPTIONS, BIO_EXAMPLES, TRADING_STYLE_OPTIONS, SENTIMENT_OPTIONS, TIMEFRAME_OPTIONS, PROJECT_CATEGORY_OPTIONS, } from './options.js';
|
|
2
|
+
export { PERSONALITY_OPTIONS, VOICE_OPTIONS, BIO_EXAMPLES, TRADING_STYLE_OPTIONS, SENTIMENT_OPTIONS, TIMEFRAME_OPTIONS, PROJECT_CATEGORY_OPTIONS, DEFAULT_SECTOR_VALUES, } from './options.js';
|
|
3
3
|
export { buildSoulMarkdown, buildStrategyMarkdown } from './formatting.js';
|
|
@@ -203,6 +203,14 @@ export const TIMEFRAME_OPTIONS = [
|
|
|
203
203
|
description: 'Longer-term, macro-style predictions',
|
|
204
204
|
},
|
|
205
205
|
];
|
|
206
|
+
export const DEFAULT_SECTOR_VALUES = new Set([
|
|
207
|
+
'l1',
|
|
208
|
+
'l2',
|
|
209
|
+
'defi',
|
|
210
|
+
'ai',
|
|
211
|
+
'lending',
|
|
212
|
+
'prediction-markets',
|
|
213
|
+
]);
|
|
206
214
|
export const PROJECT_CATEGORY_OPTIONS = [
|
|
207
215
|
{
|
|
208
216
|
label: '🔷 Layer 1',
|
|
@@ -224,6 +232,16 @@ export const PROJECT_CATEGORY_OPTIONS = [
|
|
|
224
232
|
value: 'ai',
|
|
225
233
|
description: 'AI and compute tokens — FET, RENDER, TAO, AKT, etc.',
|
|
226
234
|
},
|
|
235
|
+
{
|
|
236
|
+
label: '🏛️ Lending',
|
|
237
|
+
value: 'lending',
|
|
238
|
+
description: 'Lending and borrowing protocols — AAVE, COMP, MORPHO, etc.',
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
label: '🎯 Prediction Markets',
|
|
242
|
+
value: 'prediction-markets',
|
|
243
|
+
description: 'Prediction and betting markets — POLY, GNO, etc.',
|
|
244
|
+
},
|
|
227
245
|
{
|
|
228
246
|
label: '🐸 Memecoins',
|
|
229
247
|
value: 'meme',
|
|
@@ -254,16 +272,6 @@ export const PROJECT_CATEGORY_OPTIONS = [
|
|
|
254
272
|
value: 'dex',
|
|
255
273
|
description: 'Decentralized exchanges — UNI, SUSHI, CRV, JUP, etc.',
|
|
256
274
|
},
|
|
257
|
-
{
|
|
258
|
-
label: '🏛️ Lending',
|
|
259
|
-
value: 'lending',
|
|
260
|
-
description: 'Lending and borrowing protocols — AAVE, COMP, MORPHO, etc.',
|
|
261
|
-
},
|
|
262
|
-
{
|
|
263
|
-
label: '💵 Stablecoin',
|
|
264
|
-
value: 'stablecoin',
|
|
265
|
-
description: 'Stablecoin protocols and pegged assets — MKR, FXS, LQTY, etc.',
|
|
266
|
-
},
|
|
267
275
|
{
|
|
268
276
|
label: '🌉 Cross-chain',
|
|
269
277
|
value: 'cross-chain',
|
|
@@ -289,11 +297,6 @@ export const PROJECT_CATEGORY_OPTIONS = [
|
|
|
289
297
|
value: 'social',
|
|
290
298
|
description: 'Social and identity protocols — LENS, CYBER, ID, etc.',
|
|
291
299
|
},
|
|
292
|
-
{
|
|
293
|
-
label: '🎯 Prediction Markets',
|
|
294
|
-
value: 'prediction-markets',
|
|
295
|
-
description: 'Prediction and betting markets — POLY, GNO, etc.',
|
|
296
|
-
},
|
|
297
300
|
{
|
|
298
301
|
label: '🖼️ NFT',
|
|
299
302
|
value: 'nft',
|
|
@@ -5,7 +5,7 @@ import { SelectPrompt } from '../../../../components/SelectPrompt.js';
|
|
|
5
5
|
import { MultiSelectPrompt, } from '../../../../components/MultiSelectPrompt.js';
|
|
6
6
|
import { TextPrompt } from '../../../../components/TextPrompt.js';
|
|
7
7
|
import { CharacterSummaryCard } from '../../../../components/CharacterSummaryCard.js';
|
|
8
|
-
import { PERSONALITY_OPTIONS, VOICE_OPTIONS, TRADING_STYLE_OPTIONS, PROJECT_CATEGORY_OPTIONS, SENTIMENT_OPTIONS, TIMEFRAME_OPTIONS, BIO_EXAMPLES, } from '../../presets/index.js';
|
|
8
|
+
import { PERSONALITY_OPTIONS, VOICE_OPTIONS, TRADING_STYLE_OPTIONS, PROJECT_CATEGORY_OPTIONS, SENTIMENT_OPTIONS, TIMEFRAME_OPTIONS, DEFAULT_SECTOR_VALUES, BIO_EXAMPLES, } from '../../presets/index.js';
|
|
9
9
|
import { colors, symbols } from '../../../shared/theme.js';
|
|
10
10
|
import { required, compose, maxLength } from '../validation.js';
|
|
11
11
|
function buildSelectItems(options, addCustom = false) {
|
|
@@ -25,6 +25,7 @@ const tradingStyleItems = buildSelectItems(TRADING_STYLE_OPTIONS, true);
|
|
|
25
25
|
const categoryItems = buildSelectItems(PROJECT_CATEGORY_OPTIONS);
|
|
26
26
|
const sentimentItems = buildSelectItems(SENTIMENT_OPTIONS);
|
|
27
27
|
const timeframeItems = buildSelectItems(TIMEFRAME_OPTIONS);
|
|
28
|
+
const timeframeDefaultSelected = new Set(TIMEFRAME_OPTIONS.filter((opt) => opt.value !== '1h').map((opt) => opt.value));
|
|
28
29
|
export function IdentityStep({ agentName, onComplete }) {
|
|
29
30
|
const [subStep, setSubStep] = useState('personality');
|
|
30
31
|
const [personalityLabel, setPersonalityLabel] = useState('');
|
|
@@ -121,5 +122,5 @@ export function IdentityStep({ agentName, onComplete }) {
|
|
|
121
122
|
};
|
|
122
123
|
onComplete(result);
|
|
123
124
|
}, [personality, tone, voiceStyle, tradingStyle, sectors, sentiment, timeframes, onComplete]);
|
|
124
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(CharacterSummaryCard, { name: agentName, personality: personalityLabel || undefined, voice: voiceLabel || undefined, tradingStyle: tradingStyleLabel || undefined, sectors: sectorsLabel || undefined, sentiment: sentimentLabel || undefined, timeframe: timeframesLabel || undefined }), subStep === 'personality' && (_jsx(SelectPrompt, { label: "Choose a personality", items: personalityItems, onSelect: handlePersonalitySelect })), subStep === 'personality-custom' && (_jsx(TextPrompt, { label: "Describe your agent's personality", placeholder: "e.g. stoic realist with a dry wit", onSubmit: handlePersonalityCustom, validate: required('Personality') })), subStep === 'voice' && (_jsx(SelectPrompt, { label: "Choose a voice", items: voiceItems, onSelect: handleVoiceSelect })), subStep === 'voice-custom' && (_jsx(TextPrompt, { label: "Describe your agent's voice", placeholder: "e.g. writes like a bloomberg terminal on acid", onSubmit: handleVoiceCustom, validate: required('Voice') })), subStep === 'trading' && (_jsx(SelectPrompt, { label: "How does your agent evaluate signals?", items: tradingStyleItems, onSelect: handleTradingStyleSelect })), subStep === 'trading-custom' && (_jsx(TextPrompt, { label: "Describe your agent's trading style", placeholder: "e.g. combines on-chain data with sentiment analysis", onSubmit: handleTradingStyleCustom, validate: required('Trading style') })), subStep === 'sectors' && (_jsx(MultiSelectPrompt, { label: "Which categories should your agent trade?", items: categoryItems, onSubmit: handleSectors })), subStep === 'sentiment' && (_jsx(SelectPrompt, { label: "What's your agent's market sentiment?", items: sentimentItems, onSelect: handleSentimentSelect })), subStep === 'timeframe' && (_jsx(MultiSelectPrompt, { label: "Which timeframes should your agent participate in?", items: timeframeItems, onSubmit: handleTimeframes })), subStep === 'bio' && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { flexDirection: "column", marginLeft: 2, marginBottom: 1, children: [_jsxs(Text, { color: colors.grayDim, italic: true, children: [symbols.arrow, " Examples:"] }), BIO_EXAMPLES.map((example, i) => (_jsx(Box, { marginLeft: 2, marginTop: i > 0 ? 1 : 0, children: _jsxs(Text, { color: colors.grayDim, italic: true, children: [symbols.diamond, " ", `"${example}"`] }) }, i)))] }), _jsx(TextPrompt, { label: "Write your agent's bio", placeholder: `short bio for your ${personalityLabel} agent`, onSubmit: handleBio, maxLength: 1000, validate: compose(required('Bio'), maxLength(1000)) })] }))] }));
|
|
125
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(CharacterSummaryCard, { name: agentName, personality: personalityLabel || undefined, voice: voiceLabel || undefined, tradingStyle: tradingStyleLabel || undefined, sectors: sectorsLabel || undefined, sentiment: sentimentLabel || undefined, timeframe: timeframesLabel || undefined }), subStep === 'personality' && (_jsx(SelectPrompt, { label: "Choose a personality", items: personalityItems, onSelect: handlePersonalitySelect })), subStep === 'personality-custom' && (_jsx(TextPrompt, { label: "Describe your agent's personality", placeholder: "e.g. stoic realist with a dry wit", onSubmit: handlePersonalityCustom, validate: required('Personality') })), subStep === 'voice' && (_jsx(SelectPrompt, { label: "Choose a voice", items: voiceItems, onSelect: handleVoiceSelect })), subStep === 'voice-custom' && (_jsx(TextPrompt, { label: "Describe your agent's voice", placeholder: "e.g. writes like a bloomberg terminal on acid", onSubmit: handleVoiceCustom, validate: required('Voice') })), subStep === 'trading' && (_jsx(SelectPrompt, { label: "How does your agent evaluate signals?", items: tradingStyleItems, onSelect: handleTradingStyleSelect })), subStep === 'trading-custom' && (_jsx(TextPrompt, { label: "Describe your agent's trading style", placeholder: "e.g. combines on-chain data with sentiment analysis", onSubmit: handleTradingStyleCustom, validate: required('Trading style') })), subStep === 'sectors' && (_jsx(MultiSelectPrompt, { label: "Which categories should your agent trade?", items: categoryItems, defaultSelected: DEFAULT_SECTOR_VALUES, hint: "Recommended categories selected \u2014 press spacebar to toggle", onSubmit: handleSectors })), subStep === 'sentiment' && (_jsx(SelectPrompt, { label: "What's your agent's market sentiment?", items: sentimentItems, onSelect: handleSentimentSelect })), subStep === 'timeframe' && (_jsxs(Box, { flexDirection: "column", children: [_jsx(Box, { marginLeft: 2, marginBottom: 1, children: _jsxs(Text, { color: colors.hot, bold: true, children: [symbols.arrow, " Warning: Selecting the 1h timeframe will significantly increase token usage."] }) }), _jsx(MultiSelectPrompt, { label: "Which timeframes should your agent participate in?", items: timeframeItems, defaultSelected: timeframeDefaultSelected, hint: "4h and 24h selected by default \u2014 press spacebar to toggle", onSubmit: handleTimeframes })] })), subStep === 'bio' && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { flexDirection: "column", marginLeft: 2, marginBottom: 1, children: [_jsxs(Text, { color: colors.grayDim, italic: true, children: [symbols.arrow, " Examples:"] }), BIO_EXAMPLES.map((example, i) => (_jsx(Box, { marginLeft: 2, marginTop: i > 0 ? 1 : 0, children: _jsxs(Text, { color: colors.grayDim, italic: true, children: [symbols.diamond, " ", `"${example}"`] }) }, i)))] }), _jsx(TextPrompt, { label: "Write your agent's bio", placeholder: `short bio for your ${personalityLabel} agent`, onSubmit: handleBio, maxLength: 1000, validate: compose(required('Bio'), maxLength(1000)) })] }))] }));
|
|
125
126
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import fsExtra from 'fs-extra';
|
|
4
|
-
import { HiveClient
|
|
4
|
+
import { HiveClient } from '@zhive/sdk';
|
|
5
5
|
import { styled, symbols } from '../../shared/theme.js';
|
|
6
6
|
import { getHiveDir, HIVE_API_URL } from '../../../shared/config/constant.js';
|
|
7
7
|
import { loadAgentConfig } from '../../../shared/config/agent.js';
|
|
@@ -13,26 +13,20 @@ async function checkAgent(agentDir, dirName) {
|
|
|
13
13
|
configError: null,
|
|
14
14
|
registrationStatus: 'skipped',
|
|
15
15
|
};
|
|
16
|
-
let
|
|
16
|
+
let config;
|
|
17
17
|
try {
|
|
18
|
-
|
|
18
|
+
config = await loadAgentConfig(agentDir);
|
|
19
19
|
result.name = config.name;
|
|
20
|
-
configLoaded = true;
|
|
21
20
|
}
|
|
22
21
|
catch (err) {
|
|
23
22
|
const message = err instanceof Error ? err.message : String(err);
|
|
24
23
|
result.configError = message;
|
|
25
24
|
}
|
|
26
|
-
if (!
|
|
27
|
-
return result;
|
|
28
|
-
}
|
|
29
|
-
const credentials = await loadConfig(agentDir);
|
|
30
|
-
if (!credentials?.apiKey) {
|
|
31
|
-
result.registrationStatus = 'no-api-key';
|
|
25
|
+
if (!config) {
|
|
32
26
|
return result;
|
|
33
27
|
}
|
|
34
28
|
try {
|
|
35
|
-
const client = new HiveClient(HIVE_API_URL,
|
|
29
|
+
const client = new HiveClient(HIVE_API_URL, config.apiKey);
|
|
36
30
|
await client.getMe();
|
|
37
31
|
result.registrationStatus = 'registered';
|
|
38
32
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { HiveClient
|
|
3
|
+
import { HiveClient } from '@zhive/sdk';
|
|
4
4
|
import { styled, symbols } from '../../shared/theme.js';
|
|
5
5
|
import { HIVE_API_URL } from '../../../shared/config/constant.js';
|
|
6
6
|
import { findAgentByName, scanAgents } from '../../../shared/config/agent.js';
|
|
@@ -37,12 +37,7 @@ export function createMegathreadCreateCommentCommand() {
|
|
|
37
37
|
}
|
|
38
38
|
process.exit(1);
|
|
39
39
|
}
|
|
40
|
-
const
|
|
41
|
-
if (!credentials?.apiKey) {
|
|
42
|
-
console.error(styled.red(`${symbols.cross} No credentials found for agent "${agentName}". The agent may need to be registered first.`));
|
|
43
|
-
process.exit(1);
|
|
44
|
-
}
|
|
45
|
-
const client = new HiveClient(HIVE_API_URL, credentials.apiKey);
|
|
40
|
+
const client = new HiveClient(HIVE_API_URL, agentConfig.apiKey);
|
|
46
41
|
const payload = {
|
|
47
42
|
text,
|
|
48
43
|
conviction,
|
|
@@ -17,7 +17,6 @@ vi.mock('@zhive/sdk', async () => {
|
|
|
17
17
|
HiveClient: vi.fn().mockImplementation(() => ({
|
|
18
18
|
postMegathreadComment: vi.fn(),
|
|
19
19
|
})),
|
|
20
|
-
loadConfig: vi.fn(),
|
|
21
20
|
};
|
|
22
21
|
});
|
|
23
22
|
vi.mock('../../shared/theme.js', () => ({
|
|
@@ -31,10 +30,9 @@ vi.mock('../../shared/theme.js', () => ({
|
|
|
31
30
|
check: '✓',
|
|
32
31
|
},
|
|
33
32
|
}));
|
|
34
|
-
import { HiveClient
|
|
33
|
+
import { HiveClient } from '@zhive/sdk';
|
|
35
34
|
import { createMegathreadCreateCommentCommand } from './create-comment.js';
|
|
36
35
|
const MockHiveClient = HiveClient;
|
|
37
|
-
const mockLoadConfig = loadConfig;
|
|
38
36
|
describe('createMegathreadCreateCommentCommand', () => {
|
|
39
37
|
let consoleLogSpy;
|
|
40
38
|
let consoleErrorSpy;
|
|
@@ -114,7 +112,6 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
114
112
|
expect(consoleErrorOutput.join('\n')).toContain('number');
|
|
115
113
|
});
|
|
116
114
|
it('accepts valid conviction at upper boundary', async () => {
|
|
117
|
-
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
118
115
|
mockPostMegathreadComment.mockResolvedValue(undefined);
|
|
119
116
|
const command = createMegathreadCreateCommentCommand();
|
|
120
117
|
await command.parseAsync([
|
|
@@ -133,7 +130,6 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
133
130
|
});
|
|
134
131
|
});
|
|
135
132
|
it('accepts valid conviction at lower boundary', async () => {
|
|
136
|
-
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
137
133
|
mockPostMegathreadComment.mockResolvedValue(undefined);
|
|
138
134
|
const command = createMegathreadCreateCommentCommand();
|
|
139
135
|
await command.parseAsync([
|
|
@@ -152,7 +148,6 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
152
148
|
});
|
|
153
149
|
});
|
|
154
150
|
it('accepts decimal conviction values', async () => {
|
|
155
|
-
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
156
151
|
mockPostMegathreadComment.mockResolvedValue(undefined);
|
|
157
152
|
const command = createMegathreadCreateCommentCommand();
|
|
158
153
|
await command.parseAsync([
|
|
@@ -193,26 +188,10 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
193
188
|
});
|
|
194
189
|
describe('credentials validation', () => {
|
|
195
190
|
it('shows error when credentials are missing', async () => {
|
|
196
|
-
mockLoadConfig.mockResolvedValue(null);
|
|
197
191
|
const command = createMegathreadCreateCommentCommand();
|
|
198
192
|
await expect(command.parseAsync([
|
|
199
193
|
'--agent',
|
|
200
|
-
'
|
|
201
|
-
'--round',
|
|
202
|
-
'round-123',
|
|
203
|
-
'--conviction',
|
|
204
|
-
'50',
|
|
205
|
-
'--text',
|
|
206
|
-
'Test comment',
|
|
207
|
-
], { from: 'user' })).rejects.toThrow('process.exit(1)');
|
|
208
|
-
expect(consoleErrorOutput.join('\n')).toContain('No credentials found for agent "test-agent"');
|
|
209
|
-
});
|
|
210
|
-
it('shows error when credentials have no API key', async () => {
|
|
211
|
-
mockLoadConfig.mockResolvedValue({ apiKey: null });
|
|
212
|
-
const command = createMegathreadCreateCommentCommand();
|
|
213
|
-
await expect(command.parseAsync([
|
|
214
|
-
'--agent',
|
|
215
|
-
'test-agent',
|
|
194
|
+
'no-cred',
|
|
216
195
|
'--round',
|
|
217
196
|
'round-123',
|
|
218
197
|
'--conviction',
|
|
@@ -220,12 +199,11 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
220
199
|
'--text',
|
|
221
200
|
'Test comment',
|
|
222
201
|
], { from: 'user' })).rejects.toThrow('process.exit(1)');
|
|
223
|
-
expect(consoleErrorOutput.join('\n')).toContain('
|
|
202
|
+
expect(consoleErrorOutput.join('\n')).toContain('Agent "no-cred" not found');
|
|
224
203
|
});
|
|
225
204
|
});
|
|
226
205
|
describe('successful comment posting', () => {
|
|
227
206
|
it('posts comment and shows success message', async () => {
|
|
228
|
-
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
229
207
|
mockPostMegathreadComment.mockResolvedValue(undefined);
|
|
230
208
|
const command = createMegathreadCreateCommentCommand();
|
|
231
209
|
await command.parseAsync([
|
|
@@ -249,7 +227,6 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
249
227
|
expect(output).toContain('Bullish on Bitcoin!');
|
|
250
228
|
});
|
|
251
229
|
it('formats negative conviction correctly', async () => {
|
|
252
|
-
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
253
230
|
mockPostMegathreadComment.mockResolvedValue(undefined);
|
|
254
231
|
const command = createMegathreadCreateCommentCommand();
|
|
255
232
|
await command.parseAsync([
|
|
@@ -266,7 +243,6 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
266
243
|
expect(output).toContain('-30.0%');
|
|
267
244
|
});
|
|
268
245
|
it('truncates long text in success message', async () => {
|
|
269
|
-
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
270
246
|
mockPostMegathreadComment.mockResolvedValue(undefined);
|
|
271
247
|
const longText = 'A'.repeat(100);
|
|
272
248
|
const command = createMegathreadCreateCommentCommand();
|
|
@@ -283,7 +259,6 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
283
259
|
});
|
|
284
260
|
describe('API error handling', () => {
|
|
285
261
|
it('shows error when API call fails', async () => {
|
|
286
|
-
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
287
262
|
mockPostMegathreadComment.mockRejectedValue(new Error('Network error'));
|
|
288
263
|
const command = createMegathreadCreateCommentCommand();
|
|
289
264
|
await expect(command.parseAsync([
|
|
@@ -300,7 +275,6 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
300
275
|
expect(consoleErrorOutput.join('\n')).toContain('Network error');
|
|
301
276
|
});
|
|
302
277
|
it('handles non-Error exceptions', async () => {
|
|
303
|
-
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
304
278
|
mockPostMegathreadComment.mockRejectedValue('String error');
|
|
305
279
|
const command = createMegathreadCreateCommentCommand();
|
|
306
280
|
await expect(command.parseAsync([
|
|
@@ -319,7 +293,6 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
319
293
|
});
|
|
320
294
|
describe('works with different fixture agents', () => {
|
|
321
295
|
it('works with empty-agent', async () => {
|
|
322
|
-
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
323
296
|
mockPostMegathreadComment.mockResolvedValue(undefined);
|
|
324
297
|
const command = createMegathreadCreateCommentCommand();
|
|
325
298
|
await command.parseAsync([
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { HiveClient
|
|
3
|
+
import { HiveClient } from '@zhive/sdk';
|
|
4
4
|
import { styled, symbols } from '../../shared/theme.js';
|
|
5
5
|
import { HIVE_API_URL } from '../../../shared/config/constant.js';
|
|
6
6
|
import { findAgentByName, scanAgents } from '../../../shared/config/agent.js';
|
|
@@ -52,12 +52,7 @@ export function createMegathreadCreateCommentsCommand() {
|
|
|
52
52
|
}
|
|
53
53
|
process.exit(1);
|
|
54
54
|
}
|
|
55
|
-
const
|
|
56
|
-
if (!credentials?.apiKey) {
|
|
57
|
-
console.error(styled.red(`${symbols.cross} No credentials found for agent "${agentName}". The agent may need to be registered first.`));
|
|
58
|
-
process.exit(1);
|
|
59
|
-
}
|
|
60
|
-
const client = new HiveClient(HIVE_API_URL, credentials.apiKey);
|
|
55
|
+
const client = new HiveClient(HIVE_API_URL, agentConfig.apiKey);
|
|
61
56
|
const payload = {
|
|
62
57
|
comments: [],
|
|
63
58
|
};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import { durationMsToTimeframe, HiveClient } from '@zhive/sdk';
|
|
1
2
|
import { Command } from 'commander';
|
|
2
|
-
import { HiveClient, durationMsToTimeframe, loadConfig } from '@zhive/sdk';
|
|
3
|
-
import { styled, symbols, border } from '../../shared/theme.js';
|
|
4
|
-
import { HIVE_API_URL } from '../../../shared/config/constant.js';
|
|
5
|
-
import { findAgentByName, scanAgents } from '../../../shared/config/agent.js';
|
|
6
3
|
import z from 'zod';
|
|
4
|
+
import { findAgentByName, scanAgents } from '../../../shared/config/agent.js';
|
|
5
|
+
import { HIVE_API_URL } from '../../../shared/config/constant.js';
|
|
7
6
|
import { printZodError } from '../../shared/ validation.js';
|
|
7
|
+
import { border, styled, symbols } from '../../shared/theme.js';
|
|
8
8
|
const VALID_TIMEFRAMES = ['1h', '4h', '24h'];
|
|
9
9
|
const ListMegathreadOptionsSchema = z.object({
|
|
10
10
|
agent: z.string(),
|
|
@@ -50,12 +50,7 @@ export function createMegathreadListCommand() {
|
|
|
50
50
|
}
|
|
51
51
|
process.exit(1);
|
|
52
52
|
}
|
|
53
|
-
const
|
|
54
|
-
if (!config?.apiKey) {
|
|
55
|
-
console.error(styled.red(`${symbols.cross} No credentials found for agent "${agentName}". The agent may need to be registered first.`));
|
|
56
|
-
process.exit(1);
|
|
57
|
-
}
|
|
58
|
-
const client = new HiveClient(HIVE_API_URL, config.apiKey);
|
|
53
|
+
const client = new HiveClient(HIVE_API_URL, agentConfig.apiKey);
|
|
59
54
|
try {
|
|
60
55
|
const rounds = await client.getUnpredictedRounds(timeframes);
|
|
61
56
|
console.log('');
|
|
@@ -17,7 +17,6 @@ vi.mock('@zhive/sdk', async () => {
|
|
|
17
17
|
HiveClient: vi.fn().mockImplementation(() => ({
|
|
18
18
|
getUnpredictedRounds: vi.fn(),
|
|
19
19
|
})),
|
|
20
|
-
loadConfig: vi.fn(),
|
|
21
20
|
TIMEFRAME_DURATION_MS: {
|
|
22
21
|
H1: 3600000,
|
|
23
22
|
H4: 14400000,
|
|
@@ -30,10 +29,9 @@ vi.mock('@zhive/sdk', async () => {
|
|
|
30
29
|
},
|
|
31
30
|
};
|
|
32
31
|
});
|
|
33
|
-
import { HiveClient
|
|
32
|
+
import { HiveClient } from '@zhive/sdk';
|
|
34
33
|
import { createMegathreadListCommand } from './list.js';
|
|
35
34
|
const MockHiveClient = HiveClient;
|
|
36
|
-
const mockLoadConfig = loadConfig;
|
|
37
35
|
function createMockActiveRound(overrides = {}) {
|
|
38
36
|
return {
|
|
39
37
|
roundId: 'round-123',
|
|
@@ -88,21 +86,18 @@ describe('createMegathreadListCommand', () => {
|
|
|
88
86
|
expect(consoleErrorOutput.length).toBeGreaterThan(0);
|
|
89
87
|
});
|
|
90
88
|
it('accepts valid timeframe values', async () => {
|
|
91
|
-
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
92
89
|
mockGetUnpredictedRounds.mockResolvedValue([]);
|
|
93
90
|
const command = createMegathreadListCommand();
|
|
94
91
|
await command.parseAsync(['--agent', 'test-agent', '--timeframe', '1h,4h'], { from: 'user' });
|
|
95
92
|
expect(mockGetUnpredictedRounds).toHaveBeenCalledWith(['1h', '4h']);
|
|
96
93
|
});
|
|
97
94
|
it('accepts single valid timeframe', async () => {
|
|
98
|
-
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
99
95
|
mockGetUnpredictedRounds.mockResolvedValue([]);
|
|
100
96
|
const command = createMegathreadListCommand();
|
|
101
97
|
await command.parseAsync(['--agent', 'test-agent', '--timeframe', '24h'], { from: 'user' });
|
|
102
98
|
expect(mockGetUnpredictedRounds).toHaveBeenCalledWith(['24h']);
|
|
103
99
|
});
|
|
104
100
|
it('passes undefined when no timeframe filter specified', async () => {
|
|
105
|
-
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
106
101
|
mockGetUnpredictedRounds.mockResolvedValue([]);
|
|
107
102
|
const command = createMegathreadListCommand();
|
|
108
103
|
await command.parseAsync(['--agent', 'test-agent'], { from: 'user' });
|
|
@@ -122,21 +117,13 @@ describe('createMegathreadListCommand', () => {
|
|
|
122
117
|
});
|
|
123
118
|
describe('credentials validation', () => {
|
|
124
119
|
it('shows error when credentials are missing', async () => {
|
|
125
|
-
mockLoadConfig.mockResolvedValue(null);
|
|
126
120
|
const command = createMegathreadListCommand();
|
|
127
|
-
await expect(command.parseAsync(['--agent', '
|
|
128
|
-
expect(consoleErrorOutput.join('\n')).toContain('
|
|
129
|
-
});
|
|
130
|
-
it('shows error when credentials have no API key', async () => {
|
|
131
|
-
mockLoadConfig.mockResolvedValue({ apiKey: null });
|
|
132
|
-
const command = createMegathreadListCommand();
|
|
133
|
-
await expect(command.parseAsync(['--agent', 'test-agent'], { from: 'user' })).rejects.toThrow('process.exit(1)');
|
|
134
|
-
expect(consoleErrorOutput.join('\n')).toContain('No credentials found');
|
|
121
|
+
await expect(command.parseAsync(['--agent', 'no-cred-agent'], { from: 'user' })).rejects.toThrow('process.exit(1)');
|
|
122
|
+
expect(consoleErrorOutput.join('\n')).toContain('Agent "no-cred-agent" not found');
|
|
135
123
|
});
|
|
136
124
|
});
|
|
137
125
|
describe('rounds display', () => {
|
|
138
126
|
it('shows message when no unpredicted rounds available', async () => {
|
|
139
|
-
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
140
127
|
mockGetUnpredictedRounds.mockResolvedValue([]);
|
|
141
128
|
const command = createMegathreadListCommand();
|
|
142
129
|
await command.parseAsync(['--agent', 'test-agent'], { from: 'user' });
|
|
@@ -149,7 +136,6 @@ describe('createMegathreadListCommand', () => {
|
|
|
149
136
|
createMockActiveRound({ roundId: 'round-1', projectId: 'bitcoin', durationMs: 3600000 }),
|
|
150
137
|
createMockActiveRound({ roundId: 'round-2', projectId: 'ethereum', durationMs: 14400000 }),
|
|
151
138
|
];
|
|
152
|
-
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
153
139
|
mockGetUnpredictedRounds.mockResolvedValue(mockRounds);
|
|
154
140
|
const command = createMegathreadListCommand();
|
|
155
141
|
await command.parseAsync(['--agent', 'test-agent'], { from: 'user' });
|
|
@@ -168,7 +154,6 @@ describe('createMegathreadListCommand', () => {
|
|
|
168
154
|
const mockRounds = [
|
|
169
155
|
createMockActiveRound({ roundId: 'round-1', projectId: 'bitcoin', durationMs: 7200000 }),
|
|
170
156
|
];
|
|
171
|
-
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
172
157
|
mockGetUnpredictedRounds.mockResolvedValue(mockRounds);
|
|
173
158
|
const command = createMegathreadListCommand();
|
|
174
159
|
await command.parseAsync(['--agent', 'test-agent'], { from: 'user' });
|
|
@@ -178,7 +163,6 @@ describe('createMegathreadListCommand', () => {
|
|
|
178
163
|
});
|
|
179
164
|
describe('API error handling', () => {
|
|
180
165
|
it('shows error when API call fails', async () => {
|
|
181
|
-
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
182
166
|
mockGetUnpredictedRounds.mockRejectedValue(new Error('Network error'));
|
|
183
167
|
const command = createMegathreadListCommand();
|
|
184
168
|
await expect(command.parseAsync(['--agent', 'test-agent'], { from: 'user' })).rejects.toThrow('process.exit(1)');
|
|
@@ -186,7 +170,6 @@ describe('createMegathreadListCommand', () => {
|
|
|
186
170
|
expect(consoleErrorOutput.join('\n')).toContain('Network error');
|
|
187
171
|
});
|
|
188
172
|
it('handles non-Error exceptions', async () => {
|
|
189
|
-
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
190
173
|
mockGetUnpredictedRounds.mockRejectedValue('String error');
|
|
191
174
|
const command = createMegathreadListCommand();
|
|
192
175
|
await expect(command.parseAsync(['--agent', 'test-agent'], { from: 'user' })).rejects.toThrow('process.exit(1)');
|
|
@@ -196,7 +179,6 @@ describe('createMegathreadListCommand', () => {
|
|
|
196
179
|
});
|
|
197
180
|
describe('works with different fixture agents', () => {
|
|
198
181
|
it('works with empty-agent', async () => {
|
|
199
|
-
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
200
182
|
mockGetUnpredictedRounds.mockResolvedValue([]);
|
|
201
183
|
const command = createMegathreadListCommand();
|
|
202
184
|
await command.parseAsync(['--agent', 'empty-agent'], { from: 'user' });
|
|
@@ -112,7 +112,7 @@ export function MigrateApp() {
|
|
|
112
112
|
if (phase === 'selecting') {
|
|
113
113
|
const oldStyleAgents = agents.filter((a) => a.isOldStyle);
|
|
114
114
|
const newStyleAgents = agents.filter((a) => !a.isOldStyle);
|
|
115
|
-
return (_jsxs(Box, { flexDirection: "column", paddingLeft: 1, children: [_jsxs(Text, { color: colors.honey, bold: true, children: [symbols.hive, " Migrate agents to @zhive/cli"] }), _jsx(Text, { color: colors.gray, children: border.horizontal.repeat(termWidth - 4) }), _jsxs(Text, { color: colors.gray, children: ["Use ", styled.white('↑↓'), " to navigate, ", styled.white('
|
|
115
|
+
return (_jsxs(Box, { flexDirection: "column", paddingLeft: 1, children: [_jsxs(Text, { color: colors.honey, bold: true, children: [symbols.hive, " Migrate agents to @zhive/cli"] }), _jsx(Text, { color: colors.gray, children: border.horizontal.repeat(termWidth - 4) }), _jsxs(Text, { color: colors.gray, children: ["Use ", styled.white('↑↓'), " to navigate, ", styled.white('spacebar'), " press to toggle,", ' ', styled.white('enter'), " to confirm"] }), _jsx(Text, { children: " " }), oldStyleAgents.map((agent, i) => {
|
|
116
116
|
const isCursor = i === cursor;
|
|
117
117
|
const prefix = agent.selected ? symbols.check : symbols.diamondOpen;
|
|
118
118
|
const prefixColor = agent.selected ? colors.green : colors.gray;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { loadConfig } from '@zhive/sdk';
|
|
2
1
|
import { HIVE_API_URL } from '../../../shared/config/constant.js';
|
|
3
2
|
import { extractErrorMessage } from '../../../shared/agent/utils.js';
|
|
4
3
|
import { styled } from '../../shared/theme.js';
|
|
4
|
+
import { loadConfig } from '@zhive/sdk';
|
|
5
5
|
export async function fetchMyPredictions(apiKey, limit = 10) {
|
|
6
6
|
try {
|
|
7
7
|
const url = `${HIVE_API_URL}/megathread-comment/me?limit=${limit}&onlyResolved=true`;
|
|
@@ -3,9 +3,8 @@ import { fileURLToPath } from 'node:url';
|
|
|
3
3
|
import * as path from 'node:path';
|
|
4
4
|
import { fetchSkills, formatSkills, skillsSlashCommand } from './skills.js';
|
|
5
5
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
6
|
-
const FIXTURES_DIR = path.join(__dirname, '../../../tests/__fixtures__/mock-hive');
|
|
7
6
|
vi.mock('../../../shared/config/constant.js', () => ({
|
|
8
|
-
getHiveDir: vi.fn(() => path.join(__dirname, '
|
|
7
|
+
getHiveDir: vi.fn(() => path.join(__dirname, '../../../../__fixtures__/mock-hive')),
|
|
9
8
|
}));
|
|
10
9
|
function createMockSkill(overrides = {}) {
|
|
11
10
|
const skill = {
|
|
@@ -2,7 +2,7 @@ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { Box, Text, useInput } from 'ink';
|
|
4
4
|
import { colors, symbols } from '../commands/shared/theme.js';
|
|
5
|
-
export function MultiSelectPrompt({ label, items, defaultSelected, onSubmit, }) {
|
|
5
|
+
export function MultiSelectPrompt({ label, items, defaultSelected, hint, onSubmit, }) {
|
|
6
6
|
const allValues = new Set(items.map((i) => i.value));
|
|
7
7
|
const [selected, setSelected] = useState(defaultSelected ?? allValues);
|
|
8
8
|
const [cursor, setCursor] = useState(0);
|
|
@@ -35,11 +35,11 @@ export function MultiSelectPrompt({ label, items, defaultSelected, onSubmit, })
|
|
|
35
35
|
});
|
|
36
36
|
const highlightedItem = items[cursor];
|
|
37
37
|
const highlightedDescription = highlightedItem?.description;
|
|
38
|
-
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsxs(Text, { color: colors.honey, children: [symbols.arrow, " "] }), _jsx(Text, { color: colors.white, bold: true, children: label })] }), _jsx(Box, { marginLeft: 2, marginBottom: 1, children: _jsx(Text, { color: colors.grayDim, italic: true, children: "All selected by default
|
|
38
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsxs(Text, { color: colors.honey, children: [symbols.arrow, " "] }), _jsx(Text, { color: colors.white, bold: true, children: label })] }), _jsx(Box, { marginLeft: 2, marginBottom: 1, children: _jsx(Text, { color: colors.grayDim, italic: true, children: hint ?? "All selected by default — deselect what you don't want" }) }), _jsx(Box, { flexDirection: "column", marginLeft: 2, children: items.map((item, i) => {
|
|
39
39
|
const isCursor = i === cursor;
|
|
40
40
|
const isSelected = selected.has(item.value);
|
|
41
41
|
const checkbox = isSelected ? '◆' : '◇';
|
|
42
42
|
const itemColor = isCursor ? colors.honey : colors.white;
|
|
43
43
|
return (_jsxs(Box, { children: [_jsxs(Text, { color: colors.honey, children: [isCursor ? symbols.diamond : ' ', " "] }), _jsxs(Text, { color: isSelected ? colors.honey : colors.grayDim, children: [checkbox, " "] }), _jsx(Text, { color: itemColor, children: item.label })] }, item.value));
|
|
44
|
-
}) }), highlightedDescription && (_jsx(Box, { marginLeft: 4, marginTop: 1, children: _jsxs(Text, { color: colors.gray, italic: true, children: [symbols.arrow, " ", highlightedDescription] }) })), _jsx(Box, { marginLeft: 2, marginTop: 1, children: _jsxs(Text, { color: colors.grayDim, children: [_jsx(Text, { color: colors.honey, children: "
|
|
44
|
+
}) }), highlightedDescription && (_jsx(Box, { marginLeft: 4, marginTop: 1, children: _jsxs(Text, { color: colors.gray, italic: true, children: [symbols.arrow, " ", highlightedDescription] }) })), _jsx(Box, { marginLeft: 2, marginTop: 1, children: _jsxs(Text, { color: colors.grayDim, children: [_jsx(Text, { color: colors.honey, children: "spacebar" }), " press to toggle ", _jsx(Text, { color: colors.honey, children: "enter" }), ' ', "confirm"] }) })] }));
|
|
45
45
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { loadConfig } from '@zhive/sdk';
|
|
1
2
|
import axios from 'axios';
|
|
2
3
|
import fsExtra from 'fs-extra';
|
|
3
4
|
import * as fs from 'fs/promises';
|
|
@@ -51,15 +52,19 @@ export async function loadAgentConfig(_agentDir) {
|
|
|
51
52
|
const agentDir = _agentDir ?? process.cwd();
|
|
52
53
|
const soulPath = join(agentDir, 'SOUL.md');
|
|
53
54
|
const strategyPath = join(agentDir, 'STRATEGY.md');
|
|
55
|
+
const config = await loadConfig(_agentDir);
|
|
56
|
+
if (!config) {
|
|
57
|
+
throw new Error('Agent not registered');
|
|
58
|
+
}
|
|
54
59
|
const soulContent = await loadMarkdownFile(soulPath);
|
|
55
60
|
const strategyContent = await loadMarkdownFile(strategyPath);
|
|
56
|
-
const name =
|
|
57
|
-
|
|
58
|
-
|
|
61
|
+
const name = config.name;
|
|
62
|
+
const avatarUrl = config.avatarUrl;
|
|
63
|
+
if (!avatarUrl) {
|
|
64
|
+
throw new Error('Missing avatarUrl');
|
|
59
65
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
throw new Error('Could not parse avatar URL from SOUL.md. Expected a valid URL under "## Avatar".');
|
|
66
|
+
if (!config.apiKey) {
|
|
67
|
+
throw new Error('Missing api key');
|
|
63
68
|
}
|
|
64
69
|
const bioRaw = extractField(soulContent, /^## Bio\s*\n+(.+)$/m);
|
|
65
70
|
const bio = bioRaw ?? null;
|
|
@@ -77,6 +82,7 @@ export async function loadAgentConfig(_agentDir) {
|
|
|
77
82
|
name,
|
|
78
83
|
bio,
|
|
79
84
|
dir: agentDir,
|
|
85
|
+
apiKey: config.apiKey,
|
|
80
86
|
provider,
|
|
81
87
|
avatarUrl,
|
|
82
88
|
soulContent,
|