@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.
- package/README.md +118 -0
- package/dist/agent/analysis.js +160 -0
- package/dist/agent/app.js +122 -0
- package/dist/agent/chat-prompt.js +65 -0
- package/dist/agent/commands/registry.js +12 -0
- package/dist/agent/components/AsciiTicker.js +81 -0
- package/dist/agent/components/CommandInput.js +65 -0
- package/dist/agent/components/HoneycombBoot.js +291 -0
- package/dist/agent/components/Spinner.js +37 -0
- package/dist/agent/config.js +75 -0
- package/dist/agent/edit-section.js +59 -0
- package/dist/agent/fetch-rules.js +21 -0
- package/dist/agent/helpers.js +22 -0
- package/dist/agent/hooks/useAgent.js +480 -0
- package/dist/agent/memory-prompt.js +47 -0
- package/dist/agent/model.js +92 -0
- package/dist/agent/objects.js +1 -0
- package/dist/agent/process-lifecycle.js +18 -0
- package/dist/agent/prompt.js +353 -0
- package/dist/agent/run-headless.js +189 -0
- package/dist/agent/skills/index.js +2 -0
- package/dist/agent/skills/skill-parser.js +149 -0
- package/dist/agent/skills/types.js +1 -0
- package/dist/agent/theme.js +41 -0
- package/dist/agent/tools/index.js +76 -0
- package/dist/agent/tools/market/client.js +41 -0
- package/dist/agent/tools/market/index.js +3 -0
- package/dist/agent/tools/market/tools.js +518 -0
- package/dist/agent/tools/mindshare/client.js +124 -0
- package/dist/agent/tools/mindshare/index.js +3 -0
- package/dist/agent/tools/mindshare/tools.js +563 -0
- package/dist/agent/tools/read-skill-tool.js +30 -0
- package/dist/agent/tools/ta/index.js +1 -0
- package/dist/agent/tools/ta/indicators.js +201 -0
- package/dist/agent/types.js +1 -0
- package/dist/agents.js +110 -0
- package/dist/ai-providers.js +66 -0
- package/dist/avatar.js +34 -0
- package/dist/backtest/default-backtest-data.js +200 -0
- package/dist/backtest/fetch.js +41 -0
- package/dist/backtest/import.js +106 -0
- package/dist/backtest/index.js +10 -0
- package/dist/backtest/results.js +113 -0
- package/dist/backtest/runner.js +134 -0
- package/dist/backtest/storage.js +11 -0
- package/dist/backtest/types.js +1 -0
- package/dist/commands/create/ai-generate.js +126 -0
- package/dist/commands/create/commands/index.js +10 -0
- package/dist/commands/create/generate.js +73 -0
- package/dist/commands/create/presets/data.js +225 -0
- package/dist/commands/create/presets/formatting.js +81 -0
- package/dist/commands/create/presets/index.js +3 -0
- package/dist/commands/create/presets/options.js +307 -0
- package/dist/commands/create/presets/types.js +1 -0
- package/dist/commands/create/presets.js +613 -0
- package/dist/commands/create/ui/CreateApp.js +172 -0
- package/dist/commands/create/ui/steps/ApiKeyStep.js +89 -0
- package/dist/commands/create/ui/steps/AvatarStep.js +16 -0
- package/dist/commands/create/ui/steps/DoneStep.js +14 -0
- package/dist/commands/create/ui/steps/IdentityStep.js +125 -0
- package/dist/commands/create/ui/steps/NameStep.js +148 -0
- package/dist/commands/create/ui/steps/ScaffoldStep.js +59 -0
- package/dist/commands/create/ui/steps/SoulStep.js +21 -0
- package/dist/commands/create/ui/steps/StrategyStep.js +20 -0
- package/dist/commands/create/ui/steps/StreamingGenerationStep.js +56 -0
- package/dist/commands/create/ui/validation.js +34 -0
- package/dist/commands/create/validate-api-key.js +27 -0
- package/dist/commands/install.js +50 -0
- package/dist/commands/list/commands/index.js +7 -0
- package/dist/commands/list/ui/ListApp.js +79 -0
- package/dist/commands/migrate-templates/commands/index.js +9 -0
- package/dist/commands/migrate-templates/migrate.js +87 -0
- package/dist/commands/migrate-templates/ui/MigrateApp.js +132 -0
- package/dist/commands/run/commands/index.js +17 -0
- package/dist/commands/run/run-headless.js +111 -0
- package/dist/commands/shared/theme.js +57 -0
- package/dist/commands/shared/welcome.js +304 -0
- package/dist/commands/start/commands/backtest.js +35 -0
- package/dist/commands/start/commands/index.js +62 -0
- package/dist/commands/start/commands/prediction.js +73 -0
- package/dist/commands/start/commands/skills.js +44 -0
- package/dist/commands/start/commands/skills.test.js +140 -0
- package/dist/commands/start/hooks/types.js +1 -0
- package/dist/commands/start/hooks/useAgent.js +177 -0
- package/dist/commands/start/hooks/useChat.js +266 -0
- package/dist/commands/start/hooks/usePollActivity.js +45 -0
- package/dist/commands/start/hooks/utils.js +152 -0
- package/dist/commands/start/services/backtest/default-backtest-data.js +200 -0
- package/dist/commands/start/services/backtest/fetch.js +42 -0
- package/dist/commands/start/services/backtest/import.js +109 -0
- package/dist/commands/start/services/backtest/index.js +10 -0
- package/dist/commands/start/services/backtest/results.js +113 -0
- package/dist/commands/start/services/backtest/runner.js +103 -0
- package/dist/commands/start/services/backtest/storage.js +11 -0
- package/dist/commands/start/services/backtest/types.js +1 -0
- package/dist/commands/start/services/command-registry.js +13 -0
- package/dist/commands/start/ui/AsciiTicker.js +81 -0
- package/dist/commands/start/ui/CommandInput.js +65 -0
- package/dist/commands/start/ui/HoneycombBoot.js +291 -0
- package/dist/commands/start/ui/PollText.js +23 -0
- package/dist/commands/start/ui/PredictionsPanel.js +88 -0
- package/dist/commands/start/ui/SelectAgentApp.js +93 -0
- package/dist/commands/start/ui/Spinner.js +29 -0
- package/dist/commands/start/ui/SpinnerContext.js +20 -0
- package/dist/commands/start/ui/app.js +36 -0
- package/dist/commands/start-all/AgentProcessManager.js +98 -0
- package/dist/commands/start-all/commands/index.js +24 -0
- package/dist/commands/start-all/ui/Dashboard.js +91 -0
- package/dist/components/AsciiTicker.js +81 -0
- package/dist/components/CharacterSummaryCard.js +33 -0
- package/dist/components/CodeBlock.js +11 -0
- package/dist/components/ColoredStats.js +18 -0
- package/dist/components/Header.js +10 -0
- package/dist/components/HoneycombLoader.js +190 -0
- package/dist/components/InputGuard.js +6 -0
- package/dist/components/MultiSelectPrompt.js +45 -0
- package/dist/components/SelectPrompt.js +20 -0
- package/dist/components/Spinner.js +16 -0
- package/dist/components/StepIndicator.js +31 -0
- package/dist/components/StreamingText.js +50 -0
- package/dist/components/TextPrompt.js +28 -0
- package/dist/components/stdout-spinner.js +48 -0
- package/dist/config.js +28 -0
- package/dist/create/CreateApp.js +153 -0
- package/dist/create/ai-generate.js +147 -0
- package/dist/create/generate.js +73 -0
- package/dist/create/steps/ApiKeyStep.js +97 -0
- package/dist/create/steps/AvatarStep.js +16 -0
- package/dist/create/steps/BioStep.js +14 -0
- package/dist/create/steps/DoneStep.js +14 -0
- package/dist/create/steps/IdentityStep.js +163 -0
- package/dist/create/steps/NameStep.js +71 -0
- package/dist/create/steps/ScaffoldStep.js +58 -0
- package/dist/create/steps/SoulStep.js +58 -0
- package/dist/create/steps/StrategyStep.js +58 -0
- package/dist/create/validate-api-key.js +47 -0
- package/dist/create/welcome.js +304 -0
- package/dist/index.js +60 -0
- package/dist/list/ListApp.js +79 -0
- package/dist/load-agent-env.js +30 -0
- package/dist/migrate-templates/MigrateApp.js +131 -0
- package/dist/migrate-templates/migrate.js +86 -0
- package/dist/presets.js +613 -0
- package/dist/shared/agent/agent-runtime.js +144 -0
- package/dist/shared/agent/analysis.js +171 -0
- package/dist/shared/agent/helpers.js +1 -0
- package/dist/shared/agent/prompts/chat-prompt.js +60 -0
- package/dist/shared/agent/prompts/megathread.js +202 -0
- package/dist/shared/agent/prompts/memory-prompt.js +47 -0
- package/dist/shared/agent/prompts/prompt.js +18 -0
- package/dist/shared/agent/skills/index.js +2 -0
- package/dist/shared/agent/skills/skill-parser.js +167 -0
- package/dist/shared/agent/skills/skill-parser.test.js +190 -0
- package/dist/shared/agent/skills/types.js +1 -0
- package/dist/shared/agent/tools/edit-section.js +60 -0
- package/dist/shared/agent/tools/execute-skill-tool.js +134 -0
- package/dist/shared/agent/tools/fetch-rules.js +22 -0
- package/dist/shared/agent/tools/formatting.js +48 -0
- package/dist/shared/agent/tools/index.js +87 -0
- package/dist/shared/agent/tools/market/client.js +41 -0
- package/dist/shared/agent/tools/market/index.js +3 -0
- package/dist/shared/agent/tools/market/tools.js +497 -0
- package/dist/shared/agent/tools/mindshare/client.js +124 -0
- package/dist/shared/agent/tools/mindshare/index.js +3 -0
- package/dist/shared/agent/tools/mindshare/tools.js +167 -0
- package/dist/shared/agent/tools/read-skill-tool.js +30 -0
- package/dist/shared/agent/tools/ta/index.js +1 -0
- package/dist/shared/agent/tools/ta/indicators.js +201 -0
- package/dist/shared/agent/types.js +1 -0
- package/dist/shared/agent/utils.js +43 -0
- package/dist/shared/config/agent.js +177 -0
- package/dist/shared/config/ai-providers.js +156 -0
- package/dist/shared/config/config.js +22 -0
- package/dist/shared/config/constant.js +8 -0
- package/dist/shared/config/env-loader.js +30 -0
- package/dist/shared/types.js +1 -0
- package/dist/start/AgentProcessManager.js +98 -0
- package/dist/start/Dashboard.js +92 -0
- package/dist/start/SelectAgentApp.js +81 -0
- package/dist/start/StartApp.js +189 -0
- package/dist/start/patch-headless.js +101 -0
- package/dist/start/patch-managed-mode.js +142 -0
- package/dist/start/start-command.js +24 -0
- package/dist/theme.js +54 -0
- package/package.json +68 -0
- package/templates/components/HoneycombBoot.tsx +343 -0
- package/templates/fetch-rules.ts +23 -0
- package/templates/skills/mindshare/SKILL.md +197 -0
- package/templates/skills/ta/SKILL.md +179 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
import { colors, symbols, border } from '../commands/shared/theme.js';
|
|
4
|
+
export function Header() {
|
|
5
|
+
const leftPart = ` ${symbols.hive} Hive `;
|
|
6
|
+
const termWidth = process.stdout.columns || 60;
|
|
7
|
+
const fillerWidth = Math.max(0, termWidth - leftPart.length - 4);
|
|
8
|
+
const filler = border.horizontal.repeat(fillerWidth);
|
|
9
|
+
return (_jsx(Box, { flexDirection: "column", marginBottom: 0, children: _jsxs(Text, { children: [_jsx(Text, { color: colors.honey, bold: true, children: leftPart }), _jsxs(Text, { color: colors.grayDim, children: [border.horizontal, border.horizontal, border.horizontal, filler] })] }) }));
|
|
10
|
+
}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect, useRef } from 'react';
|
|
3
|
+
import { Box, Text } from 'ink';
|
|
4
|
+
import { colors, animation } from '../commands/shared/theme.js';
|
|
5
|
+
const ROWS = 3;
|
|
6
|
+
const HEX_W = 8;
|
|
7
|
+
const HEX_H = 4;
|
|
8
|
+
const NUM_BEES = 3;
|
|
9
|
+
const NUM_STREAMS = 4;
|
|
10
|
+
const PULSE_SPAWN_INTERVAL = 4;
|
|
11
|
+
const PULSE_TTL = 8;
|
|
12
|
+
const PULSE_COLORS = [colors.green, colors.red, colors.honey];
|
|
13
|
+
function isHexEdge(r, c) {
|
|
14
|
+
const rowInHex = ((r % HEX_H) + HEX_H) % HEX_H;
|
|
15
|
+
const isOddHex = Math.floor(r / HEX_H) % 2 === 1;
|
|
16
|
+
const colOffset = isOddHex ? HEX_W / 2 : 0;
|
|
17
|
+
const colInHex = (((c - colOffset) % HEX_W) + HEX_W) % HEX_W;
|
|
18
|
+
if (rowInHex === 0 || rowInHex === HEX_H - 1) {
|
|
19
|
+
return colInHex >= 2 && colInHex <= 5;
|
|
20
|
+
}
|
|
21
|
+
if (rowInHex === 1 || rowInHex === 2) {
|
|
22
|
+
return colInHex === 1 || colInHex === 6;
|
|
23
|
+
}
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
function initBees(cols, gridRows) {
|
|
27
|
+
const bees = [];
|
|
28
|
+
for (let i = 0; i < NUM_BEES; i++) {
|
|
29
|
+
bees.push({
|
|
30
|
+
r: Math.floor(Math.random() * gridRows),
|
|
31
|
+
c: Math.floor(Math.random() * cols),
|
|
32
|
+
vr: Math.random() > 0.5 ? 1 : -1,
|
|
33
|
+
vc: Math.random() > 0.5 ? 1 : -1,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return bees;
|
|
37
|
+
}
|
|
38
|
+
function initStreamCols(cols) {
|
|
39
|
+
const streamCols = [];
|
|
40
|
+
const spacing = Math.floor(cols / (NUM_STREAMS + 1));
|
|
41
|
+
for (let i = 1; i <= NUM_STREAMS; i++) {
|
|
42
|
+
streamCols.push(spacing * i);
|
|
43
|
+
}
|
|
44
|
+
return streamCols;
|
|
45
|
+
}
|
|
46
|
+
export function HoneycombLoader({ label }) {
|
|
47
|
+
const [frame, setFrame] = useState(0);
|
|
48
|
+
const cols = process.stdout.columns || 60;
|
|
49
|
+
const gridRows = ROWS * HEX_H;
|
|
50
|
+
const beesRef = useRef(initBees(cols, gridRows));
|
|
51
|
+
const pulsesRef = useRef([]);
|
|
52
|
+
const streamColsRef = useRef(initStreamCols(cols));
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
const timer = setInterval(() => {
|
|
55
|
+
setFrame((prev) => prev + 1);
|
|
56
|
+
}, animation.TICK_MS);
|
|
57
|
+
return () => {
|
|
58
|
+
clearInterval(timer);
|
|
59
|
+
};
|
|
60
|
+
}, []);
|
|
61
|
+
// Advance bees every other frame
|
|
62
|
+
if (frame > 0 && frame % 2 === 0) {
|
|
63
|
+
const bees = beesRef.current;
|
|
64
|
+
for (const bee of bees) {
|
|
65
|
+
bee.r += bee.vr;
|
|
66
|
+
bee.c += bee.vc;
|
|
67
|
+
if (bee.r <= 0 || bee.r >= gridRows - 1) {
|
|
68
|
+
bee.vr *= -1;
|
|
69
|
+
bee.r = Math.max(0, Math.min(gridRows - 1, bee.r));
|
|
70
|
+
}
|
|
71
|
+
if (bee.c <= 0 || bee.c >= cols - 1) {
|
|
72
|
+
bee.vc *= -1;
|
|
73
|
+
bee.c = Math.max(0, Math.min(cols - 1, bee.c));
|
|
74
|
+
}
|
|
75
|
+
if (Math.random() > 0.3) {
|
|
76
|
+
bee.vc = Math.random() > 0.5 ? 1 : -1;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Spawn pulses
|
|
81
|
+
if (frame % PULSE_SPAWN_INTERVAL === 0) {
|
|
82
|
+
const newPulses = [];
|
|
83
|
+
for (let i = 0; i < 2; i++) {
|
|
84
|
+
const pr = Math.floor(Math.random() * gridRows);
|
|
85
|
+
const pc = Math.floor(Math.random() * cols);
|
|
86
|
+
if (isHexEdge(pr, pc)) {
|
|
87
|
+
const color = PULSE_COLORS[Math.floor(Math.random() * PULSE_COLORS.length)];
|
|
88
|
+
newPulses.push({ r: pr, c: pc, ttl: PULSE_TTL, color });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
pulsesRef.current = [
|
|
92
|
+
...pulsesRef.current.filter((p) => p.ttl > 1).map((p) => ({ ...p, ttl: p.ttl - 1 })),
|
|
93
|
+
...newPulses,
|
|
94
|
+
];
|
|
95
|
+
}
|
|
96
|
+
// Build the grid
|
|
97
|
+
const grid = [];
|
|
98
|
+
const streamCols = streamColsRef.current;
|
|
99
|
+
for (let r = 0; r < gridRows; r++) {
|
|
100
|
+
const row = [];
|
|
101
|
+
for (let c = 0; c < cols; c++) {
|
|
102
|
+
const hexEdge = isHexEdge(r, c);
|
|
103
|
+
// Scanning wave
|
|
104
|
+
const scanRow = frame % (gridRows + 6);
|
|
105
|
+
const dist = Math.abs(r - scanRow);
|
|
106
|
+
if (hexEdge && dist === 0) {
|
|
107
|
+
row.push({ char: '⬢', color: colors.honey });
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (hexEdge && dist <= 1) {
|
|
111
|
+
row.push({ char: '⬡', color: colors.honey });
|
|
112
|
+
continue;
|
|
113
|
+
}
|
|
114
|
+
// Data streams
|
|
115
|
+
let isStream = false;
|
|
116
|
+
for (const sc of streamCols) {
|
|
117
|
+
if (c === sc) {
|
|
118
|
+
const streamOffset = (frame * 2 + sc) % (gridRows * 3);
|
|
119
|
+
const streamDist = (((r - streamOffset) % gridRows) + gridRows) % gridRows;
|
|
120
|
+
if (streamDist < 6) {
|
|
121
|
+
const charIdx = (frame + r) % animation.DATA_CHARS.length;
|
|
122
|
+
const streamChar = animation.DATA_CHARS[charIdx];
|
|
123
|
+
if (streamDist === 0) {
|
|
124
|
+
row.push({ char: streamChar, color: colors.white });
|
|
125
|
+
}
|
|
126
|
+
else if (streamDist < 3) {
|
|
127
|
+
row.push({ char: streamChar, color: colors.green });
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
row.push({ char: streamChar, color: colors.grayDim });
|
|
131
|
+
}
|
|
132
|
+
isStream = true;
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (isStream)
|
|
138
|
+
continue;
|
|
139
|
+
// Default hex skeleton
|
|
140
|
+
if (hexEdge) {
|
|
141
|
+
row.push({ char: '·', color: colors.grayDim });
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
row.push({ char: ' ', color: colors.grayDim });
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
grid.push(row);
|
|
148
|
+
}
|
|
149
|
+
// Overlay pulses
|
|
150
|
+
for (const pulse of pulsesRef.current) {
|
|
151
|
+
if (pulse.r >= 0 && pulse.r < gridRows && pulse.c >= 0 && pulse.c < cols) {
|
|
152
|
+
const brightness = pulse.ttl / PULSE_TTL;
|
|
153
|
+
const cell = grid[pulse.r][pulse.c];
|
|
154
|
+
if (cell.char === '·' || cell.char === ' ') {
|
|
155
|
+
grid[pulse.r][pulse.c] = {
|
|
156
|
+
char: brightness > 0.5 ? '⬡' : '·',
|
|
157
|
+
color: pulse.color,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// Overlay bees
|
|
163
|
+
for (const bee of beesRef.current) {
|
|
164
|
+
const br = Math.max(0, Math.min(gridRows - 1, Math.round(bee.r)));
|
|
165
|
+
const bc = Math.max(0, Math.min(cols - 1, Math.round(bee.c)));
|
|
166
|
+
grid[br][bc] = { char: '◆', color: colors.honey };
|
|
167
|
+
}
|
|
168
|
+
// Render grid rows
|
|
169
|
+
const rowElements = grid.map((rowCells, r) => {
|
|
170
|
+
const segments = [];
|
|
171
|
+
let runColor = rowCells[0]?.color ?? colors.grayDim;
|
|
172
|
+
let runChars = '';
|
|
173
|
+
for (let c = 0; c < rowCells.length; c++) {
|
|
174
|
+
const cell = rowCells[c];
|
|
175
|
+
if (cell.color === runColor) {
|
|
176
|
+
runChars += cell.char;
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
segments.push(_jsx(Text, { color: runColor, children: runChars }, segments.length));
|
|
180
|
+
runColor = cell.color;
|
|
181
|
+
runChars = cell.char;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
if (runChars.length > 0) {
|
|
185
|
+
segments.push(_jsx(Text, { color: runColor, children: runChars }, segments.length));
|
|
186
|
+
}
|
|
187
|
+
return _jsx(Text, { children: segments }, r);
|
|
188
|
+
});
|
|
189
|
+
return (_jsxs(Box, { flexDirection: "column", children: [rowElements, _jsxs(Box, { justifyContent: "center", marginTop: 0, children: [_jsx(Text, { color: colors.honey, children: '⬡ ' }), _jsx(Text, { color: colors.gray, children: label })] })] }));
|
|
190
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Box, Text, useInput } from 'ink';
|
|
4
|
+
import { colors, symbols } from '../commands/shared/theme.js';
|
|
5
|
+
export function MultiSelectPrompt({ label, items, defaultSelected, onSubmit, }) {
|
|
6
|
+
const allValues = new Set(items.map((i) => i.value));
|
|
7
|
+
const [selected, setSelected] = useState(defaultSelected ?? allValues);
|
|
8
|
+
const [cursor, setCursor] = useState(0);
|
|
9
|
+
useInput((_input, key) => {
|
|
10
|
+
if (key.upArrow) {
|
|
11
|
+
setCursor((prev) => (prev > 0 ? prev - 1 : items.length - 1));
|
|
12
|
+
}
|
|
13
|
+
if (key.downArrow) {
|
|
14
|
+
setCursor((prev) => (prev < items.length - 1 ? prev + 1 : 0));
|
|
15
|
+
}
|
|
16
|
+
if (_input === ' ') {
|
|
17
|
+
const item = items[cursor];
|
|
18
|
+
if (!item)
|
|
19
|
+
return;
|
|
20
|
+
setSelected((prev) => {
|
|
21
|
+
const next = new Set(prev);
|
|
22
|
+
if (next.has(item.value)) {
|
|
23
|
+
next.delete(item.value);
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
next.add(item.value);
|
|
27
|
+
}
|
|
28
|
+
return next;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
if (key.return) {
|
|
32
|
+
const selectedItems = items.filter((i) => selected.has(i.value));
|
|
33
|
+
onSubmit(selectedItems);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
const highlightedItem = items[cursor];
|
|
37
|
+
const highlightedDescription = highlightedItem?.description;
|
|
38
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsxs(Text, { color: colors.honey, children: [symbols.arrow, " "] }), _jsx(Text, { color: colors.white, bold: true, children: label })] }), _jsx(Box, { marginLeft: 2, marginBottom: 1, children: _jsx(Text, { color: colors.grayDim, italic: true, children: "All selected by default \u2014 deselect what you don't want" }) }), _jsx(Box, { flexDirection: "column", marginLeft: 2, children: items.map((item, i) => {
|
|
39
|
+
const isCursor = i === cursor;
|
|
40
|
+
const isSelected = selected.has(item.value);
|
|
41
|
+
const checkbox = isSelected ? '◆' : '◇';
|
|
42
|
+
const itemColor = isCursor ? colors.honey : colors.white;
|
|
43
|
+
return (_jsxs(Box, { children: [_jsxs(Text, { color: colors.honey, children: [isCursor ? symbols.diamond : ' ', " "] }), _jsxs(Text, { color: isSelected ? colors.honey : colors.grayDim, children: [checkbox, " "] }), _jsx(Text, { color: itemColor, children: item.label })] }, item.value));
|
|
44
|
+
}) }), highlightedDescription && (_jsx(Box, { marginLeft: 4, marginTop: 1, children: _jsxs(Text, { color: colors.gray, italic: true, children: [symbols.arrow, " ", highlightedDescription] }) })), _jsx(Box, { marginLeft: 2, marginTop: 1, children: _jsxs(Text, { color: colors.grayDim, children: [_jsx(Text, { color: colors.honey, children: "space" }), " toggle ", _jsx(Text, { color: colors.honey, children: "enter" }), ' ', "confirm"] }) })] }));
|
|
45
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Box, Text } from 'ink';
|
|
4
|
+
import SelectInput from 'ink-select-input';
|
|
5
|
+
import { colors, symbols } from '../commands/shared/theme.js';
|
|
6
|
+
export function SelectPrompt({ label, items, onSelect }) {
|
|
7
|
+
const [highlightedValue, setHighlightedValue] = useState(items[0]?.value ?? '');
|
|
8
|
+
const handleSelect = (item) => {
|
|
9
|
+
const found = items.find((i) => i.value === item.value);
|
|
10
|
+
if (found) {
|
|
11
|
+
onSelect(found);
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const handleHighlight = (item) => {
|
|
15
|
+
setHighlightedValue(item.value);
|
|
16
|
+
};
|
|
17
|
+
const highlightedItem = items.find((i) => i.value === highlightedValue);
|
|
18
|
+
const highlightedDescription = highlightedItem?.description;
|
|
19
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { marginBottom: 1, children: [_jsxs(Text, { color: colors.honey, children: [symbols.arrow, " "] }), _jsx(Text, { color: colors.white, bold: true, children: label })] }), _jsx(Box, { marginLeft: 2, children: _jsx(SelectInput, { items: items, onSelect: handleSelect, onHighlight: handleHighlight, indicatorComponent: ({ isSelected }) => (_jsxs(Text, { color: colors.honey, children: [isSelected ? symbols.diamond : ' ', " "] })), itemComponent: ({ isSelected, label: itemLabel }) => (_jsx(Text, { color: isSelected ? colors.honey : colors.white, children: itemLabel })) }) }), highlightedDescription && (_jsx(Box, { marginLeft: 4, marginTop: 1, children: _jsxs(Text, { color: colors.gray, italic: true, children: [symbols.arrow, " ", highlightedDescription] }) }))] }));
|
|
20
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
|
+
import { Box, Text } from 'ink';
|
|
4
|
+
import { colors, symbols } from '../commands/shared/theme.js';
|
|
5
|
+
export function Spinner({ label }) {
|
|
6
|
+
const [frame, setFrame] = useState(0);
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
const timer = setInterval(() => {
|
|
9
|
+
setFrame((prev) => (prev + 1) % symbols.spinner.length);
|
|
10
|
+
}, 120);
|
|
11
|
+
return () => {
|
|
12
|
+
clearInterval(timer);
|
|
13
|
+
};
|
|
14
|
+
}, []);
|
|
15
|
+
return (_jsxs(Box, { children: [_jsxs(Text, { color: colors.honey, children: [symbols.spinner[frame], " "] }), _jsx(Text, { color: colors.gray, children: label })] }));
|
|
16
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Box, Text } from 'ink';
|
|
4
|
+
import { colors, symbols } from '../commands/shared/theme.js';
|
|
5
|
+
export function StepIndicator({ steps, currentIndex }) {
|
|
6
|
+
return (_jsx(Box, { marginLeft: 1, marginBottom: 1, children: steps.map((step, i) => {
|
|
7
|
+
const isCurrent = i === currentIndex;
|
|
8
|
+
const isCompleted = i < currentIndex;
|
|
9
|
+
let symbol;
|
|
10
|
+
let symbolColor;
|
|
11
|
+
let labelColor;
|
|
12
|
+
let bold = false;
|
|
13
|
+
if (isCurrent) {
|
|
14
|
+
symbol = symbols.dot;
|
|
15
|
+
symbolColor = colors.honey;
|
|
16
|
+
labelColor = colors.honey;
|
|
17
|
+
bold = true;
|
|
18
|
+
}
|
|
19
|
+
else if (isCompleted) {
|
|
20
|
+
symbol = symbols.check;
|
|
21
|
+
symbolColor = colors.green;
|
|
22
|
+
labelColor = colors.gray;
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
symbol = symbols.diamondOpen;
|
|
26
|
+
symbolColor = colors.grayDim;
|
|
27
|
+
labelColor = colors.grayDim;
|
|
28
|
+
}
|
|
29
|
+
return (_jsxs(React.Fragment, { children: [i > 0 && _jsx(Text, { children: " " }), _jsx(Text, { color: symbolColor, children: symbol }), _jsxs(Text, { color: labelColor, bold: bold, children: [' ', step.label] })] }, step.key));
|
|
30
|
+
}) }));
|
|
31
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect, useRef } from 'react';
|
|
3
|
+
import { Box, Text } from 'ink';
|
|
4
|
+
import { colors, border } from '../commands/shared/theme.js';
|
|
5
|
+
import { extractErrorMessage } from '../shared/agent/utils.js';
|
|
6
|
+
export function StreamingText({ stream, title, onComplete, onError, }) {
|
|
7
|
+
const [text, setText] = useState('');
|
|
8
|
+
const bufferRef = useRef('');
|
|
9
|
+
const completedRef = useRef(false);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if (!stream) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
bufferRef.current = '';
|
|
15
|
+
completedRef.current = false;
|
|
16
|
+
let cancelled = false;
|
|
17
|
+
const flushInterval = setInterval(() => {
|
|
18
|
+
if (!cancelled) {
|
|
19
|
+
setText(bufferRef.current);
|
|
20
|
+
}
|
|
21
|
+
}, 80);
|
|
22
|
+
const consume = async () => {
|
|
23
|
+
for await (const chunk of stream) {
|
|
24
|
+
if (cancelled) {
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
bufferRef.current += chunk;
|
|
28
|
+
}
|
|
29
|
+
if (!cancelled && !completedRef.current) {
|
|
30
|
+
completedRef.current = true;
|
|
31
|
+
const finalText = bufferRef.current;
|
|
32
|
+
setText(finalText);
|
|
33
|
+
onComplete?.(finalText);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
consume().catch((err) => {
|
|
37
|
+
if (cancelled)
|
|
38
|
+
return;
|
|
39
|
+
const message = extractErrorMessage(err);
|
|
40
|
+
onError?.(message);
|
|
41
|
+
});
|
|
42
|
+
return () => {
|
|
43
|
+
cancelled = true;
|
|
44
|
+
clearInterval(flushInterval);
|
|
45
|
+
};
|
|
46
|
+
}, [stream]);
|
|
47
|
+
const termWidth = process.stdout.columns || 60;
|
|
48
|
+
const boxWidth = Math.min(termWidth - 4, 76);
|
|
49
|
+
return (_jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [title && (_jsx(Box, { children: _jsxs(Text, { color: colors.grayDim, children: [border.topLeft, border.horizontal, " ", title, ' ', border.horizontal.repeat(Math.max(0, boxWidth - title.length - 5)), border.topRight] }) })), _jsx(Box, { paddingLeft: 1, paddingRight: 1, width: boxWidth, children: _jsx(Text, { color: colors.white, wrap: "wrap", children: text || ' ' }) }), title && (_jsx(Box, { children: _jsxs(Text, { color: colors.grayDim, children: [border.bottomLeft, border.horizontal.repeat(Math.max(0, boxWidth - 2)), border.bottomRight] }) }))] }));
|
|
50
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Box, Text, useInput } from 'ink';
|
|
4
|
+
import TextInput from 'ink-text-input';
|
|
5
|
+
import { colors, symbols } from '../commands/shared/theme.js';
|
|
6
|
+
export function TextPrompt({ label, placeholder, onSubmit, validate, maxLength, }) {
|
|
7
|
+
const [value, setValue] = useState('');
|
|
8
|
+
const [error, setError] = useState('');
|
|
9
|
+
useInput((_input, key) => {
|
|
10
|
+
if (key.tab && value === '' && placeholder) {
|
|
11
|
+
setValue(placeholder);
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
const handleSubmit = (input) => {
|
|
15
|
+
const trimmed = input.trim();
|
|
16
|
+
if (validate) {
|
|
17
|
+
const result = validate(trimmed);
|
|
18
|
+
if (result !== true) {
|
|
19
|
+
setError(result);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
setError('');
|
|
24
|
+
onSubmit(trimmed);
|
|
25
|
+
};
|
|
26
|
+
const charCounter = maxLength ? ` ${value.length}/${maxLength}` : '';
|
|
27
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsxs(Text, { color: colors.honey, children: [symbols.arrow, " "] }), _jsx(Text, { color: colors.white, bold: true, children: label }), maxLength && (_jsx(Text, { color: value.length > maxLength ? colors.red : colors.grayDim, children: charCounter }))] }), _jsx(Box, { marginLeft: 2, children: _jsx(TextInput, { value: value, onChange: setValue, onSubmit: handleSubmit, placeholder: placeholder }) }), error !== '' && (_jsx(Box, { marginLeft: 2, children: _jsxs(Text, { color: colors.red, children: [symbols.cross, " ", error] }) }))] }));
|
|
28
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
const FRAMES = ['\u25D0', '\u25D3', '\u25D1', '\u25D2']; // ◐ ◓ ◑ ◒
|
|
3
|
+
const INTERVAL_MS = 200;
|
|
4
|
+
const HONEY_ANSI = '\x1b[38;2;245;166;35m';
|
|
5
|
+
const RESET_ANSI = '\x1b[0m';
|
|
6
|
+
let _frame = 0;
|
|
7
|
+
let _timer = null;
|
|
8
|
+
const _entries = new Map();
|
|
9
|
+
let _nextId = 0;
|
|
10
|
+
function rawWrite(data) {
|
|
11
|
+
try {
|
|
12
|
+
fs.writeSync(process.stdout.fd, data);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
// Ignore write errors (non-TTY, closed fd, etc.)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function tick() {
|
|
19
|
+
_frame = (_frame + 1) % FRAMES.length;
|
|
20
|
+
const char = `${HONEY_ANSI}${FRAMES[_frame]}${RESET_ANSI}`;
|
|
21
|
+
for (const getPosition of _entries.values()) {
|
|
22
|
+
const pos = getPosition();
|
|
23
|
+
if (!pos || pos.linesFromBottom <= 0)
|
|
24
|
+
continue;
|
|
25
|
+
rawWrite('\x1b7'); // Save cursor (DEC)
|
|
26
|
+
rawWrite(`\x1b[${pos.linesFromBottom}A`); // Move up N lines
|
|
27
|
+
rawWrite(`\x1b[${pos.col + 1}G`); // Move to column (1-indexed)
|
|
28
|
+
rawWrite(char);
|
|
29
|
+
rawWrite('\x1b8'); // Restore cursor (DEC)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function register(getPosition) {
|
|
33
|
+
const id = _nextId++;
|
|
34
|
+
_entries.set(id, getPosition);
|
|
35
|
+
if (!_timer) {
|
|
36
|
+
_timer = setInterval(tick, INTERVAL_MS);
|
|
37
|
+
}
|
|
38
|
+
return id;
|
|
39
|
+
}
|
|
40
|
+
export function unregister(id) {
|
|
41
|
+
_entries.delete(id);
|
|
42
|
+
if (_entries.size === 0 && _timer) {
|
|
43
|
+
clearInterval(_timer);
|
|
44
|
+
_timer = null;
|
|
45
|
+
_frame = 0;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export { FRAMES };
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
export const HIVE_API_URL = 'https://api.zhive.ai';
|
|
5
|
+
export const HIVE_FRONTEND_URL = 'https://www.zhive.ai';
|
|
6
|
+
export function getHiveDir() {
|
|
7
|
+
const hiveDir = path.join(os.homedir(), '.hive');
|
|
8
|
+
return hiveDir;
|
|
9
|
+
}
|
|
10
|
+
export async function readConfig() {
|
|
11
|
+
try {
|
|
12
|
+
const configPath = path.join(getHiveDir(), 'config.json');
|
|
13
|
+
const config = (await fs.readJson(configPath));
|
|
14
|
+
if (!config.providerId || !config.apiKey) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
return config;
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export async function writeConfig(config) {
|
|
24
|
+
const hiveDir = getHiveDir();
|
|
25
|
+
await fs.ensureDir(hiveDir);
|
|
26
|
+
const configPath = path.join(hiveDir, 'config.json');
|
|
27
|
+
await fs.writeJson(configPath, config, { spaces: 2, mode: 0o600 });
|
|
28
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useCallback } from 'react';
|
|
3
|
+
import { Box, Text, useApp } from 'ink';
|
|
4
|
+
import { Header } from '../components/Header.js';
|
|
5
|
+
import { AsciiTicker } from '../components/AsciiTicker.js';
|
|
6
|
+
import { StepIndicator } from '../components/StepIndicator.js';
|
|
7
|
+
import { ApiKeyStep } from './steps/ApiKeyStep.js';
|
|
8
|
+
import { NameStep } from './steps/NameStep.js';
|
|
9
|
+
import { IdentityStep } from './steps/IdentityStep.js';
|
|
10
|
+
import { AvatarStep } from './steps/AvatarStep.js';
|
|
11
|
+
import { SoulStep } from './steps/SoulStep.js';
|
|
12
|
+
import { StrategyStep } from './steps/StrategyStep.js';
|
|
13
|
+
import { ScaffoldStep } from './steps/ScaffoldStep.js';
|
|
14
|
+
import { DoneStep } from './steps/DoneStep.js';
|
|
15
|
+
import { colors, symbols } from '../theme.js';
|
|
16
|
+
import { getProvider } from '../ai-providers.js';
|
|
17
|
+
function ensureAvatarUrl(content, avatarUrl) {
|
|
18
|
+
const lines = content.split('\n');
|
|
19
|
+
const avatarIdx = lines.findIndex((l) => /^## Avatar/.test(l));
|
|
20
|
+
if (avatarIdx === -1) {
|
|
21
|
+
return content;
|
|
22
|
+
}
|
|
23
|
+
// Find the next section header after ## Avatar
|
|
24
|
+
let nextSectionIdx = lines.length;
|
|
25
|
+
for (let i = avatarIdx + 1; i < lines.length; i++) {
|
|
26
|
+
if (/^##?\s/.test(lines[i])) {
|
|
27
|
+
nextSectionIdx = i;
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
// Replace the content between ## Avatar and next section with the raw URL
|
|
32
|
+
const before = lines.slice(0, avatarIdx + 1);
|
|
33
|
+
const after = lines.slice(nextSectionIdx);
|
|
34
|
+
const result = [...before, '', avatarUrl, '', ...after];
|
|
35
|
+
return result.join('\n');
|
|
36
|
+
}
|
|
37
|
+
function ensureSectionLine(content, sectionHeader, linePrefix, value) {
|
|
38
|
+
const lines = content.split('\n');
|
|
39
|
+
const sectionIdx = lines.findIndex((l) => new RegExp(`^##\\s+${sectionHeader}`).test(l));
|
|
40
|
+
if (sectionIdx === -1) {
|
|
41
|
+
// Section missing — append it at the end
|
|
42
|
+
return content + `\n\n## ${sectionHeader}\n\n${linePrefix} ${value}\n`;
|
|
43
|
+
}
|
|
44
|
+
// Find the next section header after this one
|
|
45
|
+
let nextSectionIdx = lines.length;
|
|
46
|
+
for (let i = sectionIdx + 1; i < lines.length; i++) {
|
|
47
|
+
if (/^##?\s/.test(lines[i])) {
|
|
48
|
+
nextSectionIdx = i;
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// Look for existing line with the prefix in this section
|
|
53
|
+
const prefixRegex = new RegExp(`^${linePrefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s`);
|
|
54
|
+
const lineIdx = lines.findIndex((l, i) => i > sectionIdx && i < nextSectionIdx && prefixRegex.test(l));
|
|
55
|
+
if (lineIdx !== -1) {
|
|
56
|
+
// Replace the existing line
|
|
57
|
+
lines[lineIdx] = `${linePrefix} ${value}`;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
// Insert after the section header (skip blank lines)
|
|
61
|
+
let insertIdx = sectionIdx + 1;
|
|
62
|
+
while (insertIdx < nextSectionIdx && lines[insertIdx].trim() === '') {
|
|
63
|
+
insertIdx++;
|
|
64
|
+
}
|
|
65
|
+
lines.splice(insertIdx, 0, `${linePrefix} ${value}`);
|
|
66
|
+
}
|
|
67
|
+
return lines.join('\n');
|
|
68
|
+
}
|
|
69
|
+
function ensureStrategyFields(content, sectors, sentiment, timeframes) {
|
|
70
|
+
const sectorsLine = sectors.length > 0 ? sectors.join(', ') : 'all categories';
|
|
71
|
+
const timeframesLine = timeframes.length > 0 ? timeframes.join(', ') : '1h, 4h, 24h';
|
|
72
|
+
let patched = ensureSectionLine(content, 'Sentiment', '- Bias:', sentiment);
|
|
73
|
+
patched = ensureSectionLine(patched, 'Sector Focus', '- Sectors:', sectorsLine);
|
|
74
|
+
patched = ensureSectionLine(patched, 'Timeframe', '- Active timeframes:', timeframesLine);
|
|
75
|
+
return patched;
|
|
76
|
+
}
|
|
77
|
+
const STEP_ORDER = ['name', 'identity', 'avatar', 'api-key', 'soul', 'strategy', 'scaffold', 'done'];
|
|
78
|
+
const STEP_LABELS = {
|
|
79
|
+
'api-key': 'API Key',
|
|
80
|
+
'name': 'Name',
|
|
81
|
+
'identity': 'Identity',
|
|
82
|
+
'avatar': 'Avatar',
|
|
83
|
+
'soul': 'Soul',
|
|
84
|
+
'strategy': 'Strategy',
|
|
85
|
+
'scaffold': 'Scaffold',
|
|
86
|
+
'done': 'Done',
|
|
87
|
+
};
|
|
88
|
+
const STEP_DEFS = STEP_ORDER.map((s) => ({ key: s, label: STEP_LABELS[s] }));
|
|
89
|
+
export function CreateApp({ initialName }) {
|
|
90
|
+
const { exit } = useApp();
|
|
91
|
+
const [step, setStep] = useState(initialName ? 'identity' : 'name');
|
|
92
|
+
const [providerId, setProviderId] = useState(null);
|
|
93
|
+
const [apiKey, setApiKey] = useState('');
|
|
94
|
+
const [agentName, setAgentName] = useState(initialName ?? '');
|
|
95
|
+
const [bio, setBio] = useState('');
|
|
96
|
+
const [personality, setPersonality] = useState('');
|
|
97
|
+
const [tone, setTone] = useState('');
|
|
98
|
+
const [voiceStyle, setVoiceStyle] = useState('');
|
|
99
|
+
const [tradingStyle, setTradingStyle] = useState('');
|
|
100
|
+
const [sectors, setSectors] = useState([]);
|
|
101
|
+
const [sentiment, setSentiment] = useState('');
|
|
102
|
+
const [timeframes, setTimeframes] = useState([]);
|
|
103
|
+
const [avatarUrl, setAvatarUrl] = useState('');
|
|
104
|
+
const [soulContent, setSoulContent] = useState('');
|
|
105
|
+
const [strategyContent, setStrategyContent] = useState('');
|
|
106
|
+
const [resolvedProjectDir, setResolvedProjectDir] = useState('');
|
|
107
|
+
const [error, setError] = useState('');
|
|
108
|
+
const stepIndex = STEP_ORDER.indexOf(step);
|
|
109
|
+
const provider = providerId ? getProvider(providerId) : null;
|
|
110
|
+
const handleApiKey = useCallback((result) => {
|
|
111
|
+
setProviderId(result.providerId);
|
|
112
|
+
setApiKey(result.apiKey);
|
|
113
|
+
setStep('soul');
|
|
114
|
+
}, []);
|
|
115
|
+
const handleName = useCallback((name) => {
|
|
116
|
+
setAgentName(name);
|
|
117
|
+
setStep('identity');
|
|
118
|
+
}, []);
|
|
119
|
+
const handleIdentity = useCallback((result) => {
|
|
120
|
+
setPersonality(result.personality);
|
|
121
|
+
setTone(result.tone);
|
|
122
|
+
setVoiceStyle(result.voiceStyle);
|
|
123
|
+
setTradingStyle(result.tradingStyle);
|
|
124
|
+
setSectors(result.sectors);
|
|
125
|
+
setSentiment(result.sentiment);
|
|
126
|
+
setTimeframes(result.timeframes);
|
|
127
|
+
setBio(result.bio);
|
|
128
|
+
setStep('avatar');
|
|
129
|
+
}, []);
|
|
130
|
+
const handleAvatar = useCallback((value) => {
|
|
131
|
+
setAvatarUrl(value);
|
|
132
|
+
setStep('api-key');
|
|
133
|
+
}, []);
|
|
134
|
+
const handleSoul = useCallback((content) => {
|
|
135
|
+
const patched = ensureAvatarUrl(content, avatarUrl);
|
|
136
|
+
setSoulContent(patched);
|
|
137
|
+
setStep('strategy');
|
|
138
|
+
}, [avatarUrl]);
|
|
139
|
+
const handleStrategy = useCallback((content) => {
|
|
140
|
+
const patched = ensureStrategyFields(content, sectors, sentiment, timeframes);
|
|
141
|
+
setStrategyContent(patched);
|
|
142
|
+
setStep('scaffold');
|
|
143
|
+
}, [sectors, sentiment, timeframes]);
|
|
144
|
+
const handleScaffoldComplete = useCallback((projectDir) => {
|
|
145
|
+
setResolvedProjectDir(projectDir);
|
|
146
|
+
setStep('done');
|
|
147
|
+
}, []);
|
|
148
|
+
const handleScaffoldError = useCallback((message) => {
|
|
149
|
+
setError(message);
|
|
150
|
+
exit();
|
|
151
|
+
}, [exit]);
|
|
152
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Header, {}), _jsx(StepIndicator, { steps: STEP_DEFS, currentIndex: stepIndex }), step !== 'done' && (_jsx(Box, { marginBottom: 1, children: _jsx(AsciiTicker, { step: stepIndex + 1 }) })), step === 'api-key' && (_jsx(ApiKeyStep, { onComplete: handleApiKey })), step === 'name' && (_jsx(NameStep, { onComplete: handleName })), step === 'identity' && (_jsx(IdentityStep, { agentName: agentName, onComplete: handleIdentity })), step === 'avatar' && (_jsx(AvatarStep, { agentName: agentName, onComplete: handleAvatar })), step === 'soul' && providerId && (_jsx(SoulStep, { providerId: providerId, apiKey: apiKey, agentName: agentName, bio: bio, avatarUrl: avatarUrl, personality: personality, tone: tone, voiceStyle: voiceStyle, tradingStyle: tradingStyle, sectors: sectors, sentiment: sentiment, timeframes: timeframes, onComplete: handleSoul })), step === 'strategy' && providerId && (_jsx(StrategyStep, { providerId: providerId, apiKey: apiKey, agentName: agentName, bio: bio, personality: personality, tone: tone, voiceStyle: voiceStyle, tradingStyle: tradingStyle, sectors: sectors, sentiment: sentiment, timeframes: timeframes, onComplete: handleStrategy })), step === 'scaffold' && provider && (_jsx(ScaffoldStep, { projectName: agentName, provider: provider, apiKey: apiKey, soulContent: soulContent, strategyContent: strategyContent, onComplete: handleScaffoldComplete, onError: handleScaffoldError })), step === 'done' && (_jsx(DoneStep, { projectDir: resolvedProjectDir })), error !== '' && (_jsx(Box, { marginTop: 1, marginLeft: 2, children: _jsxs(Text, { color: colors.red, children: [symbols.cross, " ", error] }) }))] }));
|
|
153
|
+
}
|