monomind 1.10.18 → 1.10.20

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "monomind",
3
- "version": "1.10.18",
3
+ "version": "1.10.20",
4
4
  "description": "Monomind - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -27,6 +27,8 @@
27
27
  "packages/@monomind/cli/scripts/**/*.js",
28
28
  "packages/@monomind/cli/scripts/**/*.sh",
29
29
  "packages/@monomind/cli/package.json",
30
+ "scripts/*.mjs",
31
+ "scripts/*.sh",
30
32
  "packages/@monomind/shared/dist/**/*.js",
31
33
  "packages/@monomind/shared/dist/**/*.d.ts",
32
34
  "!packages/@monomind/shared/dist/**/*.map",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@monoes/monomindcli",
3
- "version": "1.10.18",
3
+ "version": "1.10.20",
4
4
  "type": "module",
5
5
  "description": "Monomind CLI - Enterprise AI agent orchestration with 60+ specialized agents, swarm coordination, MCP server, self-learning hooks, and vector memory for Claude Code",
6
6
  "main": "dist/src/index.js",
@@ -30,7 +30,7 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
30
30
  import { resolve, join, dirname, basename, relative } from 'node:path';
31
31
  import { createRequire } from 'node:module';
32
32
  import { fileURLToPath } from 'node:url';
33
- import { execFileSync } from 'node:child_process';
33
+ import { execFileSync, execSync, spawn } from 'node:child_process';
34
34
 
35
35
  const __dir = dirname(fileURLToPath(import.meta.url));
36
36
  const CWD = process.cwd();
@@ -128,12 +128,60 @@ function detectLayersHeuristic(fileNodes) {
128
128
  return layers;
129
129
  }
130
130
 
131
- // ── Anthropic API helpers (raw fetch — no SDK needed) ────────────────────────
131
+ // ── Anthropic API helpers ─────────────────────────────────────────────────────
132
+ // Two paths:
133
+ // 1. Direct API via ANTHROPIC_API_KEY (fastest, parallel-safe, requires key)
134
+ // 2. `claude -p` CLI passthrough (reuses Claude Code's auth — no key needed)
135
+ // Slower (CLI cold-start per call), but works inside any Claude Code
136
+ // session without extra setup.
132
137
  const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY;
133
138
  const ANTHROPIC_URL = 'https://api.anthropic.com/v1/messages';
134
139
  const MODEL = 'claude-haiku-4-5-20251001'; // cheapest for bulk analysis
135
140
 
136
- async function callClaude(systemPrompt, userPrompt, maxTokens = 1024) {
141
+ // Detect `claude` CLI once at startup.
142
+ let _claudeCliPath = null;
143
+ function _detectClaudeCli() {
144
+ if (_claudeCliPath !== null) return _claudeCliPath;
145
+ try {
146
+ const out = execSync('command -v claude 2>/dev/null', { encoding: 'utf-8' }).trim();
147
+ _claudeCliPath = out || '';
148
+ } catch { _claudeCliPath = ''; }
149
+ return _claudeCliPath;
150
+ }
151
+
152
+ const USE_CLAUDE_CLI = !ANTHROPIC_API_KEY && !!_detectClaudeCli();
153
+
154
+ async function callClaudeViaCli(systemPrompt, userPrompt, maxTokens = 1024) {
155
+ return new Promise((resolveP, reject) => {
156
+ const args = [
157
+ '-p',
158
+ '--model', 'haiku',
159
+ '--output-format', 'text',
160
+ '--bare', // skip hooks/skills/auto-memory — we want a fast, clean call
161
+ // Combine system + user into a single prompt argument
162
+ `${systemPrompt}\n\n---\n\n${userPrompt}`,
163
+ ];
164
+ const child = spawn(_claudeCliPath, args, {
165
+ stdio: ['ignore', 'pipe', 'pipe'],
166
+ env: { ...process.env },
167
+ });
168
+ let out = '', err = '';
169
+ child.stdout.on('data', d => out += d.toString());
170
+ child.stderr.on('data', d => err += d.toString());
171
+ const timeout = setTimeout(() => {
172
+ child.kill('SIGKILL');
173
+ reject(new Error('claude -p timed out after 60s'));
174
+ }, 60000);
175
+ child.on('close', code => {
176
+ clearTimeout(timeout);
177
+ if (code !== 0) return reject(new Error(`claude -p exited ${code}: ${err.slice(0, 200)}`));
178
+ resolveP(out.trim());
179
+ });
180
+ child.on('error', e => { clearTimeout(timeout); reject(e); });
181
+ });
182
+ }
183
+
184
+ async function callClaudeViaApi(systemPrompt, userPrompt, maxTokens = 1024) {
137
185
  const body = JSON.stringify({
138
186
  model: MODEL,
139
187
  max_tokens: maxTokens,
@@ -153,7 +201,6 @@ async function callClaude(systemPrompt, userPrompt, maxTokens = 1024) {
153
201
  const data = await resp.json();
154
202
  return data.content?.[0]?.text ?? '';
155
203
  }
156
- // Retry on 429 (rate limit) and 5xx; fail fast on 4xx
157
204
  if (resp.status === 429 || resp.status >= 500) {
158
205
  const retryAfter = parseInt(resp.headers.get('retry-after') || '0', 10);
159
206
  const backoff = retryAfter > 0 ? retryAfter * 1000 : Math.min(2 ** attempt * 1000, 8000);
@@ -172,6 +219,16 @@ async function callClaude(systemPrompt, userPrompt, maxTokens = 1024) {
172
219
  throw lastError || new Error('Anthropic API failed after 3 attempts');
173
220
  }
174
221
 
222
+ async function callClaude(systemPrompt, userPrompt, maxTokens = 1024) {
223
+ if (ANTHROPIC_API_KEY) {
224
+ return callClaudeViaApi(systemPrompt, userPrompt, maxTokens);
225
+ }
226
+ if (USE_CLAUDE_CLI) {
227
+ return callClaudeViaCli(systemPrompt, userPrompt, maxTokens);
228
+ }
229
+ throw new Error('No LLM path available: set ANTHROPIC_API_KEY or install `claude` CLI');
230
+ }
231
+
175
232
  function parseJson(text) {
176
233
  try {
177
234
  const fenceMatch = text.match(/```(?:json)?\s*\n?([\s\S]*?)\n?\s*```/);
@@ -640,12 +697,13 @@ async function main() {
640
697
  const batch = toAnalyze.slice(0, limit);
641
698
  console.log(`[understand] Analyzing ${batch.length} files (${toAnalyze.length - batch.length} skipped/already enriched)`);
642
699
 
643
- if (!ANTHROPIC_API_KEY && !noLlm) {
644
- console.warn('[understand] ANTHROPIC_API_KEY not set falling back to --no-llm heuristic mode');
645
- // Fall through to heuristic only
700
+ const llmPath = ANTHROPIC_API_KEY ? 'api' : (USE_CLAUDE_CLI ? 'claude-cli' : 'none');
701
+ if (llmPath === 'none' && !noLlm) {
702
+ console.warn('[understand] No LLM path available (no ANTHROPIC_API_KEY and no `claude` CLI) — falling back to --no-llm heuristic mode');
703
+ } else if (llmPath === 'claude-cli' && !noLlm) {
704
+ console.log('[understand] Using `claude -p` CLI passthrough (no API key needed; reusing Claude Code auth)');
646
705
  }
647
-
648
- const useLlm = !noLlm && !!ANTHROPIC_API_KEY;
706
+ const useLlm = !noLlm && llmPath !== 'none';
649
707
 
650
708
  // ── Get project context for better prompts ────────────────────────────────
651
709
  let projectContext = `Project directory: ${basename(projectDir)}`;
@@ -798,7 +856,7 @@ async function main() {
798
856
  async function detectAndWriteLayers(db, fileNodes, forceHeuristic, dryRun, dir) {
799
857
  let layers;
800
858
 
801
- if (!forceHeuristic && ANTHROPIC_API_KEY) {
859
+ if (!forceHeuristic && (ANTHROPIC_API_KEY || USE_CLAUDE_CLI)) {
802
860
  console.log('[understand] Detecting architectural layers via LLM...');
803
861
  const filePaths = fileNodes.map(n => n.file_path).filter(Boolean);
804
862
  try {
@@ -0,0 +1,392 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Monomind Installer (formerly Monomind)
4
+ # https://github.com/nokhodian/monomind
5
+ #
6
+ # Usage:
7
+ # curl -fsSL https://cdn.jsdelivr.net/gh/nokhodian/monomind@main/scripts/install.sh | bash
8
+ # curl -fsSL https://cdn.jsdelivr.net/gh/nokhodian/monomind@main/scripts/install.sh | bash -s -- --full
9
+ # curl -fsSL https://cdn.jsdelivr.net/gh/nokhodian/monomind@main/scripts/install.sh | bash -s -- --global
10
+ # curl -fsSL https://cdn.jsdelivr.net/gh/nokhodian/monomind@main/scripts/install.sh | bash -s -- --minimal
11
+ #
12
+ # Options (via arguments):
13
+ # --global Global install (npm install -g)
14
+ # --minimal Minimal install (no optional deps)
15
+ # --full Full setup (global + MCP + doctor + init)
16
+ # --version=X.X.X Specific version
17
+ #
18
+ # Options (via environment - requires export):
19
+ # export MONOMIND_VERSION=alpha
20
+ # export MONOMIND_MINIMAL=1
21
+ # export MONOMIND_GLOBAL=1
22
+ #
23
+
24
+ set -euo pipefail
25
+
26
+ # Colors
27
+ RED='\033[0;31m'
28
+ GREEN='\033[0;32m'
29
+ YELLOW='\033[1;33m'
30
+ BLUE='\033[0;34m'
31
+ CYAN='\033[0;36m'
32
+ BOLD='\033[1m'
33
+ DIM='\033[2m'
34
+ NC='\033[0m' # No Color
35
+
36
+ # Default configuration (can be overridden by env vars)
37
+ VERSION="${MONOMIND_VERSION:-${MONOMIND_VERSION:-latest}}"
38
+ MINIMAL="${MONOMIND_MINIMAL:-0}"
39
+ GLOBAL="${MONOMIND_GLOBAL:-0}"
40
+ SETUP_MCP="${MONOMIND_SETUP_MCP:-0}"
41
+ RUN_DOCTOR="${MONOMIND_DOCTOR:-0}"
42
+ RUN_INIT="${MONOMIND_INIT:-1}"
43
+
44
+ # Parse command line arguments
45
+ while [[ $# -gt 0 ]]; do
46
+ case $1 in
47
+ --global|-g)
48
+ GLOBAL="1"
49
+ shift
50
+ ;;
51
+ --minimal|-m)
52
+ MINIMAL="1"
53
+ shift
54
+ ;;
55
+ --setup-mcp|--mcp)
56
+ SETUP_MCP="1"
57
+ shift
58
+ ;;
59
+ --doctor|-d)
60
+ RUN_DOCTOR="1"
61
+ shift
62
+ ;;
63
+ --init|-i)
64
+ RUN_INIT="1"
65
+ shift
66
+ ;;
67
+ --no-init)
68
+ RUN_INIT="0"
69
+ shift
70
+ ;;
71
+ --full|-f)
72
+ GLOBAL="1"
73
+ SETUP_MCP="1"
74
+ RUN_DOCTOR="1"
75
+ RUN_INIT="1"
76
+ shift
77
+ ;;
78
+ --version=*)
79
+ VERSION="${1#*=}"
80
+ shift
81
+ ;;
82
+ --help|-h)
83
+ echo "Monomind Installer"
84
+ echo ""
85
+ echo "Usage: curl -fsSL .../install.sh | bash -s -- [OPTIONS]"
86
+ echo ""
87
+ echo "Options:"
88
+ echo " --global, -g Install globally (npm install -g monomind)"
89
+ echo " --minimal, -m Minimal install (skip optional deps)"
90
+ echo " --setup-mcp Auto-configure MCP server for Claude Code"
91
+ echo " --doctor, -d Run diagnostics after install"
92
+ echo " --no-init Skip project initialization (enabled by default)"
93
+ echo " --full, -f Full setup (global + mcp + doctor + init)"
94
+ echo " --version=X.X.X Install specific version (default: alpha)"
95
+ echo " --help, -h Show this help"
96
+ exit 0
97
+ ;;
98
+ *)
99
+ shift
100
+ ;;
101
+ esac
102
+ done
103
+
104
+ PACKAGE="monomind@${VERSION}"
105
+
106
+ # Progress animation
107
+ SPINNER_CHARS="⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏"
108
+ SPINNER_INDEX=0
109
+
110
+ spinner() {
111
+ printf "\r${CYAN}${SPINNER_CHARS:SPINNER_INDEX++:1}${NC} $1"
112
+ SPINNER_INDEX=$((SPINNER_INDEX % 10))
113
+ }
114
+
115
+ print_banner() {
116
+ echo ""
117
+ echo -e "${CYAN}╔═══════════════════════════════════════════════════════════╗${NC}"
118
+ echo -e "${CYAN}║${NC} ${BOLD}Monomind${NC} — AI Agent Orchestration for Claude Code ${CYAN}║${NC}"
119
+ echo -e "${CYAN}╚═══════════════════════════════════════════════════════════╝${NC}"
120
+ echo ""
121
+ }
122
+
123
+ print_step() {
124
+ echo -e "${GREEN}▸${NC} $1"
125
+ }
126
+
127
+ print_substep() {
128
+ echo -e " ${DIM}├─${NC} $1"
129
+ }
130
+
131
+ print_success() {
132
+ echo -e "${GREEN}✓${NC} $1"
133
+ }
134
+
135
+ print_warning() {
136
+ echo -e "${YELLOW}⚠${NC} $1"
137
+ }
138
+
139
+ print_error() {
140
+ echo -e "${RED}✗${NC} $1"
141
+ }
142
+
143
+ print_info() {
144
+ echo -e "${BLUE}ℹ${NC} $1"
145
+ }
146
+
147
+ check_requirements() {
148
+ print_step "Checking requirements..."
149
+
150
+ # Check Node.js
151
+ if command -v node &> /dev/null; then
152
+ NODE_VERSION=$(node -v | sed 's/v//')
153
+ NODE_MAJOR=$(echo "$NODE_VERSION" | cut -d. -f1)
154
+ if [ "$NODE_MAJOR" -ge 20 ]; then
155
+ print_substep "Node.js ${GREEN}v${NODE_VERSION}${NC} ✓"
156
+ else
157
+ print_error "Node.js 20+ required (found v${NODE_VERSION})"
158
+ echo ""
159
+ echo "Install Node.js 20+:"
160
+ echo " curl -fsSL https://fnm.vercel.app/install | bash"
161
+ echo " fnm install 20"
162
+ exit 1
163
+ fi
164
+ else
165
+ print_error "Node.js not found"
166
+ echo ""
167
+ echo "Install Node.js 20+:"
168
+ echo " curl -fsSL https://fnm.vercel.app/install | bash"
169
+ echo " fnm install 20"
170
+ exit 1
171
+ fi
172
+
173
+ # Check npm
174
+ if command -v npm &> /dev/null; then
175
+ NPM_VERSION=$(npm -v)
176
+ print_substep "npm ${GREEN}v${NPM_VERSION}${NC} ✓"
177
+ else
178
+ print_error "npm not found"
179
+ exit 1
180
+ fi
181
+
182
+ # Check Claude Code CLI
183
+ if command -v claude &> /dev/null; then
184
+ CLAUDE_VERSION=$(claude --version 2>/dev/null | head -1 || echo "installed")
185
+ print_substep "Claude Code ${GREEN}${CLAUDE_VERSION}${NC} ✓"
186
+ else
187
+ print_warning "Claude Code CLI not found"
188
+ print_substep "Installing Claude Code CLI via npm..."
189
+ if npm install -g @anthropic-ai/claude-code 2>/dev/null; then
190
+ if command -v claude &> /dev/null; then
191
+ CLAUDE_VERSION=$(claude --version 2>/dev/null | head -1 || echo "installed")
192
+ print_substep "Claude Code ${GREEN}${CLAUDE_VERSION}${NC} ✓"
193
+ else
194
+ print_substep "Installed. Restart terminal to use 'claude' command"
195
+ fi
196
+ else
197
+ print_warning "npm install failed. Try manually:"
198
+ print_substep "${BOLD}npm install -g @anthropic-ai/claude-code${NC}"
199
+ fi
200
+ fi
201
+
202
+ echo ""
203
+ }
204
+
205
+ show_install_options() {
206
+ print_step "Installation options:"
207
+ print_substep "Package: ${BOLD}${PACKAGE}${NC}"
208
+ if [ "$GLOBAL" = "1" ]; then
209
+ print_substep "Mode: ${BOLD}Global${NC} (npm install -g)"
210
+ else
211
+ print_substep "Mode: ${BOLD}npx${NC} (on-demand)"
212
+ fi
213
+ if [ "$MINIMAL" = "1" ]; then
214
+ print_substep "Profile: ${BOLD}Minimal${NC} (--omit=optional)"
215
+ else
216
+ print_substep "Profile: ${BOLD}Full${NC} (all features)"
217
+ fi
218
+ echo ""
219
+ }
220
+
221
+ install_package() {
222
+ local START_TIME=$(date +%s)
223
+
224
+ if [ "$GLOBAL" = "1" ]; then
225
+ print_step "Installing globally..."
226
+
227
+ if [ "$MINIMAL" = "1" ]; then
228
+ npm install -g "$PACKAGE" --omit=optional 2>&1 | while read -r line; do
229
+ if [[ "$line" == *"added"* ]]; then
230
+ print_substep "$line"
231
+ fi
232
+ done
233
+ else
234
+ npm install -g "$PACKAGE" 2>&1 | while read -r line; do
235
+ if [[ "$line" == *"added"* ]]; then
236
+ print_substep "$line"
237
+ fi
238
+ done
239
+ fi
240
+ else
241
+ print_step "Installing for npx usage..."
242
+ # Actually run npx to pre-install the package
243
+ npx -y "$PACKAGE" --version >/dev/null 2>&1 || true
244
+ print_substep "Package installed for npx"
245
+ fi
246
+
247
+ local END_TIME=$(date +%s)
248
+ local DURATION=$((END_TIME - START_TIME))
249
+
250
+ echo ""
251
+ print_success "Installed in ${BOLD}${DURATION}s${NC}"
252
+ }
253
+
254
+ verify_installation() {
255
+ print_step "Verifying installation..."
256
+
257
+ local VERSION_OUTPUT
258
+ if [ "$GLOBAL" = "1" ]; then
259
+ VERSION_OUTPUT=$(monomind --version 2>/dev/null || monomind --version 2>/dev/null || echo "")
260
+ if [ -z "$VERSION_OUTPUT" ]; then
261
+ print_warning "Global command not found in PATH"
262
+ print_substep "Try: ${BOLD}npm install -g monomind@${VERSION}${NC}"
263
+ return 0 # Don't fail - npm might need PATH refresh
264
+ fi
265
+ else
266
+ # For npx mode, package was already installed during install_package
267
+ VERSION_OUTPUT=$(npx "$PACKAGE" --version 2>/dev/null || echo "")
268
+ fi
269
+
270
+ if [ -n "$VERSION_OUTPUT" ]; then
271
+ print_substep "Version: ${GREEN}${VERSION_OUTPUT}${NC}"
272
+ echo ""
273
+ return 0
274
+ else
275
+ print_error "Installation verification failed"
276
+ return 1
277
+ fi
278
+ }
279
+
280
+ show_quickstart() {
281
+ echo -e "${CYAN}╔═══════════════════════════════════════════════════════════╗${NC}"
282
+ echo -e "${CYAN}║${NC} ${BOLD}Quick Start${NC} ${CYAN}║${NC}"
283
+ echo -e "${CYAN}╚═══════════════════════════════════════════════════════════╝${NC}"
284
+ echo ""
285
+
286
+ if [ "$GLOBAL" = "1" ]; then
287
+ echo -e " ${DIM}# Initialize project${NC}"
288
+ echo -e " ${BOLD}monomind init --wizard${NC}"
289
+ echo ""
290
+ echo -e " ${DIM}# Run system diagnostics${NC}"
291
+ echo -e " ${BOLD}monomind doctor${NC}"
292
+ echo ""
293
+ echo -e " ${DIM}# Add as MCP server to Claude Code${NC}"
294
+ echo -e " ${BOLD}claude mcp add monomind -- monomind mcp start${NC}"
295
+ else
296
+ echo -e " ${DIM}# Initialize project${NC}"
297
+ echo -e " ${BOLD}npx monomind@latest init --wizard${NC}"
298
+ echo ""
299
+ echo -e " ${DIM}# Run system diagnostics${NC}"
300
+ echo -e " ${BOLD}npx monomind@latest doctor${NC}"
301
+ echo ""
302
+ echo -e " ${DIM}# Add as MCP server to Claude Code${NC}"
303
+ echo -e " ${BOLD}claude mcp add monomind -- npx -y monomind@latest mcp start${NC}"
304
+ fi
305
+
306
+ echo ""
307
+ echo -e "${DIM}Documentation: https://github.com/nokhodian/monomind${NC}"
308
+ echo -e "${DIM}Issues: https://github.com/nokhodian/monomind/issues${NC}"
309
+ echo ""
310
+ }
311
+
312
+ setup_mcp_server() {
313
+ if [ "$SETUP_MCP" != "1" ]; then
314
+ return 0
315
+ fi
316
+
317
+ print_step "Setting up MCP server..."
318
+
319
+ if ! command -v claude &> /dev/null; then
320
+ print_warning "Claude CLI not found, skipping MCP setup"
321
+ return 0
322
+ fi
323
+
324
+ # Check if already configured
325
+ if claude mcp list 2>/dev/null | grep -q "monomind\|monomind"; then
326
+ print_substep "MCP server already configured ✓"
327
+ return 0
328
+ fi
329
+
330
+ # Add MCP server (pass MONOMIND_CWD so tools resolve paths correctly
331
+ # even when the MCP server is spawned with cwd='/')
332
+ if [ "$GLOBAL" = "1" ]; then
333
+ claude mcp add monomind -e MONOMIND_CWD="$HOME" -- monomind mcp start 2>/dev/null && \
334
+ print_substep "MCP server configured ✓" || \
335
+ print_warning "MCP setup failed - run manually: claude mcp add monomind -e MONOMIND_CWD=\"\$HOME\" -- monomind mcp start"
336
+ else
337
+ claude mcp add monomind -e MONOMIND_CWD="$HOME" -- npx -y monomind@${VERSION} mcp start 2>/dev/null && \
338
+ print_substep "MCP server configured ✓" || \
339
+ print_warning "MCP setup failed - run manually: claude mcp add monomind -e MONOMIND_CWD=\"\$HOME\" -- npx -y monomind@latest mcp start"
340
+ fi
341
+ echo ""
342
+ }
343
+
344
+ run_doctor() {
345
+ if [ "$RUN_DOCTOR" != "1" ]; then
346
+ return 0
347
+ fi
348
+
349
+ print_step "Running diagnostics..."
350
+ echo ""
351
+
352
+ if [ "$GLOBAL" = "1" ]; then
353
+ monomind doctor 2>&1 || true
354
+ else
355
+ npx monomind@${VERSION} doctor 2>&1 || true
356
+ fi
357
+ echo ""
358
+ }
359
+
360
+ run_init() {
361
+ if [ "$RUN_INIT" != "1" ]; then
362
+ return 0
363
+ fi
364
+
365
+ print_step "Initializing project..."
366
+ echo ""
367
+
368
+ if [ "$GLOBAL" = "1" ]; then
369
+ monomind init --yes 2>&1 || true
370
+ else
371
+ npx monomind@${VERSION} init --yes 2>&1 || true
372
+ fi
373
+ echo ""
374
+ }
375
+
376
+ # Main
377
+ main() {
378
+ print_banner
379
+ check_requirements
380
+ show_install_options
381
+ install_package
382
+ verify_installation
383
+ setup_mcp_server
384
+ run_doctor
385
+ run_init
386
+ show_quickstart
387
+
388
+ print_success "${BOLD}Monomind is ready!${NC}"
389
+ echo ""
390
+ }
391
+
392
+ main "$@"