@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.
Files changed (101) hide show
  1. package/dist/CLAUDE.md +7 -0
  2. package/dist/backtest/CLAUDE.md +7 -0
  3. package/dist/cli.js +20 -0
  4. package/dist/commands/agent/commands/profile.js +3 -2
  5. package/dist/commands/agent/commands/profile.test.js +10 -12
  6. package/dist/commands/doctor/commands/index.js +93 -0
  7. package/dist/commands/megathread/commands/create-comment.js +4 -9
  8. package/dist/commands/megathread/commands/create-comment.test.js +15 -173
  9. package/dist/commands/megathread/commands/list.js +5 -5
  10. package/dist/commands/megathread/commands/list.test.js +14 -14
  11. package/dist/commands/start/commands/prediction.js +3 -4
  12. package/dist/commands/start/hooks/useChat.js +40 -41
  13. package/dist/commands/start/services/command-registry.js +1 -1
  14. package/dist/index.js +2 -0
  15. package/dist/{agent → services/agent}/analysis.js +5 -5
  16. package/dist/{load-agent-env.js → services/agent/env.js} +1 -1
  17. package/dist/{agent → services/agent/helpers}/model.js +2 -2
  18. package/dist/{agent → services/agent/prompts}/memory-prompt.js +20 -22
  19. package/dist/{agent → services/agent/prompts}/prompt.js +80 -54
  20. package/dist/{agent → services/agent}/tools/market/client.js +1 -1
  21. package/dist/{agent → services/agent}/tools/mindshare/client.js +1 -1
  22. package/dist/{agents.js → services/config/agent.js} +2 -2
  23. package/dist/{config.js → services/config/config.js} +1 -7
  24. package/dist/services/config/constant.js +8 -0
  25. package/dist/shared/agent/config.js +75 -0
  26. package/dist/shared/agent/env.js +30 -0
  27. package/dist/shared/agent/helpers/model.js +92 -0
  28. package/dist/shared/ai-providers.js +66 -0
  29. package/dist/shared/config/agent.js +0 -11
  30. package/dist/shared/config/agent.test.js +4 -35
  31. package/package.json +2 -2
  32. package/dist/agent/app.js +0 -122
  33. package/dist/agent/commands/registry.js +0 -12
  34. package/dist/agent/components/AsciiTicker.js +0 -81
  35. package/dist/agent/components/CommandInput.js +0 -65
  36. package/dist/agent/components/HoneycombBoot.js +0 -291
  37. package/dist/agent/components/Spinner.js +0 -37
  38. package/dist/agent/hooks/useAgent.js +0 -480
  39. package/dist/agent/objects.js +0 -1
  40. package/dist/agent/process-lifecycle.js +0 -18
  41. package/dist/agent/run-headless.js +0 -189
  42. package/dist/agent/theme.js +0 -41
  43. package/dist/avatar.js +0 -34
  44. package/dist/backtest/default-backtest-data.js +0 -200
  45. package/dist/backtest/fetch.js +0 -41
  46. package/dist/backtest/import.js +0 -106
  47. package/dist/backtest/index.js +0 -10
  48. package/dist/backtest/results.js +0 -113
  49. package/dist/backtest/runner.js +0 -134
  50. package/dist/backtest/storage.js +0 -11
  51. package/dist/backtest/types.js +0 -1
  52. package/dist/commands/install.js +0 -50
  53. package/dist/commands/start/ui/PollText.js +0 -23
  54. package/dist/commands/start/ui/PredictionsPanel.js +0 -88
  55. package/dist/commands/start/ui/SpinnerContext.js +0 -20
  56. package/dist/components/InputGuard.js +0 -6
  57. package/dist/components/stdout-spinner.js +0 -48
  58. package/dist/create/CreateApp.js +0 -153
  59. package/dist/create/ai-generate.js +0 -147
  60. package/dist/create/generate.js +0 -73
  61. package/dist/create/steps/ApiKeyStep.js +0 -97
  62. package/dist/create/steps/AvatarStep.js +0 -16
  63. package/dist/create/steps/BioStep.js +0 -14
  64. package/dist/create/steps/DoneStep.js +0 -14
  65. package/dist/create/steps/IdentityStep.js +0 -163
  66. package/dist/create/steps/NameStep.js +0 -71
  67. package/dist/create/steps/ScaffoldStep.js +0 -58
  68. package/dist/create/steps/SoulStep.js +0 -58
  69. package/dist/create/steps/StrategyStep.js +0 -58
  70. package/dist/create/validate-api-key.js +0 -47
  71. package/dist/create/welcome.js +0 -304
  72. package/dist/list/ListApp.js +0 -79
  73. package/dist/migrate-templates/MigrateApp.js +0 -131
  74. package/dist/migrate-templates/migrate.js +0 -86
  75. package/dist/presets.js +0 -613
  76. package/dist/start/AgentProcessManager.js +0 -98
  77. package/dist/start/Dashboard.js +0 -92
  78. package/dist/start/SelectAgentApp.js +0 -81
  79. package/dist/start/StartApp.js +0 -189
  80. package/dist/start/patch-headless.js +0 -101
  81. package/dist/start/patch-managed-mode.js +0 -142
  82. package/dist/start/start-command.js +0 -24
  83. package/dist/theme.js +0 -54
  84. /package/dist/{agent → services/agent}/config.js +0 -0
  85. /package/dist/{agent → services/agent}/helpers.js +0 -0
  86. /package/dist/{agent → services/agent/prompts}/chat-prompt.js +0 -0
  87. /package/dist/{agent → services/agent}/skills/index.js +0 -0
  88. /package/dist/{agent → services/agent}/skills/skill-parser.js +0 -0
  89. /package/dist/{agent → services/agent}/skills/types.js +0 -0
  90. /package/dist/{agent → services/agent/tools}/edit-section.js +0 -0
  91. /package/dist/{agent → services/agent/tools}/fetch-rules.js +0 -0
  92. /package/dist/{agent → services/agent}/tools/index.js +0 -0
  93. /package/dist/{agent → services/agent}/tools/market/index.js +0 -0
  94. /package/dist/{agent → services/agent}/tools/market/tools.js +0 -0
  95. /package/dist/{agent → services/agent}/tools/mindshare/index.js +0 -0
  96. /package/dist/{agent → services/agent}/tools/mindshare/tools.js +0 -0
  97. /package/dist/{agent → services/agent}/tools/read-skill-tool.js +0 -0
  98. /package/dist/{agent → services/agent}/tools/ta/index.js +0 -0
  99. /package/dist/{agent → services/agent}/tools/ta/indicators.js +0 -0
  100. /package/dist/{agent → services/agent}/types.js +0 -0
  101. /package/dist/{ai-providers.js → services/ai-providers.js} +0 -0
package/dist/CLAUDE.md ADDED
@@ -0,0 +1,7 @@
1
+ <claude-mem-context>
2
+ # Recent Activity
3
+
4
+ <!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
5
+
6
+ *No recent activity*
7
+ </claude-mem-context>
@@ -0,0 +1,7 @@
1
+ <claude-mem-context>
2
+ # Recent Activity
3
+
4
+ <!-- This section is auto-generated by claude-mem. Edit content outside the tags. -->
5
+
6
+ *No recent activity*
7
+ </claude-mem-context>
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 { findAgentByName, loadAgentCredentials, scanAgents } from '../../../shared/config/agent.js';
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 loadAgentCredentials(agentConfig.dir, agentConfig.name);
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
- loadCredentials: vi.fn(),
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 { loadCredentials } from '@zhive/sdk';
35
+ import { loadConfig } from '@zhive/sdk';
38
36
  import { createAgentProfileCommand } from './profile.js';
39
- const mockLoadCredentials = loadCredentials;
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
- mockLoadCredentials.mockResolvedValue(null);
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
- mockLoadCredentials.mockResolvedValue({ apiKey: null });
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
- mockLoadCredentials.mockResolvedValue({ apiKey: 'test-api-key' });
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
- mockLoadCredentials.mockResolvedValue({ apiKey: 'test-api-key' });
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
- mockLoadCredentials.mockResolvedValue({ apiKey: 'test-api-key' });
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
- mockLoadCredentials.mockResolvedValue({ apiKey: 'test-api-key' });
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, loadAgentCredentials, scanAgents } from '../../../shared/config/agent.js';
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, token, timeframe, } = parseResult.data;
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 loadAgentCredentials(agentConfig.dir, agentConfig.name);
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
- loadCredentials: vi.fn(),
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, loadCredentials } from '@zhive/sdk';
34
+ import { HiveClient, loadConfig } from '@zhive/sdk';
35
35
  import { createMegathreadCreateCommentCommand } from './create-comment.js';
36
36
  const MockHiveClient = HiveClient;
37
- const mockLoadCredentials = loadCredentials;
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
- mockLoadCredentials.mockResolvedValue({ apiKey: 'test-api-key' });
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
- mockLoadCredentials.mockResolvedValue({ apiKey: 'test-api-key' });
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
- mockLoadCredentials.mockResolvedValue({ apiKey: 'test-api-key' });
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
- mockLoadCredentials.mockResolvedValue(null);
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
- mockLoadCredentials.mockResolvedValue({ apiKey: null });
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
- mockLoadCredentials.mockResolvedValue({ apiKey: 'test-api-key' });
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
- mockLoadCredentials.mockResolvedValue({ apiKey: 'test-api-key' });
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
- mockLoadCredentials.mockResolvedValue({ apiKey: 'test-api-key' });
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
- mockLoadCredentials.mockResolvedValue({ apiKey: 'test-api-key' });
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
- mockLoadCredentials.mockResolvedValue({ apiKey: 'test-api-key' });
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
- mockLoadCredentials.mockResolvedValue({ apiKey: 'test-api-key' });
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');