@zhive/cli 0.5.0

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 (189) hide show
  1. package/README.md +118 -0
  2. package/dist/agent/analysis.js +160 -0
  3. package/dist/agent/app.js +122 -0
  4. package/dist/agent/chat-prompt.js +65 -0
  5. package/dist/agent/commands/registry.js +12 -0
  6. package/dist/agent/components/AsciiTicker.js +81 -0
  7. package/dist/agent/components/CommandInput.js +65 -0
  8. package/dist/agent/components/HoneycombBoot.js +291 -0
  9. package/dist/agent/components/Spinner.js +37 -0
  10. package/dist/agent/config.js +75 -0
  11. package/dist/agent/edit-section.js +59 -0
  12. package/dist/agent/fetch-rules.js +21 -0
  13. package/dist/agent/helpers.js +22 -0
  14. package/dist/agent/hooks/useAgent.js +480 -0
  15. package/dist/agent/memory-prompt.js +47 -0
  16. package/dist/agent/model.js +92 -0
  17. package/dist/agent/objects.js +1 -0
  18. package/dist/agent/process-lifecycle.js +18 -0
  19. package/dist/agent/prompt.js +353 -0
  20. package/dist/agent/run-headless.js +189 -0
  21. package/dist/agent/skills/index.js +2 -0
  22. package/dist/agent/skills/skill-parser.js +149 -0
  23. package/dist/agent/skills/types.js +1 -0
  24. package/dist/agent/theme.js +41 -0
  25. package/dist/agent/tools/index.js +76 -0
  26. package/dist/agent/tools/market/client.js +41 -0
  27. package/dist/agent/tools/market/index.js +3 -0
  28. package/dist/agent/tools/market/tools.js +518 -0
  29. package/dist/agent/tools/mindshare/client.js +124 -0
  30. package/dist/agent/tools/mindshare/index.js +3 -0
  31. package/dist/agent/tools/mindshare/tools.js +563 -0
  32. package/dist/agent/tools/read-skill-tool.js +30 -0
  33. package/dist/agent/tools/ta/index.js +1 -0
  34. package/dist/agent/tools/ta/indicators.js +201 -0
  35. package/dist/agent/types.js +1 -0
  36. package/dist/agents.js +110 -0
  37. package/dist/ai-providers.js +66 -0
  38. package/dist/avatar.js +34 -0
  39. package/dist/backtest/default-backtest-data.js +200 -0
  40. package/dist/backtest/fetch.js +41 -0
  41. package/dist/backtest/import.js +106 -0
  42. package/dist/backtest/index.js +10 -0
  43. package/dist/backtest/results.js +113 -0
  44. package/dist/backtest/runner.js +134 -0
  45. package/dist/backtest/storage.js +11 -0
  46. package/dist/backtest/types.js +1 -0
  47. package/dist/commands/create/ai-generate.js +126 -0
  48. package/dist/commands/create/commands/index.js +10 -0
  49. package/dist/commands/create/generate.js +73 -0
  50. package/dist/commands/create/presets/data.js +225 -0
  51. package/dist/commands/create/presets/formatting.js +81 -0
  52. package/dist/commands/create/presets/index.js +3 -0
  53. package/dist/commands/create/presets/options.js +307 -0
  54. package/dist/commands/create/presets/types.js +1 -0
  55. package/dist/commands/create/presets.js +613 -0
  56. package/dist/commands/create/ui/CreateApp.js +172 -0
  57. package/dist/commands/create/ui/steps/ApiKeyStep.js +89 -0
  58. package/dist/commands/create/ui/steps/AvatarStep.js +16 -0
  59. package/dist/commands/create/ui/steps/DoneStep.js +14 -0
  60. package/dist/commands/create/ui/steps/IdentityStep.js +125 -0
  61. package/dist/commands/create/ui/steps/NameStep.js +148 -0
  62. package/dist/commands/create/ui/steps/ScaffoldStep.js +59 -0
  63. package/dist/commands/create/ui/steps/SoulStep.js +21 -0
  64. package/dist/commands/create/ui/steps/StrategyStep.js +20 -0
  65. package/dist/commands/create/ui/steps/StreamingGenerationStep.js +56 -0
  66. package/dist/commands/create/ui/validation.js +34 -0
  67. package/dist/commands/create/validate-api-key.js +27 -0
  68. package/dist/commands/install.js +50 -0
  69. package/dist/commands/list/commands/index.js +7 -0
  70. package/dist/commands/list/ui/ListApp.js +79 -0
  71. package/dist/commands/migrate-templates/commands/index.js +9 -0
  72. package/dist/commands/migrate-templates/migrate.js +87 -0
  73. package/dist/commands/migrate-templates/ui/MigrateApp.js +132 -0
  74. package/dist/commands/run/commands/index.js +17 -0
  75. package/dist/commands/run/run-headless.js +111 -0
  76. package/dist/commands/shared/theme.js +57 -0
  77. package/dist/commands/shared/welcome.js +304 -0
  78. package/dist/commands/start/commands/backtest.js +35 -0
  79. package/dist/commands/start/commands/index.js +62 -0
  80. package/dist/commands/start/commands/prediction.js +73 -0
  81. package/dist/commands/start/commands/skills.js +44 -0
  82. package/dist/commands/start/commands/skills.test.js +140 -0
  83. package/dist/commands/start/hooks/types.js +1 -0
  84. package/dist/commands/start/hooks/useAgent.js +177 -0
  85. package/dist/commands/start/hooks/useChat.js +266 -0
  86. package/dist/commands/start/hooks/usePollActivity.js +45 -0
  87. package/dist/commands/start/hooks/utils.js +152 -0
  88. package/dist/commands/start/services/backtest/default-backtest-data.js +200 -0
  89. package/dist/commands/start/services/backtest/fetch.js +42 -0
  90. package/dist/commands/start/services/backtest/import.js +109 -0
  91. package/dist/commands/start/services/backtest/index.js +10 -0
  92. package/dist/commands/start/services/backtest/results.js +113 -0
  93. package/dist/commands/start/services/backtest/runner.js +103 -0
  94. package/dist/commands/start/services/backtest/storage.js +11 -0
  95. package/dist/commands/start/services/backtest/types.js +1 -0
  96. package/dist/commands/start/services/command-registry.js +13 -0
  97. package/dist/commands/start/ui/AsciiTicker.js +81 -0
  98. package/dist/commands/start/ui/CommandInput.js +65 -0
  99. package/dist/commands/start/ui/HoneycombBoot.js +291 -0
  100. package/dist/commands/start/ui/PollText.js +23 -0
  101. package/dist/commands/start/ui/PredictionsPanel.js +88 -0
  102. package/dist/commands/start/ui/SelectAgentApp.js +93 -0
  103. package/dist/commands/start/ui/Spinner.js +29 -0
  104. package/dist/commands/start/ui/SpinnerContext.js +20 -0
  105. package/dist/commands/start/ui/app.js +36 -0
  106. package/dist/commands/start-all/AgentProcessManager.js +98 -0
  107. package/dist/commands/start-all/commands/index.js +24 -0
  108. package/dist/commands/start-all/ui/Dashboard.js +91 -0
  109. package/dist/components/AsciiTicker.js +81 -0
  110. package/dist/components/CharacterSummaryCard.js +33 -0
  111. package/dist/components/CodeBlock.js +11 -0
  112. package/dist/components/ColoredStats.js +18 -0
  113. package/dist/components/Header.js +10 -0
  114. package/dist/components/HoneycombLoader.js +190 -0
  115. package/dist/components/InputGuard.js +6 -0
  116. package/dist/components/MultiSelectPrompt.js +45 -0
  117. package/dist/components/SelectPrompt.js +20 -0
  118. package/dist/components/Spinner.js +16 -0
  119. package/dist/components/StepIndicator.js +31 -0
  120. package/dist/components/StreamingText.js +50 -0
  121. package/dist/components/TextPrompt.js +28 -0
  122. package/dist/components/stdout-spinner.js +48 -0
  123. package/dist/config.js +28 -0
  124. package/dist/create/CreateApp.js +153 -0
  125. package/dist/create/ai-generate.js +147 -0
  126. package/dist/create/generate.js +73 -0
  127. package/dist/create/steps/ApiKeyStep.js +97 -0
  128. package/dist/create/steps/AvatarStep.js +16 -0
  129. package/dist/create/steps/BioStep.js +14 -0
  130. package/dist/create/steps/DoneStep.js +14 -0
  131. package/dist/create/steps/IdentityStep.js +163 -0
  132. package/dist/create/steps/NameStep.js +71 -0
  133. package/dist/create/steps/ScaffoldStep.js +58 -0
  134. package/dist/create/steps/SoulStep.js +58 -0
  135. package/dist/create/steps/StrategyStep.js +58 -0
  136. package/dist/create/validate-api-key.js +47 -0
  137. package/dist/create/welcome.js +304 -0
  138. package/dist/index.js +60 -0
  139. package/dist/list/ListApp.js +79 -0
  140. package/dist/load-agent-env.js +30 -0
  141. package/dist/migrate-templates/MigrateApp.js +131 -0
  142. package/dist/migrate-templates/migrate.js +86 -0
  143. package/dist/presets.js +613 -0
  144. package/dist/shared/agent/agent-runtime.js +144 -0
  145. package/dist/shared/agent/analysis.js +171 -0
  146. package/dist/shared/agent/helpers.js +1 -0
  147. package/dist/shared/agent/prompts/chat-prompt.js +60 -0
  148. package/dist/shared/agent/prompts/megathread.js +202 -0
  149. package/dist/shared/agent/prompts/memory-prompt.js +47 -0
  150. package/dist/shared/agent/prompts/prompt.js +18 -0
  151. package/dist/shared/agent/skills/index.js +2 -0
  152. package/dist/shared/agent/skills/skill-parser.js +167 -0
  153. package/dist/shared/agent/skills/skill-parser.test.js +190 -0
  154. package/dist/shared/agent/skills/types.js +1 -0
  155. package/dist/shared/agent/tools/edit-section.js +60 -0
  156. package/dist/shared/agent/tools/execute-skill-tool.js +134 -0
  157. package/dist/shared/agent/tools/fetch-rules.js +22 -0
  158. package/dist/shared/agent/tools/formatting.js +48 -0
  159. package/dist/shared/agent/tools/index.js +87 -0
  160. package/dist/shared/agent/tools/market/client.js +41 -0
  161. package/dist/shared/agent/tools/market/index.js +3 -0
  162. package/dist/shared/agent/tools/market/tools.js +497 -0
  163. package/dist/shared/agent/tools/mindshare/client.js +124 -0
  164. package/dist/shared/agent/tools/mindshare/index.js +3 -0
  165. package/dist/shared/agent/tools/mindshare/tools.js +167 -0
  166. package/dist/shared/agent/tools/read-skill-tool.js +30 -0
  167. package/dist/shared/agent/tools/ta/index.js +1 -0
  168. package/dist/shared/agent/tools/ta/indicators.js +201 -0
  169. package/dist/shared/agent/types.js +1 -0
  170. package/dist/shared/agent/utils.js +43 -0
  171. package/dist/shared/config/agent.js +177 -0
  172. package/dist/shared/config/ai-providers.js +156 -0
  173. package/dist/shared/config/config.js +22 -0
  174. package/dist/shared/config/constant.js +8 -0
  175. package/dist/shared/config/env-loader.js +30 -0
  176. package/dist/shared/types.js +1 -0
  177. package/dist/start/AgentProcessManager.js +98 -0
  178. package/dist/start/Dashboard.js +92 -0
  179. package/dist/start/SelectAgentApp.js +81 -0
  180. package/dist/start/StartApp.js +189 -0
  181. package/dist/start/patch-headless.js +101 -0
  182. package/dist/start/patch-managed-mode.js +142 -0
  183. package/dist/start/start-command.js +24 -0
  184. package/dist/theme.js +54 -0
  185. package/package.json +68 -0
  186. package/templates/components/HoneycombBoot.tsx +343 -0
  187. package/templates/fetch-rules.ts +23 -0
  188. package/templates/skills/mindshare/SKILL.md +197 -0
  189. package/templates/skills/ta/SKILL.md +179 -0
@@ -0,0 +1,103 @@
1
+ import { processMegathreadRound } from '../../../../shared/agent/analysis.js';
2
+ import { initializeAgentRuntime } from '../../../../shared/agent/agent-runtime.js';
3
+ /**
4
+ * Run a backtest against an agent configuration.
5
+ */
6
+ export async function runBacktest(backtest, config, callbacks) {
7
+ const runtime = await initializeAgentRuntime(config.agentPath);
8
+ const threads = backtest.threads;
9
+ const results = [];
10
+ for (let i = 0; i < threads.length; i++) {
11
+ const thread = threads[i];
12
+ callbacks?.onThreadStart?.(i, threads.length, thread);
13
+ // Run megathread analysis
14
+ const defaultDurationMs = 3 * 60 * 60 * 1000; // 3h default backtest window
15
+ const analysisResult = await processMegathreadRound({
16
+ projectId: thread.project_id,
17
+ durationMs: defaultDurationMs,
18
+ recentComments: [],
19
+ agentRuntime: runtime,
20
+ priceAtStart: thread.price_on_fetch,
21
+ currentPrice: thread.price_on_eval,
22
+ });
23
+ // Calculate actual price change
24
+ const actualPriceChangePercent = calculatePriceChange(thread.price_on_fetch, thread.price_on_eval);
25
+ // Build result
26
+ const result = buildThreadResult(i, thread, analysisResult, actualPriceChangePercent);
27
+ results.push(result);
28
+ callbacks?.onThreadComplete?.(i, result);
29
+ }
30
+ // Calculate summary statistics
31
+ const runResult = buildRunResult(backtest.metadata.id, runtime.config.name, results);
32
+ return runResult;
33
+ }
34
+ /**
35
+ * Calculate percentage price change.
36
+ */
37
+ function calculatePriceChange(priceOnFetch, priceOnEval) {
38
+ const change = ((priceOnEval - priceOnFetch) / priceOnFetch) * 100;
39
+ return change;
40
+ }
41
+ /**
42
+ * Build a thread result from analysis output.
43
+ */
44
+ function buildThreadResult(index, thread, analysis, actualPriceChangePercent) {
45
+ if (analysis.skip) {
46
+ return {
47
+ thread_index: index,
48
+ project_id: thread.project_id,
49
+ project_name: thread.project_name,
50
+ thread_text: thread.text,
51
+ predicted_conviction: 0,
52
+ predicted_summary: '',
53
+ skipped: true,
54
+ actual_price_change_percent: actualPriceChangePercent,
55
+ direction_correct: null,
56
+ absolute_error: null,
57
+ };
58
+ }
59
+ // Determine direction correctness
60
+ const predictedDirection = Math.sign(analysis.conviction);
61
+ const actualDirection = Math.sign(actualPriceChangePercent);
62
+ const directionCorrect = predictedDirection === actualDirection;
63
+ // Calculate absolute error
64
+ const absoluteError = Math.abs(analysis.conviction - actualPriceChangePercent);
65
+ return {
66
+ thread_index: index,
67
+ project_id: thread.project_id,
68
+ project_name: thread.project_name,
69
+ thread_text: thread.text,
70
+ predicted_conviction: analysis.conviction,
71
+ predicted_summary: analysis.summary,
72
+ skipped: false,
73
+ actual_price_change_percent: actualPriceChangePercent,
74
+ direction_correct: directionCorrect,
75
+ absolute_error: absoluteError,
76
+ };
77
+ }
78
+ /**
79
+ * Build the final run result with summary statistics.
80
+ */
81
+ function buildRunResult(backtestId, agentName, results) {
82
+ const totalThreads = results.length;
83
+ const predictedResults = results.filter((r) => !r.skipped);
84
+ const threadsPredicted = predictedResults.length;
85
+ const threadsSkipped = totalThreads - threadsPredicted;
86
+ // Calculate direction accuracy
87
+ const correctDirections = predictedResults.filter((r) => r.direction_correct === true).length;
88
+ const directionAccuracy = threadsPredicted > 0 ? (correctDirections / threadsPredicted) * 100 : 0;
89
+ // Calculate mean absolute error
90
+ const totalError = predictedResults.reduce((sum, r) => sum + (r.absolute_error ?? 0), 0);
91
+ const meanAbsoluteError = threadsPredicted > 0 ? totalError / threadsPredicted : 0;
92
+ return {
93
+ backtest_id: backtestId,
94
+ agent_name: agentName,
95
+ run_at: new Date().toISOString(),
96
+ thread_results: results,
97
+ total_threads: totalThreads,
98
+ threads_predicted: threadsPredicted,
99
+ threads_skipped: threadsSkipped,
100
+ direction_accuracy: directionAccuracy,
101
+ mean_absolute_error: meanAbsoluteError,
102
+ };
103
+ }
@@ -0,0 +1,11 @@
1
+ import { DEFAULT_BACKTEST_DATA } from './default-backtest-data.js';
2
+ /**
3
+ * ID for the bundled default backtest dataset.
4
+ */
5
+ export const DEFAULT_BACKTEST_ID = 'default';
6
+ /**
7
+ * Load the bundled default backtest dataset.
8
+ */
9
+ export function loadDefaultBacktest() {
10
+ return DEFAULT_BACKTEST_DATA;
11
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,13 @@
1
+ export const SLASH_COMMANDS = [
2
+ { name: '/skills', description: 'List available skills' },
3
+ { name: '/help', description: 'Show available commands' },
4
+ { name: '/clear', description: 'Clear chat history' },
5
+ { name: '/memory', description: 'Show current memory state' },
6
+ { name: '/backtest', description: 'Run agent against test set (/backtest <num> fetches from API)' },
7
+ { name: '/prediction', description: 'Show your last 10 resolved predictions' },
8
+ ];
9
+ export function filterCommands(prefix) {
10
+ const lowerPrefix = prefix.toLowerCase();
11
+ const filtered = SLASH_COMMANDS.filter((cmd) => cmd.name.toLowerCase().startsWith(lowerPrefix));
12
+ return filtered;
13
+ }
@@ -0,0 +1,81 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState, useEffect } from 'react';
3
+ import { Box, Text } from 'ink';
4
+ import { animation, colors } from '../../shared/theme.js';
5
+ function buildTickerChars(step) {
6
+ const stepStr = String(step).padStart(2, '0');
7
+ const digits = stepStr.split('');
8
+ return animation.HEX_CHARS + digits.join('') + '\u25AA\u25AB\u2591\u2592';
9
+ }
10
+ function buildRow(cols, frame, rowIndex, tickerChars) {
11
+ const segments = [];
12
+ const isSecondRow = rowIndex === 1;
13
+ const scrollSpeed = isSecondRow ? 3 : 2;
14
+ const direction = isSecondRow ? -1 : 1;
15
+ const sinFreq = isSecondRow ? 0.4 : 0.3;
16
+ const sinPhase = isSecondRow ? -0.4 : 0.6;
17
+ const wrapLen = cols * 2;
18
+ for (let c = 0; c < cols; c++) {
19
+ const scrolledC = direction === 1
20
+ ? (c + frame * scrollSpeed) % wrapLen
21
+ : (cols - c + frame * scrollSpeed) % wrapLen;
22
+ const charIdx = scrolledC % tickerChars.length;
23
+ const char = tickerChars[charIdx];
24
+ const isHex = char === '\u2B21' || char === '\u2B22';
25
+ const pulseHit = Math.sin((c + frame * sinPhase) * sinFreq) > 0.5;
26
+ // Edge fade: dim the outermost 4 columns
27
+ const edgeDist = Math.min(c, cols - 1 - c);
28
+ if (edgeDist < 2) {
29
+ segments.push({ char: '\u00B7', color: colors.grayDim });
30
+ continue;
31
+ }
32
+ if (edgeDist < 4) {
33
+ segments.push({ char, color: colors.grayDim });
34
+ continue;
35
+ }
36
+ if (pulseHit && isHex) {
37
+ segments.push({ char, color: colors.honey });
38
+ }
39
+ else if (pulseHit) {
40
+ segments.push({ char, color: colors.green });
41
+ }
42
+ else {
43
+ segments.push({ char, color: colors.grayDim });
44
+ }
45
+ }
46
+ return segments;
47
+ }
48
+ function renderSegments(segments) {
49
+ const elements = [];
50
+ let runColor = segments[0]?.color ?? colors.grayDim;
51
+ let runChars = '';
52
+ for (let i = 0; i < segments.length; i++) {
53
+ const seg = segments[i];
54
+ if (seg.color === runColor) {
55
+ runChars += seg.char;
56
+ }
57
+ else {
58
+ elements.push(_jsx(Text, { color: runColor, children: runChars }, `${elements.length}`));
59
+ runColor = seg.color;
60
+ runChars = seg.char;
61
+ }
62
+ }
63
+ if (runChars.length > 0) {
64
+ elements.push(_jsx(Text, { color: runColor, children: runChars }, `${elements.length}`));
65
+ }
66
+ return elements;
67
+ }
68
+ export function AsciiTicker({ rows = 1, step = 1 }) {
69
+ const [frame, setFrame] = useState(0);
70
+ const cols = process.stdout.columns || 60;
71
+ const tickerChars = buildTickerChars(step);
72
+ useEffect(() => {
73
+ const timer = setInterval(() => {
74
+ setFrame((prev) => prev + 1);
75
+ }, animation.TICK_MS);
76
+ return () => {
77
+ clearInterval(timer);
78
+ };
79
+ }, []);
80
+ return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: renderSegments(buildRow(cols, frame, 0, tickerChars)) }), rows === 2 && _jsx(Text, { children: renderSegments(buildRow(cols, frame, 1, tickerChars)) })] }));
81
+ }
@@ -0,0 +1,65 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { useState, useCallback, useMemo } from 'react';
3
+ import { Box, Text, useInput } from 'ink';
4
+ import TextInput from 'ink-text-input';
5
+ import { filterCommands } from '../services/command-registry.js';
6
+ import { colors, symbols } from '../../shared/theme.js';
7
+ export function CommandInput({ value, onChange, onSubmit, placeholder, }) {
8
+ const [selectedIndex, setSelectedIndex] = useState(0);
9
+ // Determine if autocomplete should be active
10
+ const isAutocompleteActive = value.startsWith('/') && !value.includes(' ');
11
+ // Get filtered commands
12
+ const filteredCommands = useMemo(() => {
13
+ if (!isAutocompleteActive) {
14
+ return [];
15
+ }
16
+ const commands = filterCommands(value);
17
+ return commands;
18
+ }, [value, isAutocompleteActive]);
19
+ // Reset selection when filtered commands change
20
+ const commandCount = filteredCommands.length;
21
+ const safeSelectedIndex = commandCount > 0 ? Math.min(selectedIndex, commandCount - 1) : 0;
22
+ const handleChange = useCallback((newValue) => {
23
+ onChange(newValue);
24
+ setSelectedIndex(0);
25
+ }, [onChange]);
26
+ const handleSubmit = useCallback((submittedValue) => {
27
+ // If autocomplete is active and there are matches, complete first
28
+ if (isAutocompleteActive && filteredCommands.length > 0) {
29
+ const selected = filteredCommands[safeSelectedIndex];
30
+ if (selected && submittedValue !== selected.name) {
31
+ onChange(selected.name);
32
+ onSubmit(selected.name);
33
+ return;
34
+ }
35
+ }
36
+ onSubmit(submittedValue);
37
+ }, [isAutocompleteActive, filteredCommands, safeSelectedIndex, onChange, onSubmit]);
38
+ useInput((input, key) => {
39
+ if (!isAutocompleteActive || filteredCommands.length === 0) {
40
+ return;
41
+ }
42
+ if (key.upArrow) {
43
+ setSelectedIndex((prev) => (prev > 0 ? prev - 1 : commandCount - 1));
44
+ }
45
+ else if (key.downArrow) {
46
+ setSelectedIndex((prev) => (prev < commandCount - 1 ? prev + 1 : 0));
47
+ }
48
+ else if (key.tab) {
49
+ // Tab to complete without submitting
50
+ const selected = filteredCommands[safeSelectedIndex];
51
+ if (selected) {
52
+ onChange(selected.name);
53
+ }
54
+ }
55
+ else if (key.escape) {
56
+ // Escape to clear input
57
+ onChange('');
58
+ setSelectedIndex(0);
59
+ }
60
+ }, { isActive: isAutocompleteActive && filteredCommands.length > 0 });
61
+ return (_jsxs(Box, { flexDirection: "column", children: [isAutocompleteActive && filteredCommands.length > 0 && (_jsx(Box, { flexDirection: "column", marginBottom: 0, marginLeft: 2, children: filteredCommands.map((cmd, index) => {
62
+ const isSelected = index === safeSelectedIndex;
63
+ return (_jsxs(Box, { children: [_jsxs(Text, { color: isSelected ? colors.honey : colors.gray, children: [isSelected ? symbols.diamond : ' ', ' '] }), _jsx(Text, { color: isSelected ? colors.honey : colors.white, children: cmd.name }), _jsxs(Text, { color: colors.gray, children: [" - ", cmd.description] })] }, cmd.name));
64
+ }) })), _jsxs(Box, { children: [_jsxs(Text, { color: colors.honey, children: [symbols.arrow, " "] }), _jsx(TextInput, { value: value, onChange: handleChange, onSubmit: handleSubmit, placeholder: placeholder })] })] }));
65
+ }
@@ -0,0 +1,291 @@
1
+ import chalk from 'chalk';
2
+ import { animation, colors } from '../../shared/theme.js';
3
+ const BOOT_TOTAL_FRAMES = 58;
4
+ const BOOT_FRAME_MS = 80;
5
+ const DURATION_MS = BOOT_TOTAL_FRAMES * BOOT_FRAME_MS;
6
+ const NUM_BEES = 4;
7
+ const NUM_STREAMS = 5;
8
+ const SCRAMBLE_CHARS = '\u2B21\u2B22\u25C6\u25C7\u2591\u2592!@#$%01';
9
+ const BOOT_MESSAGES = [
10
+ { prefix: '\u2B21', text: 'Initializing {name} agent...', frame: 30 },
11
+ { prefix: '\u25C6', text: 'Loading personality matrix...', frame: 36 },
12
+ { prefix: '\u25C7', text: 'Connecting to the hive...', frame: 42 },
13
+ { prefix: '\u2713', text: 'Neural link established', frame: 48 },
14
+ ];
15
+ // ─── Private helpers ─────────────────────────────────
16
+ function isHexEdge(r, c) {
17
+ const rowInHex = ((r % animation.HEX_H) + animation.HEX_H) % animation.HEX_H;
18
+ const isOddHex = Math.floor(r / animation.HEX_H) % 2 === 1;
19
+ const colOffset = isOddHex ? animation.HEX_W / 2 : 0;
20
+ const colInHex = (((c - colOffset) % animation.HEX_W) + animation.HEX_W) % animation.HEX_W;
21
+ if (rowInHex === 0 || rowInHex === animation.HEX_H - 1) {
22
+ return colInHex >= 2 && colInHex <= 5;
23
+ }
24
+ if (rowInHex === 1 || rowInHex === 2) {
25
+ return colInHex === 1 || colInHex === 6;
26
+ }
27
+ return false;
28
+ }
29
+ // ─── Raw ANSI boot animation ────────────────────────
30
+ export function showHoneycombBoot(agentName) {
31
+ return new Promise((resolve) => {
32
+ const cols = process.stdout.columns || 60;
33
+ const gridRows = process.stdout.rows || 24;
34
+ let frame = 0;
35
+ // Init bees
36
+ const bees = [];
37
+ for (let i = 0; i < NUM_BEES; i++) {
38
+ bees.push({
39
+ r: Math.floor(Math.random() * gridRows),
40
+ c: Math.floor(Math.random() * cols),
41
+ vr: Math.random() > 0.5 ? 1 : -1,
42
+ vc: Math.random() > 0.5 ? 1 : -1,
43
+ });
44
+ }
45
+ // Init stream columns
46
+ const streamCols = [];
47
+ const spacing = Math.floor(cols / (NUM_STREAMS + 1));
48
+ for (let i = 1; i <= NUM_STREAMS; i++) {
49
+ streamCols.push(spacing * i);
50
+ }
51
+ let pulses = [];
52
+ // Text positioning
53
+ const centerR = Math.floor(gridRows / 2) - 2;
54
+ const centerC = Math.floor(cols / 2);
55
+ const nameText = `\u2B21 ${agentName} agent \u2B21`;
56
+ const nameStart = Math.max(0, centerC - Math.floor(nameText.length / 2));
57
+ const msgStartRow = centerR + 4;
58
+ // Quiet zone around text: no animation renders here
59
+ const PADDING_H = 3;
60
+ const PADDING_V = 1;
61
+ const longestMsg = BOOT_MESSAGES.reduce((max, m) => Math.max(max, m.prefix.length + 1 + m.text.replace('{name}', agentName).length), 0);
62
+ const msgLeftEdge = Math.floor((cols - longestMsg) / 2);
63
+ const msgRightEdge = msgLeftEdge + longestMsg;
64
+ const quietLeft = Math.min(nameStart, msgLeftEdge) - PADDING_H;
65
+ const quietRight = Math.max(nameStart + nameText.length, msgRightEdge) + PADDING_H;
66
+ const quietTop = centerR - 1 - PADDING_V;
67
+ const quietBottom = msgStartRow + BOOT_MESSAGES.length + PADDING_V;
68
+ // Hide cursor
69
+ process.stdout.write('\x1b[?25l');
70
+ // Clear screen
71
+ process.stdout.write('\x1b[2J');
72
+ function renderFrame() {
73
+ // Move cursor to top-left
74
+ process.stdout.write('\x1b[H');
75
+ // Advance bees every other frame
76
+ if (frame > 0 && frame % 2 === 0) {
77
+ for (const bee of bees) {
78
+ bee.r += bee.vr;
79
+ bee.c += bee.vc;
80
+ if (bee.r <= 0 || bee.r >= gridRows - 1) {
81
+ bee.vr *= -1;
82
+ bee.r = Math.max(0, Math.min(gridRows - 1, bee.r));
83
+ }
84
+ if (bee.c <= 0 || bee.c >= cols - 1) {
85
+ bee.vc *= -1;
86
+ bee.c = Math.max(0, Math.min(cols - 1, bee.c));
87
+ }
88
+ if (Math.random() > 0.3) {
89
+ bee.vc = Math.random() > 0.5 ? 1 : -1;
90
+ }
91
+ }
92
+ }
93
+ // Spawn pulses
94
+ if (frame % 4 === 0) {
95
+ for (let i = 0; i < 3; i++) {
96
+ const pr = Math.floor(Math.random() * gridRows);
97
+ const pc = Math.floor(Math.random() * cols);
98
+ if (isHexEdge(pr, pc)) {
99
+ const pulseColors = [colors.green, colors.red, colors.honey];
100
+ const color = pulseColors[Math.floor(Math.random() * pulseColors.length)];
101
+ pulses.push({ r: pr, c: pc, ttl: 8, color });
102
+ }
103
+ }
104
+ pulses = pulses.filter((p) => p.ttl > 0).map((p) => ({ ...p, ttl: p.ttl - 1 }));
105
+ }
106
+ // Build grid: char + color pairs
107
+ const charGrid = [];
108
+ const colorGrid = [];
109
+ for (let r = 0; r < gridRows; r++) {
110
+ const chars = [];
111
+ const clrs = [];
112
+ for (let c = 0; c < cols; c++) {
113
+ // Skip animation in quiet zone around text
114
+ const inQuietZone = r >= quietTop && r <= quietBottom && c >= quietLeft && c < quietRight;
115
+ if (inQuietZone) {
116
+ chars.push(' ');
117
+ clrs.push(colors.grayDim);
118
+ continue;
119
+ }
120
+ const hexEdge = isHexEdge(r, c);
121
+ // Scanning wave
122
+ const scanRow = frame % (gridRows + 6);
123
+ const dist = Math.abs(r - scanRow);
124
+ if (hexEdge && dist === 0) {
125
+ chars.push('\u2B22');
126
+ clrs.push(colors.honey);
127
+ continue;
128
+ }
129
+ if (hexEdge && dist <= 1) {
130
+ chars.push('\u2B21');
131
+ clrs.push(colors.honey);
132
+ continue;
133
+ }
134
+ // Data streams
135
+ let isStream = false;
136
+ if (frame >= 8) {
137
+ for (const sc of streamCols) {
138
+ if (c === sc) {
139
+ const streamOffset = ((frame - 8) * 2 + sc) % (gridRows * 3);
140
+ const streamDist = (((r - streamOffset) % gridRows) + gridRows) % gridRows;
141
+ if (streamDist < 6) {
142
+ const charIdx = (frame + r) % animation.DATA_CHARS.length;
143
+ const streamChar = animation.DATA_CHARS[charIdx];
144
+ chars.push(streamChar);
145
+ if (streamDist === 0) {
146
+ clrs.push(colors.white);
147
+ }
148
+ else if (streamDist < 3) {
149
+ clrs.push(colors.green);
150
+ }
151
+ else {
152
+ clrs.push(colors.grayDim);
153
+ }
154
+ isStream = true;
155
+ break;
156
+ }
157
+ }
158
+ }
159
+ }
160
+ if (isStream)
161
+ continue;
162
+ // Default
163
+ if (hexEdge) {
164
+ chars.push('\u00B7');
165
+ clrs.push(colors.grayDim);
166
+ }
167
+ else {
168
+ chars.push(' ');
169
+ clrs.push(colors.grayDim);
170
+ }
171
+ }
172
+ charGrid.push(chars);
173
+ colorGrid.push(clrs);
174
+ }
175
+ // Overlay pulses (skip quiet zone)
176
+ for (const pulse of pulses) {
177
+ if (pulse.r >= 0 && pulse.r < gridRows && pulse.c >= 0 && pulse.c < cols) {
178
+ const inQuietZone = pulse.r >= quietTop &&
179
+ pulse.r <= quietBottom &&
180
+ pulse.c >= quietLeft &&
181
+ pulse.c < quietRight;
182
+ if (inQuietZone)
183
+ continue;
184
+ const brightness = pulse.ttl / 8;
185
+ const cell = charGrid[pulse.r][pulse.c];
186
+ if (cell === '\u00B7' || cell === ' ') {
187
+ charGrid[pulse.r][pulse.c] = brightness > 0.5 ? '\u2B21' : '\u00B7';
188
+ colorGrid[pulse.r][pulse.c] = pulse.color;
189
+ }
190
+ }
191
+ }
192
+ // Overlay bees (skip quiet zone)
193
+ for (const bee of bees) {
194
+ const br = Math.max(0, Math.min(gridRows - 1, Math.round(bee.r)));
195
+ const bc = Math.max(0, Math.min(cols - 1, Math.round(bee.c)));
196
+ const inQuietZone = br >= quietTop && br <= quietBottom && bc >= quietLeft && bc < quietRight;
197
+ if (!inQuietZone) {
198
+ charGrid[br][bc] = '\u25C6';
199
+ colorGrid[br][bc] = colors.honey;
200
+ }
201
+ }
202
+ // Overlay agent name with scramble→reveal effect
203
+ if (frame >= 22) {
204
+ const scrambleProgress = Math.min(1, (frame - 22) / 8);
205
+ // Top/bottom border lines around name
206
+ for (let c = nameStart; c < nameStart + nameText.length && c < cols; c++) {
207
+ if (centerR - 1 >= 0) {
208
+ charGrid[centerR - 1][c] = '\u2500';
209
+ colorGrid[centerR - 1][c] = colors.honey;
210
+ }
211
+ if (centerR + 1 < gridRows) {
212
+ charGrid[centerR + 1][c] = '\u2500';
213
+ colorGrid[centerR + 1][c] = colors.honey;
214
+ }
215
+ }
216
+ // Name text with scramble effect
217
+ for (let i = 0; i < nameText.length; i++) {
218
+ const c = nameStart + i;
219
+ if (c >= cols)
220
+ break;
221
+ const charThreshold = i / nameText.length;
222
+ if (charThreshold <= scrambleProgress) {
223
+ charGrid[centerR][c] = nameText[i];
224
+ colorGrid[centerR][c] = colors.honey;
225
+ }
226
+ else {
227
+ const scrambleIdx = Math.floor(Math.random() * SCRAMBLE_CHARS.length);
228
+ charGrid[centerR][c] = SCRAMBLE_CHARS[scrambleIdx];
229
+ colorGrid[centerR][c] = colors.gray;
230
+ }
231
+ }
232
+ }
233
+ // Overlay typewriter boot messages
234
+ for (let idx = 0; idx < BOOT_MESSAGES.length; idx++) {
235
+ const msg = BOOT_MESSAGES[idx];
236
+ if (frame < msg.frame)
237
+ continue;
238
+ const r = msgStartRow + idx;
239
+ if (r < 0 || r >= gridRows)
240
+ continue;
241
+ const fullText = `${msg.prefix} ${msg.text.replace('{name}', agentName)}`;
242
+ const msgCol = Math.floor((cols - fullText.length) / 2);
243
+ const visibleChars = Math.min(fullText.length, (frame - msg.frame) * 3);
244
+ const isCheckmark = msg.prefix === '\u2713';
245
+ const msgColor = isCheckmark ? colors.green : colors.honey;
246
+ for (let i = 0; i < visibleChars; i++) {
247
+ const c = msgCol + i;
248
+ if (c < 0 || c >= cols)
249
+ continue;
250
+ charGrid[r][c] = fullText[i];
251
+ colorGrid[r][c] = msgColor;
252
+ }
253
+ }
254
+ // Render to stdout
255
+ let output = '';
256
+ for (let r = 0; r < gridRows; r++) {
257
+ let line = '';
258
+ let runColor = colorGrid[r][0];
259
+ let runChars = '';
260
+ for (let c = 0; c < cols; c++) {
261
+ const curColor = colorGrid[r][c];
262
+ const curChar = charGrid[r][c];
263
+ if (curColor === runColor) {
264
+ runChars += curChar;
265
+ }
266
+ else {
267
+ line += chalk.hex(runColor)(runChars);
268
+ runColor = curColor;
269
+ runChars = curChar;
270
+ }
271
+ }
272
+ if (runChars.length > 0) {
273
+ line += chalk.hex(runColor)(runChars);
274
+ }
275
+ output += line;
276
+ if (r < gridRows - 1) {
277
+ output += '\n';
278
+ }
279
+ }
280
+ process.stdout.write(output);
281
+ frame++;
282
+ }
283
+ const timer = setInterval(renderFrame, BOOT_FRAME_MS);
284
+ setTimeout(() => {
285
+ clearInterval(timer);
286
+ // Clear screen, show cursor, move to top
287
+ process.stdout.write('\x1b[2J\x1b[H\x1b[?25h');
288
+ resolve();
289
+ }, DURATION_MS);
290
+ });
291
+ }
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useState, useEffect } from 'react';
3
+ import { Text } from 'ink';
4
+ export function TypewriterText({ text, color, speed = 25, }) {
5
+ const [visible, setVisible] = useState(0);
6
+ useEffect(() => {
7
+ if (visible >= text.length)
8
+ return;
9
+ const timer = setTimeout(() => {
10
+ setVisible((prev) => Math.min(prev + 2, text.length));
11
+ }, speed);
12
+ return () => {
13
+ clearTimeout(timer);
14
+ };
15
+ }, [visible, text, speed]);
16
+ return _jsx(Text, { color: color, children: text.slice(0, visible) });
17
+ }
18
+ export function PollText({ text, color, animate, }) {
19
+ if (animate) {
20
+ return _jsx(TypewriterText, { text: text, color: color });
21
+ }
22
+ return _jsx(Text, { color: color, children: text });
23
+ }