adaptive-bitmask 1.0.0 → 2.0.4
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 +220 -255
- package/dist/ai/index.d.mts +16 -1
- package/dist/ai/index.d.ts +16 -1
- package/dist/ai/index.js +102 -6
- package/dist/ai/index.mjs +53 -5
- package/dist/{chunk-ZWEXRT33.mjs → chunk-QICJNGMQ.mjs} +53 -2
- package/dist/cli/index.d.mts +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +378 -0
- package/dist/cli/index.mjs +355 -0
- package/dist/{coordinator-Df48t6yJ.d.mts → coordinator-CqBBHhXv.d.mts} +6 -1
- package/dist/{coordinator-Df48t6yJ.d.ts → coordinator-CqBBHhXv.d.ts} +6 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +53 -2
- package/dist/index.mjs +1 -1
- package/package.json +17 -4
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
|
|
26
|
+
// src/cli/index.ts
|
|
27
|
+
var import_prompts = require("@clack/prompts");
|
|
28
|
+
var import_picocolors = __toESM(require("picocolors"));
|
|
29
|
+
var import_node_fs = __toESM(require("fs"));
|
|
30
|
+
var import_node_path = __toESM(require("path"));
|
|
31
|
+
async function main() {
|
|
32
|
+
(0, import_prompts.intro)(`${import_picocolors.default.bgCyan(import_picocolors.default.black(" create-swarm "))} ${import_picocolors.default.dim("v1.0.0")}`);
|
|
33
|
+
const projectName = await (0, import_prompts.text)({
|
|
34
|
+
message: "What is your project name?",
|
|
35
|
+
placeholder: "my-agent-swarm",
|
|
36
|
+
validate(value) {
|
|
37
|
+
if (!value || value.length === 0) return "Value is required";
|
|
38
|
+
if (import_node_fs.default.existsSync(import_node_path.default.join(process.cwd(), value))) return "Directory already exists";
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
if ((0, import_prompts.isCancel)(projectName) || typeof projectName !== "string") {
|
|
42
|
+
(0, import_prompts.cancel)("Operation cancelled");
|
|
43
|
+
process.exit(0);
|
|
44
|
+
}
|
|
45
|
+
const intent = await (0, import_prompts.text)({
|
|
46
|
+
message: "What is your swarm's primary intent?",
|
|
47
|
+
placeholder: "algorithmic trading",
|
|
48
|
+
initialValue: "algorithmic trading"
|
|
49
|
+
});
|
|
50
|
+
if ((0, import_prompts.isCancel)(intent) || typeof intent !== "string") {
|
|
51
|
+
(0, import_prompts.cancel)("Operation cancelled");
|
|
52
|
+
process.exit(0);
|
|
53
|
+
}
|
|
54
|
+
const agentCount = await (0, import_prompts.text)({
|
|
55
|
+
message: "How many agents in the swarm?",
|
|
56
|
+
placeholder: "10",
|
|
57
|
+
initialValue: "10",
|
|
58
|
+
validate(value) {
|
|
59
|
+
if (!value) return "Value is required";
|
|
60
|
+
const num = parseInt(value);
|
|
61
|
+
if (isNaN(num) || num <= 0) return "Must be a positive number";
|
|
62
|
+
if (num > 1e3) return "Let's start smaller (< 1000)";
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
if ((0, import_prompts.isCancel)(agentCount) || typeof agentCount !== "string") {
|
|
66
|
+
(0, import_prompts.cancel)("Operation cancelled");
|
|
67
|
+
process.exit(0);
|
|
68
|
+
}
|
|
69
|
+
const useAiSdk = await (0, import_prompts.confirm)({
|
|
70
|
+
message: "Integrate with Vercel AI SDK (CoordinationSession + Middleware)?",
|
|
71
|
+
initialValue: true
|
|
72
|
+
});
|
|
73
|
+
if ((0, import_prompts.isCancel)(useAiSdk) || typeof useAiSdk !== "boolean") {
|
|
74
|
+
(0, import_prompts.cancel)("Operation cancelled");
|
|
75
|
+
process.exit(0);
|
|
76
|
+
}
|
|
77
|
+
const useDashboard = await (0, import_prompts.confirm)({
|
|
78
|
+
message: "Scaffold a Live Dashboard / Control Plane (WebSocket)?",
|
|
79
|
+
initialValue: true
|
|
80
|
+
});
|
|
81
|
+
if ((0, import_prompts.isCancel)(useDashboard) || typeof useDashboard !== "boolean") {
|
|
82
|
+
(0, import_prompts.cancel)("Operation cancelled");
|
|
83
|
+
process.exit(0);
|
|
84
|
+
}
|
|
85
|
+
const deployment = await (0, import_prompts.select)({
|
|
86
|
+
message: "Choose a deployment strategy:",
|
|
87
|
+
options: [
|
|
88
|
+
{ value: "cloud", label: "Cloud LLMs (OpenAI/Anthropic)", hint: "Fast, paid" },
|
|
89
|
+
{ value: "local", label: "Local Models (Ollama/Llama)", hint: "Private, free" },
|
|
90
|
+
{ value: "sim", label: "Simulation / Mock", hint: "Ultra-fast testing (no LLM latency)" }
|
|
91
|
+
]
|
|
92
|
+
});
|
|
93
|
+
if ((0, import_prompts.isCancel)(deployment) || typeof deployment !== "string") {
|
|
94
|
+
(0, import_prompts.cancel)("Operation cancelled");
|
|
95
|
+
process.exit(0);
|
|
96
|
+
}
|
|
97
|
+
const s = (0, import_prompts.spinner)();
|
|
98
|
+
s.start(`Scaffolding ${projectName}...`);
|
|
99
|
+
const projectPath = import_node_path.default.join(process.cwd(), projectName);
|
|
100
|
+
import_node_fs.default.mkdirSync(projectPath, { recursive: true });
|
|
101
|
+
const pkg = {
|
|
102
|
+
name: projectName,
|
|
103
|
+
version: "0.1.0",
|
|
104
|
+
type: "module",
|
|
105
|
+
scripts: {
|
|
106
|
+
start: "tsx index.ts",
|
|
107
|
+
dev: "tsx --watch index.ts"
|
|
108
|
+
},
|
|
109
|
+
dependencies: {
|
|
110
|
+
"adaptive-bitmask": "^1.0.0",
|
|
111
|
+
"dotenv": "^16.4.5",
|
|
112
|
+
"p-limit": "^5.0.0"
|
|
113
|
+
},
|
|
114
|
+
devDependencies: {
|
|
115
|
+
"typescript": "^5.4.0",
|
|
116
|
+
"tsx": "^4.10.0",
|
|
117
|
+
"@types/node": "^20.0.0"
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
if (useAiSdk) {
|
|
121
|
+
pkg.dependencies["ai"] = "^4.0.0";
|
|
122
|
+
pkg.dependencies["zod"] = "^3.23.0";
|
|
123
|
+
pkg.dependencies["@ai-sdk/openai"] = "latest";
|
|
124
|
+
}
|
|
125
|
+
if (useDashboard) {
|
|
126
|
+
pkg.dependencies["ws"] = "^8.17.0";
|
|
127
|
+
pkg.devDependencies["@types/ws"] = "^8.5.10";
|
|
128
|
+
}
|
|
129
|
+
import_node_fs.default.writeFileSync(import_node_path.default.join(projectPath, "package.json"), JSON.stringify(pkg, null, 2));
|
|
130
|
+
const tsconfig = {
|
|
131
|
+
compilerOptions: {
|
|
132
|
+
target: "ES2022",
|
|
133
|
+
module: "ESNext",
|
|
134
|
+
moduleResolution: "bundler",
|
|
135
|
+
strict: true,
|
|
136
|
+
esModuleInterop: true,
|
|
137
|
+
skipLibCheck: true
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
import_node_fs.default.writeFileSync(import_node_path.default.join(projectPath, "tsconfig.json"), JSON.stringify(tsconfig, null, 2));
|
|
141
|
+
const envContent = deployment === "cloud" ? "OPENAI_API_KEY=sk-your-key-here\n" : deployment === "local" ? "OLLAMA_BASE_URL=http://localhost:11434\n" : "";
|
|
142
|
+
import_node_fs.default.writeFileSync(import_node_path.default.join(projectPath, ".env"), envContent);
|
|
143
|
+
import_node_fs.default.writeFileSync(import_node_path.default.join(projectPath, ".gitignore"), "node_modules\n.env\ndist\n");
|
|
144
|
+
const indexTs = generateIndexTs({
|
|
145
|
+
projectName,
|
|
146
|
+
intent,
|
|
147
|
+
agentCount: parseInt(agentCount),
|
|
148
|
+
useAiSdk,
|
|
149
|
+
useDashboard,
|
|
150
|
+
deployment
|
|
151
|
+
});
|
|
152
|
+
import_node_fs.default.writeFileSync(import_node_path.default.join(projectPath, "index.ts"), indexTs);
|
|
153
|
+
s.stop(`Project ${projectName} scaffolded!`);
|
|
154
|
+
(0, import_prompts.outro)(`
|
|
155
|
+
${import_picocolors.default.green("Success!")} Your swarm is ready.
|
|
156
|
+
${useDashboard ? import_picocolors.default.blue("\u{1F5A5}\uFE0F Dashboard active at: http://localhost:3000") : ""}
|
|
157
|
+
|
|
158
|
+
${import_picocolors.default.dim("Next steps:")}
|
|
159
|
+
${import_picocolors.default.cyan(`cd ${projectName}`)}
|
|
160
|
+
${import_picocolors.default.cyan("npm install")}
|
|
161
|
+
${import_picocolors.default.cyan("npm start")}
|
|
162
|
+
|
|
163
|
+
${import_picocolors.default.yellow("Note:")} Edit ${import_picocolors.default.bold("index.ts")} to customize agent prompts and scoring.
|
|
164
|
+
`);
|
|
165
|
+
}
|
|
166
|
+
function generateIndexTs(config) {
|
|
167
|
+
const { intent, agentCount, useAiSdk, useDashboard, deployment } = config;
|
|
168
|
+
let imports = `import 'dotenv/config';
|
|
169
|
+
import { SharedCognition } from 'adaptive-bitmask';
|
|
170
|
+
import pLimit from 'p-limit';`;
|
|
171
|
+
if (useAiSdk) {
|
|
172
|
+
imports += `
|
|
173
|
+
import { CoordinationSession } from 'adaptive-bitmask/ai';
|
|
174
|
+
import { openai } from '@ai-sdk/openai';
|
|
175
|
+
import { generateText } from 'ai';`;
|
|
176
|
+
}
|
|
177
|
+
if (useDashboard) {
|
|
178
|
+
imports += `
|
|
179
|
+
import { WebSocketServer } from 'ws';
|
|
180
|
+
import { createServer } from 'http';`;
|
|
181
|
+
}
|
|
182
|
+
const concurrency = Math.min(agentCount, 10);
|
|
183
|
+
let dashboardCode = "";
|
|
184
|
+
if (useDashboard) {
|
|
185
|
+
dashboardCode = `
|
|
186
|
+
/**
|
|
187
|
+
* \u{1F5A5}\uFE0F DASHBOARD / CONTROL PLANE
|
|
188
|
+
* Real-time monitoring of agent "thinking", bandwidth, and coordination.
|
|
189
|
+
*/
|
|
190
|
+
const server = createServer((req, res) => {
|
|
191
|
+
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
192
|
+
res.end(\`
|
|
193
|
+
<html>
|
|
194
|
+
<head>
|
|
195
|
+
<title>Shared Cognition Dashboard</title>
|
|
196
|
+
<style>
|
|
197
|
+
body { font-family: system-ui; background: #0f172a; color: #f8fafc; margin: 0; padding: 2rem; }
|
|
198
|
+
.grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
|
|
199
|
+
.card { background: #1e293b; padding: 1.5rem; border-radius: 0.5rem; border: 1px solid #334155; }
|
|
200
|
+
.log { font-family: monospace; height: 300px; overflow-y: auto; background: #000; padding: 1rem; border-radius: 0.25rem; font-size: 0.8rem; }
|
|
201
|
+
.agent-thinking { color: #38bdf8; }
|
|
202
|
+
.decision { color: #4ade80; font-weight: bold; }
|
|
203
|
+
.feature { display: inline-block; background: #334155; padding: 0.2rem 0.5rem; border-radius: 1rem; margin-right: 0.5rem; font-size: 0.7rem; }
|
|
204
|
+
h1 { margin-top: 0; color: #e2e8f0; }
|
|
205
|
+
</style>
|
|
206
|
+
</head>
|
|
207
|
+
<body>
|
|
208
|
+
<h1>\u{1F9E0} Shared Cognition Dashboard</h1>
|
|
209
|
+
<div class="grid">
|
|
210
|
+
<div class="card">
|
|
211
|
+
<h2>Swarm Status</h2>
|
|
212
|
+
<div id="status">Waiting for round...</div>
|
|
213
|
+
<h3>Active Consensus Features</h3>
|
|
214
|
+
<div id="features"></div>
|
|
215
|
+
</div>
|
|
216
|
+
<div class="card">
|
|
217
|
+
<h2>Real-time Analytics</h2>
|
|
218
|
+
<p>Coordination Latency: <span id="latency">0</span>ms</p>
|
|
219
|
+
<p>Total Agents: ${agentCount}</p>
|
|
220
|
+
<p>Bandwidth Reduction: 85x (Bitmask Protocol)</p>
|
|
221
|
+
</div>
|
|
222
|
+
</div>
|
|
223
|
+
<div class="card" style="margin-top: 1rem;">
|
|
224
|
+
<h2>Live Agent Logs ("Thinking")</h2>
|
|
225
|
+
<div id="logs" class="log"></div>
|
|
226
|
+
</div>
|
|
227
|
+
<script>
|
|
228
|
+
const ws = new WebSocket('ws://localhost:3001');
|
|
229
|
+
const logEl = document.getElementById('logs');
|
|
230
|
+
const statusEl = document.getElementById('status');
|
|
231
|
+
const featuresEl = document.getElementById('features');
|
|
232
|
+
const latencyEl = document.getElementById('latency');
|
|
233
|
+
|
|
234
|
+
ws.onmessage = (event) => {
|
|
235
|
+
const data = JSON.parse(event.data);
|
|
236
|
+
if (data.type === 'log') {
|
|
237
|
+
const div = document.createElement('div');
|
|
238
|
+
const time = new Date(data.timestamp).toLocaleTimeString();
|
|
239
|
+
div.innerHTML = \\\`[\${time}] <b>\${data.agentId}:</b> \${data.content}\\\`;
|
|
240
|
+
if (data.logType === 'thinking') div.className = 'agent-thinking';
|
|
241
|
+
if (data.logType === 'decision') div.className = 'decision';
|
|
242
|
+
logEl.prepend(div);
|
|
243
|
+
} else if (data.type === 'update') {
|
|
244
|
+
statusEl.innerText = \\\`Round Complete: \${data.decision}\\\`;
|
|
245
|
+
featuresEl.innerHTML = data.features.map(f => \\\`<span class="feature">\${f}</span>\\\`).join('');
|
|
246
|
+
latencyEl.innerText = data.latency.toFixed(2);
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
</script>
|
|
250
|
+
</body>
|
|
251
|
+
</html>
|
|
252
|
+
\`);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
const wss = new WebSocketServer({ port: 3001 });
|
|
256
|
+
server.listen(3000);
|
|
257
|
+
|
|
258
|
+
function broadcast(data: any) {
|
|
259
|
+
const msg = JSON.stringify(data);
|
|
260
|
+
wss.clients.forEach(c => c.send(msg));
|
|
261
|
+
}
|
|
262
|
+
`;
|
|
263
|
+
}
|
|
264
|
+
const concurrencyLimit = Math.min(agentCount, 10);
|
|
265
|
+
let agentLogic = "";
|
|
266
|
+
if (deployment === "sim") {
|
|
267
|
+
agentLogic = `
|
|
268
|
+
/**
|
|
269
|
+
* SIMULATION MODE: Parallel Mock Agent Execution
|
|
270
|
+
*/
|
|
271
|
+
const mockFeatures = ['price_up', 'volume_spike', 'momentum_strong', 'breakout_detected', 'EMERGENCY_halt'];
|
|
272
|
+
|
|
273
|
+
async function runAgent(id: number${useAiSdk ? ", session: any" : ""}) {
|
|
274
|
+
const agentName = \`Agent-\${id}\`;
|
|
275
|
+
|
|
276
|
+
// Simulate "Thinking"
|
|
277
|
+
${useAiSdk ? `session.logThinking(agentName, 'Analyzing market indicators...');` : useDashboard ? `broadcast({ type: 'log', agentId: agentName, logType: 'thinking', content: 'Analyzing market indicators...', timestamp: Date.now() });` : ""}
|
|
278
|
+
|
|
279
|
+
await new Promise(r => setTimeout(r, 10 + Math.random() * 50));
|
|
280
|
+
|
|
281
|
+
const count = Math.floor(Math.random() * 3) + 1;
|
|
282
|
+
const features = [];
|
|
283
|
+
for(let i=0; i<count; i++) {
|
|
284
|
+
features.push(mockFeatures[Math.floor(Math.random() * mockFeatures.length)]);
|
|
285
|
+
}
|
|
286
|
+
return features;
|
|
287
|
+
}`;
|
|
288
|
+
} else if (useAiSdk) {
|
|
289
|
+
agentLogic = `
|
|
290
|
+
/**
|
|
291
|
+
* AI SDK MODE: Parallel LLM Execution
|
|
292
|
+
*/
|
|
293
|
+
async function runAgent(id: number, session: any) {
|
|
294
|
+
const agentName = \`Agent-\${id}\`;
|
|
295
|
+
session.logThinking(agentName, 'Prompting LLM for observation...');
|
|
296
|
+
|
|
297
|
+
const { text } = await generateText({
|
|
298
|
+
model: openai('gpt-4o-mini'),
|
|
299
|
+
system: \`You are a \${intent} agent. Analyze the situation and output 1-3 relevant features from the schema as comma-separated strings.\`,
|
|
300
|
+
prompt: 'Current state analysis...',
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
const features = text.split(',').map(f => f.trim());
|
|
304
|
+
return features;
|
|
305
|
+
}`;
|
|
306
|
+
} else {
|
|
307
|
+
agentLogic = `
|
|
308
|
+
/**
|
|
309
|
+
* BASIC MODE: Parallel fetch execution
|
|
310
|
+
*/
|
|
311
|
+
async function runAgent(id: number) {
|
|
312
|
+
const agentName = \`Agent-\${id}\`;
|
|
313
|
+
${useDashboard ? `broadcast({ type: 'log', agentId: agentName, logType: 'thinking', content: 'Fetching data...', timestamp: Date.now() });` : ""}
|
|
314
|
+
return ['feature_a', 'feature_b'];
|
|
315
|
+
}`;
|
|
316
|
+
}
|
|
317
|
+
return `${imports}
|
|
318
|
+
|
|
319
|
+
const intent = "${intent}";
|
|
320
|
+
const agentCount = ${agentCount};
|
|
321
|
+
const limit = pLimit(${concurrencyLimit});
|
|
322
|
+
|
|
323
|
+
${dashboardCode}
|
|
324
|
+
|
|
325
|
+
${useAiSdk ? `const session = new CoordinationSession({
|
|
326
|
+
features: ['price_up', 'volume_spike', 'trend_up', 'volatility_high'],
|
|
327
|
+
onLog: (log) => {
|
|
328
|
+
${useDashboard ? "broadcast({ type: 'log', agentId: log.agentId, logType: log.type, content: log.content, timestamp: log.timestamp });" : "console.log(`[${new Date(log.timestamp).toLocaleTimeString()}] ${log.agentId}: ${log.content}`);"}
|
|
329
|
+
}
|
|
330
|
+
});` : `const cognition = new SharedCognition();`}
|
|
331
|
+
|
|
332
|
+
${agentLogic}
|
|
333
|
+
|
|
334
|
+
async function runSwarm() {
|
|
335
|
+
console.log(\`\u{1F680} Starting swarm: "\${intent}" with \${agentCount} agents...\`);
|
|
336
|
+
|
|
337
|
+
while (true) {
|
|
338
|
+
const start = performance.now();
|
|
339
|
+
${useAiSdk ? "session.startRound();" : ""}
|
|
340
|
+
|
|
341
|
+
const agentTasks = Array.from({ length: agentCount }, (_, i) =>
|
|
342
|
+
limit(() => runAgent(i${useAiSdk ? ", session" : ""}))
|
|
343
|
+
);
|
|
344
|
+
|
|
345
|
+
const allObservations = await Promise.all(agentTasks);
|
|
346
|
+
const llmTime = performance.now() - start;
|
|
347
|
+
|
|
348
|
+
const coordStart = performance.now();
|
|
349
|
+
${useAiSdk ? `
|
|
350
|
+
allObservations.forEach((obs, i) => session.report(\`agent-\${i}\`, obs));
|
|
351
|
+
const { decision, result, aggregatedFeatures } = session.decide();
|
|
352
|
+
const finalScore = result.finalScore;
|
|
353
|
+
` : `
|
|
354
|
+
const { decision, finalScore, activeFeatures: aggregatedFeatures } = cognition.processSwarmTick(allObservations);
|
|
355
|
+
`}
|
|
356
|
+
const coordTime = performance.now() - coordStart;
|
|
357
|
+
|
|
358
|
+
${useDashboard ? `
|
|
359
|
+
broadcast({
|
|
360
|
+
type: 'update',
|
|
361
|
+
decision,
|
|
362
|
+
features: aggregatedFeatures,
|
|
363
|
+
latency: coordTime,
|
|
364
|
+
totalLatency: performance.now() - start
|
|
365
|
+
});
|
|
366
|
+
` : ""}
|
|
367
|
+
|
|
368
|
+
console.log(\`\\nDecision: \${decision} (Coord: \${coordTime.toFixed(2)}ms, Total: \${(performance.now() - start).toFixed(2)}ms)\`);
|
|
369
|
+
|
|
370
|
+
// Pause between ticks
|
|
371
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
runSwarm().catch(console.error);
|
|
376
|
+
`;
|
|
377
|
+
}
|
|
378
|
+
main().catch(console.error);
|