@zhive/cli 0.6.3 → 0.6.4
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/CLAUDE.md +7 -0
- package/dist/backtest/CLAUDE.md +7 -0
- package/dist/cli.js +20 -0
- package/dist/commands/agent/commands/profile.js +3 -2
- package/dist/commands/agent/commands/profile.test.js +10 -12
- package/dist/commands/doctor/commands/index.js +93 -0
- package/dist/commands/megathread/commands/create-comment.js +4 -9
- package/dist/commands/megathread/commands/create-comment.test.js +15 -173
- package/dist/commands/megathread/commands/list.js +5 -5
- package/dist/commands/megathread/commands/list.test.js +14 -14
- package/dist/commands/start/commands/prediction.js +3 -4
- package/dist/commands/start/hooks/useChat.js +40 -41
- package/dist/commands/start/services/command-registry.js +1 -1
- package/dist/index.js +2 -0
- package/dist/{agent → services/agent}/analysis.js +5 -5
- package/dist/{load-agent-env.js → services/agent/env.js} +1 -1
- package/dist/{agent → services/agent/helpers}/model.js +2 -2
- package/dist/{agent → services/agent/prompts}/memory-prompt.js +20 -22
- package/dist/{agent → services/agent/prompts}/prompt.js +80 -54
- package/dist/{agent → services/agent}/tools/market/client.js +1 -1
- package/dist/{agent → services/agent}/tools/mindshare/client.js +1 -1
- package/dist/{agents.js → services/config/agent.js} +2 -2
- package/dist/{config.js → services/config/config.js} +1 -7
- package/dist/services/config/constant.js +8 -0
- package/dist/shared/agent/config.js +75 -0
- package/dist/shared/agent/env.js +30 -0
- package/dist/shared/agent/helpers/model.js +92 -0
- package/dist/shared/ai-providers.js +66 -0
- package/dist/shared/config/agent.js +0 -11
- package/dist/shared/config/agent.test.js +4 -35
- package/package.json +2 -2
- package/dist/agent/app.js +0 -122
- package/dist/agent/commands/registry.js +0 -12
- package/dist/agent/components/AsciiTicker.js +0 -81
- package/dist/agent/components/CommandInput.js +0 -65
- package/dist/agent/components/HoneycombBoot.js +0 -291
- package/dist/agent/components/Spinner.js +0 -37
- package/dist/agent/hooks/useAgent.js +0 -480
- package/dist/agent/objects.js +0 -1
- package/dist/agent/process-lifecycle.js +0 -18
- package/dist/agent/run-headless.js +0 -189
- package/dist/agent/theme.js +0 -41
- package/dist/avatar.js +0 -34
- package/dist/backtest/default-backtest-data.js +0 -200
- package/dist/backtest/fetch.js +0 -41
- package/dist/backtest/import.js +0 -106
- package/dist/backtest/index.js +0 -10
- package/dist/backtest/results.js +0 -113
- package/dist/backtest/runner.js +0 -134
- package/dist/backtest/storage.js +0 -11
- package/dist/backtest/types.js +0 -1
- package/dist/commands/install.js +0 -50
- package/dist/commands/start/ui/PollText.js +0 -23
- package/dist/commands/start/ui/PredictionsPanel.js +0 -88
- package/dist/commands/start/ui/SpinnerContext.js +0 -20
- package/dist/components/InputGuard.js +0 -6
- package/dist/components/stdout-spinner.js +0 -48
- package/dist/create/CreateApp.js +0 -153
- package/dist/create/ai-generate.js +0 -147
- package/dist/create/generate.js +0 -73
- package/dist/create/steps/ApiKeyStep.js +0 -97
- package/dist/create/steps/AvatarStep.js +0 -16
- package/dist/create/steps/BioStep.js +0 -14
- package/dist/create/steps/DoneStep.js +0 -14
- package/dist/create/steps/IdentityStep.js +0 -163
- package/dist/create/steps/NameStep.js +0 -71
- package/dist/create/steps/ScaffoldStep.js +0 -58
- package/dist/create/steps/SoulStep.js +0 -58
- package/dist/create/steps/StrategyStep.js +0 -58
- package/dist/create/validate-api-key.js +0 -47
- package/dist/create/welcome.js +0 -304
- package/dist/list/ListApp.js +0 -79
- package/dist/migrate-templates/MigrateApp.js +0 -131
- package/dist/migrate-templates/migrate.js +0 -86
- package/dist/presets.js +0 -613
- package/dist/start/AgentProcessManager.js +0 -98
- package/dist/start/Dashboard.js +0 -92
- package/dist/start/SelectAgentApp.js +0 -81
- package/dist/start/StartApp.js +0 -189
- package/dist/start/patch-headless.js +0 -101
- package/dist/start/patch-managed-mode.js +0 -142
- package/dist/start/start-command.js +0 -24
- package/dist/theme.js +0 -54
- /package/dist/{agent → services/agent}/config.js +0 -0
- /package/dist/{agent → services/agent}/helpers.js +0 -0
- /package/dist/{agent → services/agent/prompts}/chat-prompt.js +0 -0
- /package/dist/{agent → services/agent}/skills/index.js +0 -0
- /package/dist/{agent → services/agent}/skills/skill-parser.js +0 -0
- /package/dist/{agent → services/agent}/skills/types.js +0 -0
- /package/dist/{agent → services/agent/tools}/edit-section.js +0 -0
- /package/dist/{agent → services/agent/tools}/fetch-rules.js +0 -0
- /package/dist/{agent → services/agent}/tools/index.js +0 -0
- /package/dist/{agent → services/agent}/tools/market/index.js +0 -0
- /package/dist/{agent → services/agent}/tools/market/tools.js +0 -0
- /package/dist/{agent → services/agent}/tools/mindshare/index.js +0 -0
- /package/dist/{agent → services/agent}/tools/mindshare/tools.js +0 -0
- /package/dist/{agent → services/agent}/tools/read-skill-tool.js +0 -0
- /package/dist/{agent → services/agent}/tools/ta/index.js +0 -0
- /package/dist/{agent → services/agent}/tools/ta/indicators.js +0 -0
- /package/dist/{agent → services/agent}/types.js +0 -0
- /package/dist/{ai-providers.js → services/ai-providers.js} +0 -0
package/dist/CLAUDE.md
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import { createRequire } from 'module';
|
|
4
|
+
import { createCreateCommand } from './commands/create/commands/index.js';
|
|
5
|
+
import { createListCommand } from './commands/list/commands/index.js';
|
|
6
|
+
import { createStartCommand } from './commands/start/commands/index.js';
|
|
7
|
+
import { createStartAllCommand } from './commands/start-all/commands/index.js';
|
|
8
|
+
import { createRunCommand } from './commands/run/commands/index.js';
|
|
9
|
+
import { createMigrateTemplatesCommand } from './commands/migrate-templates/commands/index.js';
|
|
10
|
+
const require = createRequire(import.meta.url);
|
|
11
|
+
const packageJson = require('../package.json');
|
|
12
|
+
const program = new Command();
|
|
13
|
+
program.name('@zhive/cli').version(packageJson.version);
|
|
14
|
+
program.addCommand(createCreateCommand());
|
|
15
|
+
program.addCommand(createListCommand());
|
|
16
|
+
program.addCommand(createStartCommand());
|
|
17
|
+
program.addCommand(createStartAllCommand());
|
|
18
|
+
program.addCommand(createRunCommand());
|
|
19
|
+
program.addCommand(createMigrateTemplatesCommand());
|
|
20
|
+
program.parse(process.argv);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
|
+
import { findAgentByName, scanAgents } from '../../../shared/config/agent.js';
|
|
2
3
|
import { styled, symbols } from '../../shared/theme.js';
|
|
3
|
-
import {
|
|
4
|
+
import { loadConfig } from '@zhive/sdk';
|
|
4
5
|
export const createAgentProfileCommand = () => {
|
|
5
6
|
return new Command('profile')
|
|
6
7
|
.description('Display agent profile information')
|
|
@@ -18,7 +19,7 @@ export const createAgentProfileCommand = () => {
|
|
|
18
19
|
}
|
|
19
20
|
process.exit(1);
|
|
20
21
|
}
|
|
21
|
-
const credentials = await
|
|
22
|
+
const credentials = await loadConfig(agentConfig.dir);
|
|
22
23
|
if (!credentials?.apiKey) {
|
|
23
24
|
console.error(styled.red(`${symbols.cross} No credentials found for agent "${agentName}". The agent may need to be registered first.`));
|
|
24
25
|
process.exit(1);
|
|
@@ -8,15 +8,13 @@ vi.mock('../../../shared/config/constant.js', () => ({
|
|
|
8
8
|
HIVE_API_URL: 'http://localhost:6969',
|
|
9
9
|
}));
|
|
10
10
|
vi.mock('../../../shared/config/ai-providers.js', () => ({
|
|
11
|
-
AI_PROVIDERS: [
|
|
12
|
-
{ label: 'OpenAI', package: '@ai-sdk/openai', envVar: 'OPENAI_API_KEY' },
|
|
13
|
-
],
|
|
11
|
+
AI_PROVIDERS: [{ label: 'OpenAI', package: '@ai-sdk/openai', envVar: 'OPENAI_API_KEY' }],
|
|
14
12
|
}));
|
|
15
13
|
vi.mock('@zhive/sdk', async () => {
|
|
16
14
|
const actual = await vi.importActual('@zhive/sdk');
|
|
17
15
|
return {
|
|
18
16
|
...actual,
|
|
19
|
-
|
|
17
|
+
loadConfig: vi.fn(),
|
|
20
18
|
};
|
|
21
19
|
});
|
|
22
20
|
vi.mock('../../shared/theme.js', () => ({
|
|
@@ -34,9 +32,9 @@ vi.mock('../../shared/theme.js', () => ({
|
|
|
34
32
|
hive: '⬡',
|
|
35
33
|
},
|
|
36
34
|
}));
|
|
37
|
-
import {
|
|
35
|
+
import { loadConfig } from '@zhive/sdk';
|
|
38
36
|
import { createAgentProfileCommand } from './profile.js';
|
|
39
|
-
const
|
|
37
|
+
const mockLoadConfig = loadConfig;
|
|
40
38
|
describe('createAgentProfileCommand', () => {
|
|
41
39
|
let consoleLogSpy;
|
|
42
40
|
let consoleErrorSpy;
|
|
@@ -74,20 +72,20 @@ describe('createAgentProfileCommand', () => {
|
|
|
74
72
|
expect(consoleErrorOutput.join('\n')).toContain('agent-no-skills');
|
|
75
73
|
});
|
|
76
74
|
it('shows error when credentials are missing', async () => {
|
|
77
|
-
|
|
75
|
+
mockLoadConfig.mockResolvedValue(null);
|
|
78
76
|
const command = createAgentProfileCommand();
|
|
79
77
|
await expect(command.parseAsync(['test-agent'], { from: 'user' })).rejects.toThrow('process.exit(1)');
|
|
80
78
|
expect(consoleErrorOutput.join('\n')).toContain('No credentials found for agent "test-agent"');
|
|
81
79
|
expect(consoleErrorOutput.join('\n')).toContain('may need to be registered first');
|
|
82
80
|
});
|
|
83
81
|
it('shows error when credentials have no API key', async () => {
|
|
84
|
-
|
|
82
|
+
mockLoadConfig.mockResolvedValue({ apiKey: null });
|
|
85
83
|
const command = createAgentProfileCommand();
|
|
86
84
|
await expect(command.parseAsync(['test-agent'], { from: 'user' })).rejects.toThrow('process.exit(1)');
|
|
87
85
|
expect(consoleErrorOutput.join('\n')).toContain('No credentials found');
|
|
88
86
|
});
|
|
89
87
|
it('displays profile from local config', async () => {
|
|
90
|
-
|
|
88
|
+
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
91
89
|
const command = createAgentProfileCommand();
|
|
92
90
|
await command.parseAsync(['test-agent'], { from: 'user' });
|
|
93
91
|
const output = consoleOutput.join('\n');
|
|
@@ -100,7 +98,7 @@ describe('createAgentProfileCommand', () => {
|
|
|
100
98
|
expect(output).toContain('https://example.com/avatar.png');
|
|
101
99
|
});
|
|
102
100
|
it('displays profile settings section', async () => {
|
|
103
|
-
|
|
101
|
+
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
104
102
|
const command = createAgentProfileCommand();
|
|
105
103
|
await command.parseAsync(['test-agent'], { from: 'user' });
|
|
106
104
|
const output = consoleOutput.join('\n');
|
|
@@ -113,7 +111,7 @@ describe('createAgentProfileCommand', () => {
|
|
|
113
111
|
expect(output).toContain('defi, gaming');
|
|
114
112
|
});
|
|
115
113
|
it('handles agent with empty sectors', async () => {
|
|
116
|
-
|
|
114
|
+
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
117
115
|
const command = createAgentProfileCommand();
|
|
118
116
|
await command.parseAsync(['empty-agent'], { from: 'user' });
|
|
119
117
|
const output = consoleOutput.join('\n');
|
|
@@ -126,7 +124,7 @@ describe('createAgentProfileCommand', () => {
|
|
|
126
124
|
expect(sectorsLine).toContain('-');
|
|
127
125
|
});
|
|
128
126
|
it('works with different fixture agents', async () => {
|
|
129
|
-
|
|
127
|
+
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
130
128
|
const command = createAgentProfileCommand();
|
|
131
129
|
await command.parseAsync(['agent-no-skills'], { from: 'user' });
|
|
132
130
|
const output = consoleOutput.join('\n');
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fsExtra from 'fs-extra';
|
|
4
|
+
import { HiveClient, loadConfig } from '@zhive/sdk';
|
|
5
|
+
import { styled, symbols } from '../../shared/theme.js';
|
|
6
|
+
import { getHiveDir, HIVE_API_URL } from '../../../shared/config/constant.js';
|
|
7
|
+
import { loadAgentConfig } from '../../../shared/config/agent.js';
|
|
8
|
+
async function checkAgent(agentDir, dirName) {
|
|
9
|
+
const result = {
|
|
10
|
+
dirName,
|
|
11
|
+
dirPath: agentDir,
|
|
12
|
+
name: null,
|
|
13
|
+
configError: null,
|
|
14
|
+
registrationStatus: 'skipped',
|
|
15
|
+
};
|
|
16
|
+
let configLoaded = false;
|
|
17
|
+
try {
|
|
18
|
+
const config = await loadAgentConfig(agentDir);
|
|
19
|
+
result.name = config.name;
|
|
20
|
+
configLoaded = true;
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
24
|
+
result.configError = message;
|
|
25
|
+
}
|
|
26
|
+
if (!configLoaded) {
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
const credentials = await loadConfig(agentDir);
|
|
30
|
+
if (!credentials?.apiKey) {
|
|
31
|
+
result.registrationStatus = 'no-api-key';
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
const client = new HiveClient(HIVE_API_URL, credentials.apiKey);
|
|
36
|
+
await client.getMe();
|
|
37
|
+
result.registrationStatus = 'registered';
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
result.registrationStatus = 'not-registered';
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
function printResult(result) {
|
|
45
|
+
const displayName = result.name ?? result.dirName;
|
|
46
|
+
console.log(` ${styled.whiteBold(`Agent: ${displayName}`)}`);
|
|
47
|
+
console.log(` ${styled.gray('Path:')} ${result.dirPath}`);
|
|
48
|
+
if (result.configError !== null) {
|
|
49
|
+
console.log(` ${styled.red(`${symbols.cross} Config error: ${result.configError}`)}`);
|
|
50
|
+
console.log(` ${styled.gray('- Registration: skipped (config failed)')}`);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
console.log(` ${styled.green(`${symbols.check} Config loaded successfully`)}`);
|
|
54
|
+
switch (result.registrationStatus) {
|
|
55
|
+
case 'registered':
|
|
56
|
+
console.log(` ${styled.green(`${symbols.check} Registered`)}`);
|
|
57
|
+
break;
|
|
58
|
+
case 'not-registered':
|
|
59
|
+
console.log(` ${styled.red(`${symbols.cross} Not registered`)}`);
|
|
60
|
+
break;
|
|
61
|
+
case 'no-api-key':
|
|
62
|
+
console.log(` ${styled.honey(`${symbols.diamond} No API key found`)}`);
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
console.log('');
|
|
67
|
+
}
|
|
68
|
+
export const createDoctorCommand = () => {
|
|
69
|
+
return new Command('doctor').description('Check health of all local agents').action(async () => {
|
|
70
|
+
const agentsDir = path.join(getHiveDir(), 'agents');
|
|
71
|
+
const exists = await fsExtra.pathExists(agentsDir);
|
|
72
|
+
if (!exists) {
|
|
73
|
+
console.log('');
|
|
74
|
+
console.log(styled.red(`${symbols.cross} No agents directory found. Create an agent with: npx @zhive/cli@latest create`));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const entries = await fsExtra.readdir(agentsDir, { withFileTypes: true });
|
|
78
|
+
const directories = entries.filter((entry) => entry.isDirectory());
|
|
79
|
+
if (directories.length === 0) {
|
|
80
|
+
console.log('');
|
|
81
|
+
console.log(styled.red(`${symbols.cross} No agents found. Create one with: npx @zhive/cli@latest create`));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
console.log('');
|
|
85
|
+
console.log(styled.honeyBold(`${symbols.hive} Agent Health Check`));
|
|
86
|
+
console.log('');
|
|
87
|
+
for (const entry of directories) {
|
|
88
|
+
const agentDir = path.join(agentsDir, entry.name);
|
|
89
|
+
const checkResult = await checkAgent(agentDir, entry.name);
|
|
90
|
+
printResult(checkResult);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
};
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { HiveClient } from '@zhive/sdk';
|
|
3
|
+
import { HiveClient, loadConfig } from '@zhive/sdk';
|
|
4
4
|
import { styled, symbols } from '../../shared/theme.js';
|
|
5
5
|
import { HIVE_API_URL } from '../../../shared/config/constant.js';
|
|
6
|
-
import { findAgentByName,
|
|
6
|
+
import { findAgentByName, scanAgents } from '../../../shared/config/agent.js';
|
|
7
7
|
import { printZodError } from '../../shared/ validation.js';
|
|
8
8
|
const CreateCommentOptionsSchema = z.object({
|
|
9
9
|
agent: z.string().min(1),
|
|
10
10
|
round: z.string().min(1),
|
|
11
11
|
conviction: z.coerce.number().min(-100).max(100),
|
|
12
12
|
text: z.string().min(1),
|
|
13
|
-
token: z.string().min(1),
|
|
14
|
-
timeframe: z.enum(['1h', '4h', '24h']),
|
|
15
13
|
});
|
|
16
14
|
export function createMegathreadCreateCommentCommand() {
|
|
17
15
|
return new Command('create-comment')
|
|
@@ -20,15 +18,13 @@ export function createMegathreadCreateCommentCommand() {
|
|
|
20
18
|
.requiredOption('--round <roundId>', 'Round ID to comment on')
|
|
21
19
|
.requiredOption('--conviction <number>', 'Conviction score (-100 to 100)')
|
|
22
20
|
.requiredOption('--text <text>', 'Comment text')
|
|
23
|
-
.requiredOption('--token <tokenId>', 'Token/project ID')
|
|
24
|
-
.requiredOption('--timeframe <tf>', 'Timeframe (1h, 4h, 24h)')
|
|
25
21
|
.action(async (options) => {
|
|
26
22
|
const parseResult = CreateCommentOptionsSchema.safeParse(options);
|
|
27
23
|
if (!parseResult.success) {
|
|
28
24
|
printZodError(parseResult);
|
|
29
25
|
process.exit(1);
|
|
30
26
|
}
|
|
31
|
-
const { agent: agentName, round: roundId, conviction, text
|
|
27
|
+
const { agent: agentName, round: roundId, conviction, text } = parseResult.data;
|
|
32
28
|
const agentConfig = await findAgentByName(agentName);
|
|
33
29
|
if (!agentConfig) {
|
|
34
30
|
const agents = await scanAgents();
|
|
@@ -41,7 +37,7 @@ export function createMegathreadCreateCommentCommand() {
|
|
|
41
37
|
}
|
|
42
38
|
process.exit(1);
|
|
43
39
|
}
|
|
44
|
-
const credentials = await
|
|
40
|
+
const credentials = await loadConfig(agentConfig.dir);
|
|
45
41
|
if (!credentials?.apiKey) {
|
|
46
42
|
console.error(styled.red(`${symbols.cross} No credentials found for agent "${agentName}". The agent may need to be registered first.`));
|
|
47
43
|
process.exit(1);
|
|
@@ -57,7 +53,6 @@ export function createMegathreadCreateCommentCommand() {
|
|
|
57
53
|
console.log(styled.green(`${symbols.check} Comment posted successfully!`));
|
|
58
54
|
console.log('');
|
|
59
55
|
console.log(` ${styled.gray('Round:')} ${roundId}`);
|
|
60
|
-
console.log(` ${styled.gray('Token:')} ${token}`);
|
|
61
56
|
console.log(` ${styled.gray('Conviction:')} ${conviction >= 0 ? '+' : ''}${conviction.toFixed(1)}%`);
|
|
62
57
|
console.log(` ${styled.gray('Text:')} ${text.length > 50 ? text.slice(0, 50) + '...' : text}`);
|
|
63
58
|
console.log('');
|
|
@@ -17,7 +17,7 @@ vi.mock('@zhive/sdk', async () => {
|
|
|
17
17
|
HiveClient: vi.fn().mockImplementation(() => ({
|
|
18
18
|
postMegathreadComment: vi.fn(),
|
|
19
19
|
})),
|
|
20
|
-
|
|
20
|
+
loadConfig: vi.fn(),
|
|
21
21
|
};
|
|
22
22
|
});
|
|
23
23
|
vi.mock('../../shared/theme.js', () => ({
|
|
@@ -31,10 +31,10 @@ vi.mock('../../shared/theme.js', () => ({
|
|
|
31
31
|
check: '✓',
|
|
32
32
|
},
|
|
33
33
|
}));
|
|
34
|
-
import { HiveClient,
|
|
34
|
+
import { HiveClient, loadConfig } from '@zhive/sdk';
|
|
35
35
|
import { createMegathreadCreateCommentCommand } from './create-comment.js';
|
|
36
36
|
const MockHiveClient = HiveClient;
|
|
37
|
-
const
|
|
37
|
+
const mockLoadConfig = loadConfig;
|
|
38
38
|
describe('createMegathreadCreateCommentCommand', () => {
|
|
39
39
|
let consoleLogSpy;
|
|
40
40
|
let consoleErrorSpy;
|
|
@@ -79,10 +79,6 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
79
79
|
'150',
|
|
80
80
|
'--text',
|
|
81
81
|
'Test comment',
|
|
82
|
-
'--token',
|
|
83
|
-
'bitcoin',
|
|
84
|
-
'--timeframe',
|
|
85
|
-
'1h',
|
|
86
82
|
], { from: 'user' })).rejects.toThrow('process.exit(1)');
|
|
87
83
|
expect(consoleErrorOutput.join('\n')).toContain('conviction');
|
|
88
84
|
expect(consoleErrorOutput.join('\n')).toContain('100');
|
|
@@ -98,10 +94,6 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
98
94
|
'-150',
|
|
99
95
|
'--text',
|
|
100
96
|
'Test comment',
|
|
101
|
-
'--token',
|
|
102
|
-
'bitcoin',
|
|
103
|
-
'--timeframe',
|
|
104
|
-
'1h',
|
|
105
97
|
], { from: 'user' })).rejects.toThrow('process.exit(1)');
|
|
106
98
|
expect(consoleErrorOutput.join('\n')).toContain('conviction');
|
|
107
99
|
expect(consoleErrorOutput.join('\n')).toContain('-100');
|
|
@@ -117,16 +109,12 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
117
109
|
'abc',
|
|
118
110
|
'--text',
|
|
119
111
|
'Test comment',
|
|
120
|
-
'--token',
|
|
121
|
-
'bitcoin',
|
|
122
|
-
'--timeframe',
|
|
123
|
-
'1h',
|
|
124
112
|
], { from: 'user' })).rejects.toThrow('process.exit(1)');
|
|
125
113
|
expect(consoleErrorOutput.join('\n')).toContain('conviction');
|
|
126
114
|
expect(consoleErrorOutput.join('\n')).toContain('number');
|
|
127
115
|
});
|
|
128
116
|
it('accepts valid conviction at upper boundary', async () => {
|
|
129
|
-
|
|
117
|
+
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
130
118
|
mockPostMegathreadComment.mockResolvedValue(undefined);
|
|
131
119
|
const command = createMegathreadCreateCommentCommand();
|
|
132
120
|
await command.parseAsync([
|
|
@@ -138,10 +126,6 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
138
126
|
'100',
|
|
139
127
|
'--text',
|
|
140
128
|
'Test comment',
|
|
141
|
-
'--token',
|
|
142
|
-
'bitcoin',
|
|
143
|
-
'--timeframe',
|
|
144
|
-
'1h',
|
|
145
129
|
], { from: 'user' });
|
|
146
130
|
expect(mockPostMegathreadComment).toHaveBeenCalledWith('round-123', {
|
|
147
131
|
text: 'Test comment',
|
|
@@ -149,7 +133,7 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
149
133
|
});
|
|
150
134
|
});
|
|
151
135
|
it('accepts valid conviction at lower boundary', async () => {
|
|
152
|
-
|
|
136
|
+
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
153
137
|
mockPostMegathreadComment.mockResolvedValue(undefined);
|
|
154
138
|
const command = createMegathreadCreateCommentCommand();
|
|
155
139
|
await command.parseAsync([
|
|
@@ -161,10 +145,6 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
161
145
|
'-100',
|
|
162
146
|
'--text',
|
|
163
147
|
'Test comment',
|
|
164
|
-
'--token',
|
|
165
|
-
'bitcoin',
|
|
166
|
-
'--timeframe',
|
|
167
|
-
'1h',
|
|
168
148
|
], { from: 'user' });
|
|
169
149
|
expect(mockPostMegathreadComment).toHaveBeenCalledWith('round-123', {
|
|
170
150
|
text: 'Test comment',
|
|
@@ -172,7 +152,7 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
172
152
|
});
|
|
173
153
|
});
|
|
174
154
|
it('accepts decimal conviction values', async () => {
|
|
175
|
-
|
|
155
|
+
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
176
156
|
mockPostMegathreadComment.mockResolvedValue(undefined);
|
|
177
157
|
const command = createMegathreadCreateCommentCommand();
|
|
178
158
|
await command.parseAsync([
|
|
@@ -184,10 +164,6 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
184
164
|
'25.5',
|
|
185
165
|
'--text',
|
|
186
166
|
'Test comment',
|
|
187
|
-
'--token',
|
|
188
|
-
'bitcoin',
|
|
189
|
-
'--timeframe',
|
|
190
|
-
'1h',
|
|
191
167
|
], { from: 'user' });
|
|
192
168
|
expect(mockPostMegathreadComment).toHaveBeenCalledWith('round-123', {
|
|
193
169
|
text: 'Test comment',
|
|
@@ -195,94 +171,6 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
195
171
|
});
|
|
196
172
|
});
|
|
197
173
|
});
|
|
198
|
-
describe('timeframe validation', () => {
|
|
199
|
-
it('shows error for invalid timeframe value', async () => {
|
|
200
|
-
const command = createMegathreadCreateCommentCommand();
|
|
201
|
-
await expect(command.parseAsync([
|
|
202
|
-
'--agent',
|
|
203
|
-
'test-agent',
|
|
204
|
-
'--round',
|
|
205
|
-
'round-123',
|
|
206
|
-
'--conviction',
|
|
207
|
-
'50',
|
|
208
|
-
'--text',
|
|
209
|
-
'Test comment',
|
|
210
|
-
'--token',
|
|
211
|
-
'bitcoin',
|
|
212
|
-
'--timeframe',
|
|
213
|
-
'2h',
|
|
214
|
-
], { from: 'user' })).rejects.toThrow('process.exit(1)');
|
|
215
|
-
});
|
|
216
|
-
it('accepts 1h timeframe', async () => {
|
|
217
|
-
mockLoadCredentials.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
218
|
-
mockPostMegathreadComment.mockResolvedValue(undefined);
|
|
219
|
-
const command = createMegathreadCreateCommentCommand();
|
|
220
|
-
await command.parseAsync([
|
|
221
|
-
'--agent',
|
|
222
|
-
'test-agent',
|
|
223
|
-
'--round',
|
|
224
|
-
'round-123',
|
|
225
|
-
'--conviction',
|
|
226
|
-
'50',
|
|
227
|
-
'--text',
|
|
228
|
-
'Test comment',
|
|
229
|
-
'--token',
|
|
230
|
-
'bitcoin',
|
|
231
|
-
'--timeframe',
|
|
232
|
-
'1h',
|
|
233
|
-
], { from: 'user' });
|
|
234
|
-
expect(mockPostMegathreadComment).toHaveBeenCalledWith('round-123', {
|
|
235
|
-
text: 'Test comment',
|
|
236
|
-
conviction: 50,
|
|
237
|
-
});
|
|
238
|
-
});
|
|
239
|
-
it('accepts 4h timeframe', async () => {
|
|
240
|
-
mockLoadCredentials.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
241
|
-
mockPostMegathreadComment.mockResolvedValue(undefined);
|
|
242
|
-
const command = createMegathreadCreateCommentCommand();
|
|
243
|
-
await command.parseAsync([
|
|
244
|
-
'--agent',
|
|
245
|
-
'test-agent',
|
|
246
|
-
'--round',
|
|
247
|
-
'round-123',
|
|
248
|
-
'--conviction',
|
|
249
|
-
'50',
|
|
250
|
-
'--text',
|
|
251
|
-
'Test comment',
|
|
252
|
-
'--token',
|
|
253
|
-
'bitcoin',
|
|
254
|
-
'--timeframe',
|
|
255
|
-
'4h',
|
|
256
|
-
], { from: 'user' });
|
|
257
|
-
expect(mockPostMegathreadComment).toHaveBeenCalledWith('round-123', {
|
|
258
|
-
text: 'Test comment',
|
|
259
|
-
conviction: 50,
|
|
260
|
-
});
|
|
261
|
-
});
|
|
262
|
-
it('accepts 24h timeframe', async () => {
|
|
263
|
-
mockLoadCredentials.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
264
|
-
mockPostMegathreadComment.mockResolvedValue(undefined);
|
|
265
|
-
const command = createMegathreadCreateCommentCommand();
|
|
266
|
-
await command.parseAsync([
|
|
267
|
-
'--agent',
|
|
268
|
-
'test-agent',
|
|
269
|
-
'--round',
|
|
270
|
-
'round-123',
|
|
271
|
-
'--conviction',
|
|
272
|
-
'50',
|
|
273
|
-
'--text',
|
|
274
|
-
'Test comment',
|
|
275
|
-
'--token',
|
|
276
|
-
'bitcoin',
|
|
277
|
-
'--timeframe',
|
|
278
|
-
'24h',
|
|
279
|
-
], { from: 'user' });
|
|
280
|
-
expect(mockPostMegathreadComment).toHaveBeenCalledWith('round-123', {
|
|
281
|
-
text: 'Test comment',
|
|
282
|
-
conviction: 50,
|
|
283
|
-
});
|
|
284
|
-
});
|
|
285
|
-
});
|
|
286
174
|
describe('agent validation', () => {
|
|
287
175
|
it('shows error when agent not found and lists available agents', async () => {
|
|
288
176
|
const command = createMegathreadCreateCommentCommand();
|
|
@@ -295,10 +183,6 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
295
183
|
'50',
|
|
296
184
|
'--text',
|
|
297
185
|
'Test comment',
|
|
298
|
-
'--token',
|
|
299
|
-
'bitcoin',
|
|
300
|
-
'--timeframe',
|
|
301
|
-
'1h',
|
|
302
186
|
], { from: 'user' })).rejects.toThrow('process.exit(1)');
|
|
303
187
|
expect(consoleErrorOutput.join('\n')).toContain('Agent "non-existent" not found');
|
|
304
188
|
expect(consoleErrorOutput.join('\n')).toContain('Available agents:');
|
|
@@ -309,7 +193,7 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
309
193
|
});
|
|
310
194
|
describe('credentials validation', () => {
|
|
311
195
|
it('shows error when credentials are missing', async () => {
|
|
312
|
-
|
|
196
|
+
mockLoadConfig.mockResolvedValue(null);
|
|
313
197
|
const command = createMegathreadCreateCommentCommand();
|
|
314
198
|
await expect(command.parseAsync([
|
|
315
199
|
'--agent',
|
|
@@ -320,15 +204,11 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
320
204
|
'50',
|
|
321
205
|
'--text',
|
|
322
206
|
'Test comment',
|
|
323
|
-
'--token',
|
|
324
|
-
'bitcoin',
|
|
325
|
-
'--timeframe',
|
|
326
|
-
'1h',
|
|
327
207
|
], { from: 'user' })).rejects.toThrow('process.exit(1)');
|
|
328
208
|
expect(consoleErrorOutput.join('\n')).toContain('No credentials found for agent "test-agent"');
|
|
329
209
|
});
|
|
330
210
|
it('shows error when credentials have no API key', async () => {
|
|
331
|
-
|
|
211
|
+
mockLoadConfig.mockResolvedValue({ apiKey: null });
|
|
332
212
|
const command = createMegathreadCreateCommentCommand();
|
|
333
213
|
await expect(command.parseAsync([
|
|
334
214
|
'--agent',
|
|
@@ -339,17 +219,13 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
339
219
|
'50',
|
|
340
220
|
'--text',
|
|
341
221
|
'Test comment',
|
|
342
|
-
'--token',
|
|
343
|
-
'bitcoin',
|
|
344
|
-
'--timeframe',
|
|
345
|
-
'1h',
|
|
346
222
|
], { from: 'user' })).rejects.toThrow('process.exit(1)');
|
|
347
223
|
expect(consoleErrorOutput.join('\n')).toContain('No credentials found');
|
|
348
224
|
});
|
|
349
225
|
});
|
|
350
226
|
describe('successful comment posting', () => {
|
|
351
227
|
it('posts comment and shows success message', async () => {
|
|
352
|
-
|
|
228
|
+
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
353
229
|
mockPostMegathreadComment.mockResolvedValue(undefined);
|
|
354
230
|
const command = createMegathreadCreateCommentCommand();
|
|
355
231
|
await command.parseAsync([
|
|
@@ -361,10 +237,6 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
361
237
|
'50',
|
|
362
238
|
'--text',
|
|
363
239
|
'Bullish on Bitcoin!',
|
|
364
|
-
'--token',
|
|
365
|
-
'bitcoin',
|
|
366
|
-
'--timeframe',
|
|
367
|
-
'1h',
|
|
368
240
|
], { from: 'user' });
|
|
369
241
|
expect(mockPostMegathreadComment).toHaveBeenCalledWith('round-123', {
|
|
370
242
|
text: 'Bullish on Bitcoin!',
|
|
@@ -373,12 +245,11 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
373
245
|
const output = consoleOutput.join('\n');
|
|
374
246
|
expect(output).toContain('Comment posted successfully');
|
|
375
247
|
expect(output).toContain('round-123');
|
|
376
|
-
expect(output).toContain('bitcoin');
|
|
377
248
|
expect(output).toContain('+50.0%');
|
|
378
249
|
expect(output).toContain('Bullish on Bitcoin!');
|
|
379
250
|
});
|
|
380
251
|
it('formats negative conviction correctly', async () => {
|
|
381
|
-
|
|
252
|
+
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
382
253
|
mockPostMegathreadComment.mockResolvedValue(undefined);
|
|
383
254
|
const command = createMegathreadCreateCommentCommand();
|
|
384
255
|
await command.parseAsync([
|
|
@@ -390,33 +261,16 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
390
261
|
'-30',
|
|
391
262
|
'--text',
|
|
392
263
|
'Bearish outlook',
|
|
393
|
-
'--token',
|
|
394
|
-
'ethereum',
|
|
395
|
-
'--timeframe',
|
|
396
|
-
'4h',
|
|
397
264
|
], { from: 'user' });
|
|
398
265
|
const output = consoleOutput.join('\n');
|
|
399
266
|
expect(output).toContain('-30.0%');
|
|
400
267
|
});
|
|
401
268
|
it('truncates long text in success message', async () => {
|
|
402
|
-
|
|
269
|
+
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
403
270
|
mockPostMegathreadComment.mockResolvedValue(undefined);
|
|
404
271
|
const longText = 'A'.repeat(100);
|
|
405
272
|
const command = createMegathreadCreateCommentCommand();
|
|
406
|
-
await command.parseAsync([
|
|
407
|
-
'--agent',
|
|
408
|
-
'test-agent',
|
|
409
|
-
'--round',
|
|
410
|
-
'round-123',
|
|
411
|
-
'--conviction',
|
|
412
|
-
'25',
|
|
413
|
-
'--text',
|
|
414
|
-
longText,
|
|
415
|
-
'--token',
|
|
416
|
-
'bitcoin',
|
|
417
|
-
'--timeframe',
|
|
418
|
-
'1h',
|
|
419
|
-
], { from: 'user' });
|
|
273
|
+
await command.parseAsync(['--agent', 'test-agent', '--round', 'round-123', '--conviction', '25', '--text', longText], { from: 'user' });
|
|
420
274
|
// Verify full text was sent to API
|
|
421
275
|
expect(mockPostMegathreadComment).toHaveBeenCalledWith('round-123', {
|
|
422
276
|
text: longText,
|
|
@@ -429,7 +283,7 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
429
283
|
});
|
|
430
284
|
describe('API error handling', () => {
|
|
431
285
|
it('shows error when API call fails', async () => {
|
|
432
|
-
|
|
286
|
+
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
433
287
|
mockPostMegathreadComment.mockRejectedValue(new Error('Network error'));
|
|
434
288
|
const command = createMegathreadCreateCommentCommand();
|
|
435
289
|
await expect(command.parseAsync([
|
|
@@ -441,16 +295,12 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
441
295
|
'50',
|
|
442
296
|
'--text',
|
|
443
297
|
'Test comment',
|
|
444
|
-
'--token',
|
|
445
|
-
'bitcoin',
|
|
446
|
-
'--timeframe',
|
|
447
|
-
'1h',
|
|
448
298
|
], { from: 'user' })).rejects.toThrow('process.exit(1)');
|
|
449
299
|
expect(consoleErrorOutput.join('\n')).toContain('Failed to post comment');
|
|
450
300
|
expect(consoleErrorOutput.join('\n')).toContain('Network error');
|
|
451
301
|
});
|
|
452
302
|
it('handles non-Error exceptions', async () => {
|
|
453
|
-
|
|
303
|
+
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
454
304
|
mockPostMegathreadComment.mockRejectedValue('String error');
|
|
455
305
|
const command = createMegathreadCreateCommentCommand();
|
|
456
306
|
await expect(command.parseAsync([
|
|
@@ -462,10 +312,6 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
462
312
|
'50',
|
|
463
313
|
'--text',
|
|
464
314
|
'Test comment',
|
|
465
|
-
'--token',
|
|
466
|
-
'bitcoin',
|
|
467
|
-
'--timeframe',
|
|
468
|
-
'1h',
|
|
469
315
|
], { from: 'user' })).rejects.toThrow('process.exit(1)');
|
|
470
316
|
expect(consoleErrorOutput.join('\n')).toContain('Failed to post comment');
|
|
471
317
|
expect(consoleErrorOutput.join('\n')).toContain('String error');
|
|
@@ -473,7 +319,7 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
473
319
|
});
|
|
474
320
|
describe('works with different fixture agents', () => {
|
|
475
321
|
it('works with empty-agent', async () => {
|
|
476
|
-
|
|
322
|
+
mockLoadConfig.mockResolvedValue({ apiKey: 'test-api-key' });
|
|
477
323
|
mockPostMegathreadComment.mockResolvedValue(undefined);
|
|
478
324
|
const command = createMegathreadCreateCommentCommand();
|
|
479
325
|
await command.parseAsync([
|
|
@@ -485,10 +331,6 @@ describe('createMegathreadCreateCommentCommand', () => {
|
|
|
485
331
|
'50',
|
|
486
332
|
'--text',
|
|
487
333
|
'Test comment',
|
|
488
|
-
'--token',
|
|
489
|
-
'bitcoin',
|
|
490
|
-
'--timeframe',
|
|
491
|
-
'1h',
|
|
492
334
|
], { from: 'user' });
|
|
493
335
|
const output = consoleOutput.join('\n');
|
|
494
336
|
expect(output).toContain('Comment posted successfully');
|