@zhive/cli 0.6.2 → 0.6.3
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/dist/{services/agent → agent}/analysis.js +5 -5
- package/dist/agent/app.js +122 -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/hooks/useAgent.js +480 -0
- package/dist/{services/agent/prompts → agent}/memory-prompt.js +22 -20
- package/dist/{services/agent/helpers → agent}/model.js +2 -2
- package/dist/agent/process-lifecycle.js +18 -0
- package/dist/{services/agent/prompts → agent}/prompt.js +54 -80
- package/dist/agent/run-headless.js +189 -0
- package/dist/agent/theme.js +41 -0
- package/dist/{services/agent → agent}/tools/market/client.js +1 -1
- package/dist/{services/agent → agent}/tools/mindshare/client.js +1 -1
- package/dist/agent/types.js +1 -0
- package/dist/{services/config/agent.js → agents.js} +2 -2
- 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/install.js +50 -0
- package/dist/commands/megathread/commands/create-comment.js +1 -4
- package/dist/commands/megathread/commands/create-comment.test.js +1 -19
- package/dist/commands/megathread/commands/list.test.js +1 -0
- package/dist/commands/start/commands/prediction.js +1 -2
- package/dist/commands/start/hooks/utils.js +3 -3
- package/dist/commands/start/ui/PollText.js +23 -0
- package/dist/commands/start/ui/PredictionsPanel.js +88 -0
- package/dist/commands/start/ui/SpinnerContext.js +20 -0
- package/dist/components/InputGuard.js +6 -0
- package/dist/components/stdout-spinner.js +48 -0
- package/dist/{services/config/config.js → config.js} +7 -1
- 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/list/ListApp.js +79 -0
- package/dist/{services/agent/env.js → load-agent-env.js} +1 -1
- 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/handler.js +1 -5
- package/dist/shared/config/constant.js +2 -2
- 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 +2 -2
- package/dist/CLAUDE.md +0 -7
- package/dist/backtest/CLAUDE.md +0 -7
- package/dist/cli.js +0 -20
- package/dist/services/config/constant.js +0 -8
- package/dist/shared/agent/config.js +0 -75
- package/dist/shared/agent/env.js +0 -30
- package/dist/shared/agent/helpers/model.js +0 -92
- package/dist/shared/ai-providers.js +0 -66
- /package/dist/{services/agent/prompts → agent}/chat-prompt.js +0 -0
- /package/dist/{services/agent → agent}/config.js +0 -0
- /package/dist/{services/agent/tools → agent}/edit-section.js +0 -0
- /package/dist/{services/agent/tools → agent}/fetch-rules.js +0 -0
- /package/dist/{services/agent → agent}/helpers.js +0 -0
- /package/dist/{services/agent/skills/types.js → agent/objects.js} +0 -0
- /package/dist/{services/agent → agent}/skills/index.js +0 -0
- /package/dist/{services/agent → agent}/skills/skill-parser.js +0 -0
- /package/dist/{services/agent → agent/skills}/types.js +0 -0
- /package/dist/{services/agent → agent}/tools/index.js +0 -0
- /package/dist/{services/agent → agent}/tools/market/index.js +0 -0
- /package/dist/{services/agent → agent}/tools/market/tools.js +0 -0
- /package/dist/{services/agent → agent}/tools/mindshare/index.js +0 -0
- /package/dist/{services/agent → agent}/tools/mindshare/tools.js +0 -0
- /package/dist/{services/agent → agent}/tools/read-skill-tool.js +0 -0
- /package/dist/{services/agent → agent}/tools/ta/index.js +0 -0
- /package/dist/{services/agent → agent}/tools/ta/indicators.js +0 -0
- /package/dist/{services/ai-providers.js → ai-providers.js} +0 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { generateText } from 'ai';
|
|
2
|
+
import { createOpenAI } from '@ai-sdk/openai';
|
|
3
|
+
import { createAnthropic } from '@ai-sdk/anthropic';
|
|
4
|
+
import { createGoogleGenerativeAI } from '@ai-sdk/google';
|
|
5
|
+
import { createXai } from '@ai-sdk/xai';
|
|
6
|
+
import { createOpenRouter } from '@openrouter/ai-sdk-provider';
|
|
7
|
+
import { getProvider } from '../ai-providers.js';
|
|
8
|
+
/**
|
|
9
|
+
* Make a lightweight test call to validate the user's API key.
|
|
10
|
+
* Returns true if the key works, or an error message string on failure.
|
|
11
|
+
*/
|
|
12
|
+
export async function validateApiKey(providerId, apiKey) {
|
|
13
|
+
try {
|
|
14
|
+
const model = buildTestModel(providerId, apiKey);
|
|
15
|
+
await generateText({
|
|
16
|
+
model,
|
|
17
|
+
prompt: 'Say "ok"',
|
|
18
|
+
maxOutputTokens: 16,
|
|
19
|
+
});
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
24
|
+
if (message.includes('401') ||
|
|
25
|
+
message.includes('Unauthorized') ||
|
|
26
|
+
message.includes('invalid')) {
|
|
27
|
+
return 'Invalid API key. Please check and try again.';
|
|
28
|
+
}
|
|
29
|
+
return `API validation failed: ${message.slice(0, 120)}`;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function buildTestModel(providerId, apiKey) {
|
|
33
|
+
const provider = getProvider(providerId);
|
|
34
|
+
const modelId = provider.models.validation;
|
|
35
|
+
switch (providerId) {
|
|
36
|
+
case 'openai':
|
|
37
|
+
return createOpenAI({ apiKey })(modelId);
|
|
38
|
+
case 'anthropic':
|
|
39
|
+
return createAnthropic({ apiKey })(modelId);
|
|
40
|
+
case 'google':
|
|
41
|
+
return createGoogleGenerativeAI({ apiKey })(modelId);
|
|
42
|
+
case 'xai':
|
|
43
|
+
return createXai({ apiKey })(modelId);
|
|
44
|
+
case 'openrouter':
|
|
45
|
+
return createOpenRouter({ apiKey }).chat(modelId);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
const HEX_W = 8;
|
|
3
|
+
const HEX_H = 4;
|
|
4
|
+
const DATA_CHARS = '01▪▫░▒';
|
|
5
|
+
const TICK_MS = 80;
|
|
6
|
+
const DURATION_MS = 3200;
|
|
7
|
+
const NUM_BEES = 4;
|
|
8
|
+
const NUM_STREAMS = 5;
|
|
9
|
+
const HONEY = '#F5A623';
|
|
10
|
+
const GREEN = '#27C587';
|
|
11
|
+
const DIM = '#555555';
|
|
12
|
+
const WHITE = '#FFFFFF';
|
|
13
|
+
const RED = '#E14B4B';
|
|
14
|
+
const SCRAMBLE_CHARS = '⬡⬢◆◇░▒!@#$%01';
|
|
15
|
+
const BOOT_MESSAGES = [
|
|
16
|
+
{ prefix: '⬡', text: 'Initializing creation studio...', frame: 18, color: HONEY },
|
|
17
|
+
{ prefix: '◆', text: 'Loading agent templates...', frame: 24, color: HONEY },
|
|
18
|
+
{ prefix: '◇', text: 'Connecting to hive network...', frame: 30, color: HONEY },
|
|
19
|
+
{ prefix: '✓', text: 'Ready', frame: 36, color: GREEN },
|
|
20
|
+
];
|
|
21
|
+
function isHexEdge(r, c) {
|
|
22
|
+
const rowInHex = ((r % HEX_H) + HEX_H) % HEX_H;
|
|
23
|
+
const isOddHex = Math.floor(r / HEX_H) % 2 === 1;
|
|
24
|
+
const colOffset = isOddHex ? HEX_W / 2 : 0;
|
|
25
|
+
const colInHex = (((c - colOffset) % HEX_W) + HEX_W) % HEX_W;
|
|
26
|
+
if (rowInHex === 0 || rowInHex === HEX_H - 1) {
|
|
27
|
+
return colInHex >= 2 && colInHex <= 5;
|
|
28
|
+
}
|
|
29
|
+
if (rowInHex === 1 || rowInHex === 2) {
|
|
30
|
+
return colInHex === 1 || colInHex === 6;
|
|
31
|
+
}
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
export function showWelcome() {
|
|
35
|
+
return new Promise((resolve) => {
|
|
36
|
+
const cols = process.stdout.columns || 60;
|
|
37
|
+
const gridRows = process.stdout.rows || 24;
|
|
38
|
+
let frame = 0;
|
|
39
|
+
// Init bees
|
|
40
|
+
const bees = [];
|
|
41
|
+
for (let i = 0; i < NUM_BEES; i++) {
|
|
42
|
+
bees.push({
|
|
43
|
+
r: Math.floor(Math.random() * gridRows),
|
|
44
|
+
c: Math.floor(Math.random() * cols),
|
|
45
|
+
vr: Math.random() > 0.5 ? 1 : -1,
|
|
46
|
+
vc: Math.random() > 0.5 ? 1 : -1,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
// Init stream columns
|
|
50
|
+
const streamCols = [];
|
|
51
|
+
const spacing = Math.floor(cols / (NUM_STREAMS + 1));
|
|
52
|
+
for (let i = 1; i <= NUM_STREAMS; i++) {
|
|
53
|
+
streamCols.push(spacing * i);
|
|
54
|
+
}
|
|
55
|
+
let pulses = [];
|
|
56
|
+
// Title positioning
|
|
57
|
+
const title = '\u2B21 HIVE';
|
|
58
|
+
const subtitle = 'Agent Creation Studio';
|
|
59
|
+
const titleRow = Math.floor(gridRows / 2) - 1;
|
|
60
|
+
const subtitleRow = titleRow + 1;
|
|
61
|
+
const titleCol = Math.floor((cols - title.length) / 2);
|
|
62
|
+
const subtitleCol = Math.floor((cols - subtitle.length) / 2);
|
|
63
|
+
// Boot message row positions
|
|
64
|
+
const msgStartRow = subtitleRow + 2;
|
|
65
|
+
// Quiet zone around title + boot messages: no animation renders here
|
|
66
|
+
const PADDING_H = 3;
|
|
67
|
+
const PADDING_V = 1;
|
|
68
|
+
const longestMsg = BOOT_MESSAGES.reduce((max, m) => Math.max(max, m.prefix.length + 1 + m.text.length), 0);
|
|
69
|
+
const msgLeftEdge = Math.floor((cols - longestMsg) / 2);
|
|
70
|
+
const msgRightEdge = msgLeftEdge + longestMsg;
|
|
71
|
+
const quietLeft = Math.min(titleCol, subtitleCol, msgLeftEdge) - PADDING_H;
|
|
72
|
+
const quietRight = Math.max(titleCol + title.length, subtitleCol + subtitle.length, msgRightEdge) + PADDING_H;
|
|
73
|
+
const quietTop = titleRow - PADDING_V;
|
|
74
|
+
const quietBottom = msgStartRow + BOOT_MESSAGES.length + PADDING_V;
|
|
75
|
+
// Hide cursor
|
|
76
|
+
process.stdout.write('\x1b[?25l');
|
|
77
|
+
// Clear screen
|
|
78
|
+
process.stdout.write('\x1b[2J');
|
|
79
|
+
function renderFrame() {
|
|
80
|
+
// Move cursor to top-left
|
|
81
|
+
process.stdout.write('\x1b[H');
|
|
82
|
+
// Advance bees every other frame
|
|
83
|
+
if (frame > 0 && frame % 2 === 0) {
|
|
84
|
+
for (const bee of bees) {
|
|
85
|
+
bee.r += bee.vr;
|
|
86
|
+
bee.c += bee.vc;
|
|
87
|
+
if (bee.r <= 0 || bee.r >= gridRows - 1) {
|
|
88
|
+
bee.vr *= -1;
|
|
89
|
+
bee.r = Math.max(0, Math.min(gridRows - 1, bee.r));
|
|
90
|
+
}
|
|
91
|
+
if (bee.c <= 0 || bee.c >= cols - 1) {
|
|
92
|
+
bee.vc *= -1;
|
|
93
|
+
bee.c = Math.max(0, Math.min(cols - 1, bee.c));
|
|
94
|
+
}
|
|
95
|
+
if (Math.random() > 0.3) {
|
|
96
|
+
bee.vc = Math.random() > 0.5 ? 1 : -1;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Spawn pulses
|
|
101
|
+
if (frame % 4 === 0) {
|
|
102
|
+
for (let i = 0; i < 3; i++) {
|
|
103
|
+
const pr = Math.floor(Math.random() * gridRows);
|
|
104
|
+
const pc = Math.floor(Math.random() * cols);
|
|
105
|
+
if (isHexEdge(pr, pc)) {
|
|
106
|
+
const pulseColors = [GREEN, RED, HONEY];
|
|
107
|
+
const color = pulseColors[Math.floor(Math.random() * pulseColors.length)];
|
|
108
|
+
pulses.push({ r: pr, c: pc, ttl: 8, color });
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
pulses = pulses.filter((p) => p.ttl > 0).map((p) => ({ ...p, ttl: p.ttl - 1 }));
|
|
112
|
+
}
|
|
113
|
+
// Build grid: char + color pairs
|
|
114
|
+
const charGrid = [];
|
|
115
|
+
const colorGrid = [];
|
|
116
|
+
for (let r = 0; r < gridRows; r++) {
|
|
117
|
+
const chars = [];
|
|
118
|
+
const clrs = [];
|
|
119
|
+
for (let c = 0; c < cols; c++) {
|
|
120
|
+
// Skip animation in quiet zone around title
|
|
121
|
+
if (r >= quietTop && r <= quietBottom && c >= quietLeft && c < quietRight) {
|
|
122
|
+
chars.push(' ');
|
|
123
|
+
clrs.push(DIM);
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
const hexEdge = isHexEdge(r, c);
|
|
127
|
+
// Scanning wave
|
|
128
|
+
const scanRow = frame % (gridRows + 6);
|
|
129
|
+
const dist = Math.abs(r - scanRow);
|
|
130
|
+
if (hexEdge && dist === 0) {
|
|
131
|
+
chars.push('⬢');
|
|
132
|
+
clrs.push(HONEY);
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (hexEdge && dist <= 1) {
|
|
136
|
+
chars.push('⬡');
|
|
137
|
+
clrs.push(HONEY);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
// Data streams
|
|
141
|
+
let isStream = false;
|
|
142
|
+
for (const sc of streamCols) {
|
|
143
|
+
if (c === sc) {
|
|
144
|
+
const streamOffset = (frame * 2 + sc) % (gridRows * 3);
|
|
145
|
+
const streamDist = (((r - streamOffset) % gridRows) + gridRows) % gridRows;
|
|
146
|
+
if (streamDist < 6) {
|
|
147
|
+
const charIdx = (frame + r) % DATA_CHARS.length;
|
|
148
|
+
const streamChar = DATA_CHARS[charIdx];
|
|
149
|
+
chars.push(streamChar);
|
|
150
|
+
if (streamDist === 0) {
|
|
151
|
+
clrs.push(WHITE);
|
|
152
|
+
}
|
|
153
|
+
else if (streamDist < 3) {
|
|
154
|
+
clrs.push(GREEN);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
clrs.push(DIM);
|
|
158
|
+
}
|
|
159
|
+
isStream = true;
|
|
160
|
+
break;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (isStream)
|
|
165
|
+
continue;
|
|
166
|
+
// Default
|
|
167
|
+
if (hexEdge) {
|
|
168
|
+
chars.push('·');
|
|
169
|
+
clrs.push(DIM);
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
chars.push(' ');
|
|
173
|
+
clrs.push(DIM);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
charGrid.push(chars);
|
|
177
|
+
colorGrid.push(clrs);
|
|
178
|
+
}
|
|
179
|
+
// Overlay pulses (skip quiet zone)
|
|
180
|
+
for (const pulse of pulses) {
|
|
181
|
+
if (pulse.r >= 0 && pulse.r < gridRows && pulse.c >= 0 && pulse.c < cols) {
|
|
182
|
+
const inQuietZone = pulse.r >= quietTop &&
|
|
183
|
+
pulse.r <= quietBottom &&
|
|
184
|
+
pulse.c >= quietLeft &&
|
|
185
|
+
pulse.c < quietRight;
|
|
186
|
+
if (inQuietZone)
|
|
187
|
+
continue;
|
|
188
|
+
const brightness = pulse.ttl / 8;
|
|
189
|
+
const cell = charGrid[pulse.r][pulse.c];
|
|
190
|
+
if (cell === '·' || cell === ' ') {
|
|
191
|
+
charGrid[pulse.r][pulse.c] = brightness > 0.5 ? '⬡' : '·';
|
|
192
|
+
colorGrid[pulse.r][pulse.c] = pulse.color;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// Overlay bees (skip quiet zone)
|
|
197
|
+
for (const bee of bees) {
|
|
198
|
+
const br = Math.max(0, Math.min(gridRows - 1, Math.round(bee.r)));
|
|
199
|
+
const bc = Math.max(0, Math.min(cols - 1, Math.round(bee.c)));
|
|
200
|
+
const inQuietZone = br >= quietTop && br <= quietBottom && bc >= quietLeft && bc < quietRight;
|
|
201
|
+
if (!inQuietZone) {
|
|
202
|
+
charGrid[br][bc] = '◆';
|
|
203
|
+
colorGrid[br][bc] = HONEY;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
// Overlay title with scramble→reveal effect
|
|
207
|
+
const TITLE_START_FRAME = 6;
|
|
208
|
+
const TITLE_REVEAL_FRAMES = 8;
|
|
209
|
+
if (frame >= TITLE_START_FRAME && titleRow >= 0 && titleRow < gridRows) {
|
|
210
|
+
const scrambleProgress = Math.min(1, (frame - TITLE_START_FRAME) / TITLE_REVEAL_FRAMES);
|
|
211
|
+
for (let i = 0; i < title.length; i++) {
|
|
212
|
+
const tc = titleCol + i;
|
|
213
|
+
if (tc < 0 || tc >= cols)
|
|
214
|
+
continue;
|
|
215
|
+
const charThreshold = i / title.length;
|
|
216
|
+
if (charThreshold <= scrambleProgress) {
|
|
217
|
+
charGrid[titleRow][tc] = title[i];
|
|
218
|
+
colorGrid[titleRow][tc] = HONEY;
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
const scrambleIdx = Math.floor(Math.random() * SCRAMBLE_CHARS.length);
|
|
222
|
+
charGrid[titleRow][tc] = SCRAMBLE_CHARS[scrambleIdx];
|
|
223
|
+
colorGrid[titleRow][tc] = DIM;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// Overlay subtitle with scramble→reveal (starts a few frames after title)
|
|
228
|
+
const SUB_START_FRAME = 10;
|
|
229
|
+
const SUB_REVEAL_FRAMES = 8;
|
|
230
|
+
if (frame >= SUB_START_FRAME && subtitleRow >= 0 && subtitleRow < gridRows) {
|
|
231
|
+
const scrambleProgress = Math.min(1, (frame - SUB_START_FRAME) / SUB_REVEAL_FRAMES);
|
|
232
|
+
for (let i = 0; i < subtitle.length; i++) {
|
|
233
|
+
const sc = subtitleCol + i;
|
|
234
|
+
if (sc < 0 || sc >= cols)
|
|
235
|
+
continue;
|
|
236
|
+
const charThreshold = i / subtitle.length;
|
|
237
|
+
if (charThreshold <= scrambleProgress) {
|
|
238
|
+
charGrid[subtitleRow][sc] = subtitle[i];
|
|
239
|
+
colorGrid[subtitleRow][sc] = DIM;
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
const scrambleIdx = Math.floor(Math.random() * SCRAMBLE_CHARS.length);
|
|
243
|
+
charGrid[subtitleRow][sc] = SCRAMBLE_CHARS[scrambleIdx];
|
|
244
|
+
colorGrid[subtitleRow][sc] = DIM;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// Overlay typewriter boot messages
|
|
249
|
+
for (let idx = 0; idx < BOOT_MESSAGES.length; idx++) {
|
|
250
|
+
const msg = BOOT_MESSAGES[idx];
|
|
251
|
+
if (frame < msg.frame)
|
|
252
|
+
continue;
|
|
253
|
+
const r = msgStartRow + idx;
|
|
254
|
+
if (r < 0 || r >= gridRows)
|
|
255
|
+
continue;
|
|
256
|
+
const fullText = `${msg.prefix} ${msg.text}`;
|
|
257
|
+
const msgCol = Math.floor((cols - fullText.length) / 2);
|
|
258
|
+
const visibleChars = Math.min(fullText.length, (frame - msg.frame) * 3);
|
|
259
|
+
for (let i = 0; i < visibleChars; i++) {
|
|
260
|
+
const c = msgCol + i;
|
|
261
|
+
if (c < 0 || c >= cols)
|
|
262
|
+
continue;
|
|
263
|
+
charGrid[r][c] = fullText[i];
|
|
264
|
+
colorGrid[r][c] = msg.color;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
// Render to stdout
|
|
268
|
+
let output = '';
|
|
269
|
+
for (let r = 0; r < gridRows; r++) {
|
|
270
|
+
let line = '';
|
|
271
|
+
let runColor = colorGrid[r][0];
|
|
272
|
+
let runChars = '';
|
|
273
|
+
for (let c = 0; c < cols; c++) {
|
|
274
|
+
const curColor = colorGrid[r][c];
|
|
275
|
+
const curChar = charGrid[r][c];
|
|
276
|
+
if (curColor === runColor) {
|
|
277
|
+
runChars += curChar;
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
line += chalk.hex(runColor)(runChars);
|
|
281
|
+
runColor = curColor;
|
|
282
|
+
runChars = curChar;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
if (runChars.length > 0) {
|
|
286
|
+
line += chalk.hex(runColor)(runChars);
|
|
287
|
+
}
|
|
288
|
+
output += line;
|
|
289
|
+
if (r < gridRows - 1) {
|
|
290
|
+
output += '\n';
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
process.stdout.write(output);
|
|
294
|
+
frame++;
|
|
295
|
+
}
|
|
296
|
+
const timer = setInterval(renderFrame, TICK_MS);
|
|
297
|
+
setTimeout(() => {
|
|
298
|
+
clearInterval(timer);
|
|
299
|
+
// Clear screen, show cursor, move to top
|
|
300
|
+
process.stdout.write('\x1b[2J\x1b[H\x1b[?25h');
|
|
301
|
+
resolve();
|
|
302
|
+
}, DURATION_MS);
|
|
303
|
+
});
|
|
304
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect } from 'react';
|
|
3
|
+
import { Box, Text, useApp } from 'ink';
|
|
4
|
+
import { colors, symbols, border } from '../theme.js';
|
|
5
|
+
import { scanAgents, fetchBulkStats, sortByHoney } from '../agents.js';
|
|
6
|
+
const COL = {
|
|
7
|
+
name: 0,
|
|
8
|
+
honey: 8,
|
|
9
|
+
wax: 8,
|
|
10
|
+
winRate: 10,
|
|
11
|
+
confidence: 8,
|
|
12
|
+
provider: 0,
|
|
13
|
+
created: 14,
|
|
14
|
+
};
|
|
15
|
+
function cell(text, width) {
|
|
16
|
+
return ` ${text}`.padEnd(width);
|
|
17
|
+
}
|
|
18
|
+
function formatDate(date) {
|
|
19
|
+
const formatted = date.toLocaleDateString('en-US', {
|
|
20
|
+
year: 'numeric',
|
|
21
|
+
month: 'short',
|
|
22
|
+
day: 'numeric',
|
|
23
|
+
});
|
|
24
|
+
return formatted;
|
|
25
|
+
}
|
|
26
|
+
export function ListApp() {
|
|
27
|
+
const { exit } = useApp();
|
|
28
|
+
const [rows, setRows] = useState(null);
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
const load = async () => {
|
|
31
|
+
const agents = await scanAgents();
|
|
32
|
+
if (agents.length === 0) {
|
|
33
|
+
setRows([]);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const names = agents.map((a) => a.name);
|
|
37
|
+
const statsMap = await fetchBulkStats(names);
|
|
38
|
+
const agentRows = agents.map((info) => ({
|
|
39
|
+
info,
|
|
40
|
+
stats: statsMap.get(info.name) ?? null,
|
|
41
|
+
}));
|
|
42
|
+
const sortedRows = sortByHoney(agentRows);
|
|
43
|
+
setRows(sortedRows);
|
|
44
|
+
};
|
|
45
|
+
void load();
|
|
46
|
+
}, []);
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
if (rows !== null) {
|
|
49
|
+
exit();
|
|
50
|
+
}
|
|
51
|
+
}, [rows]);
|
|
52
|
+
if (rows === null) {
|
|
53
|
+
return (_jsx(Box, { marginLeft: 2, children: _jsx(Text, { color: colors.gray, children: "Scanning agents..." }) }));
|
|
54
|
+
}
|
|
55
|
+
if (rows.length === 0) {
|
|
56
|
+
return (_jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsxs(Box, { marginBottom: 1, children: [_jsxs(Text, { color: colors.honey, children: [symbols.hive, " "] }), _jsx(Text, { color: colors.white, bold: true, children: "No agents found" })] }), _jsxs(Text, { color: colors.gray, children: ["Create one with: ", _jsx(Text, { color: colors.white, children: "npx @hive-org/cli@latest create" })] })] }));
|
|
57
|
+
}
|
|
58
|
+
const nameW = Math.max(COL.name, ...rows.map((r) => r.info.name.length)) + 2;
|
|
59
|
+
const providerW = Math.max(COL.provider, ...rows.map((r) => r.info.provider.length)) + 2;
|
|
60
|
+
const honeyW = COL.honey;
|
|
61
|
+
const waxW = COL.wax;
|
|
62
|
+
const winRateW = COL.winRate;
|
|
63
|
+
const confidenceW = COL.confidence;
|
|
64
|
+
const createdW = COL.created;
|
|
65
|
+
const sep = border.horizontal;
|
|
66
|
+
const totalWidth = nameW + 1 + honeyW + 1 + waxW + 1 + winRateW + 1 + confidenceW + 1 + providerW + 1 + createdW;
|
|
67
|
+
const topBorder = `${border.topLeft}${sep.repeat(totalWidth)}${border.topRight}`;
|
|
68
|
+
const midBorder = `${border.teeLeft}${sep.repeat(totalWidth)}${border.teeRight}`;
|
|
69
|
+
const botBorder = `${border.bottomLeft}${sep.repeat(totalWidth)}${border.bottomRight}`;
|
|
70
|
+
const v = border.vertical;
|
|
71
|
+
return (_jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsxs(Box, { marginBottom: 1, children: [_jsxs(Text, { color: colors.honey, children: [symbols.hive, " "] }), _jsx(Text, { color: colors.white, bold: true, children: "Your Hive Agents" }), _jsxs(Text, { color: colors.grayDim, children: [" (", rows.length, ")"] })] }), _jsx(Box, { children: _jsx(Text, { color: colors.honey, children: topBorder }) }), _jsxs(Box, { children: [_jsx(Text, { color: colors.honey, children: v }), _jsx(Text, { color: colors.white, bold: true, children: cell('Name', nameW) }), _jsx(Text, { color: colors.honey, children: v }), _jsx(Text, { color: colors.white, bold: true, children: cell('Honey', honeyW) }), _jsx(Text, { color: colors.honey, children: v }), _jsx(Text, { color: colors.white, bold: true, children: cell('Wax', waxW) }), _jsx(Text, { color: colors.honey, children: v }), _jsx(Text, { color: colors.white, bold: true, children: cell('Win Rate', winRateW) }), _jsx(Text, { color: colors.honey, children: v }), _jsx(Text, { color: colors.white, bold: true, children: cell('Conf', confidenceW) }), _jsx(Text, { color: colors.honey, children: v }), _jsx(Text, { color: colors.white, bold: true, children: cell('Provider', providerW) }), _jsx(Text, { color: colors.honey, children: v }), _jsx(Text, { color: colors.white, bold: true, children: cell('Created', createdW) }), _jsx(Text, { color: colors.honey, children: v })] }), _jsx(Box, { children: _jsx(Text, { color: colors.honey, children: midBorder }) }), rows.map((row) => {
|
|
72
|
+
const s = row.stats;
|
|
73
|
+
const honeyText = s !== null ? String(Math.floor(s.honey)) : '-';
|
|
74
|
+
const waxText = s !== null ? String(Math.floor(s.wax)) : '-';
|
|
75
|
+
const winRateText = s !== null ? `${(s.win_rate * 100).toFixed(2)}%` : '-';
|
|
76
|
+
const confidenceText = s !== null ? s.confidence.toFixed(2) : '-';
|
|
77
|
+
return (_jsxs(Box, { children: [_jsx(Text, { color: colors.honey, children: v }), _jsx(Text, { color: colors.white, children: cell(row.info.name, nameW) }), _jsx(Text, { color: colors.honey, children: v }), _jsx(Text, { color: colors.honey, children: cell(honeyText, honeyW) }), _jsx(Text, { color: colors.honey, children: v }), _jsx(Text, { color: colors.wax, children: cell(waxText, waxW) }), _jsx(Text, { color: colors.honey, children: v }), _jsx(Text, { color: colors.green, children: cell(winRateText, winRateW) }), _jsx(Text, { color: colors.honey, children: v }), _jsx(Text, { color: colors.cyan, children: cell(confidenceText, confidenceW) }), _jsx(Text, { color: colors.honey, children: v }), _jsx(Text, { color: colors.gray, children: cell(row.info.provider, providerW) }), _jsx(Text, { color: colors.honey, children: v }), _jsx(Text, { color: colors.grayDim, children: cell(formatDate(row.info.created), createdW) }), _jsx(Text, { color: colors.honey, children: v })] }, row.info.name));
|
|
78
|
+
}), _jsx(Box, { children: _jsx(Text, { color: colors.honey, children: botBorder }) })] }));
|
|
79
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
3
|
+
import { Box, Text, useInput, useApp } from 'ink';
|
|
4
|
+
import { scanAgents } from '../agents.js';
|
|
5
|
+
import { colors, symbols, styled, border } from '../theme.js';
|
|
6
|
+
import { isOldStyleAgent, migrateAgent } from './migrate.js';
|
|
7
|
+
export function MigrateApp() {
|
|
8
|
+
const { exit } = useApp();
|
|
9
|
+
const [phase, setPhase] = useState('scanning');
|
|
10
|
+
const [agents, setAgents] = useState([]);
|
|
11
|
+
const [cursor, setCursor] = useState(0);
|
|
12
|
+
const [results, setResults] = useState([]);
|
|
13
|
+
const [currentStep, setCurrentStep] = useState('');
|
|
14
|
+
const [currentAgent, setCurrentAgent] = useState('');
|
|
15
|
+
// ─── Scan phase ────────────────────────────────────
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
const scan = async () => {
|
|
18
|
+
const discovered = await scanAgents();
|
|
19
|
+
if (discovered.length === 0) {
|
|
20
|
+
setPhase('done');
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const selectableAgents = discovered.map((info) => {
|
|
24
|
+
const oldStyle = isOldStyleAgent(info.dir);
|
|
25
|
+
return {
|
|
26
|
+
info,
|
|
27
|
+
selected: oldStyle,
|
|
28
|
+
isOldStyle: oldStyle,
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
const hasOldStyle = selectableAgents.some((a) => a.isOldStyle);
|
|
32
|
+
if (!hasOldStyle) {
|
|
33
|
+
setResults(selectableAgents.map((a) => ({
|
|
34
|
+
name: a.info.name,
|
|
35
|
+
success: true,
|
|
36
|
+
error: 'Already migrated',
|
|
37
|
+
})));
|
|
38
|
+
setPhase('done');
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
setAgents(selectableAgents);
|
|
42
|
+
setPhase('selecting');
|
|
43
|
+
};
|
|
44
|
+
scan().catch((err) => {
|
|
45
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
46
|
+
setResults([{ name: 'scan', success: false, error: message }]);
|
|
47
|
+
setPhase('done');
|
|
48
|
+
});
|
|
49
|
+
}, []);
|
|
50
|
+
// ─── Keyboard input (selecting phase) ──────────────
|
|
51
|
+
useInput((input, key) => {
|
|
52
|
+
if (phase !== 'selecting')
|
|
53
|
+
return;
|
|
54
|
+
const oldStyleAgents = agents.filter((a) => a.isOldStyle);
|
|
55
|
+
if (key.upArrow) {
|
|
56
|
+
setCursor((prev) => Math.max(0, prev - 1));
|
|
57
|
+
}
|
|
58
|
+
else if (key.downArrow) {
|
|
59
|
+
setCursor((prev) => Math.min(oldStyleAgents.length - 1, prev + 1));
|
|
60
|
+
}
|
|
61
|
+
else if (input === ' ') {
|
|
62
|
+
// Toggle selection
|
|
63
|
+
const targetName = oldStyleAgents[cursor]?.info.name;
|
|
64
|
+
if (targetName) {
|
|
65
|
+
setAgents((prev) => prev.map((a) => a.info.name === targetName ? { ...a, selected: !a.selected } : a));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
else if (key.return) {
|
|
69
|
+
const selected = agents.filter((a) => a.selected && a.isOldStyle);
|
|
70
|
+
if (selected.length > 0) {
|
|
71
|
+
setPhase('migrating');
|
|
72
|
+
runMigrations(selected);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else if (input === 'q' || key.escape) {
|
|
76
|
+
exit();
|
|
77
|
+
}
|
|
78
|
+
}, { isActive: phase === 'selecting' });
|
|
79
|
+
// ─── Migrate phase ─────────────────────────────────
|
|
80
|
+
const runMigrations = useCallback(async (selected) => {
|
|
81
|
+
const migrateResults = [];
|
|
82
|
+
for (const agent of selected) {
|
|
83
|
+
setCurrentAgent(agent.info.name);
|
|
84
|
+
setCurrentStep('Starting migration');
|
|
85
|
+
const result = await migrateAgent(agent.info.dir, agent.info.name, (step) => {
|
|
86
|
+
setCurrentStep(step);
|
|
87
|
+
});
|
|
88
|
+
migrateResults.push(result);
|
|
89
|
+
setResults([...migrateResults]);
|
|
90
|
+
}
|
|
91
|
+
setCurrentAgent('');
|
|
92
|
+
setCurrentStep('');
|
|
93
|
+
setPhase('done');
|
|
94
|
+
}, []);
|
|
95
|
+
// ─── Done phase — exit after a short delay ─────────
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
if (phase === 'done') {
|
|
98
|
+
const timer = setTimeout(() => {
|
|
99
|
+
exit();
|
|
100
|
+
}, 1500);
|
|
101
|
+
return () => {
|
|
102
|
+
clearTimeout(timer);
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
}, [phase, exit]);
|
|
106
|
+
// ─── Render ────────────────────────────────────────
|
|
107
|
+
const termWidth = process.stdout.columns || 60;
|
|
108
|
+
if (phase === 'scanning') {
|
|
109
|
+
return (_jsx(Box, { flexDirection: "column", paddingLeft: 1, children: _jsxs(Text, { color: colors.honey, children: [symbols.hive, " Scanning agents..."] }) }));
|
|
110
|
+
}
|
|
111
|
+
if (phase === 'selecting') {
|
|
112
|
+
const oldStyleAgents = agents.filter((a) => a.isOldStyle);
|
|
113
|
+
const newStyleAgents = agents.filter((a) => !a.isOldStyle);
|
|
114
|
+
return (_jsxs(Box, { flexDirection: "column", paddingLeft: 1, children: [_jsxs(Text, { color: colors.honey, bold: true, children: [symbols.hive, " Migrate agents to @hive-org/cli"] }), _jsx(Text, { color: colors.gray, children: border.horizontal.repeat(termWidth - 4) }), _jsxs(Text, { color: colors.gray, children: ["Use ", styled.white('↑↓'), " to navigate, ", styled.white('space'), " to toggle, ", styled.white('enter'), " to confirm"] }), _jsx(Text, { children: " " }), oldStyleAgents.map((agent, i) => {
|
|
115
|
+
const isCursor = i === cursor;
|
|
116
|
+
const prefix = agent.selected ? symbols.check : symbols.diamondOpen;
|
|
117
|
+
const prefixColor = agent.selected ? colors.green : colors.gray;
|
|
118
|
+
const nameColor = isCursor ? colors.white : colors.gray;
|
|
119
|
+
const cursorChar = isCursor ? symbols.arrow : ' ';
|
|
120
|
+
return (_jsxs(Box, { children: [_jsxs(Text, { color: colors.honey, children: [cursorChar, " "] }), _jsxs(Text, { color: prefixColor, children: [prefix, " "] }), _jsx(Text, { color: nameColor, bold: isCursor, children: agent.info.name }), _jsxs(Text, { color: colors.gray, children: [" (", agent.info.provider, ")"] })] }, agent.info.name));
|
|
121
|
+
}), newStyleAgents.length > 0 && (_jsxs(_Fragment, { children: [_jsx(Text, { children: " " }), _jsx(Text, { color: colors.gray, children: "Already migrated:" }), newStyleAgents.map((agent) => (_jsx(Box, { children: _jsxs(Text, { color: colors.gray, children: [' ', symbols.check, " ", agent.info.name] }) }, agent.info.name)))] })), _jsx(Text, { children: " " }), _jsx(Text, { color: colors.gray, children: styled.dim('q/esc to cancel') })] }));
|
|
122
|
+
}
|
|
123
|
+
if (phase === 'migrating') {
|
|
124
|
+
return (_jsxs(Box, { flexDirection: "column", paddingLeft: 1, children: [_jsxs(Text, { color: colors.honey, bold: true, children: [symbols.hive, " Migrating agents..."] }), _jsx(Text, { color: colors.gray, children: border.horizontal.repeat(termWidth - 4) }), results.map((r) => (_jsx(Box, { children: _jsxs(Text, { color: r.success ? colors.green : colors.red, children: [r.success ? symbols.check : symbols.cross, " ", r.name] }) }, r.name))), currentAgent && (_jsx(Box, { children: _jsxs(Text, { color: colors.honey, children: [symbols.diamond, " ", currentAgent, ": ", currentStep] }) }))] }));
|
|
125
|
+
}
|
|
126
|
+
// phase === 'done'
|
|
127
|
+
const successCount = results.filter((r) => r.success && !r.error).length;
|
|
128
|
+
const alreadyNew = results.filter((r) => r.error === 'Already migrated').length;
|
|
129
|
+
const failCount = results.filter((r) => !r.success).length;
|
|
130
|
+
return (_jsxs(Box, { flexDirection: "column", paddingLeft: 1, children: [_jsxs(Text, { color: colors.honey, bold: true, children: [symbols.hive, " Migration complete"] }), _jsx(Text, { color: colors.gray, children: border.horizontal.repeat(termWidth - 4) }), results.map((r) => (_jsxs(Box, { children: [r.success && !r.error && (_jsxs(Text, { color: colors.green, children: [symbols.check, " ", r.name, " \u2014 migrated"] })), r.error === 'Already migrated' && (_jsxs(Text, { color: colors.gray, children: [symbols.check, " ", r.name, " \u2014 already migrated"] })), !r.success && r.error !== 'Already migrated' && (_jsxs(Text, { color: colors.red, children: [symbols.cross, " ", r.name, " \u2014 ", r.error] }))] }, r.name))), agents.length === 0 && results.length === 0 && (_jsx(Text, { color: colors.gray, children: "No agents found in ~/.hive/agents/" })), _jsx(Text, { children: " " }), successCount > 0 && (_jsxs(Text, { color: colors.gray, children: ["Agents now run via @hive-org/cli. ", styled.white('npx @hive-org/cli@latest start'), " always uses the latest version."] }))] }));
|
|
131
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import fs from 'fs-extra';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
/** Files scaffolded by the old `hive create` that are now in @hive-org/cli */
|
|
4
|
+
const OLD_FILES = [
|
|
5
|
+
'index.tsx',
|
|
6
|
+
'analysis.ts',
|
|
7
|
+
'prompt.ts',
|
|
8
|
+
'chat-prompt.ts',
|
|
9
|
+
'memory-prompt.ts',
|
|
10
|
+
'edit-section.ts',
|
|
11
|
+
'fetch-rules.ts',
|
|
12
|
+
'helpers.ts',
|
|
13
|
+
'theme.ts',
|
|
14
|
+
'types.ts',
|
|
15
|
+
'process-lifecycle.ts',
|
|
16
|
+
'tsconfig.json',
|
|
17
|
+
];
|
|
18
|
+
/** Directories scaffolded by the old `hive create` */
|
|
19
|
+
const OLD_DIRS = ['hooks', 'components', 'hive'];
|
|
20
|
+
export function isOldStyleAgent(agentDir) {
|
|
21
|
+
const indexPath = path.join(agentDir, 'index.tsx');
|
|
22
|
+
return fs.pathExistsSync(indexPath);
|
|
23
|
+
}
|
|
24
|
+
export async function migrateAgent(agentDir, name, onStep) {
|
|
25
|
+
try {
|
|
26
|
+
// 1. Verify it's a valid agent
|
|
27
|
+
const soulPath = path.join(agentDir, 'SOUL.md');
|
|
28
|
+
const soulExists = await fs.pathExists(soulPath);
|
|
29
|
+
if (!soulExists) {
|
|
30
|
+
return { name, success: false, error: 'No SOUL.md found — not a valid agent' };
|
|
31
|
+
}
|
|
32
|
+
// 2. Delete old scaffolded files
|
|
33
|
+
onStep('Removing old runtime files');
|
|
34
|
+
for (const file of OLD_FILES) {
|
|
35
|
+
const filePath = path.join(agentDir, file);
|
|
36
|
+
const exists = await fs.pathExists(filePath);
|
|
37
|
+
if (exists) {
|
|
38
|
+
await fs.remove(filePath);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// 3. Delete old directories
|
|
42
|
+
onStep('Removing old directories');
|
|
43
|
+
for (const dir of OLD_DIRS) {
|
|
44
|
+
const dirPath = path.join(agentDir, dir);
|
|
45
|
+
const exists = await fs.pathExists(dirPath);
|
|
46
|
+
if (exists) {
|
|
47
|
+
await fs.remove(dirPath);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// 4. Rewrite package.json
|
|
51
|
+
onStep('Rewriting package.json');
|
|
52
|
+
const pkgPath = path.join(agentDir, 'package.json');
|
|
53
|
+
const pkgExists = await fs.pathExists(pkgPath);
|
|
54
|
+
let pkgName = `hive-agent-${name}`;
|
|
55
|
+
if (pkgExists) {
|
|
56
|
+
const oldPkg = await fs.readJson(pkgPath);
|
|
57
|
+
pkgName = oldPkg.name ?? pkgName;
|
|
58
|
+
}
|
|
59
|
+
const newPkg = {
|
|
60
|
+
name: pkgName,
|
|
61
|
+
private: true,
|
|
62
|
+
type: 'module',
|
|
63
|
+
scripts: {
|
|
64
|
+
start: 'npx @hive-org/cli@latest start',
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
await fs.writeJson(pkgPath, newPkg, { spaces: 2 });
|
|
68
|
+
// 5. Remove old node_modules and lock files (no longer needed)
|
|
69
|
+
onStep('Cleaning up old dependencies');
|
|
70
|
+
const nodeModulesPath = path.join(agentDir, 'node_modules');
|
|
71
|
+
const nodeModulesExists = await fs.pathExists(nodeModulesPath);
|
|
72
|
+
if (nodeModulesExists) {
|
|
73
|
+
await fs.remove(nodeModulesPath);
|
|
74
|
+
}
|
|
75
|
+
const lockPath = path.join(agentDir, 'package-lock.json');
|
|
76
|
+
const lockExists = await fs.pathExists(lockPath);
|
|
77
|
+
if (lockExists) {
|
|
78
|
+
await fs.remove(lockPath);
|
|
79
|
+
}
|
|
80
|
+
return { name, success: true };
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
84
|
+
return { name, success: false, error: message.slice(0, 200) };
|
|
85
|
+
}
|
|
86
|
+
}
|