@zhive/cli 0.6.0 → 0.6.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 (88) hide show
  1. package/dist/{services/agent → agent}/analysis.js +5 -5
  2. package/dist/agent/app.js +122 -0
  3. package/dist/agent/commands/registry.js +12 -0
  4. package/dist/agent/components/AsciiTicker.js +81 -0
  5. package/dist/agent/components/CommandInput.js +65 -0
  6. package/dist/agent/components/HoneycombBoot.js +291 -0
  7. package/dist/agent/components/Spinner.js +37 -0
  8. package/dist/agent/hooks/useAgent.js +480 -0
  9. package/dist/{services/agent/prompts → agent}/memory-prompt.js +22 -20
  10. package/dist/{services/agent/helpers → agent}/model.js +2 -2
  11. package/dist/agent/process-lifecycle.js +18 -0
  12. package/dist/{services/agent/prompts → agent}/prompt.js +54 -80
  13. package/dist/agent/run-headless.js +189 -0
  14. package/dist/agent/theme.js +41 -0
  15. package/dist/{services/agent → agent}/tools/market/client.js +1 -1
  16. package/dist/{services/agent → agent}/tools/mindshare/client.js +1 -1
  17. package/dist/agent/types.js +1 -0
  18. package/dist/{services/config/agent.js → agents.js} +2 -2
  19. package/dist/avatar.js +34 -0
  20. package/dist/backtest/default-backtest-data.js +200 -0
  21. package/dist/backtest/fetch.js +41 -0
  22. package/dist/backtest/import.js +106 -0
  23. package/dist/backtest/index.js +10 -0
  24. package/dist/backtest/results.js +113 -0
  25. package/dist/backtest/runner.js +134 -0
  26. package/dist/backtest/storage.js +11 -0
  27. package/dist/backtest/types.js +1 -0
  28. package/dist/commands/install.js +50 -0
  29. package/dist/commands/start/ui/PollText.js +23 -0
  30. package/dist/commands/start/ui/PredictionsPanel.js +88 -0
  31. package/dist/commands/start/ui/SpinnerContext.js +20 -0
  32. package/dist/components/InputGuard.js +6 -0
  33. package/dist/components/stdout-spinner.js +48 -0
  34. package/dist/{services/config/config.js → config.js} +7 -1
  35. package/dist/create/CreateApp.js +153 -0
  36. package/dist/create/ai-generate.js +147 -0
  37. package/dist/create/generate.js +73 -0
  38. package/dist/create/steps/ApiKeyStep.js +97 -0
  39. package/dist/create/steps/AvatarStep.js +16 -0
  40. package/dist/create/steps/BioStep.js +14 -0
  41. package/dist/create/steps/DoneStep.js +14 -0
  42. package/dist/create/steps/IdentityStep.js +163 -0
  43. package/dist/create/steps/NameStep.js +71 -0
  44. package/dist/create/steps/ScaffoldStep.js +58 -0
  45. package/dist/create/steps/SoulStep.js +58 -0
  46. package/dist/create/steps/StrategyStep.js +58 -0
  47. package/dist/create/validate-api-key.js +47 -0
  48. package/dist/create/welcome.js +304 -0
  49. package/dist/list/ListApp.js +79 -0
  50. package/dist/{services/agent/env.js → load-agent-env.js} +1 -1
  51. package/dist/migrate-templates/MigrateApp.js +131 -0
  52. package/dist/migrate-templates/migrate.js +86 -0
  53. package/dist/presets.js +613 -0
  54. package/dist/start/AgentProcessManager.js +98 -0
  55. package/dist/start/Dashboard.js +92 -0
  56. package/dist/start/SelectAgentApp.js +81 -0
  57. package/dist/start/StartApp.js +189 -0
  58. package/dist/start/patch-headless.js +101 -0
  59. package/dist/start/patch-managed-mode.js +142 -0
  60. package/dist/start/start-command.js +24 -0
  61. package/dist/theme.js +54 -0
  62. package/package.json +2 -2
  63. package/dist/CLAUDE.md +0 -7
  64. package/dist/backtest/CLAUDE.md +0 -7
  65. package/dist/cli.js +0 -20
  66. package/dist/services/config/constant.js +0 -8
  67. package/dist/shared/agent/config.js +0 -75
  68. package/dist/shared/agent/env.js +0 -30
  69. package/dist/shared/agent/helpers/model.js +0 -92
  70. package/dist/shared/ai-providers.js +0 -66
  71. /package/dist/{services/agent/prompts → agent}/chat-prompt.js +0 -0
  72. /package/dist/{services/agent → agent}/config.js +0 -0
  73. /package/dist/{services/agent/tools → agent}/edit-section.js +0 -0
  74. /package/dist/{services/agent/tools → agent}/fetch-rules.js +0 -0
  75. /package/dist/{services/agent → agent}/helpers.js +0 -0
  76. /package/dist/{services/agent/skills/types.js → agent/objects.js} +0 -0
  77. /package/dist/{services/agent → agent}/skills/index.js +0 -0
  78. /package/dist/{services/agent → agent}/skills/skill-parser.js +0 -0
  79. /package/dist/{services/agent → agent/skills}/types.js +0 -0
  80. /package/dist/{services/agent → agent}/tools/index.js +0 -0
  81. /package/dist/{services/agent → agent}/tools/market/index.js +0 -0
  82. /package/dist/{services/agent → agent}/tools/market/tools.js +0 -0
  83. /package/dist/{services/agent → agent}/tools/mindshare/index.js +0 -0
  84. /package/dist/{services/agent → agent}/tools/mindshare/tools.js +0 -0
  85. /package/dist/{services/agent → agent}/tools/read-skill-tool.js +0 -0
  86. /package/dist/{services/agent → agent}/tools/ta/index.js +0 -0
  87. /package/dist/{services/agent → agent}/tools/ta/indicators.js +0 -0
  88. /package/dist/{services/ai-providers.js → ai-providers.js} +0 -0
@@ -1,4 +1,3 @@
1
- // ─── Shared Types ─────────────────────────────────
2
1
  function humanDuration(ms) {
3
2
  const hours = ms / 3_600_000;
4
3
  if (hours >= 24) {
@@ -80,8 +79,32 @@ Only skip if this project is outside the expertise list defined in your STRATEGY
80
79
  - Major protocol upgrade, big institutional entry, trend reversal → ±6.0 to ±12.0
81
80
  - Black swan, regulatory bombshell, massive exploit → ±12.0 to ±25.0
82
81
 
83
- IMPORTANT: Vary your conviction numbers. Do NOT reuse the same number across rounds. Each round has different context — your conviction should reflect that.`;
84
- // ── Prompt (dynamic per signal — changes every call) ──
82
+ IMPORTANT: Vary your conviction numbers. Do NOT reuse the same number across rounds. Each round has different context — your conviction should reflect that.
83
+
84
+ ## The prediction game
85
+
86
+ This is a price prediction game for megathread rounds. Each round has a project, a duration, and a round-start baseline price. Your conviction = predicted TOTAL % change from the round-start price by end of the round.
87
+
88
+ Key inputs for each round:
89
+ - **Round-start price** — your scoring baseline. You predict % change from this.
90
+ - **Current price** — how much has already moved from baseline. Your prediction should account for movement that already happened.
91
+ - **Time remaining** — less time = less room for further movement. Late in the round, anchor your prediction close to where the price already is relative to baseline.
92
+ - **Catalysts & momentum** — news, sentiment shifts, or technical setups that could move price in the remaining window.
93
+
94
+ Scoring:
95
+ - Correct direction + close to actual = max honey (up to +100)
96
+ - Correct direction but far off = less honey
97
+ - Wrong direction = -25 honey penalty
98
+ - Skipping = no penalty, no reward
99
+ - Earlier predictions earn dramatically more honey (cubic time decay)
100
+ - Predicting late earns almost nothing even if correct
101
+
102
+ ## Using tools
103
+
104
+ If you have tools available, use them to research current price, OHLC data, technical indicators, mindshare data, and social sentiment. When you use a tool, drop a specific number or fact from the result into your post. Not a data dump, just one concrete detail woven into your take. Examples: "mindshare down 40% this week and nobody cares", "rsi at 28 after that flush", "volume 3x'd overnight". If a tool returns bad data (NaN, null, zero, empty, errors), silently ignore it. Never mention NaN, missing data, "no data", or failed lookups in your post. Just use the tools that gave you something real, or post from instinct if none did.
105
+
106
+ If your tools return nothing or you have limited data, just run with it. You know crypto. You know this space. Use your general knowledge, recent market conditions, and your trading instincts to form a directional lean. An imperfect prediction beats no prediction. Do NOT mention that you lack data. Never say "no data", "limited data", "couldn't find", "no tools", or anything that reveals you're operating without information. Just post with conviction like you always do. The only exception: if you're deliberately bluffing in character, that's a personality move, not a disclaimer.`;
107
+ // ── Prompt (dynamic per round — changes every call) ──
85
108
  let recentPostsSection = '';
86
109
  if (recentPosts && recentPosts.length > 0) {
87
110
  const listed = recentPosts.map((p) => `- "${p}"`).join('\n');
@@ -107,7 +130,6 @@ ${memory}
107
130
  const roundStartMs = Math.floor(now / durationMs) * durationMs;
108
131
  const timeRemainingMs = Math.max(0, roundStartMs + durationMs - now);
109
132
  const timeRemaining = humanDuration(timeRemainingMs);
110
- const lateInRound = timeRemainingMs < durationMs * 0.25;
111
133
  const nowIso = new Date().toISOString();
112
134
  // ── Price context lines ──
113
135
  const hasBothPrices = priceAtStart !== undefined && currentPrice !== undefined;
@@ -119,33 +141,11 @@ ${memory}
119
141
  }
120
142
  let priceContextLines = '';
121
143
  if (hasBothPrices) {
122
- priceContextLines = `- Round-start price: $${priceAtStart} (baseline for scoring)
144
+ priceContextLines = `- Round-start price: $${priceAtStart} (scoring baseline)
123
145
  - Current price: $${currentPrice} (${currentChangeStr} from round start)`;
124
146
  }
125
147
  else if (priceAtStart !== undefined) {
126
- priceContextLines = `- Round-start price: $${priceAtStart} (baseline for scoring)`;
127
- }
128
- // ── What-matters block ──
129
- let whatMattersBlock;
130
- if (hasBothPrices) {
131
- whatMattersBlock = `What matters:
132
- - **Round-start price** ($${priceAtStart}) — your baseline. Scoring measures % change from here.
133
- - **Current price** ($${currentPrice}, ${currentChangeStr} from baseline) — price has already moved this much. Your prediction should be close to this unless you expect further movement.
134
- - **Time remaining** (~${timeRemaining}) — less time = less room for further movement from current price.${lateInRound ? ' Almost no time left — anchor your prediction to the current change (' + currentChangeStr + ').' : ''}
135
- - **Catalysts & momentum** — news, sentiment shifts, or technical setups that could move price in the remaining window.`;
136
- }
137
- else if (priceAtStart !== undefined) {
138
- whatMattersBlock = `What matters:
139
- - **Round-start price** ($${priceAtStart}) — your baseline. Scoring measures % change from here.
140
- - **Current price** — check with tools. Compare to $${priceAtStart} to see how much has already moved.
141
- - **Time remaining** (~${timeRemaining}) — less time = less room for further movement from current price.${lateInRound ? ' Almost no time left — anchor your prediction to where the price is NOW relative to $' + priceAtStart + '.' : ''}
142
- - **Catalysts & momentum** — news, sentiment shifts, or technical setups that could move price in the remaining window.`;
143
- }
144
- else {
145
- whatMattersBlock = `What matters:
146
- - **Current price** — check with tools. This is the most important input to your prediction.
147
- - **Time remaining** (~${timeRemaining}) — the runway left for price movement. Less time = smaller realistic moves. Scale your conviction accordingly.${lateInRound ? ' Round is almost over — keep your conviction small.' : ''}
148
- - **Catalysts & momentum** — news, sentiment shifts, or technical setups that could move price in the remaining window.`;
148
+ priceContextLines = `- Round-start price: $${priceAtStart} (scoring baseline)`;
149
149
  }
150
150
  // ── Scoring & conviction lines ──
151
151
  let scoringLine;
@@ -173,36 +173,11 @@ ${memory}
173
173
  - Round duration: ${timeframe}
174
174
  - Time remaining: ~${timeRemaining}
175
175
  ${priceContextLines ? priceContextLines + '\n' : ''}
176
- ## The game
177
-
178
- This is a price prediction game. You're predicting the % price change for c/${projectId} over this ${timeframe} round.
179
-
180
- ${whatMattersBlock}
181
-
182
176
  ## Your task
183
177
 
184
- This is a **megathread round** for c/${projectId}. Form your price conviction for where c/${projectId} will be relative to ${taskBaseline} by end of this ${timeframe} round (~${timeRemaining} left).
185
-
186
- **If you have tools available**, use them to research:
187
- - Check current price, OHLC data, and technical indicators (RSI, MACD, volume, etc.)
188
- - Look at mindshare data and social sentiment
189
- - Use any available skills that help you gather market context
190
-
191
- **When you use a tool, drop a specific number or fact from the result into your post.** Not a data dump, just one concrete detail woven into your take. Examples: "mindshare down 40% this week and nobody cares", "rsi at 28 after that flush", "volume 3x'd overnight". If a tool returns bad data (NaN, null, zero, empty, errors), silently ignore it. Never mention NaN, missing data, "no data", or failed lookups in your post. Just use the tools that gave you something real, or post from instinct if none did.
192
-
193
- **If your tools return nothing or you have limited data**, just run with it. You know crypto. You know this space. Use your general knowledge of c/${projectId}, recent market conditions, and your trading instincts to form a directional lean. An imperfect prediction beats no prediction. Do NOT mention that you lack data, have no data, or couldn't find information. Never say "no data", "limited data", "couldn't find", "no tools", or anything that reveals you're operating without information. Just post with conviction like you always do. The only exception: if you're deliberately bluffing in character — pretending to reference data and then pulling the rug — that's a personality move, not a disclaimer.
194
-
195
- Form a thesis based on what you find or what you know.${thesisHint}
196
-
197
- ## How scoring works
178
+ This is a **megathread round** for c/${projectId}. Form your price conviction for where c/${projectId} will be relative to ${taskBaseline} by end of this ${timeframe} round (~${timeRemaining} left).${thesisHint}
198
179
 
199
180
  ${scoringLine}
200
- - Correct direction + close to actual = max honey (up to +100)
201
- - Correct direction but far off = less honey
202
- - Wrong direction = -25 honey penalty
203
- - Skipping = no penalty, no reward
204
- - Earlier predictions earn dramatically more honey (cubic time decay)
205
- - Predicting late earns almost nothing even if correct
206
181
  ${recentPostsSection}${memorySection}
207
182
  Give your take in character and a conviction number.
208
183
  ${convictionLine}`;
@@ -301,7 +276,28 @@ Set skip to true and set summary and conviction to null. Real people don't comme
301
276
  - Major protocol upgrade, big institutional entry, trend reversal → ±6.0 to ±12.0
302
277
  - Black swan, regulatory bombshell, massive exploit → ±12.0 to ±25.0
303
278
 
304
- IMPORTANT: Vary your conviction numbers. Do NOT reuse the same number across signals. Each signal has different strength — your conviction should reflect that.`;
279
+ IMPORTANT: Vary your conviction numbers. Do NOT reuse the same number across signals. Each signal has different strength — your conviction should reflect that.
280
+
281
+ ## The prediction game
282
+
283
+ This is a price prediction game. Each signal has a snapshot price captured at signal time and a 3-hour evaluation window. Your conviction = predicted % change from the snapshot price by evaluation time.
284
+
285
+ Key inputs for each signal:
286
+ - **Snapshot price** — your scoring baseline. You predict % change from this.
287
+ - **Current price** — check with tools to see how much has already moved since the signal.
288
+ - **Time left** — less time = less room for further movement. Late in the window, anchor your prediction close to where the price already is relative to the snapshot.
289
+
290
+ Scoring:
291
+ - Correct direction + close to actual = max honey (up to +100)
292
+ - Correct direction but far off = less honey
293
+ - Wrong direction = -25 honey penalty
294
+ - Skipping = no penalty, no reward
295
+ - Earlier predictions earn dramatically more honey (cubic time decay)
296
+ - Predicting late earns almost nothing even if correct
297
+
298
+ ## Using tools
299
+
300
+ If you have tools available, use them to check price action, technicals, or mindshare before forming your take. When you use a tool, drop a specific number or fact from the result into your post. Not a data dump, just one concrete detail woven into your take. Examples: "mindshare down 40% this week and nobody cares", "rsi at 28 after that flush", "volume 3x'd overnight". If a tool returns bad data (NaN, null, zero, empty, errors), silently ignore it. Never mention NaN, missing data, "no data", or failed lookups in your post. Just use the tools that gave you something real, or post from instinct if none did.`;
305
301
  // ── Prompt (dynamic per signal — changes every call) ──
306
302
  let citationsSection = '';
307
303
  if (citations.length > 0) {
@@ -338,42 +334,20 @@ ${memory}
338
334
  const signalTimeMs = new Date(timestamp).getTime();
339
335
  const timeRemainingMs = Math.max(0, signalTimeMs + EVAL_WINDOW_MS - Date.now());
340
336
  const timeRemaining = humanDuration(timeRemainingMs);
341
- const lateWindow = timeRemainingMs < 45 * 60 * 1000;
342
337
  const userPrompt = `## Context
343
338
 
344
339
  - Project: c/${projectId}
345
340
  - Current date: ${currentDate}
346
341
  - Signal time: ${timestamp}
347
- - Snapshot price: $${priceOnFetch} (captured at signal time)
342
+ - Snapshot price: $${priceOnFetch} (scoring baseline)
348
343
  - Time left: ~${timeRemaining}
349
- ${citationsSection}
350
- ## The game
351
-
352
- This is a price prediction game. Your conviction = predicted % change from the snapshot price ($${priceOnFetch}), evaluated 3 hours after signal time.
353
-
354
- What matters:
355
- - **Snapshot price** ($${priceOnFetch}) — your baseline. Scoring measures % change from here.
356
- - **Current price** — how much has already moved since the signal. Check with tools.
357
- - **Time left** (~${timeRemaining}) — less time = less room for further movement from current price.${lateWindow ? ' Almost no time left — anchor your prediction to where the price is NOW relative to the snapshot.' : ''}
358
-
359
- ## How scoring works
360
-
361
- You are predicting the % price change from the snapshot price ($${priceOnFetch}) over 3 hours from signal time.
362
- - Correct direction + close to actual = max honey (up to +100)
363
- - Correct direction but far off = less honey
364
- - Wrong direction = -25 honey penalty
365
- - Skipping = no penalty, no reward
366
- - Earlier predictions earn dramatically more honey (cubic time decay)
367
- - Predicting late earns almost nothing even if correct
368
- ${recentPostsSection}${memorySection}
344
+ ${citationsSection}${recentPostsSection}${memorySection}
369
345
  Signal/event to react to:
370
346
  """
371
347
  ${threadText}
372
348
  """
373
349
 
374
- **If you have tools available**, use them to check price action, technicals, or mindshare for c/${projectId} before forming your take. When you use a tool, drop a specific number or fact from the result into your post. Not a data dump, just one concrete detail woven into your take. Examples: "mindshare down 40% this week and nobody cares", "rsi at 28 after that flush", "volume 3x'd overnight". If the tool returned nothing useful, ignore it and post from instinct.
375
-
376
350
  Give your take in character and a conviction number.
377
- Conviction: predicted % price change from $${priceOnFetch} by evaluation time (~${timeRemaining} left), up to one decimal. Positive = up, negative = down. 0 = neutral.`;
351
+ Conviction: predicted % price change from $${priceOnFetch} by evaluation time (~${timeRemaining} left), up to one decimal. Positive = up, negative = down.`;
378
352
  return { system, prompt: userPrompt };
379
353
  }
@@ -0,0 +1,189 @@
1
+ import { HiveAgent } from '@hive-org/sdk';
2
+ import { loadMemory } from '@hive-org/sdk';
3
+ import { loadAgentConfig } from './config.js';
4
+ import { resolveModelInfo } from './model.js';
5
+ import { HIVE_FRONTEND_URL } from '../config.js';
6
+ import { processSignalAndSummarize, processMegathreadRound, } from './analysis.js';
7
+ import { initializeSkills, getAllTools, getReadSkillTool, getSkillMetadataList, } from './tools/index.js';
8
+ import { getMarketClient } from './tools/market/index.js';
9
+ function formatTokens(n) {
10
+ const formatted = n.toLocaleString('en-US');
11
+ return formatted;
12
+ }
13
+ function formatUsageLine(usage) {
14
+ const cacheInfo = usage.cacheReadTokens > 0
15
+ ? ` (${formatTokens(usage.cacheReadTokens)} cached)`
16
+ : usage.cacheWriteTokens > 0
17
+ ? ` (${formatTokens(usage.cacheWriteTokens)} cache write)`
18
+ : '';
19
+ const toolInfo = usage.toolCalls > 0 ? ` \u00b7 tools: ${usage.toolNames.join(', ')}` : '';
20
+ const line = ` tokens: ${formatTokens(usage.inputTokens)} in${cacheInfo} \u00b7 ${formatTokens(usage.outputTokens)} out${toolInfo}`;
21
+ return line;
22
+ }
23
+ function logToolResults(results) {
24
+ for (const tr of results) {
25
+ const preview = tr.result.length > 200 ? tr.result.slice(0, 200) + '\u2026' : tr.result;
26
+ console.log(` ${tr.toolName}: ${preview}`);
27
+ }
28
+ }
29
+ function timestamp() {
30
+ const now = new Date();
31
+ const hours = String(now.getHours()).padStart(2, '0');
32
+ const minutes = String(now.getMinutes()).padStart(2, '0');
33
+ const seconds = String(now.getSeconds()).padStart(2, '0');
34
+ const ts = `${hours}:${minutes}:${seconds}`;
35
+ return ts;
36
+ }
37
+ export async function runHeadless() {
38
+ const { HIVE_API_URL } = await import('../config.js');
39
+ const config = await loadAgentConfig();
40
+ const initialMemory = await loadMemory();
41
+ let memoryRef = initialMemory;
42
+ const soulContent = config.soulContent;
43
+ const strategyContent = config.strategyContent;
44
+ const skillRegistry = await initializeSkills(process.cwd());
45
+ const allTools = getAllTools();
46
+ const readSkillTool = getReadSkillTool(skillRegistry);
47
+ const skillTools = { ...allTools, readSkill: readSkillTool };
48
+ const skillMetadata = getSkillMetadataList(skillRegistry);
49
+ let predictionCount = 0;
50
+ let totalInputTokens = 0;
51
+ let totalOutputTokens = 0;
52
+ let totalToolCalls = 0;
53
+ const agent = new HiveAgent(HIVE_API_URL, {
54
+ name: config.name,
55
+ avatarUrl: config.avatarUrl,
56
+ bio: config.bio ?? undefined,
57
+ agentProfile: config.agentProfile,
58
+ pollIntervalMs: 30_000,
59
+ pollLimit: 5,
60
+ onPollEmpty: () => {
61
+ console.log(`[${timestamp()}] idle — no new threads`);
62
+ },
63
+ onStop: async () => { },
64
+ onNewThread: async (thread) => {
65
+ try {
66
+ const threadPreview = thread.text.length > 80 ? thread.text.slice(0, 80) + '\u2026' : thread.text;
67
+ console.log(`[${timestamp()}] signal c/${thread.project_id}`);
68
+ console.log(` "${threadPreview}"`);
69
+ console.log(`[${timestamp()}] analyzing c/${thread.project_id}...`);
70
+ const result = await processSignalAndSummarize(thread, agent.recentComments, memoryRef, soulContent, strategyContent, skillTools, skillMetadata);
71
+ totalInputTokens += result.usage.inputTokens;
72
+ totalOutputTokens += result.usage.outputTokens;
73
+ totalToolCalls += result.usage.toolCalls;
74
+ if (result.usage.toolCalls > 0) {
75
+ const toolNames = result.usage.toolNames.join(', ');
76
+ console.log(` tools: ${toolNames} (${result.usage.toolCalls} calls)`);
77
+ // logToolResults(result.usage.toolResults);
78
+ }
79
+ else {
80
+ console.log(` tools: none`);
81
+ }
82
+ if (result.skip) {
83
+ console.log(`[${timestamp()}] skipped c/${thread.project_id} — outside expertise`);
84
+ console.log(formatUsageLine(result.usage));
85
+ return;
86
+ }
87
+ await agent.postComment(thread.id, {
88
+ thread_id: thread.id,
89
+ text: result.summary,
90
+ conviction: result.conviction,
91
+ }, thread.text);
92
+ predictionCount += 1;
93
+ const sign = result.conviction >= 0 ? '+' : '';
94
+ const threadUrl = `${HIVE_FRONTEND_URL}/c/${thread.project_id}/${thread.id}`;
95
+ console.log(`[${timestamp()}] signal c/${thread.project_id} [${sign}${result.conviction}%] "${result.summary}" (${predictionCount} total)`);
96
+ console.log(formatUsageLine(result.usage));
97
+ console.log(` ${threadUrl}`);
98
+ }
99
+ catch (err) {
100
+ const raw = err instanceof Error ? err.message : String(err);
101
+ const message = raw.length > 120 ? raw.slice(0, 120) + '\u2026' : raw;
102
+ console.error(`[${timestamp()}] error c/${thread.project_id}: ${message}`);
103
+ }
104
+ },
105
+ onNewMegathreadRound: async (round) => {
106
+ try {
107
+ const hours = Math.round(round.durationMs / 3_600_000);
108
+ const timeframe = hours >= 1 ? `${hours}h` : `${Math.round(round.durationMs / 60_000)}m`;
109
+ console.log(`[${timestamp()}] megathread c/${round.projectId} · ${timeframe} round`);
110
+ let priceAtStart;
111
+ let currentPrice;
112
+ try {
113
+ const client = getMarketClient();
114
+ const roundStartTimestamp = round.roundId.split('@Z')[0];
115
+ const [startResponse, nowResponse] = await Promise.all([
116
+ client.getPrice(round.projectId, roundStartTimestamp),
117
+ client.getPrice(round.projectId, new Date().toISOString()),
118
+ ]);
119
+ if (startResponse.price !== null) {
120
+ priceAtStart = startResponse.price;
121
+ }
122
+ if (nowResponse.price !== null) {
123
+ currentPrice = nowResponse.price;
124
+ }
125
+ }
126
+ catch {
127
+ // Price fetch failed — both stay undefined, prompt falls back to current behavior
128
+ }
129
+ if (priceAtStart !== undefined && currentPrice !== undefined) {
130
+ const changePercent = ((currentPrice - priceAtStart) / priceAtStart) * 100;
131
+ const sign = changePercent >= 0 ? '+' : '';
132
+ console.log(`[${timestamp()}] round-start: $${priceAtStart} → current: $${currentPrice} (${sign}${changePercent.toFixed(2)}%)`);
133
+ }
134
+ else if (priceAtStart !== undefined) {
135
+ console.log(`[${timestamp()}] round-start price: $${priceAtStart}`);
136
+ }
137
+ console.log(`[${timestamp()}] researching c/${round.projectId}...`);
138
+ const result = await processMegathreadRound(round.projectId, round.durationMs, agent.recentComments, memoryRef, soulContent, strategyContent, skillTools, skillMetadata, priceAtStart, currentPrice);
139
+ totalInputTokens += result.usage.inputTokens;
140
+ totalOutputTokens += result.usage.outputTokens;
141
+ totalToolCalls += result.usage.toolCalls;
142
+ if (result.usage.toolCalls > 0) {
143
+ const toolNames = result.usage.toolNames.join(', ');
144
+ console.log(` tools: ${toolNames} (${result.usage.toolCalls} calls)`);
145
+ // logToolResults(result.usage.toolResults);
146
+ }
147
+ else {
148
+ console.log(` tools: none`);
149
+ }
150
+ if (result.skip) {
151
+ console.log(`[${timestamp()}] skipped c/${round.projectId} — outside expertise`);
152
+ console.log(formatUsageLine(result.usage));
153
+ return;
154
+ }
155
+ await agent.postMegathreadComment(round.roundId, {
156
+ text: result.summary,
157
+ conviction: result.conviction,
158
+ tokenId: round.projectId,
159
+ roundDuration: round.durationMs,
160
+ });
161
+ predictionCount += 1;
162
+ const sign = result.conviction >= 0 ? '+' : '';
163
+ const megathreadUrl = `${HIVE_FRONTEND_URL}/c/${round.projectId}/megathread/${timeframe}`;
164
+ console.log(`[${timestamp()}] megathread c/${round.projectId} [${sign}${result.conviction}%] "${result.summary}" (${predictionCount} total)`);
165
+ console.log(formatUsageLine(result.usage));
166
+ console.log(` ${megathreadUrl}`);
167
+ }
168
+ catch (err) {
169
+ const raw = err instanceof Error ? err.message : String(err);
170
+ const message = raw.length > 120 ? raw.slice(0, 120) + '\u2026' : raw;
171
+ console.error(`[${timestamp()}] error c/${round.projectId}: ${message}`);
172
+ }
173
+ },
174
+ });
175
+ const shutdown = async () => {
176
+ console.log(`[${config.name}] shutting down...`);
177
+ const sessionTotal = totalInputTokens + totalOutputTokens;
178
+ const toolInfo = totalToolCalls > 0 ? ` \u00b7 ${totalToolCalls} tool calls` : '';
179
+ console.log(`[${config.name}] session tokens: ${formatTokens(totalInputTokens)} in \u00b7 ${formatTokens(totalOutputTokens)} out (${formatTokens(sessionTotal)} total)${toolInfo}`);
180
+ await agent.stop();
181
+ process.exit(0);
182
+ };
183
+ process.on('SIGINT', () => void shutdown());
184
+ process.on('SIGTERM', () => void shutdown());
185
+ await agent.start();
186
+ const modelInfoResult = resolveModelInfo();
187
+ console.log(`[${config.name}] ${modelInfoResult.modelId} \u00d7 zData`);
188
+ console.log(`[${config.name}] agent online \u2014 "${config.bio ?? ''}"`);
189
+ }
@@ -0,0 +1,41 @@
1
+ export const colors = {
2
+ honey: '#F5A623',
3
+ honeyDark: '#D4891A',
4
+ honeyBright: '#FFD700',
5
+ white: '#FFFFFF',
6
+ gray: '#A6A6A6',
7
+ grayDim: '#555555',
8
+ green: '#27C587',
9
+ red: '#E14B4B',
10
+ wax: '#C45C5C',
11
+ cyan: '#22D3EE',
12
+ hot: '#FB923C',
13
+ controversial: '#C084FC',
14
+ };
15
+ export const symbols = {
16
+ hive: '\u2B21', // ⬡
17
+ diamond: '\u25C6', // ◆
18
+ diamondOpen: '\u25C7', // ◇
19
+ dot: '\u25CF', // ●
20
+ check: '\u2713', // ✓
21
+ cross: '\u2717', // ✗
22
+ arrow: '\u203A', // ›
23
+ circle: '\u25CB', // ○
24
+ };
25
+ export const border = {
26
+ horizontal: '\u2500', // ─
27
+ vertical: '\u2502', // │
28
+ topLeft: '\u250C', // ┌
29
+ topRight: '\u2510', // ┐
30
+ bottomLeft: '\u2514', // └
31
+ bottomRight: '\u2518', // ┘
32
+ teeLeft: '\u251C', // ├
33
+ teeRight: '\u2524', // ┤
34
+ };
35
+ export const animation = {
36
+ DATA_CHARS: '01\u25AA\u25AB\u2591\u2592',
37
+ HEX_CHARS: '\u2B21\u2B22',
38
+ TICK_MS: 120,
39
+ HEX_W: 8,
40
+ HEX_H: 4,
41
+ };
@@ -1,4 +1,4 @@
1
- import { HIVE_API_URL } from '../../../config/constant.js';
1
+ import { HIVE_API_URL } from '../../../config.js';
2
2
  /**
3
3
  * Client for the backend Market API.
4
4
  */
@@ -1,4 +1,4 @@
1
- import { HIVE_API_URL } from '../../../config/constant.js';
1
+ import { HIVE_API_URL } from '../../../config.js';
2
2
  export class MindshareClient {
3
3
  constructor(baseUrl = HIVE_API_URL) {
4
4
  this._baseUrl = baseUrl;
@@ -0,0 +1 @@
1
+ export {};
@@ -2,8 +2,8 @@ import fs from 'fs-extra';
2
2
  import path from 'path';
3
3
  import os from 'os';
4
4
  import axios from 'axios';
5
- import { AI_PROVIDERS } from '../ai-providers.js';
6
- import { HIVE_API_URL } from './constant.js';
5
+ import { AI_PROVIDERS } from './ai-providers.js';
6
+ import { HIVE_API_URL } from './config.js';
7
7
  function extractField(content, pattern) {
8
8
  const match = content.match(pattern);
9
9
  if (match === null) {
package/dist/avatar.js ADDED
@@ -0,0 +1,34 @@
1
+ import axios from 'axios';
2
+ import terminalImage from 'terminal-image';
3
+ const AVATAR_WIDTH = 6;
4
+ const AVATAR_HEIGHT = 3;
5
+ export async function renderAvatar(url) {
6
+ try {
7
+ const response = await axios.get(url, {
8
+ responseType: 'arraybuffer',
9
+ timeout: 5000,
10
+ });
11
+ const buffer = Buffer.from(response.data);
12
+ const rendered = await terminalImage.buffer(buffer, {
13
+ width: AVATAR_WIDTH,
14
+ height: AVATAR_HEIGHT,
15
+ preserveAspectRatio: true,
16
+ });
17
+ return rendered.trimEnd();
18
+ }
19
+ catch {
20
+ return null;
21
+ }
22
+ }
23
+ export async function renderAvatars(agents) {
24
+ const avatarMap = new Map();
25
+ const entries = agents.filter((a) => a.avatar_url);
26
+ const results = await Promise.all(entries.map((a) => renderAvatar(a.avatar_url)));
27
+ for (let i = 0; i < entries.length; i++) {
28
+ const rendered = results[i];
29
+ if (rendered !== null) {
30
+ avatarMap.set(entries[i].name, rendered);
31
+ }
32
+ }
33
+ return avatarMap;
34
+ }