@romiluz/clawmongo 0.1.0-rc.3 → 0.1.0-rc.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.
@@ -0,0 +1,129 @@
1
+ /**
2
+ * ClawMongo CLI Branding
3
+ *
4
+ * ASCII art logo, colors, and branding elements.
5
+ *
6
+ * @module cli/branding
7
+ */
8
+ /**
9
+ * ClawMongo ASCII art logo.
10
+ */
11
+ export const LOGO = `
12
+ \x1b[36m _____ _ __ __
13
+ / ____| | | \\/ |
14
+ | | | | __ ___ __| \\ / | ___ _ __ __ _ ___
15
+ | | | |/ _\` \\ \\ /\\ / /| |\\/| |/ _ \\| '_ \\ / _\` |/ _ \\
16
+ | |____| | (_| |\\ V V / | | | | (_) | | | | (_| | (_) |
17
+ \\_____|_|\\__,_| \\_/\\_/ |_| |_|\\___/|_| |_|\\__, |\\___/
18
+ __/ |
19
+ |___/ \x1b[0m`;
20
+ /**
21
+ * Tagline displayed under the logo.
22
+ */
23
+ export const TAGLINE = "\x1b[33m MongoDB is the brain, OpenClaw is the heart.\x1b[0m";
24
+ /**
25
+ * Short tagline for compact displays.
26
+ */
27
+ export const TAGLINE_SHORT = "\x1b[2mMongoDB-native agentic AI assistant\x1b[0m";
28
+ /**
29
+ * Version banner with logo.
30
+ */
31
+ export function getVersionBanner(version) {
32
+ return `${LOGO}
33
+ ${TAGLINE}
34
+
35
+ \x1b[2mVersion ${version}\x1b[0m
36
+ `;
37
+ }
38
+ /**
39
+ * Welcome message for first-run experience.
40
+ */
41
+ export function getWelcomeMessage(version) {
42
+ return `${LOGO}
43
+ ${TAGLINE}
44
+
45
+ \x1b[32m✨ Welcome to ClawMongo v${version}!\x1b[0m
46
+
47
+ ClawMongo is a MongoDB-native fork of OpenClaw that leverages
48
+ MongoDB's capabilities (Atlas Search, Vector Search, \$rankFusion)
49
+ while maintaining full parity with OpenClaw's features.
50
+
51
+ \x1b[36m📚 Quick Start:\x1b[0m
52
+
53
+ \x1b[33mclawmongo init\x1b[0m Set up your configuration
54
+ \x1b[33mclawmongo chat\x1b[0m Start interactive chat
55
+ \x1b[33mclawmongo send\x1b[0m Send a one-shot message
56
+ \x1b[33mclawmongo health\x1b[0m Check system status
57
+
58
+ \x1b[36m🔧 Configuration:\x1b[0m
59
+
60
+ Set these environment variables:
61
+
62
+ \x1b[2mANTHROPIC_API_KEY\x1b[0m Your Anthropic API key
63
+ \x1b[2mCLAWMONGO_MONGODB_URI\x1b[0m MongoDB connection string (optional)
64
+ \x1b[2mVOYAGE_API_KEY\x1b[0m Voyage AI key for embeddings (optional)
65
+
66
+ \x1b[36m📖 Documentation:\x1b[0m
67
+
68
+ https://github.com/romiluz13/ClawMongo
69
+
70
+ \x1b[2mRun 'clawmongo --help' for all available commands.\x1b[0m
71
+ `;
72
+ }
73
+ /**
74
+ * Compact header for command output.
75
+ */
76
+ export function getCompactHeader(version) {
77
+ return `\x1b[36m🐾 ClawMongo\x1b[0m v${version}`;
78
+ }
79
+ /**
80
+ * Success message with emoji.
81
+ */
82
+ export function successMessage(text) {
83
+ return `\x1b[32m✓\x1b[0m ${text}`;
84
+ }
85
+ /**
86
+ * Error message with emoji.
87
+ */
88
+ export function errorMessage(text) {
89
+ return `\x1b[31m✗\x1b[0m ${text}`;
90
+ }
91
+ /**
92
+ * Warning message with emoji.
93
+ */
94
+ export function warnMessage(text) {
95
+ return `\x1b[33m⚠\x1b[0m ${text}`;
96
+ }
97
+ /**
98
+ * Info message with emoji.
99
+ */
100
+ export function infoMessage(text) {
101
+ return `\x1b[36mℹ\x1b[0m ${text}`;
102
+ }
103
+ /**
104
+ * Step indicator for multi-step processes.
105
+ */
106
+ export function stepIndicator(current, total, text) {
107
+ return `\x1b[36m[${current}/${total}]\x1b[0m ${text}`;
108
+ }
109
+ /**
110
+ * Progress bar.
111
+ */
112
+ export function progressBar(percent, width = 30) {
113
+ const filled = Math.round((percent / 100) * width);
114
+ const empty = width - filled;
115
+ const bar = "\x1b[32m" + "█".repeat(filled) + "\x1b[2m" + "░".repeat(empty) + "\x1b[0m";
116
+ return `${bar} ${percent.toFixed(0)}%`;
117
+ }
118
+ /**
119
+ * Box drawing for important messages.
120
+ */
121
+ export function boxMessage(title, lines) {
122
+ const maxLen = Math.max(title.length, ...lines.map(l => l.length));
123
+ const top = `┌${"─".repeat(maxLen + 2)}┐`;
124
+ const titleLine = `│ \x1b[1m${title.padEnd(maxLen)}\x1b[0m │`;
125
+ const sep = `├${"─".repeat(maxLen + 2)}┤`;
126
+ const content = lines.map(l => `│ ${l.padEnd(maxLen)} │`).join("\n");
127
+ const bottom = `└${"─".repeat(maxLen + 2)}┘`;
128
+ return `${top}\n${titleLine}\n${sep}\n${content}\n${bottom}`;
129
+ }
@@ -0,0 +1,173 @@
1
+ /**
2
+ * ClawMongo Init Command
3
+ *
4
+ * Interactive setup wizard for first-time configuration.
5
+ *
6
+ * @module cli/commands/init
7
+ */
8
+ import * as readline from "readline";
9
+ import * as fs from "fs";
10
+ import * as path from "path";
11
+ import { ExitCode } from "./types.js";
12
+ import { createOutput } from "./output.js";
13
+ import { LOGO, TAGLINE, successMessage, errorMessage, stepIndicator, boxMessage } from "../branding.js";
14
+ /**
15
+ * Prompt user for input with optional default.
16
+ */
17
+ async function prompt(rl, question, defaultValue, isSecret = false) {
18
+ const defaultHint = defaultValue ? ` \x1b[2m(${isSecret ? "****" : defaultValue})\x1b[0m` : "";
19
+ return new Promise((resolve) => {
20
+ rl.question(` ${question}${defaultHint}: `, (answer) => {
21
+ resolve(answer.trim() || defaultValue || "");
22
+ });
23
+ });
24
+ }
25
+ /**
26
+ * Prompt for yes/no confirmation.
27
+ */
28
+ async function confirm(rl, question, defaultYes = true) {
29
+ const hint = defaultYes ? "[Y/n]" : "[y/N]";
30
+ return new Promise((resolve) => {
31
+ rl.question(` ${question} ${hint}: `, (answer) => {
32
+ const a = answer.trim().toLowerCase();
33
+ if (a === "")
34
+ resolve(defaultYes);
35
+ else
36
+ resolve(a === "y" || a === "yes");
37
+ });
38
+ });
39
+ }
40
+ /**
41
+ * Select from a list of options using arrow keys.
42
+ */
43
+ async function select(rl, question, options, defaultIndex = 0) {
44
+ console.log(`\n ${question}\n`);
45
+ let selectedIndex = defaultIndex;
46
+ // For simplicity, use numbered selection (arrow keys require raw mode)
47
+ options.forEach((opt, i) => {
48
+ const marker = i === defaultIndex ? "\x1b[36m→\x1b[0m" : " ";
49
+ console.log(` ${marker} ${i + 1}. ${opt.label}`);
50
+ });
51
+ return new Promise((resolve) => {
52
+ rl.question(`\n Enter number (1-${options.length}): `, (answer) => {
53
+ const num = parseInt(answer.trim(), 10);
54
+ if (num >= 1 && num <= options.length) {
55
+ const selected = options[num - 1];
56
+ resolve(selected ? selected.value : options[0]?.value ?? "");
57
+ }
58
+ else {
59
+ const defaultOpt = options[defaultIndex];
60
+ resolve(defaultOpt ? defaultOpt.value : options[0]?.value ?? "");
61
+ }
62
+ });
63
+ });
64
+ }
65
+ /**
66
+ * Write config to .env file.
67
+ */
68
+ function writeEnvFile(config, filePath) {
69
+ const lines = [
70
+ "# ClawMongo Configuration",
71
+ "# Generated by 'clawmongo init'",
72
+ "",
73
+ ];
74
+ if (config.anthropicApiKey) {
75
+ lines.push(`ANTHROPIC_API_KEY=${config.anthropicApiKey}`);
76
+ }
77
+ if (config.mongodbUri) {
78
+ lines.push(`CLAWMONGO_MONGODB_URI=${config.mongodbUri}`);
79
+ }
80
+ if (config.voyageApiKey) {
81
+ lines.push(`VOYAGE_API_KEY=${config.voyageApiKey}`);
82
+ }
83
+ if (config.openaiApiKey) {
84
+ lines.push(`OPENAI_API_KEY=${config.openaiApiKey}`);
85
+ }
86
+ lines.push("");
87
+ fs.writeFileSync(filePath, lines.join("\n"));
88
+ }
89
+ /**
90
+ * Init command - interactive setup wizard.
91
+ */
92
+ export const initCommand = {
93
+ name: "init",
94
+ aliases: ["setup", "configure"],
95
+ description: "Interactive setup wizard",
96
+ usage: "clawmongo init [--force]",
97
+ async execute(ctx) {
98
+ const out = createOutput({ json: ctx.json });
99
+ const envPath = path.join(process.cwd(), ".env");
100
+ // Check if .env already exists
101
+ if (fs.existsSync(envPath) && !ctx.flags.force) {
102
+ out.writeln(errorMessage(".env file already exists. Use --force to overwrite."));
103
+ return ExitCode.ERROR;
104
+ }
105
+ // Show welcome banner
106
+ console.log(LOGO);
107
+ console.log(TAGLINE);
108
+ console.log("\n \x1b[1m✨ Welcome to ClawMongo Setup!\x1b[0m\n");
109
+ console.log(" This wizard will help you configure ClawMongo.");
110
+ console.log(" Press Enter to accept defaults, or type your values.\n");
111
+ const rl = readline.createInterface({
112
+ input: process.stdin,
113
+ output: process.stdout
114
+ });
115
+ const config = {};
116
+ try {
117
+ // Step 1: Anthropic API Key
118
+ console.log(stepIndicator(1, 4, "\x1b[1mAnthropic API Key\x1b[0m"));
119
+ console.log(" \x1b[2mRequired for Claude AI. Get yours at https://console.anthropic.com\x1b[0m\n");
120
+ config.anthropicApiKey = await prompt(rl, "ANTHROPIC_API_KEY", process.env.ANTHROPIC_API_KEY, true);
121
+ // Step 2: MongoDB URI
122
+ console.log("\n" + stepIndicator(2, 4, "\x1b[1mMongoDB Connection\x1b[0m"));
123
+ console.log(" \x1b[2mOptional. Enables persistent storage, Atlas Search, and vector search.\x1b[0m\n");
124
+ const useMongo = await confirm(rl, "Configure MongoDB?", true);
125
+ if (useMongo) {
126
+ config.mongodbUri = await prompt(rl, "CLAWMONGO_MONGODB_URI", process.env.CLAWMONGO_MONGODB_URI);
127
+ }
128
+ // Step 3: Embedding Provider
129
+ console.log("\n" + stepIndicator(3, 4, "\x1b[1mEmbedding Provider\x1b[0m"));
130
+ console.log(" \x1b[2mOptional. Enables semantic search and RAG capabilities.\x1b[0m\n");
131
+ const embeddingProvider = await select(rl, "Select embedding provider:", [
132
+ { value: "none", label: "None (skip for now)" },
133
+ { value: "voyage", label: "Voyage AI (recommended)" },
134
+ { value: "openai", label: "OpenAI" }
135
+ ], 0);
136
+ if (embeddingProvider === "voyage") {
137
+ config.voyageApiKey = await prompt(rl, "VOYAGE_API_KEY", process.env.VOYAGE_API_KEY, true);
138
+ }
139
+ else if (embeddingProvider === "openai") {
140
+ config.openaiApiKey = await prompt(rl, "OPENAI_API_KEY", process.env.OPENAI_API_KEY, true);
141
+ }
142
+ // Step 4: Confirm and write
143
+ console.log("\n" + stepIndicator(4, 4, "\x1b[1mConfirm Configuration\x1b[0m\n"));
144
+ const summary = [
145
+ `Anthropic API Key: ${config.anthropicApiKey ? "✓ Set" : "✗ Not set"}`,
146
+ `MongoDB URI: ${config.mongodbUri ? "✓ Set" : "✗ Not set"}`,
147
+ `Voyage API Key: ${config.voyageApiKey ? "✓ Set" : "✗ Not set"}`,
148
+ `OpenAI API Key: ${config.openaiApiKey ? "✓ Set" : "✗ Not set"}`
149
+ ];
150
+ console.log(boxMessage("Configuration Summary", summary));
151
+ console.log("");
152
+ const shouldWrite = await confirm(rl, "Write configuration to .env?", true);
153
+ if (shouldWrite) {
154
+ writeEnvFile(config, envPath);
155
+ console.log("\n" + successMessage(`Configuration saved to ${envPath}`));
156
+ console.log("\n \x1b[36m🚀 You're all set! Try these commands:\x1b[0m\n");
157
+ console.log(" \x1b[33mclawmongo health\x1b[0m Check system status");
158
+ console.log(" \x1b[33mclawmongo chat\x1b[0m Start interactive chat");
159
+ console.log(" \x1b[33mclawmongo send\x1b[0m Send a message\n");
160
+ }
161
+ else {
162
+ console.log("\n" + errorMessage("Setup cancelled."));
163
+ }
164
+ rl.close();
165
+ return ExitCode.SUCCESS;
166
+ }
167
+ catch (err) {
168
+ rl.close();
169
+ out.error(err instanceof Error ? err.message : String(err));
170
+ return ExitCode.ERROR;
171
+ }
172
+ }
173
+ };
@@ -74,15 +74,26 @@ export function generateHelp(command, prefix = "") {
74
74
  export function generateGlobalHelp(registry, version) {
75
75
  const commands = registry.list();
76
76
  const lines = [];
77
- lines.push(`ClawMongo v${version}`);
78
- lines.push("MongoDB-native agentic AI assistant");
77
+ // ASCII Logo
78
+ lines.push("\x1b[36m _____ _ __ __ ");
79
+ lines.push(" / ____| | | \\/ | ");
80
+ lines.push(" | | | | __ ___ __| \\ / | ___ _ __ __ _ ___ ");
81
+ lines.push(" | | | |/ _` \\ \\ /\\ / /| |\\/| |/ _ \\| '_ \\ / _` |/ _ \\ ");
82
+ lines.push(" | |____| | (_| |\\ V V / | | | | (_) | | | | (_| | (_) |");
83
+ lines.push(" \\_____|_|\\__,_| \\_/\\_/ |_| |_|\\___/|_| |_|\\__, |\\___/ ");
84
+ lines.push(" __/ | ");
85
+ lines.push(" |___/ \x1b[0m");
86
+ lines.push("");
87
+ lines.push("\x1b[33m MongoDB is the brain, OpenClaw is the heart.\x1b[0m");
88
+ lines.push("");
89
+ lines.push(` \x1b[2mVersion ${version}\x1b[0m`);
79
90
  lines.push("");
80
91
  lines.push("Usage: clawmongo <command> [options]");
81
92
  lines.push("");
82
93
  lines.push("Commands:");
83
94
  for (const cmd of commands) {
84
95
  const aliasStr = cmd.aliases ? ` (${cmd.aliases.join(", ")})` : "";
85
- lines.push(` ${cmd.name.padEnd(12)}${aliasStr.padEnd(8)} ${cmd.description}`);
96
+ lines.push(` \x1b[33m${cmd.name.padEnd(12)}\x1b[0m${aliasStr.padEnd(8)} ${cmd.description}`);
86
97
  }
87
98
  lines.push("");
88
99
  lines.push("Options:");
@@ -91,6 +102,6 @@ export function generateGlobalHelp(registry, version) {
91
102
  lines.push(" --json Output as JSON");
92
103
  lines.push(" -V, --verbose Verbose output");
93
104
  lines.push("");
94
- lines.push("Run 'clawmongo <command> --help' for command-specific help.");
105
+ lines.push("\x1b[2mRun 'clawmongo <command> --help' for command-specific help.\x1b[0m");
95
106
  return lines.join("\n");
96
107
  }
package/dist/main.js CHANGED
@@ -19,13 +19,17 @@ import { cronCommand } from "./cli/commands/cron.js";
19
19
  import { backupCommand } from "./cli/commands/backup.js";
20
20
  import { securityCommand } from "./cli/commands/security.js";
21
21
  import { benchmarkCommand } from "./cli/commands/benchmark.js";
22
- const VERSION = "0.1.0-rc.3";
22
+ import { initCommand } from "./cli/commands/init.js";
23
+ // Import branding
24
+ import { getVersionBanner, getWelcomeMessage } from "./cli/branding.js";
25
+ const VERSION = "0.1.0-rc.4";
23
26
  /**
24
27
  * Build the command registry.
25
28
  */
26
29
  function buildRegistry() {
27
30
  const registry = createRegistry();
28
31
  // Register all commands
32
+ registry.register(initCommand); // Setup wizard first
29
33
  registry.register(healthCommand);
30
34
  registry.register(statusCommand);
31
35
  registry.register(doctorCommand);
@@ -51,7 +55,12 @@ async function main() {
51
55
  const out = createOutput({ json: hasFlag(parsed.flags, "json") });
52
56
  // Handle --version
53
57
  if (hasFlag(parsed.flags, "version") || hasFlag(parsed.flags, "v")) {
54
- out.writeln(`clawmongo ${VERSION}`);
58
+ out.writeln(getVersionBanner(VERSION));
59
+ return;
60
+ }
61
+ // Handle no command - show welcome message
62
+ if (!parsed.command && !hasFlag(parsed.flags, "help")) {
63
+ out.writeln(getWelcomeMessage(VERSION));
55
64
  return;
56
65
  }
57
66
  // Handle --help with no command
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@romiluz/clawmongo",
3
- "version": "0.1.0-rc.3",
3
+ "version": "0.1.0-rc.4",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "MongoDB-native OpenClaw-inspired assistant runtime",