@liquidmetal-ai/raindrop-code 0.0.1-alpha20

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.
Files changed (3) hide show
  1. package/README.md +158 -0
  2. package/install.js +230 -0
  3. package/package.json +49 -0
package/README.md ADDED
@@ -0,0 +1,158 @@
1
+ # Raindrop Code
2
+
3
+ > AI-powered terminal coding assistant with deep code understanding
4
+
5
+ Raindrop Code is an intelligent coding assistant that runs in your terminal, combining the power of large language models (Claude, GPT, and compatible APIs) with deep codebase understanding, file operations, git integration, and an extensible tool ecosystem.
6
+
7
+ ## Features
8
+
9
+ - 🧠 **Deep Code Understanding** - Automatically indexes your codebase using tree-sitter for intelligent search and context-aware assistance
10
+ - šŸ› ļø **Rich Tool Ecosystem** - File operations, git, bash, web search, and more - all accessible to the AI
11
+ - šŸ¤– **Specialized Agents** - Spawn sub-agents for code review, refactoring, and custom tasks
12
+ - ⚔ **Fast & Responsive** - Incremental indexing with real-time file watching
13
+ - šŸŽØ **Modern Terminal UI** - Clean interface with syntax highlighting and markdown rendering
14
+ - šŸ”Œ **MCP Support** - Integrates with Model Context Protocol servers
15
+ - 🌐 **Multi-Provider** - Works with Anthropic (Claude), OpenAI (GPT), and OpenAI-compatible APIs
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install -g @liquidmetal-ai/raindrop-code
21
+ ```
22
+
23
+ ## Quick Start
24
+
25
+ ### 1. Set up API keys
26
+
27
+ Set at least one API key as an environment variable:
28
+
29
+ ```bash
30
+ # Anthropic Claude (recommended)
31
+ export ANTHROPIC_API_KEY=sk-ant-...
32
+
33
+ # OpenAI GPT
34
+ export OPENAI_API_KEY=sk-...
35
+
36
+ # Optional: Enable web search
37
+ export BRAVE_SEARCH_API_KEY=...
38
+ ```
39
+
40
+ ### 2. Run in your project directory
41
+
42
+ ```bash
43
+ cd my-project
44
+ raindrop-code
45
+ ```
46
+
47
+ ### 3. Start coding!
48
+
49
+ ```
50
+ > Explain how authentication works in this codebase
51
+ > Find all TODO comments
52
+ > Create a new API endpoint for user registration
53
+ > Review src/handlers/user.go for potential bugs
54
+ ```
55
+
56
+ ## Configuration
57
+
58
+ On first run, Raindrop Code creates `~/.raindrop-code/` with configuration files. Edit `~/.raindrop-code/config.yaml` to customize behavior.
59
+
60
+ ### Example Configuration
61
+
62
+ ```yaml
63
+ # Which provider to use by default
64
+ default_provider: anthropic
65
+
66
+ providers:
67
+ anthropic:
68
+ connection:
69
+ api_key: env:ANTHROPIC_API_KEY
70
+ base_url: "https://api.anthropic.com/v1"
71
+ model:
72
+ default: claude-sonnet-4-5-20250929
73
+ configs:
74
+ claude-sonnet-4-5-20250929:
75
+ context_window: 200000
76
+ params:
77
+ max_tokens: 8192
78
+ temperature: 1.0
79
+ ```
80
+
81
+ ## Available Tools
82
+
83
+ The AI has access to these tools:
84
+
85
+ | Tool | Description |
86
+ |------|-------------|
87
+ | `read_file` | Read any file in your project |
88
+ | `write_file` | Create new files |
89
+ | `edit_file` | Make precise edits to existing files |
90
+ | `bash` | Execute shell commands |
91
+ | `git` | Run git operations (status, diff, commit, etc.) |
92
+ | `search` | Intelligent code search with symbol understanding |
93
+ | `explore` | Browse directories, see file structure and symbols |
94
+ | `web_search` | Search the web (requires BRAVE_SEARCH_API_KEY) |
95
+ | `web_fetch` | Fetch content from URLs |
96
+ | `agent_tool` | Spawn specialized sub-agents |
97
+ | `workflow` | Execute multi-step workflows |
98
+
99
+ ## Commands
100
+
101
+ | Command | Description |
102
+ |---------|-------------|
103
+ | `/clear` | Clear conversation history |
104
+ | `/context` | Toggle context panel (shows indexing status) |
105
+ | `/help` | Show available commands |
106
+ | `/reindex` | Manually trigger workspace reindexing |
107
+ | `/readme` | Display README |
108
+
109
+ ## Custom Commands & Agents
110
+
111
+ Create custom commands in `~/.raindrop-code/commands/`:
112
+
113
+ ```markdown
114
+ ---
115
+ description: Run tests and fix any failures
116
+ ---
117
+
118
+ Please run the test suite and fix any failures you find.
119
+ ```
120
+
121
+ Create custom agents in `~/.raindrop-code/agents/`:
122
+
123
+ ```markdown
124
+ ---
125
+ name: security-auditor
126
+ description: Security audit specialist
127
+ tools: [read_file, search, bash]
128
+ ---
129
+
130
+ You are a security expert. Review code for vulnerabilities...
131
+ ```
132
+
133
+ ## Platform Support
134
+
135
+ - **macOS** (Apple Silicon & Intel)
136
+ - **Linux** (x64 & ARM64)
137
+ - **Windows** (x64)
138
+
139
+ ## Documentation
140
+
141
+ - [Full Documentation](https://github.com/ianschenck/raindrop-code)
142
+ - [Configuration Guide](https://github.com/ianschenck/raindrop-code#configuration)
143
+ - [Custom Agents](https://github.com/ianschenck/raindrop-code#agents)
144
+ - [API Reference](https://github.com/ianschenck/raindrop-code/wiki)
145
+
146
+ ## License
147
+
148
+ MIT License - see LICENSE file for details
149
+
150
+ ## Links
151
+
152
+ - [GitHub Repository](https://github.com/ianschenck/raindrop-code)
153
+ - [Report Issues](https://github.com/ianschenck/raindrop-code/issues)
154
+ - [LiquidMetal.AI](https://liquidmetal.ai)
155
+
156
+ ---
157
+
158
+ Built with ā¤ļø by the Raindrop team
package/install.js ADDED
@@ -0,0 +1,230 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Postinstall script for @liquidmetal-ai/raindrop-code
5
+ *
6
+ * This script ensures the correct platform-specific binary is available.
7
+ * It follows a two-tier approach:
8
+ * 1. First, check if a platform-specific optional dependency was installed
9
+ * 2. If not, download the binary from npm as a fallback
10
+ */
11
+
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+ const https = require('https');
15
+ const { execSync } = require('child_process');
16
+
17
+ // Get package version dynamically from package.json
18
+ const packageJson = require('./package.json');
19
+ const VERSION = packageJson.version;
20
+
21
+ // Lookup table for platform-specific packages
22
+ const BINARY_DISTRIBUTION_PACKAGES = {
23
+ 'darwin-x64': '@liquidmetal-ai/raindrop-code-darwin-universal',
24
+ 'darwin-arm64': '@liquidmetal-ai/raindrop-code-darwin-universal',
25
+ 'linux-x64': '@liquidmetal-ai/raindrop-code-linux-x64',
26
+ 'linux-arm64': '@liquidmetal-ai/raindrop-code-linux-arm64',
27
+ 'win32-x64': '@liquidmetal-ai/raindrop-code-win32-x64',
28
+ };
29
+
30
+ // Determine binary name based on platform
31
+ const binaryName = process.platform === 'win32' ? 'raindrop-code.exe' : 'raindrop-code';
32
+
33
+ // Paths
34
+ const binDir = path.join(__dirname, 'bin');
35
+ const fallbackBinaryPath = path.join(binDir, binaryName);
36
+
37
+ // Determine the platform-specific package name
38
+ const platformKey = `${process.platform}-${process.arch}`;
39
+ const platformSpecificPackageName = BINARY_DISTRIBUTION_PACKAGES[platformKey];
40
+
41
+ if (!platformSpecificPackageName) {
42
+ console.error(`ERROR: Unsupported platform: ${platformKey}`);
43
+ console.error(`Supported platforms: ${Object.keys(BINARY_DISTRIBUTION_PACKAGES).join(', ')}`);
44
+ process.exit(1);
45
+ }
46
+
47
+ /**
48
+ * Check if the optional dependency was installed successfully
49
+ */
50
+ function checkOptionalDependency() {
51
+ try {
52
+ const optionalDepPath = path.join(__dirname, 'node_modules', platformSpecificPackageName);
53
+ const binaryPath = path.join(optionalDepPath, 'bin', binaryName);
54
+
55
+ if (fs.existsSync(binaryPath)) {
56
+ console.log(`āœ“ Platform-specific package installed: ${platformSpecificPackageName}`);
57
+
58
+ // Create bin directory if it doesn't exist
59
+ if (!fs.existsSync(binDir)) {
60
+ fs.mkdirSync(binDir, { recursive: true });
61
+ }
62
+
63
+ // Create a symlink or copy to the expected location
64
+ if (process.platform === 'win32') {
65
+ // Windows doesn't handle symlinks well, so copy
66
+ fs.copyFileSync(binaryPath, fallbackBinaryPath);
67
+ } else {
68
+ // Unix: create symlink
69
+ const relativePath = path.relative(binDir, binaryPath);
70
+ if (fs.existsSync(fallbackBinaryPath)) {
71
+ fs.unlinkSync(fallbackBinaryPath);
72
+ }
73
+ fs.symlinkSync(relativePath, fallbackBinaryPath);
74
+ }
75
+
76
+ // Ensure executable
77
+ if (process.platform !== 'win32') {
78
+ fs.chmodSync(fallbackBinaryPath, 0o755);
79
+ }
80
+
81
+ return true;
82
+ }
83
+ } catch (error) {
84
+ // Ignore errors, fall through to download
85
+ }
86
+
87
+ return false;
88
+ }
89
+
90
+ /**
91
+ * Make an HTTPS request following redirects
92
+ */
93
+ function makeRequest(url) {
94
+ return new Promise((resolve, reject) => {
95
+ https.get(url, (response) => {
96
+ if (response.statusCode >= 200 && response.statusCode < 300) {
97
+ const chunks = [];
98
+ response.on('data', (chunk) => chunks.push(chunk));
99
+ response.on('end', () => resolve(Buffer.concat(chunks)));
100
+ } else if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
101
+ // Follow redirects
102
+ makeRequest(response.headers.location).then(resolve, reject);
103
+ } else {
104
+ reject(new Error(`Request failed with status ${response.statusCode}`));
105
+ }
106
+ }).on('error', reject);
107
+ });
108
+ }
109
+
110
+ /**
111
+ * Extract a specific file from a tarball buffer
112
+ */
113
+ function extractFileFromTarball(tarballBuffer, filepath) {
114
+ let offset = 0;
115
+
116
+ while (offset < tarballBuffer.length) {
117
+ const header = tarballBuffer.subarray(offset, offset + 512);
118
+ offset += 512;
119
+
120
+ const fileName = header.toString('utf-8', 0, 100).replace(/\0.*/g, '');
121
+ const fileSize = parseInt(header.toString('utf-8', 124, 136).replace(/\0.*/g, ''), 8);
122
+
123
+ if (fileName === filepath) {
124
+ return tarballBuffer.subarray(offset, offset + fileSize);
125
+ }
126
+
127
+ // Move to next header (data is padded to 512 byte blocks)
128
+ offset += Math.ceil(fileSize / 512) * 512;
129
+ }
130
+
131
+ throw new Error(`File ${filepath} not found in tarball`);
132
+ }
133
+
134
+ /**
135
+ * Download the platform-specific binary from npm
136
+ */
137
+ async function downloadBinary() {
138
+ console.log(`Downloading binary for ${platformKey}...`);
139
+ console.log(`Package: ${platformSpecificPackageName}@${VERSION}`);
140
+
141
+ try {
142
+ // Construct npm registry URL
143
+ const tarballUrl = `https://registry.npmjs.org/${platformSpecificPackageName}/-/${platformSpecificPackageName.split('/').pop()}-${VERSION}.tgz`;
144
+
145
+ console.log(`Fetching: ${tarballUrl}`);
146
+
147
+ // Download the tarball
148
+ const tarballBuffer = await makeRequest(tarballUrl);
149
+ console.log(`āœ“ Downloaded ${(tarballBuffer.length / 1024 / 1024).toFixed(2)} MB`);
150
+
151
+ // Decompress gzip
152
+ const zlib = require('zlib');
153
+ const tarBuffer = zlib.gunzipSync(tarballBuffer);
154
+
155
+ // Extract binary from tar (npm packages have a 'package/' prefix)
156
+ const binaryPathInTar = `package/bin/${binaryName}`;
157
+ const binaryBuffer = extractFileFromTarball(tarBuffer, binaryPathInTar);
158
+
159
+ // Write binary to disk
160
+ if (!fs.existsSync(binDir)) {
161
+ fs.mkdirSync(binDir, { recursive: true });
162
+ }
163
+
164
+ fs.writeFileSync(fallbackBinaryPath, binaryBuffer);
165
+
166
+ // Make executable on Unix
167
+ if (process.platform !== 'win32') {
168
+ fs.chmodSync(fallbackBinaryPath, 0o755);
169
+ }
170
+
171
+ console.log(`āœ“ Binary installed to ${fallbackBinaryPath}`);
172
+ return true;
173
+ } catch (error) {
174
+ console.error(`āœ— Failed to download binary: ${error.message}`);
175
+ return false;
176
+ }
177
+ }
178
+
179
+ /**
180
+ * Verify the binary works
181
+ */
182
+ function verifyBinary() {
183
+ try {
184
+ const output = execSync(`"${fallbackBinaryPath}" --version`, {
185
+ encoding: 'utf-8',
186
+ stdio: ['ignore', 'pipe', 'ignore']
187
+ });
188
+ console.log(`āœ“ Binary verified: ${output.trim()}`);
189
+ return true;
190
+ } catch (error) {
191
+ console.error(`āœ— Binary verification failed`);
192
+ return false;
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Main installation logic
198
+ */
199
+ async function main() {
200
+ console.log('raindrop-code postinstall');
201
+ console.log('========================');
202
+
203
+ // Strategy 1: Check if optional dependency was installed
204
+ if (checkOptionalDependency()) {
205
+ console.log('āœ“ Installation complete (via optional dependency)');
206
+ return;
207
+ }
208
+
209
+ console.log('Optional dependency not found, downloading binary...');
210
+
211
+ // Strategy 2: Download binary from npm
212
+ const downloadSuccess = await downloadBinary();
213
+
214
+ if (!downloadSuccess) {
215
+ console.error('\n⚠ Installation incomplete');
216
+ console.error('Please report this issue: https://github.com/ianschenck/raindrop-code/issues');
217
+ process.exit(1);
218
+ }
219
+
220
+ // Verify the binary
221
+ verifyBinary();
222
+
223
+ console.log('āœ“ Installation complete (via download)');
224
+ }
225
+
226
+ // Run installation
227
+ main().catch((error) => {
228
+ console.error('Installation failed:', error);
229
+ process.exit(1);
230
+ });
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@liquidmetal-ai/raindrop-code",
3
+ "version": "0.0.1-alpha20",
4
+ "description": "AI-powered terminal coding assistant with deep code understanding, file operations, and extensible tools",
5
+ "keywords": [
6
+ "ai",
7
+ "coding-assistant",
8
+ "code-assistant",
9
+ "cli",
10
+ "terminal",
11
+ "developer-tools",
12
+ "llm",
13
+ "claude",
14
+ "gpt",
15
+ "code-analysis",
16
+ "refactoring",
17
+ "code-review"
18
+ ],
19
+ "homepage": "https://github.com/ianschenck/raindrop-code#readme",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/ianschenck/raindrop-code.git"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/ianschenck/raindrop-code/issues"
26
+ },
27
+ "license": "MIT",
28
+ "author": "LiquidMetal.AI",
29
+ "scripts": {
30
+ "postinstall": "node install.js"
31
+ },
32
+ "engines": {
33
+ "node": ">=18"
34
+ },
35
+ "bin": {
36
+ "raindrop-code": "bin/raindrop-code"
37
+ },
38
+ "files": [
39
+ "install.js",
40
+ "README.md",
41
+ "bin/"
42
+ ],
43
+ "optionalDependencies": {
44
+ "@liquidmetal-ai/raindrop-code-darwin-universal": "0.0.1-alpha20",
45
+ "@liquidmetal-ai/raindrop-code-linux-x64": "0.0.1-alpha20",
46
+ "@liquidmetal-ai/raindrop-code-linux-arm64": "0.0.1-alpha20",
47
+ "@liquidmetal-ai/raindrop-code-win32-x64": "0.0.1-alpha20"
48
+ }
49
+ }