@zemerik/gemini-assist 1.1.1-beta

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/index.js ADDED
@@ -0,0 +1,317 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ /* prettier-ignore */
4
+
5
+ /* auto-generated by NAPI-RS */
6
+
7
+ const { existsSync, readFileSync } = require('fs')
8
+ const { join } = require('path')
9
+
10
+ const { platform, arch } = process
11
+
12
+ let nativeBinding = null
13
+ let localFileExisted = false
14
+ let loadError = null
15
+
16
+ function isMusl() {
17
+ // For Node 10
18
+ if (!process.report || typeof process.report.getReport !== 'function') {
19
+ try {
20
+ const lddPath = require('child_process').execSync('which ldd').toString().trim()
21
+ return readFileSync(lddPath, 'utf8').includes('musl')
22
+ } catch (e) {
23
+ return true
24
+ }
25
+ } else {
26
+ const { glibcVersionRuntime } = process.report.getReport().header
27
+ return !glibcVersionRuntime
28
+ }
29
+ }
30
+
31
+ switch (platform) {
32
+ case 'android':
33
+ switch (arch) {
34
+ case 'arm64':
35
+ localFileExisted = existsSync(join(__dirname, 'gemini-assist-native.android-arm64.node'))
36
+ try {
37
+ if (localFileExisted) {
38
+ nativeBinding = require('./gemini-assist-native.android-arm64.node')
39
+ } else {
40
+ nativeBinding = require('@zemerik/gemini-assist-android-arm64')
41
+ }
42
+ } catch (e) {
43
+ loadError = e
44
+ }
45
+ break
46
+ case 'arm':
47
+ localFileExisted = existsSync(join(__dirname, 'gemini-assist-native.android-arm-eabi.node'))
48
+ try {
49
+ if (localFileExisted) {
50
+ nativeBinding = require('./gemini-assist-native.android-arm-eabi.node')
51
+ } else {
52
+ nativeBinding = require('@zemerik/gemini-assist-android-arm-eabi')
53
+ }
54
+ } catch (e) {
55
+ loadError = e
56
+ }
57
+ break
58
+ default:
59
+ throw new Error(`Unsupported architecture on Android ${arch}`)
60
+ }
61
+ break
62
+ case 'win32':
63
+ switch (arch) {
64
+ case 'x64':
65
+ localFileExisted = existsSync(
66
+ join(__dirname, 'gemini-assist-native.win32-x64-msvc.node')
67
+ )
68
+ try {
69
+ if (localFileExisted) {
70
+ nativeBinding = require('./gemini-assist-native.win32-x64-msvc.node')
71
+ } else {
72
+ nativeBinding = require('@zemerik/gemini-assist-win32-x64-msvc')
73
+ }
74
+ } catch (e) {
75
+ loadError = e
76
+ }
77
+ break
78
+ case 'ia32':
79
+ localFileExisted = existsSync(
80
+ join(__dirname, 'gemini-assist-native.win32-ia32-msvc.node')
81
+ )
82
+ try {
83
+ if (localFileExisted) {
84
+ nativeBinding = require('./gemini-assist-native.win32-ia32-msvc.node')
85
+ } else {
86
+ nativeBinding = require('@zemerik/gemini-assist-win32-ia32-msvc')
87
+ }
88
+ } catch (e) {
89
+ loadError = e
90
+ }
91
+ break
92
+ case 'arm64':
93
+ localFileExisted = existsSync(
94
+ join(__dirname, 'gemini-assist-native.win32-arm64-msvc.node')
95
+ )
96
+ try {
97
+ if (localFileExisted) {
98
+ nativeBinding = require('./gemini-assist-native.win32-arm64-msvc.node')
99
+ } else {
100
+ nativeBinding = require('@zemerik/gemini-assist-win32-arm64-msvc')
101
+ }
102
+ } catch (e) {
103
+ loadError = e
104
+ }
105
+ break
106
+ default:
107
+ throw new Error(`Unsupported architecture on Windows: ${arch}`)
108
+ }
109
+ break
110
+ case 'darwin':
111
+ localFileExisted = existsSync(join(__dirname, 'gemini-assist-native.darwin-universal.node'))
112
+ try {
113
+ if (localFileExisted) {
114
+ nativeBinding = require('./gemini-assist-native.darwin-universal.node')
115
+ } else {
116
+ nativeBinding = require('@zemerik/gemini-assist-darwin-universal')
117
+ }
118
+ break
119
+ } catch {}
120
+ switch (arch) {
121
+ case 'x64':
122
+ localFileExisted = existsSync(join(__dirname, 'gemini-assist-native.darwin-x64.node'))
123
+ try {
124
+ if (localFileExisted) {
125
+ nativeBinding = require('./gemini-assist-native.darwin-x64.node')
126
+ } else {
127
+ nativeBinding = require('@zemerik/gemini-assist-darwin-x64')
128
+ }
129
+ } catch (e) {
130
+ loadError = e
131
+ }
132
+ break
133
+ case 'arm64':
134
+ localFileExisted = existsSync(
135
+ join(__dirname, 'gemini-assist-native.darwin-arm64.node')
136
+ )
137
+ try {
138
+ if (localFileExisted) {
139
+ nativeBinding = require('./gemini-assist-native.darwin-arm64.node')
140
+ } else {
141
+ nativeBinding = require('@zemerik/gemini-assist-darwin-arm64')
142
+ }
143
+ } catch (e) {
144
+ loadError = e
145
+ }
146
+ break
147
+ default:
148
+ throw new Error(`Unsupported architecture on macOS: ${arch}`)
149
+ }
150
+ break
151
+ case 'freebsd':
152
+ if (arch !== 'x64') {
153
+ throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
154
+ }
155
+ localFileExisted = existsSync(join(__dirname, 'gemini-assist-native.freebsd-x64.node'))
156
+ try {
157
+ if (localFileExisted) {
158
+ nativeBinding = require('./gemini-assist-native.freebsd-x64.node')
159
+ } else {
160
+ nativeBinding = require('@zemerik/gemini-assist-freebsd-x64')
161
+ }
162
+ } catch (e) {
163
+ loadError = e
164
+ }
165
+ break
166
+ case 'linux':
167
+ switch (arch) {
168
+ case 'x64':
169
+ if (isMusl()) {
170
+ localFileExisted = existsSync(
171
+ join(__dirname, 'gemini-assist-native.linux-x64-musl.node')
172
+ )
173
+ try {
174
+ if (localFileExisted) {
175
+ nativeBinding = require('./gemini-assist-native.linux-x64-musl.node')
176
+ } else {
177
+ nativeBinding = require('@zemerik/gemini-assist-linux-x64-musl')
178
+ }
179
+ } catch (e) {
180
+ loadError = e
181
+ }
182
+ } else {
183
+ localFileExisted = existsSync(
184
+ join(__dirname, 'gemini-assist-native.linux-x64-gnu.node')
185
+ )
186
+ try {
187
+ if (localFileExisted) {
188
+ nativeBinding = require('./gemini-assist-native.linux-x64-gnu.node')
189
+ } else {
190
+ nativeBinding = require('@zemerik/gemini-assist-linux-x64-gnu')
191
+ }
192
+ } catch (e) {
193
+ loadError = e
194
+ }
195
+ }
196
+ break
197
+ case 'arm64':
198
+ if (isMusl()) {
199
+ localFileExisted = existsSync(
200
+ join(__dirname, 'gemini-assist-native.linux-arm64-musl.node')
201
+ )
202
+ try {
203
+ if (localFileExisted) {
204
+ nativeBinding = require('./gemini-assist-native.linux-arm64-musl.node')
205
+ } else {
206
+ nativeBinding = require('@zemerik/gemini-assist-linux-arm64-musl')
207
+ }
208
+ } catch (e) {
209
+ loadError = e
210
+ }
211
+ } else {
212
+ localFileExisted = existsSync(
213
+ join(__dirname, 'gemini-assist-native.linux-arm64-gnu.node')
214
+ )
215
+ try {
216
+ if (localFileExisted) {
217
+ nativeBinding = require('./gemini-assist-native.linux-arm64-gnu.node')
218
+ } else {
219
+ nativeBinding = require('@zemerik/gemini-assist-linux-arm64-gnu')
220
+ }
221
+ } catch (e) {
222
+ loadError = e
223
+ }
224
+ }
225
+ break
226
+ case 'arm':
227
+ if (isMusl()) {
228
+ localFileExisted = existsSync(
229
+ join(__dirname, 'gemini-assist-native.linux-arm-musleabihf.node')
230
+ )
231
+ try {
232
+ if (localFileExisted) {
233
+ nativeBinding = require('./gemini-assist-native.linux-arm-musleabihf.node')
234
+ } else {
235
+ nativeBinding = require('@zemerik/gemini-assist-linux-arm-musleabihf')
236
+ }
237
+ } catch (e) {
238
+ loadError = e
239
+ }
240
+ } else {
241
+ localFileExisted = existsSync(
242
+ join(__dirname, 'gemini-assist-native.linux-arm-gnueabihf.node')
243
+ )
244
+ try {
245
+ if (localFileExisted) {
246
+ nativeBinding = require('./gemini-assist-native.linux-arm-gnueabihf.node')
247
+ } else {
248
+ nativeBinding = require('@zemerik/gemini-assist-linux-arm-gnueabihf')
249
+ }
250
+ } catch (e) {
251
+ loadError = e
252
+ }
253
+ }
254
+ break
255
+ case 'riscv64':
256
+ if (isMusl()) {
257
+ localFileExisted = existsSync(
258
+ join(__dirname, 'gemini-assist-native.linux-riscv64-musl.node')
259
+ )
260
+ try {
261
+ if (localFileExisted) {
262
+ nativeBinding = require('./gemini-assist-native.linux-riscv64-musl.node')
263
+ } else {
264
+ nativeBinding = require('@zemerik/gemini-assist-linux-riscv64-musl')
265
+ }
266
+ } catch (e) {
267
+ loadError = e
268
+ }
269
+ } else {
270
+ localFileExisted = existsSync(
271
+ join(__dirname, 'gemini-assist-native.linux-riscv64-gnu.node')
272
+ )
273
+ try {
274
+ if (localFileExisted) {
275
+ nativeBinding = require('./gemini-assist-native.linux-riscv64-gnu.node')
276
+ } else {
277
+ nativeBinding = require('@zemerik/gemini-assist-linux-riscv64-gnu')
278
+ }
279
+ } catch (e) {
280
+ loadError = e
281
+ }
282
+ }
283
+ break
284
+ case 's390x':
285
+ localFileExisted = existsSync(
286
+ join(__dirname, 'gemini-assist-native.linux-s390x-gnu.node')
287
+ )
288
+ try {
289
+ if (localFileExisted) {
290
+ nativeBinding = require('./gemini-assist-native.linux-s390x-gnu.node')
291
+ } else {
292
+ nativeBinding = require('@zemerik/gemini-assist-linux-s390x-gnu')
293
+ }
294
+ } catch (e) {
295
+ loadError = e
296
+ }
297
+ break
298
+ default:
299
+ throw new Error(`Unsupported architecture on Linux: ${arch}`)
300
+ }
301
+ break
302
+ default:
303
+ throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
304
+ }
305
+
306
+ if (!nativeBinding) {
307
+ if (loadError) {
308
+ throw loadError
309
+ }
310
+ throw new Error(`Failed to load native binding`)
311
+ }
312
+
313
+ const { RustGeminiClient, validateApiKeyRust, rustVersion } = nativeBinding
314
+
315
+ module.exports.RustGeminiClient = RustGeminiClient
316
+ module.exports.validateApiKeyRust = validateApiKeyRust
317
+ module.exports.rustVersion = rustVersion
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "gemini-assist-native",
3
+ "main": "./index.node",
4
+ "binary": {
5
+ "napi-version": 8,
6
+ "packageName": "gemini-assist-native",
7
+ "path": "./",
8
+ "host": "https://github.com/yourusername/gemini-assist/releases/download/",
9
+ "remotePath": "{version}",
10
+ "arch": {
11
+ "x86_64": {
12
+ "libc": {
13
+ "musl": {
14
+ "filePrefix": "gemini-assist-native",
15
+ "fileSuffix": ".musl-x64.node"
16
+ },
17
+ "glibc": {
18
+ "filePrefix": "gemini-assist-native",
19
+ "fileSuffix": ".glibc-x64.node"
20
+ }
21
+ },
22
+ "default": {
23
+ "filePrefix": "gemini-assist-native",
24
+ "fileSuffix": "-x64.node"
25
+ }
26
+ },
27
+ "arm64": {
28
+ "filePrefix": "gemini-assist-native",
29
+ "fileSuffix": "-arm64.node"
30
+ }
31
+ }
32
+ }
33
+ }
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@zemerik/gemini-assist",
3
+ "version": "1.1.1-beta",
4
+ "description": "AI Assistant CLI tool powered by Google Gemini API (50% JS, 50% Rust)",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "gemini-assist": "bin/gemini-assist.js",
8
+ "gassist": "bin/gemini-assist.js"
9
+ },
10
+ "scripts": {
11
+ "test": "echo \"Error: no test specified\" && exit 1",
12
+ "start": "node bin/gemini-assist.js",
13
+ "build": "napi build --platform --release",
14
+ "build:debug": "napi build --platform",
15
+ "prepublishOnly": "npm run build",
16
+ "install": "node scripts/postinstall.js"
17
+ },
18
+ "keywords": [
19
+ "gemini",
20
+ "ai",
21
+ "assistant",
22
+ "cli",
23
+ "google",
24
+ "chatbot",
25
+ "rust",
26
+ "napi"
27
+ ],
28
+ "author": "Hemang Yadav (Zemerik)",
29
+ "license": "MIT",
30
+ "dependencies": {
31
+ "@google/generative-ai": "^0.21.0",
32
+ "commander": "^11.1.0",
33
+ "dotenv": "^16.4.5",
34
+ "chalk": "^4.1.2",
35
+ "readline": "^1.3.0"
36
+ },
37
+ "devDependencies": {
38
+ "@napi-rs/cli": "^2.16.0"
39
+ },
40
+ "napi": {
41
+ "name": "gemini-assist-native",
42
+ "triples": {
43
+ "defaults": true,
44
+ "additional": [
45
+ "x86_64-apple-darwin",
46
+ "aarch64-apple-darwin",
47
+ "x86_64-pc-windows-msvc",
48
+ "aarch64-pc-windows-msvc",
49
+ "x86_64-unknown-linux-gnu",
50
+ "aarch64-unknown-linux-gnu",
51
+ "x86_64-unknown-linux-musl",
52
+ "aarch64-unknown-linux-musl"
53
+ ]
54
+ }
55
+ },
56
+ "engines": {
57
+ "node": ">=14.0.0"
58
+ },
59
+ "repository": {
60
+ "type": "git",
61
+ "url": ""
62
+ }
63
+ }
@@ -0,0 +1,11 @@
1
+ const { existsSync } = require('fs');
2
+ const { join } = require('path');
3
+
4
+ // Check if Rust build is available, if not, fallback to JS
5
+ const nativePath = join(__dirname, '..', 'index.node');
6
+
7
+ if (!existsSync(nativePath)) {
8
+ console.log('⚠ Rust native bindings not found. Building...');
9
+ console.log(' Run "npm run build" to compile Rust bindings for better performance.');
10
+ console.log(' The CLI will work with JavaScript fallback in the meantime.');
11
+ }
package/src/gemini.js ADDED
@@ -0,0 +1,127 @@
1
+ // Hybrid JS/Rust Implementation (50% JS, 50% Rust)
2
+ // Core Gemini API logic is handled by Rust (src/gemini_client.rs)
3
+ // This JS wrapper provides Node.js compatibility and fallback
4
+
5
+ let RustGeminiClient;
6
+
7
+ // Try to load Rust native bindings, fallback to JS implementation if not available
8
+ try {
9
+ const native = require('../index.node');
10
+ RustGeminiClient = native.RustGeminiClient;
11
+ } catch (error) {
12
+ // Fallback to JS implementation if Rust bindings not available
13
+ const { GoogleGenerativeAI } = require('@google/generative-ai');
14
+ // Only show fallback message once, not on every require
15
+ if (!global.__gemini_fallback_shown) {
16
+ console.log('⚠ Rust bindings not available, using JavaScript fallback');
17
+ global.__gemini_fallback_shown = true;
18
+ }
19
+
20
+ class JSGeminiClient {
21
+ constructor(apiKey, options = {}) {
22
+ this.apiKey = apiKey;
23
+ // Default to undefined to let SDK use its default, or use provided model
24
+ this.modelName = options.model;
25
+ this.temperature = options.temperature || 0.7;
26
+ this.genAI = new GoogleGenerativeAI(apiKey);
27
+
28
+ // Build model config - SDK requires a model name
29
+ // Default to gemini-2.5-flash
30
+ let modelToUse = this.modelName || 'gemini-2.5-flash';
31
+
32
+ const modelConfig = {
33
+ model: modelToUse,
34
+ generationConfig: {
35
+ temperature: this.temperature,
36
+ },
37
+ };
38
+
39
+ this.model = this.genAI.getGenerativeModel(modelConfig);
40
+
41
+ // Store actual model name being used
42
+ this.modelName = modelToUse;
43
+
44
+ this.chatHistory = [];
45
+ }
46
+
47
+ async chat(prompt) {
48
+ try {
49
+ this.chatHistory.push({
50
+ role: 'user',
51
+ parts: [{ text: prompt }]
52
+ });
53
+
54
+ const result = await this.model.generateContent(prompt);
55
+ const response = await result.response;
56
+ const text = response.text();
57
+
58
+ this.chatHistory.push({
59
+ role: 'model',
60
+ parts: [{ text: text }]
61
+ });
62
+
63
+ return text;
64
+ } catch (error) {
65
+ if (error.message.includes('API_KEY')) {
66
+ throw new Error('Invalid API key. Please check your GEMINI_API_KEY.');
67
+ } else if (error.message.includes('quota') || error.message.includes('rate limit')) {
68
+ throw new Error('API quota exceeded or rate limit reached. Please try again later.');
69
+ } else if (error.message.includes('safety')) {
70
+ throw new Error('Content was blocked by safety filters.');
71
+ } else if (error.message.includes('404') || error.message.includes('not found')) {
72
+ // Provide helpful suggestions for model issues
73
+ let suggestions = [
74
+ 'Try: --model gemini-1.5-flash (without version suffix)',
75
+ 'Try: --model gemini-1.5-pro',
76
+ 'Try: --model gemini-pro (legacy)',
77
+ 'Check your API key has access to this model',
78
+ 'View available models: https://ai.google.dev/models/gemini'
79
+ ].join('\n ');
80
+ throw new Error(`Model "${this.modelName}" not found or not available.\n\nSuggestions:\n ${suggestions}\n\nFull error: ${error.message}`);
81
+ } else {
82
+ throw new Error(`Gemini API error: ${error.message}`);
83
+ }
84
+ }
85
+ }
86
+
87
+ clearHistory() {
88
+ this.chatHistory = [];
89
+ }
90
+
91
+ async getHistoryCount() {
92
+ return this.chatHistory.length;
93
+ }
94
+ }
95
+
96
+ RustGeminiClient = JSGeminiClient;
97
+ }
98
+
99
+ // Wrapper class that uses Rust implementation
100
+ class GeminiClient {
101
+ constructor(apiKey, options = {}) {
102
+ // Default to gemini-2.5-flash
103
+ this.modelName = options.model || 'gemini-2.5-flash';
104
+ this.temperature = options.temperature || 0.7;
105
+
106
+ // Use Rust client (or JS fallback)
107
+ this.client = new RustGeminiClient(
108
+ apiKey,
109
+ this.modelName,
110
+ this.temperature
111
+ );
112
+ }
113
+
114
+ async chat(prompt) {
115
+ return await this.client.chat(prompt);
116
+ }
117
+
118
+ async clearHistory() {
119
+ return await this.client.clearHistory();
120
+ }
121
+
122
+ async getHistoryCount() {
123
+ return await this.client.getHistoryCount();
124
+ }
125
+ }
126
+
127
+ module.exports = { GeminiClient };