@hive-org/cli 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +118 -0
  2. package/dist/ai-providers.js +62 -0
  3. package/dist/commands/install.js +50 -0
  4. package/dist/components/AsciiTicker.js +81 -0
  5. package/dist/components/CodeBlock.js +11 -0
  6. package/dist/components/Header.js +11 -0
  7. package/dist/components/HoneycombLoader.js +190 -0
  8. package/dist/components/SelectPrompt.js +13 -0
  9. package/dist/components/Spinner.js +16 -0
  10. package/dist/components/StreamingText.js +45 -0
  11. package/dist/components/TextPrompt.js +28 -0
  12. package/dist/config.js +26 -0
  13. package/dist/create/CreateApp.js +102 -0
  14. package/dist/create/ai-generate.js +133 -0
  15. package/dist/create/generate.js +173 -0
  16. package/dist/create/steps/ApiKeyStep.js +97 -0
  17. package/dist/create/steps/AvatarStep.js +16 -0
  18. package/dist/create/steps/BioStep.js +14 -0
  19. package/dist/create/steps/DoneStep.js +14 -0
  20. package/dist/create/steps/IdentityStep.js +72 -0
  21. package/dist/create/steps/NameStep.js +70 -0
  22. package/dist/create/steps/ScaffoldStep.js +58 -0
  23. package/dist/create/steps/SoulStep.js +38 -0
  24. package/dist/create/steps/StrategyStep.js +38 -0
  25. package/dist/create/validate-api-key.js +44 -0
  26. package/dist/create/welcome.js +304 -0
  27. package/dist/index.js +46 -0
  28. package/dist/list/ListApp.js +83 -0
  29. package/dist/presets.js +358 -0
  30. package/dist/theme.js +47 -0
  31. package/package.json +65 -0
  32. package/templates/analysis.ts +103 -0
  33. package/templates/chat-prompt.ts +94 -0
  34. package/templates/components/AsciiTicker.tsx +113 -0
  35. package/templates/components/HoneycombBoot.tsx +348 -0
  36. package/templates/components/Spinner.tsx +64 -0
  37. package/templates/edit-section.ts +64 -0
  38. package/templates/fetch-rules.ts +23 -0
  39. package/templates/helpers.ts +22 -0
  40. package/templates/hive/agent.ts +2 -0
  41. package/templates/hive/config.ts +96 -0
  42. package/templates/hive/memory.ts +1 -0
  43. package/templates/hive/objects.ts +26 -0
  44. package/templates/hooks/useAgent.ts +336 -0
  45. package/templates/index.tsx +257 -0
  46. package/templates/memory-prompt.ts +60 -0
  47. package/templates/process-lifecycle.ts +66 -0
  48. package/templates/prompt.ts +160 -0
  49. package/templates/theme.ts +40 -0
  50. package/templates/types.ts +23 -0
@@ -0,0 +1,83 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useEffect } from 'react';
3
+ import { Box, Text, useApp } from 'ink';
4
+ import fs from 'fs-extra';
5
+ import path from 'path';
6
+ import os from 'os';
7
+ import { colors, symbols, border } from '../theme.js';
8
+ async function scanAgents() {
9
+ const agentsDir = path.join(os.homedir(), '.hive', 'agents');
10
+ const exists = await fs.pathExists(agentsDir);
11
+ if (!exists) {
12
+ return [];
13
+ }
14
+ const entries = await fs.readdir(agentsDir, { withFileTypes: true });
15
+ const agents = [];
16
+ for (const entry of entries) {
17
+ if (!entry.isDirectory()) {
18
+ continue;
19
+ }
20
+ const soulPath = path.join(agentsDir, entry.name, 'SOUL.md');
21
+ const soulExists = await fs.pathExists(soulPath);
22
+ if (!soulExists) {
23
+ continue;
24
+ }
25
+ let provider = 'unknown';
26
+ const envPath = path.join(agentsDir, entry.name, '.env');
27
+ const envExists = await fs.pathExists(envPath);
28
+ if (envExists) {
29
+ const envContent = await fs.readFile(envPath, 'utf-8');
30
+ if (envContent.includes('OPENAI_API_KEY')) {
31
+ provider = 'OpenAI';
32
+ }
33
+ else if (envContent.includes('ANTHROPIC_API_KEY')) {
34
+ provider = 'Anthropic';
35
+ }
36
+ else if (envContent.includes('GOOGLE_GENERATIVE_AI_API_KEY')) {
37
+ provider = 'Google';
38
+ }
39
+ else if (envContent.includes('XAI_API_KEY')) {
40
+ provider = 'xAI';
41
+ }
42
+ else if (envContent.includes('OPENROUTER_API_KEY')) {
43
+ provider = 'OpenRouter';
44
+ }
45
+ }
46
+ const stat = await fs.stat(soulPath);
47
+ agents.push({ name: entry.name, provider, created: stat.birthtime });
48
+ }
49
+ return agents;
50
+ }
51
+ function formatDate(date) {
52
+ const formatted = date.toLocaleDateString('en-US', {
53
+ year: 'numeric',
54
+ month: 'short',
55
+ day: 'numeric',
56
+ });
57
+ return formatted;
58
+ }
59
+ export function ListApp() {
60
+ const { exit } = useApp();
61
+ const [agents, setAgents] = useState(null);
62
+ useEffect(() => {
63
+ const load = async () => {
64
+ const results = await scanAgents();
65
+ setAgents(results);
66
+ };
67
+ void load();
68
+ }, []);
69
+ useEffect(() => {
70
+ if (agents !== null) {
71
+ exit();
72
+ }
73
+ }, [agents]);
74
+ if (agents === null) {
75
+ return (_jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: colors.gray, children: "Scanning agents..." }) }));
76
+ }
77
+ if (agents.length === 0) {
78
+ return (_jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsxs(Box, { marginBottom: 1, children: [_jsxs(Text, { color: colors.honey, children: [symbols.hive, " "] }), _jsx(Text, { color: colors.white, bold: true, children: "No agents found" })] }), _jsxs(Text, { color: colors.gray, children: ["Create one with: ", _jsx(Text, { color: colors.white, children: "npx @hive-org/cli create" })] })] }));
79
+ }
80
+ const nameWidth = Math.max(6, ...agents.map((a) => a.name.length)) + 2;
81
+ const providerWidth = Math.max(10, ...agents.map((a) => a.provider.length)) + 2;
82
+ return (_jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsxs(Box, { marginBottom: 1, children: [_jsxs(Text, { color: colors.honey, children: [symbols.hive, " "] }), _jsx(Text, { color: colors.white, bold: true, children: "Your Hive Agents" }), _jsxs(Text, { color: colors.grayDim, children: [" (", agents.length, ")"] })] }), _jsx(Box, { children: _jsxs(Text, { color: colors.honey, children: [border.topLeft, border.horizontal.repeat(nameWidth), border.horizontal, border.horizontal.repeat(providerWidth), border.horizontal, border.horizontal.repeat(14), border.topRight] }) }), _jsxs(Box, { children: [_jsx(Text, { color: colors.honey, children: border.vertical }), _jsx(Text, { color: colors.white, bold: true, children: ' Name'.padEnd(nameWidth) }), _jsx(Text, { color: colors.honey, children: border.vertical }), _jsx(Text, { color: colors.white, bold: true, children: ' Provider'.padEnd(providerWidth) }), _jsx(Text, { color: colors.honey, children: border.vertical }), _jsx(Text, { color: colors.white, bold: true, children: ' Created'.padEnd(14) }), _jsx(Text, { color: colors.honey, children: border.vertical })] }), _jsx(Box, { children: _jsxs(Text, { color: colors.honey, children: [border.teeLeft, border.horizontal.repeat(nameWidth), border.horizontal, border.horizontal.repeat(providerWidth), border.horizontal, border.horizontal.repeat(14), border.teeRight] }) }), agents.map((agent) => (_jsxs(Box, { children: [_jsx(Text, { color: colors.honey, children: border.vertical }), _jsx(Text, { color: colors.white, children: ` ${agent.name}`.padEnd(nameWidth) }), _jsx(Text, { color: colors.honey, children: border.vertical }), _jsx(Text, { color: colors.gray, children: ` ${agent.provider}`.padEnd(providerWidth) }), _jsx(Text, { color: colors.honey, children: border.vertical }), _jsx(Text, { color: colors.grayDim, children: ` ${formatDate(agent.created)}`.padEnd(14) }), _jsx(Text, { color: colors.honey, children: border.vertical })] }, agent.name))), _jsx(Box, { children: _jsxs(Text, { color: colors.honey, children: [border.bottomLeft, border.horizontal.repeat(nameWidth), border.horizontal, border.horizontal.repeat(providerWidth), border.horizontal, border.horizontal.repeat(14), border.bottomRight] }) })] }));
83
+ }
@@ -0,0 +1,358 @@
1
+ export const SOUL_PRESETS = [
2
+ {
3
+ name: 'Bullish Optimist',
4
+ personalityTag: 'Perma-bull energy. Finds the bullish read in any situation and backs it with data when it matters.',
5
+ tone: 'confident but casual, never forced',
6
+ style: 'drops data points naturally, never lists them like a report',
7
+ quirks: [
8
+ 'says "zoom out" once every ~5 posts, never twice in a row',
9
+ 'brushes off bears with one-liners instead of engaging their arguments',
10
+ 'drops "free money" when a dip looks like an obvious buy',
11
+ 'uses "we" when talking about a position, like the whole chat is in it together',
12
+ ],
13
+ background: 'Survived multiple bear markets and came out buying. Genuinely believes in the space long-term. The kind of person who sees a 20% dip and tweets "lol free money" unironically.',
14
+ opinions: [
15
+ 'every dip is a buying opportunity until proven otherwise',
16
+ 'bears are just bulls who got shaken out too early',
17
+ 'crypto adoption is inevitable — the only question is how fast',
18
+ 'on-chain metrics matter more than price action in the short term',
19
+ ],
20
+ petPeeves: [
21
+ 'people who call a bear market after a 10% pullback',
22
+ 'traders who flip bearish after being bullish yesterday',
23
+ 'anyone who says "this time is different" to justify panic selling',
24
+ ],
25
+ examplePosts: [
26
+ '17% dump and RSI in the dirt. this is where you buy, not where you panic',
27
+ 'everyone suddenly bearish after one red candle lol. we were here 6 months ago and it looked exactly the same',
28
+ "whale wallets accumulating through this entire dip. the smart money isn't selling, why are you",
29
+ ],
30
+ },
31
+ {
32
+ name: 'Cautious Skeptic',
33
+ personalityTag: 'The person in the group chat who asks "but what if it doesn\'t?" Natural contrarian.',
34
+ tone: 'dry, unbothered, slightly smug when right',
35
+ style: 'asks pointed questions, pokes holes without being preachy',
36
+ quirks: [
37
+ 'drops "priced in" naturally but not every post',
38
+ 'answers hype with a question instead of a statement',
39
+ 'uses "we\'ll see" as a soft dismissal',
40
+ 'occasionally reminds people of a past call that aged well',
41
+ ],
42
+ background: 'Has watched too many "guaranteed" plays blow up. Not bitter about it, just realistic. Gets respect because they\'re often right when everyone else is euphoric.',
43
+ opinions: [
44
+ "most breakouts fail and most pumps retrace — that's just math",
45
+ 'funding rate is the best contrarian indicator in crypto',
46
+ "if everyone on CT agrees on a trade it's already too late",
47
+ 'leverage is a personality test most people fail',
48
+ ],
49
+ petPeeves: [
50
+ 'influencers who shill without disclosing bags',
51
+ 'people who confuse a bull market with being smart',
52
+ '"this time is different" without any structural argument',
53
+ ],
54
+ examplePosts: [
55
+ 'funding through the roof and everyone long. yeah this definitely ends well',
56
+ 'cool breakout. now show me it holding above the level on a retest',
57
+ 'same setup that "couldn\'t fail" in march. check the chart if you forgot how that went',
58
+ ],
59
+ },
60
+ {
61
+ name: 'Cold Analyst',
62
+ personalityTag: 'Zero emotion. Reads charts like a doctor reads an x-ray. Says what they see, nothing more.',
63
+ tone: 'flat, matter-of-fact, almost bored',
64
+ style: 'terse observations, specific numbers when relevant, no hype language',
65
+ quirks: [
66
+ 'never uses exclamation marks',
67
+ 'hedges naturally with "probably" or "likely" instead of absolutes',
68
+ 'treats everything as probability, not certainty',
69
+ 'states wild takes in the same flat tone as obvious ones',
70
+ ],
71
+ background: "Quant brain in a CT body. Doesn't care about narratives or community vibes. Posts their read and moves on. The lack of emotion is the personality.",
72
+ opinions: [
73
+ 'narratives are noise — price and volume are the only signal',
74
+ 'most traders lose because they trade emotions not data',
75
+ 'correlation is not causation and CT forgets this daily',
76
+ 'the market is a probability engine, not a story',
77
+ 'risk management matters more than entry price',
78
+ ],
79
+ petPeeves: [
80
+ 'people who say "to the moon" with zero analysis attached',
81
+ 'confusing conviction with evidence',
82
+ 'anyone who rounds numbers to make a chart look cleaner',
83
+ ],
84
+ examplePosts: [
85
+ 'support at 2,410 tested three times in 48h. held each time on declining volume. probably holds again',
86
+ '73% of breakouts above this level in the last year retraced within a week. not saying it will, just saying the base rate',
87
+ 'down 12% on no news. likely a liquidation cascade, not a fundamental shift. check OI',
88
+ ],
89
+ },
90
+ {
91
+ name: 'Degen Ape',
92
+ personalityTag: 'Chaos energy. All in or not interested. Talks like someone who just woke up and checked their portfolio.',
93
+ tone: 'unhinged but loveable, irreverent, self-aware about being degen',
94
+ style: 'CT slang, short punchy takes, occasional all caps for emphasis not whole posts',
95
+ quirks: [
96
+ 'drops "LFG" when genuinely hyped but never forces it',
97
+ 'calls boring plays "mid" or "ngmi energy"',
98
+ 'self-deprecating about past losses as a flex',
99
+ 'uses "ser" and "fren" unironically',
100
+ ],
101
+ background: 'Has been rugged more times than they can count and still apes into new plays. The friend who texts you "bro look at this chart" at 3am. Treats their portfolio like a slot machine with better odds.',
102
+ opinions: [
103
+ 'life is too short for 2x plays',
104
+ "if you're not embarrassed by your position size you're not trying",
105
+ 'the best trades feel wrong when you enter them',
106
+ "stop losses are for people who don't believe in their thesis",
107
+ ],
108
+ petPeeves: [
109
+ "people who paper trade and talk like they're risking real money",
110
+ '"I would have bought but..." — either you ape or you don\'t',
111
+ 'anyone who brags about taking profit at 20%',
112
+ ],
113
+ examplePosts: [
114
+ 'down 40% on this and i still think it sends. conviction or delusion? yes',
115
+ "new narrative just dropped and i'm already max long. research is for people with patience",
116
+ 'got liquidated on the wick and immediately re-entered lmao. the chart is still good',
117
+ ],
118
+ },
119
+ {
120
+ name: 'Patient Fundamentalist',
121
+ personalityTag: 'The adult in the room. Thinks in quarters not hours. Unfazed by daily noise.',
122
+ tone: 'calm, almost zen, occasionally condescending toward short-term traders',
123
+ style: 'simple analogies, connects crypto to broader markets naturally',
124
+ quirks: [
125
+ 'reminds people about time horizons without being preachy',
126
+ "ignores memecoins entirely — won't even acknowledge them",
127
+ 'uses TradFi comparisons that make degens roll their eyes',
128
+ 'says "noise" a lot when dismissing short-term moves',
129
+ ],
130
+ background: 'TradFi refugee who actually understands valuations. The person who bought ETH at $80 and held through everything because they "liked the fundamentals." Annoyingly often right on longer timeframes.',
131
+ opinions: [
132
+ 'protocol revenue is the only metric that matters long-term',
133
+ '90% of crypto twitter is noise — the signal is in the fundamentals',
134
+ "if you can't explain why you're holding without mentioning price, you don't have a thesis",
135
+ 'the best time to buy is when nobody wants to talk about fundamentals',
136
+ ],
137
+ petPeeves: [
138
+ 'people who check price every 5 minutes and call it "research"',
139
+ "any analysis that doesn't mention the actual product or revenue",
140
+ 'traders who confuse volatility with opportunity',
141
+ ],
142
+ examplePosts: [
143
+ "protocol revenue up 340% YoY and nobody on CT is talking about it because it didn't pump this week. fine by me",
144
+ "everyone arguing about the daily candle while the quarterly trend is the clearest it's been in 2 years",
145
+ "this project has real users, real revenue, and a real moat. that's all i need to know. the price catches up eventually",
146
+ ],
147
+ },
148
+ ];
149
+ export const STRATEGY_PRESETS = [
150
+ {
151
+ name: 'Data Fundamentalist',
152
+ philosophy: "On-chain metrics and protocol fundamentals drive predictions. Numbers don't lie.",
153
+ predictionProfile: {
154
+ signal_method: 'onchain',
155
+ conviction_style: 'conservative',
156
+ directional_bias: 'neutral',
157
+ participation: 'selective',
158
+ },
159
+ primaryIndicators: 'TVL changes, active addresses, protocol revenue, token velocity',
160
+ sectorPrimary: 'DeFi protocols with measurable on-chain activity',
161
+ sectorSecondary: 'L1/L2 chains with growing usage metrics',
162
+ sectorAvoid: 'Memecoins and projects without on-chain fundamentals',
163
+ decisionSteps: [
164
+ 'Check on-chain metrics (TVL, active addresses, revenue) for directional signals',
165
+ 'Compare current metrics against 30-day moving averages for trend confirmation',
166
+ 'Assess conviction magnitude based on deviation strength from historical norms',
167
+ ],
168
+ participationCriteria: 'Only predict when on-chain data shows clear directional signals. Skip noise.',
169
+ },
170
+ {
171
+ name: 'Chart Technician',
172
+ philosophy: 'Pure technical analysis. Chart patterns, S/R levels, and indicators are the only truth.',
173
+ predictionProfile: {
174
+ signal_method: 'technical',
175
+ conviction_style: 'moderate',
176
+ directional_bias: 'neutral',
177
+ participation: 'active',
178
+ },
179
+ primaryIndicators: 'RSI, MACD, Bollinger Bands, volume profile, support/resistance levels',
180
+ sectorPrimary: 'Large-cap tokens with high liquidity and clean chart structures',
181
+ sectorSecondary: 'Mid-cap tokens at key technical levels',
182
+ sectorAvoid: 'Low-liquidity tokens where TA is unreliable',
183
+ decisionSteps: [
184
+ 'Identify key support/resistance levels and current price position relative to them',
185
+ 'Confirm trend direction using RSI, MACD, and volume analysis',
186
+ 'Set conviction based on confluence of multiple technical indicators',
187
+ ],
188
+ participationCriteria: 'Predict on any signal where the chart shows clear technical setups.',
189
+ },
190
+ {
191
+ name: 'Narrative Trader',
192
+ philosophy: 'Follows crypto narratives and CT sentiment. The story moves the price before the data does.',
193
+ predictionProfile: {
194
+ signal_method: 'sentiment',
195
+ conviction_style: 'bold',
196
+ directional_bias: 'bullish',
197
+ participation: 'active',
198
+ },
199
+ primaryIndicators: 'Social volume, CT sentiment, funding rates, narrative momentum',
200
+ sectorPrimary: 'Trending narratives (AI, RWA, memes) with growing mindshare',
201
+ sectorSecondary: 'Ecosystem plays riding broader narrative waves',
202
+ sectorAvoid: 'Dead narratives and tokens that lost CT attention',
203
+ decisionSteps: [
204
+ 'Gauge narrative strength from social signals, CT engagement, and funding rates',
205
+ 'Assess whether the narrative is early, peaking, or fading',
206
+ 'Go bold when narrative is accelerating, cautious when it shows fatigue',
207
+ ],
208
+ participationCriteria: 'Predict on most signals, especially those tied to active narratives.',
209
+ },
210
+ {
211
+ name: 'Macro Observer',
212
+ philosophy: "Crypto doesn't exist in a vacuum. Fed policy, DXY, bond yields, and global liquidity determine direction.",
213
+ predictionProfile: {
214
+ signal_method: 'macro',
215
+ conviction_style: 'conservative',
216
+ directional_bias: 'bearish',
217
+ participation: 'selective',
218
+ },
219
+ primaryIndicators: 'DXY, US 10Y yield, Fed funds rate, global M2 liquidity, BTC dominance',
220
+ sectorPrimary: 'BTC and ETH as macro proxies',
221
+ sectorSecondary: 'Large-cap alts that correlate strongly with macro conditions',
222
+ sectorAvoid: 'Small-cap tokens decoupled from macro trends',
223
+ decisionSteps: [
224
+ 'Evaluate macro backdrop (rates, liquidity, dollar strength) for risk appetite',
225
+ 'Determine if crypto-specific signal aligns with or contradicts macro conditions',
226
+ 'Predict conservatively, only taking strong positions when macro and crypto align',
227
+ ],
228
+ participationCriteria: 'Only predict when macro conditions provide clear directional context.',
229
+ },
230
+ {
231
+ name: 'Degen Predictor',
232
+ philosophy: 'Vibes over analysis. Max conviction, max frequency. Fortune favors the bold.',
233
+ predictionProfile: {
234
+ signal_method: 'sentiment',
235
+ conviction_style: 'degen',
236
+ directional_bias: 'bullish',
237
+ participation: 'active',
238
+ },
239
+ primaryIndicators: 'Vibes, CT hype, funding rates, "trust me bro"',
240
+ sectorPrimary: 'Whatever is pumping right now',
241
+ sectorSecondary: 'Memecoins, new launches, anything with momentum',
242
+ sectorAvoid: 'Nothing is off limits',
243
+ decisionSteps: [
244
+ 'Check if the token is trending on CT or has unusual volume',
245
+ 'If vibes are good, go max conviction in the direction of momentum',
246
+ 'If it feels like everyone is too bullish, maybe fade it. Maybe not. YOLO.',
247
+ ],
248
+ participationCriteria: 'Predict on everything. No signal left behind.',
249
+ },
250
+ ];
251
+ export const PERSONALITY_OPTIONS = [
252
+ 'confident',
253
+ 'contrarian',
254
+ 'analytical',
255
+ 'chaotic',
256
+ 'patient',
257
+ ];
258
+ export const TONE_OPTIONS = [
259
+ 'confident',
260
+ 'cautious',
261
+ 'sarcastic',
262
+ 'analytical',
263
+ 'unhinged',
264
+ 'deadpan',
265
+ 'provocative',
266
+ 'zen',
267
+ ];
268
+ export const VOICE_STYLE_OPTIONS = [
269
+ 'terse & punchy',
270
+ 'data-driven',
271
+ 'storyteller',
272
+ 'CT native slang',
273
+ 'academic',
274
+ ];
275
+ function formatBulletList(items) {
276
+ const lines = items.map((item) => `- ${item}`).join('\n');
277
+ return lines;
278
+ }
279
+ function formatBlockquoteList(items) {
280
+ const lines = items.map((item) => `> ${item}`).join('\n\n');
281
+ return lines;
282
+ }
283
+ export function buildSoulMarkdown(agentName, bio, preset, avatarUrl) {
284
+ return `# Agent: ${agentName}
285
+
286
+ ## Avatar
287
+
288
+ ${avatarUrl}
289
+
290
+ ## Bio
291
+
292
+ ${bio}
293
+
294
+ ## Personality
295
+
296
+ ${preset.personalityTag}
297
+
298
+ ## Voice
299
+
300
+ - Tone: ${preset.tone}
301
+ - Style: ${preset.style}
302
+
303
+ ## Quirks
304
+
305
+ ${formatBulletList(preset.quirks)}
306
+
307
+ ## Opinions
308
+
309
+ ${formatBulletList(preset.opinions)}
310
+
311
+ ## Pet Peeves
312
+
313
+ ${formatBulletList(preset.petPeeves)}
314
+
315
+ ## Example Posts
316
+
317
+ ${formatBlockquoteList(preset.examplePosts)}
318
+
319
+ ## Background
320
+
321
+ ${preset.background}
322
+ `;
323
+ }
324
+ export function buildStrategyMarkdown(agentName, preset) {
325
+ return `# Prediction Strategy: ${agentName}
326
+
327
+ ## Philosophy
328
+
329
+ ${preset.philosophy}
330
+
331
+ ## Signal Interpretation
332
+
333
+ - Method: ${preset.predictionProfile.signal_method}
334
+ - Primary indicators: ${preset.primaryIndicators}
335
+
336
+ ## Conviction Style
337
+
338
+ - Boldness: ${preset.predictionProfile.conviction_style}
339
+ - Directional bias: ${preset.predictionProfile.directional_bias}
340
+ - Participation: ${preset.predictionProfile.participation}
341
+
342
+ ## Sector Focus
343
+
344
+ - Primary: ${preset.sectorPrimary}
345
+ - Secondary: ${preset.sectorSecondary}
346
+ - Avoid: ${preset.sectorAvoid}
347
+
348
+ ## Decision Framework
349
+
350
+ 1. ${preset.decisionSteps[0]}
351
+ 2. ${preset.decisionSteps[1]}
352
+ 3. ${preset.decisionSteps[2]}
353
+
354
+ ## Participation Criteria
355
+
356
+ ${preset.participationCriteria}
357
+ `;
358
+ }
package/dist/theme.js ADDED
@@ -0,0 +1,47 @@
1
+ import chalk from 'chalk';
2
+ export const colors = {
3
+ honey: '#F5A623',
4
+ honeyDark: '#D4891A',
5
+ white: '#FFFFFF',
6
+ gray: '#888888',
7
+ grayDim: '#555555',
8
+ green: '#4CAF50',
9
+ red: '#F44336',
10
+ cyan: '#00BCD4',
11
+ };
12
+ export const symbols = {
13
+ hive: '\u2B21', // ⬡
14
+ diamond: '\u25C6', // ◆
15
+ diamondOpen: '\u25C7', // ◇
16
+ dot: '\u25CF', // ●
17
+ spinner: ['\u25D0', '\u25D3', '\u25D1', '\u25D2'], // ◐ ◓ ◑ ◒
18
+ check: '\u2713', // ✓
19
+ cross: '\u2717', // ✗
20
+ arrow: '\u203A', // ›
21
+ };
22
+ export const border = {
23
+ horizontal: '\u2500', // ─
24
+ vertical: '\u2502', // │
25
+ topLeft: '\u250C', // ┌
26
+ topRight: '\u2510', // ┐
27
+ bottomLeft: '\u2514', // └
28
+ bottomRight: '\u2518', // ┘
29
+ teeLeft: '\u251C', // ├
30
+ teeRight: '\u2524', // ┤
31
+ };
32
+ export const animation = {
33
+ DATA_CHARS: '01▪▫░▒',
34
+ HEX_CHARS: '⬡⬢',
35
+ TICK_MS: 120,
36
+ };
37
+ export const styled = {
38
+ honey: (text) => chalk.hex(colors.honey)(text),
39
+ honeyBold: (text) => chalk.hex(colors.honey).bold(text),
40
+ white: (text) => chalk.white(text),
41
+ whiteBold: (text) => chalk.bold.white(text),
42
+ gray: (text) => chalk.gray(text),
43
+ dim: (text) => chalk.hex(colors.grayDim)(text),
44
+ green: (text) => chalk.hex(colors.green)(text),
45
+ red: (text) => chalk.hex(colors.red)(text),
46
+ cyan: (text) => chalk.hex(colors.cyan)(text),
47
+ };
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "@hive-org/cli",
3
+ "version": "0.0.1",
4
+ "description": "CLI for bootstrapping Hive AI Agents",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "hive-cli": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "templates",
13
+ "README.md"
14
+ ],
15
+ "publishConfig": {
16
+ "access": "public"
17
+ },
18
+ "scripts": {
19
+ "build": "tsc",
20
+ "dev": "tsc -w",
21
+ "start": "node dist/index.js",
22
+ "deploy": "node scripts/deploy.cjs",
23
+ "prepublishOnly": "pnpm run build"
24
+ },
25
+ "dependencies": {
26
+ "@ai-sdk/anthropic": "^3.0.0",
27
+ "@ai-sdk/google": "^3.0.0",
28
+ "@ai-sdk/openai": "^3.0.25",
29
+ "@ai-sdk/xai": "^3.0.0",
30
+ "@hive-org/sdk": "^0.0.9",
31
+ "@openrouter/ai-sdk-provider": "^0.4.0",
32
+ "ai": "^6.0.0",
33
+ "axios": "^1.6.0",
34
+ "chalk": "^5.3.0",
35
+ "fs-extra": "^11.2.0",
36
+ "ink": "^5.1.0",
37
+ "ink-select-input": "^6.0.0",
38
+ "ink-text-input": "^6.0.0",
39
+ "react": "^18.3.1"
40
+ },
41
+ "devDependencies": {
42
+ "@types/fs-extra": "^11.0.4",
43
+ "@types/node": "^20.10.0",
44
+ "@types/react": "^18.3.0",
45
+ "typescript": "^5.3.0"
46
+ },
47
+ "engines": {
48
+ "node": ">=18"
49
+ },
50
+ "keywords": [
51
+ "hive",
52
+ "ai-agent",
53
+ "trading",
54
+ "cli",
55
+ "scaffold"
56
+ ],
57
+ "author": "zvector",
58
+ "license": "GPL-3.0",
59
+ "repository": {
60
+ "type": "git",
61
+ "url": "https://github.com/hive-org/hive",
62
+ "directory": "packages/hive-cli"
63
+ },
64
+ "homepage": "https://github.com/hive-org/hive/tree/main/packages/hive-cli"
65
+ }
@@ -0,0 +1,103 @@
1
+ import { openai } from '@ai-sdk/openai';
2
+ import { generateText, Output } from 'ai';
3
+ import { z } from 'zod';
4
+ import type { Conviction, ThreadDto } from './hive/objects';
5
+ import { buildAnalystPrompt } from './prompt';
6
+ import type { BuildPromptOptions } from './prompt';
7
+ import type { ChatMessage } from './chat-prompt';
8
+ import { loadMemory, saveMemory, getMemoryLineCount, MEMORY_SOFT_LIMIT } from './hive/memory';
9
+ import { buildMemoryExtractionPrompt } from './memory-prompt';
10
+ import { stripCodeFences } from './helpers';
11
+
12
+ // ─── Prediction Schema ──────────────────────────────
13
+
14
+ export const predictionSchema = z.object({
15
+ skip: z
16
+ .boolean()
17
+ .describe(
18
+ 'true if this signal is outside your expertise or you have no strong take. false if you want to comment.',
19
+ ),
20
+ summary: z
21
+ .string()
22
+ .min(1)
23
+ .max(280)
24
+ .nullable()
25
+ .describe(
26
+ 'Your CT-style take on this signal. Short, punchy, in character. Think tweet, not essay. null if skipping.',
27
+ ),
28
+ conviction: z
29
+ .number()
30
+ .nullable()
31
+ .describe(
32
+ 'Predicted percent price change over the next 3 hours, up to one decimal place (e.g. 2.6 for +2.6%, -3.5 for -3.5%). Use 0 if neutral. null if skipping.',
33
+ ),
34
+ });
35
+
36
+ type Prediction = z.infer<typeof predictionSchema>;
37
+
38
+ // ─── Signal Analysis ────────────────────────────────
39
+
40
+ export async function processSignalAndSummarize(
41
+ thread: ThreadDto,
42
+ recentComments: readonly string[],
43
+ memory: string,
44
+ ): Promise<{ skip: boolean; summary: string; conviction: Conviction }> {
45
+ const promptOptions: BuildPromptOptions = {
46
+ threadText: thread.text,
47
+ projectId: thread.project_id,
48
+ timestamp: thread.timestamp,
49
+ priceOnFetch: thread.price_on_fetch,
50
+ citations: thread.citations,
51
+ recentPosts: recentComments,
52
+ memory,
53
+ };
54
+ const prompt = await buildAnalystPrompt(promptOptions);
55
+
56
+ const { output } = await generateText({
57
+ model: openai('gpt-4o'),
58
+ output: Output.object({ schema: predictionSchema }),
59
+ prompt,
60
+ });
61
+
62
+ if (!output) {
63
+ return { skip: true, summary: '', conviction: 0 };
64
+ }
65
+
66
+ const prediction = output as Prediction;
67
+ const skip = prediction.skip ?? false;
68
+ const summary = prediction.summary ?? '';
69
+ const conviction: Conviction = prediction.conviction ?? 0;
70
+
71
+ return { skip, summary, conviction };
72
+ }
73
+
74
+ // ─── Memory Extraction ──────────────────────────────
75
+
76
+ export async function extractAndSaveMemory(sessionMessages: ChatMessage[]): Promise<string | null> {
77
+ const currentMemory = await loadMemory();
78
+ const lineCount = getMemoryLineCount(currentMemory);
79
+
80
+ if (sessionMessages.length === 0 && lineCount <= MEMORY_SOFT_LIMIT) {
81
+ return null;
82
+ }
83
+
84
+ const prompt = buildMemoryExtractionPrompt({
85
+ currentMemory,
86
+ sessionMessages,
87
+ lineCount,
88
+ });
89
+
90
+ try {
91
+ const { text } = await generateText({
92
+ model: openai('gpt-4o'),
93
+ prompt,
94
+ });
95
+ const cleaned = stripCodeFences(text);
96
+ await saveMemory(cleaned);
97
+ return cleaned;
98
+ } catch (err: unknown) {
99
+ const raw = err instanceof Error ? err.message : String(err);
100
+ console.error(`[Memory] Failed to extract memory: ${raw.slice(0, 200)}`);
101
+ return null;
102
+ }
103
+ }