@projectservan8n/cnapse 0.5.0 → 0.5.1
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/dist/ConfigUI-V5TM6KKS.js +306 -0
- package/dist/index.js +392 -176
- package/package.json +1 -1
- package/src/components/ConfigUI.tsx +353 -0
- package/src/components/ProviderSelector.tsx +270 -68
- package/src/index.tsx +95 -83
- package/src/lib/ollama.ts +140 -0
package/dist/index.js
CHANGED
|
@@ -192,61 +192,152 @@ function HelpMenu({ onClose, onSelect }) {
|
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
// src/components/ProviderSelector.tsx
|
|
195
|
-
import { useState as useState2 } from "react";
|
|
195
|
+
import { useState as useState2, useEffect } from "react";
|
|
196
196
|
import { Box as Box6, Text as Text6, useInput as useInput2 } from "ink";
|
|
197
|
-
import
|
|
197
|
+
import TextInput2 from "ink-text-input";
|
|
198
|
+
import Spinner from "ink-spinner";
|
|
199
|
+
|
|
200
|
+
// src/lib/ollama.ts
|
|
201
|
+
import { exec } from "child_process";
|
|
202
|
+
import { promisify } from "util";
|
|
203
|
+
var execAsync = promisify(exec);
|
|
204
|
+
async function checkOllamaStatus() {
|
|
205
|
+
try {
|
|
206
|
+
const { stdout } = await execAsync("ollama list", { timeout: 1e4 });
|
|
207
|
+
const lines = stdout.trim().split("\n");
|
|
208
|
+
const models = [];
|
|
209
|
+
for (let i = 1; i < lines.length; i++) {
|
|
210
|
+
const line = lines[i];
|
|
211
|
+
if (!line?.trim()) continue;
|
|
212
|
+
const parts = line.split(/\s{2,}/);
|
|
213
|
+
if (parts.length >= 3) {
|
|
214
|
+
models.push({
|
|
215
|
+
name: parts[0]?.trim() || "",
|
|
216
|
+
size: parts[2]?.trim() || "",
|
|
217
|
+
modified: parts[3]?.trim() || ""
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
return {
|
|
222
|
+
installed: true,
|
|
223
|
+
running: true,
|
|
224
|
+
models
|
|
225
|
+
};
|
|
226
|
+
} catch (err2) {
|
|
227
|
+
const errorMsg = err2 instanceof Error ? err2.message : "Unknown error";
|
|
228
|
+
if (errorMsg.includes("connect") || errorMsg.includes("refused")) {
|
|
229
|
+
return {
|
|
230
|
+
installed: true,
|
|
231
|
+
running: false,
|
|
232
|
+
models: [],
|
|
233
|
+
error: "Ollama is not running. Start it with: ollama serve"
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
if (errorMsg.includes("not found") || errorMsg.includes("not recognized")) {
|
|
237
|
+
return {
|
|
238
|
+
installed: false,
|
|
239
|
+
running: false,
|
|
240
|
+
models: [],
|
|
241
|
+
error: "Ollama not installed. Get it at: https://ollama.ai"
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
return {
|
|
245
|
+
installed: false,
|
|
246
|
+
running: false,
|
|
247
|
+
models: [],
|
|
248
|
+
error: errorMsg
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
function hasModel(status, modelId) {
|
|
253
|
+
const modelName = modelId.split(":")[0]?.toLowerCase() || "";
|
|
254
|
+
return status.models.some((m) => m.name.toLowerCase().startsWith(modelName));
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// src/components/ProviderSelector.tsx
|
|
258
|
+
import { Fragment, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
198
259
|
var PROVIDERS = [
|
|
199
260
|
{
|
|
200
261
|
id: "ollama",
|
|
201
262
|
name: "Ollama",
|
|
202
|
-
description: "Local AI - Free, private
|
|
203
|
-
|
|
204
|
-
models: [
|
|
263
|
+
description: "Local AI - Free, private",
|
|
264
|
+
needsApiKey: false,
|
|
265
|
+
models: [
|
|
266
|
+
{ id: "qwen2.5:0.5b", name: "Qwen 2.5 0.5B (fast)", recommended: true },
|
|
267
|
+
{ id: "qwen2.5:1.5b", name: "Qwen 2.5 1.5B" },
|
|
268
|
+
{ id: "qwen2.5:7b", name: "Qwen 2.5 7B (quality)" },
|
|
269
|
+
{ id: "llama3.2:1b", name: "Llama 3.2 1B" },
|
|
270
|
+
{ id: "llama3.2:3b", name: "Llama 3.2 3B" },
|
|
271
|
+
{ id: "codellama:7b", name: "Code Llama 7B" },
|
|
272
|
+
{ id: "llava:7b", name: "LLaVA 7B (vision)" }
|
|
273
|
+
]
|
|
205
274
|
},
|
|
206
275
|
{
|
|
207
276
|
id: "openrouter",
|
|
208
277
|
name: "OpenRouter",
|
|
209
278
|
description: "Many models, pay-per-use",
|
|
210
|
-
|
|
279
|
+
needsApiKey: true,
|
|
211
280
|
models: [
|
|
212
|
-
"qwen/qwen-2.5-coder-32b-instruct",
|
|
213
|
-
"anthropic/claude-3.5-sonnet",
|
|
214
|
-
"openai/gpt-4o",
|
|
215
|
-
"openai/gpt-4o-mini",
|
|
216
|
-
"google/gemini-pro-1.5",
|
|
217
|
-
"meta-llama/llama-3.1-70b-instruct"
|
|
281
|
+
{ id: "qwen/qwen-2.5-coder-32b-instruct", name: "Qwen Coder 32B", recommended: true },
|
|
282
|
+
{ id: "anthropic/claude-3.5-sonnet", name: "Claude 3.5 Sonnet" },
|
|
283
|
+
{ id: "openai/gpt-4o", name: "GPT-4o" },
|
|
284
|
+
{ id: "openai/gpt-4o-mini", name: "GPT-4o Mini" },
|
|
285
|
+
{ id: "google/gemini-pro-1.5", name: "Gemini Pro 1.5" }
|
|
218
286
|
]
|
|
219
287
|
},
|
|
220
288
|
{
|
|
221
289
|
id: "anthropic",
|
|
222
290
|
name: "Anthropic",
|
|
223
|
-
description: "Claude
|
|
224
|
-
|
|
225
|
-
models: [
|
|
291
|
+
description: "Claude - Best reasoning",
|
|
292
|
+
needsApiKey: true,
|
|
293
|
+
models: [
|
|
294
|
+
{ id: "claude-3-5-sonnet-20241022", name: "Claude 3.5 Sonnet", recommended: true },
|
|
295
|
+
{ id: "claude-3-opus-20240229", name: "Claude 3 Opus" },
|
|
296
|
+
{ id: "claude-3-haiku-20240307", name: "Claude 3 Haiku" }
|
|
297
|
+
]
|
|
226
298
|
},
|
|
227
299
|
{
|
|
228
300
|
id: "openai",
|
|
229
301
|
name: "OpenAI",
|
|
230
302
|
description: "GPT models",
|
|
231
|
-
|
|
232
|
-
models: [
|
|
303
|
+
needsApiKey: true,
|
|
304
|
+
models: [
|
|
305
|
+
{ id: "gpt-4o", name: "GPT-4o", recommended: true },
|
|
306
|
+
{ id: "gpt-4o-mini", name: "GPT-4o Mini" },
|
|
307
|
+
{ id: "gpt-4-turbo", name: "GPT-4 Turbo" }
|
|
308
|
+
]
|
|
233
309
|
}
|
|
234
310
|
];
|
|
235
311
|
function ProviderSelector({ onClose, onSelect }) {
|
|
236
312
|
const config = getConfig();
|
|
237
|
-
const [
|
|
313
|
+
const [step, setStep] = useState2("provider");
|
|
238
314
|
const [providerIndex, setProviderIndex] = useState2(() => {
|
|
239
315
|
const idx = PROVIDERS.findIndex((p) => p.id === config.provider);
|
|
240
316
|
return idx >= 0 ? idx : 0;
|
|
241
317
|
});
|
|
242
318
|
const [modelIndex, setModelIndex] = useState2(0);
|
|
319
|
+
const [apiKeyInput, setApiKeyInput] = useState2("");
|
|
243
320
|
const [selectedProvider, setSelectedProvider] = useState2(null);
|
|
321
|
+
const [ollamaStatus, setOllamaStatus] = useState2(null);
|
|
322
|
+
const [checkingOllama, setCheckingOllama] = useState2(false);
|
|
323
|
+
useEffect(() => {
|
|
324
|
+
if (step === "model" && selectedProvider?.id === "ollama" && !ollamaStatus) {
|
|
325
|
+
setCheckingOllama(true);
|
|
326
|
+
checkOllamaStatus().then((status) => {
|
|
327
|
+
setOllamaStatus(status);
|
|
328
|
+
setCheckingOllama(false);
|
|
329
|
+
if (!status.running) {
|
|
330
|
+
setStep("ollamaError");
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
}, [step, selectedProvider, ollamaStatus]);
|
|
244
335
|
useInput2((input, key) => {
|
|
245
336
|
if (key.escape) {
|
|
246
337
|
onClose();
|
|
247
338
|
return;
|
|
248
339
|
}
|
|
249
|
-
if (
|
|
340
|
+
if (step === "provider") {
|
|
250
341
|
if (key.upArrow) {
|
|
251
342
|
setProviderIndex((prev) => prev > 0 ? prev - 1 : PROVIDERS.length - 1);
|
|
252
343
|
} else if (key.downArrow) {
|
|
@@ -254,79 +345,194 @@ function ProviderSelector({ onClose, onSelect }) {
|
|
|
254
345
|
} else if (key.return) {
|
|
255
346
|
const provider = PROVIDERS[providerIndex];
|
|
256
347
|
setSelectedProvider(provider);
|
|
257
|
-
const
|
|
258
|
-
|
|
259
|
-
|
|
348
|
+
const currentIdx = provider.models.findIndex((m) => m.id === config.model);
|
|
349
|
+
const recommendedIdx = provider.models.findIndex((m) => m.recommended);
|
|
350
|
+
setModelIndex(currentIdx >= 0 ? currentIdx : recommendedIdx >= 0 ? recommendedIdx : 0);
|
|
351
|
+
if (provider.needsApiKey) {
|
|
352
|
+
const apiKeyProvider = provider.id;
|
|
353
|
+
if (!config.apiKeys[apiKeyProvider]) {
|
|
354
|
+
setStep("apiKey");
|
|
355
|
+
} else {
|
|
356
|
+
setStep("model");
|
|
357
|
+
}
|
|
358
|
+
} else {
|
|
359
|
+
setStep("model");
|
|
360
|
+
}
|
|
260
361
|
}
|
|
261
|
-
} else if (
|
|
362
|
+
} else if (step === "model" && selectedProvider) {
|
|
262
363
|
if (key.upArrow) {
|
|
263
364
|
setModelIndex((prev) => prev > 0 ? prev - 1 : selectedProvider.models.length - 1);
|
|
264
365
|
} else if (key.downArrow) {
|
|
265
366
|
setModelIndex((prev) => prev < selectedProvider.models.length - 1 ? prev + 1 : 0);
|
|
266
367
|
} else if (key.return) {
|
|
267
368
|
const model = selectedProvider.models[modelIndex];
|
|
369
|
+
if (selectedProvider.id === "ollama" && ollamaStatus && !hasModel(ollamaStatus, model.id)) {
|
|
370
|
+
}
|
|
268
371
|
setProvider(selectedProvider.id);
|
|
269
|
-
setModel(model);
|
|
270
|
-
|
|
271
|
-
|
|
372
|
+
setModel(model.id);
|
|
373
|
+
setStep("done");
|
|
374
|
+
onSelect(selectedProvider.id, model.id);
|
|
375
|
+
setTimeout(() => onClose(), 1500);
|
|
272
376
|
} else if (key.leftArrow || input === "b") {
|
|
273
|
-
|
|
377
|
+
setStep("provider");
|
|
378
|
+
setOllamaStatus(null);
|
|
379
|
+
}
|
|
380
|
+
} else if (step === "ollamaError") {
|
|
381
|
+
if (key.return || input === "b") {
|
|
382
|
+
setStep("provider");
|
|
383
|
+
setOllamaStatus(null);
|
|
274
384
|
}
|
|
275
385
|
}
|
|
276
386
|
});
|
|
277
|
-
|
|
278
|
-
|
|
387
|
+
const handleApiKeySubmit = (value) => {
|
|
388
|
+
if (value.trim() && selectedProvider) {
|
|
389
|
+
setApiKey(selectedProvider.id, value.trim());
|
|
390
|
+
setStep("model");
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
if (step === "provider") {
|
|
394
|
+
return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", padding: 1, width: 60, children: [
|
|
279
395
|
/* @__PURE__ */ jsx6(Box6, { marginBottom: 1, children: /* @__PURE__ */ jsx6(Text6, { bold: true, color: "cyan", children: "Select Provider" }) }),
|
|
280
|
-
/* @__PURE__ */ jsx6(Box6, { marginBottom: 1, children: /* @__PURE__ */ jsx6(Text6, { color: "gray", children: "
|
|
396
|
+
/* @__PURE__ */ jsx6(Box6, { marginBottom: 1, children: /* @__PURE__ */ jsx6(Text6, { color: "gray", dimColor: true, children: "Arrows to navigate, Enter to select" }) }),
|
|
281
397
|
PROVIDERS.map((provider, index) => {
|
|
282
398
|
const isSelected = index === providerIndex;
|
|
283
399
|
const isCurrent = provider.id === config.provider;
|
|
284
|
-
|
|
400
|
+
const hasKey = provider.needsApiKey && provider.id !== "ollama" ? !!config.apiKeys[provider.id] : true;
|
|
401
|
+
return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", children: [
|
|
285
402
|
/* @__PURE__ */ jsxs5(Text6, { color: isSelected ? "cyan" : "white", children: [
|
|
286
403
|
isSelected ? "\u276F " : " ",
|
|
287
404
|
provider.name,
|
|
288
|
-
isCurrent && /* @__PURE__ */ jsx6(Text6, { color: "green", children: " (current)" })
|
|
405
|
+
isCurrent && /* @__PURE__ */ jsx6(Text6, { color: "green", children: " (current)" }),
|
|
406
|
+
provider.needsApiKey && !hasKey && /* @__PURE__ */ jsx6(Text6, { color: "red", children: " (needs key)" }),
|
|
407
|
+
provider.needsApiKey && hasKey && !isCurrent && /* @__PURE__ */ jsx6(Text6, { color: "yellow", children: " (key saved)" })
|
|
289
408
|
] }),
|
|
290
409
|
isSelected && /* @__PURE__ */ jsxs5(Text6, { color: "gray", children: [
|
|
291
|
-
"
|
|
410
|
+
" ",
|
|
292
411
|
provider.description
|
|
293
412
|
] })
|
|
294
413
|
] }, provider.id);
|
|
295
414
|
}),
|
|
296
|
-
/* @__PURE__ */ jsx6(Box6, { marginTop: 1,
|
|
297
|
-
"Current: ",
|
|
298
|
-
config.provider,
|
|
299
|
-
" / ",
|
|
300
|
-
config.model
|
|
301
|
-
] }) })
|
|
415
|
+
/* @__PURE__ */ jsx6(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx6(Text6, { color: "gray", dimColor: true, children: "Press Esc to cancel" }) })
|
|
302
416
|
] });
|
|
303
417
|
}
|
|
304
|
-
|
|
305
|
-
/* @__PURE__ */
|
|
306
|
-
"
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
418
|
+
if (step === "apiKey" && selectedProvider) {
|
|
419
|
+
return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", padding: 1, width: 60, children: [
|
|
420
|
+
/* @__PURE__ */ jsx6(Box6, { marginBottom: 1, children: /* @__PURE__ */ jsx6(Text6, { bold: true, color: "cyan", children: "Enter API Key" }) }),
|
|
421
|
+
/* @__PURE__ */ jsxs5(Text6, { children: [
|
|
422
|
+
/* @__PURE__ */ jsx6(Text6, { color: "green", children: "\u2713" }),
|
|
423
|
+
" Provider: ",
|
|
424
|
+
selectedProvider.name
|
|
425
|
+
] }),
|
|
426
|
+
/* @__PURE__ */ jsxs5(Box6, { marginTop: 1, flexDirection: "column", children: [
|
|
427
|
+
/* @__PURE__ */ jsxs5(Text6, { color: "gray", dimColor: true, children: [
|
|
428
|
+
selectedProvider.id === "openrouter" && "Get key: openrouter.ai/keys",
|
|
429
|
+
selectedProvider.id === "anthropic" && "Get key: console.anthropic.com",
|
|
430
|
+
selectedProvider.id === "openai" && "Get key: platform.openai.com/api-keys"
|
|
431
|
+
] }),
|
|
432
|
+
/* @__PURE__ */ jsxs5(Box6, { marginTop: 1, children: [
|
|
433
|
+
/* @__PURE__ */ jsx6(Text6, { color: "cyan", children: "\u276F " }),
|
|
434
|
+
/* @__PURE__ */ jsx6(
|
|
435
|
+
TextInput2,
|
|
436
|
+
{
|
|
437
|
+
value: apiKeyInput,
|
|
438
|
+
onChange: setApiKeyInput,
|
|
439
|
+
onSubmit: handleApiKeySubmit,
|
|
440
|
+
mask: "*"
|
|
441
|
+
}
|
|
442
|
+
)
|
|
443
|
+
] })
|
|
444
|
+
] }),
|
|
445
|
+
/* @__PURE__ */ jsx6(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx6(Text6, { color: "gray", dimColor: true, children: "Press Esc to cancel" }) })
|
|
446
|
+
] });
|
|
447
|
+
}
|
|
448
|
+
if (step === "ollamaError" && ollamaStatus) {
|
|
449
|
+
return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", borderStyle: "round", borderColor: "red", padding: 1, width: 60, children: [
|
|
450
|
+
/* @__PURE__ */ jsx6(Box6, { marginBottom: 1, children: /* @__PURE__ */ jsx6(Text6, { bold: true, color: "red", children: "Ollama Not Available" }) }),
|
|
451
|
+
/* @__PURE__ */ jsx6(Text6, { color: "red", children: ollamaStatus.error }),
|
|
452
|
+
/* @__PURE__ */ jsxs5(Box6, { marginTop: 1, flexDirection: "column", children: [
|
|
453
|
+
!ollamaStatus.installed && /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
454
|
+
/* @__PURE__ */ jsx6(Text6, { children: "1. Install Ollama from https://ollama.ai" }),
|
|
455
|
+
/* @__PURE__ */ jsx6(Text6, { children: "2. Run: ollama pull qwen2.5:0.5b" }),
|
|
456
|
+
/* @__PURE__ */ jsx6(Text6, { children: "3. Try again" })
|
|
457
|
+
] }),
|
|
458
|
+
ollamaStatus.installed && !ollamaStatus.running && /* @__PURE__ */ jsxs5(Fragment, { children: [
|
|
459
|
+
/* @__PURE__ */ jsx6(Text6, { children: "1. Start Ollama: ollama serve" }),
|
|
460
|
+
/* @__PURE__ */ jsx6(Text6, { children: "2. Or run any model: ollama run qwen2.5:0.5b" }),
|
|
461
|
+
/* @__PURE__ */ jsx6(Text6, { children: "3. Try again" })
|
|
462
|
+
] })
|
|
463
|
+
] }),
|
|
464
|
+
/* @__PURE__ */ jsx6(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx6(Text6, { color: "gray", dimColor: true, children: "Press Enter or B to go back" }) })
|
|
465
|
+
] });
|
|
466
|
+
}
|
|
467
|
+
if (step === "model" && selectedProvider) {
|
|
468
|
+
const isOllama = selectedProvider.id === "ollama";
|
|
469
|
+
return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", padding: 1, width: 60, children: [
|
|
470
|
+
/* @__PURE__ */ jsx6(Box6, { marginBottom: 1, children: /* @__PURE__ */ jsx6(Text6, { bold: true, color: "cyan", children: "Select Model" }) }),
|
|
471
|
+
/* @__PURE__ */ jsxs5(Text6, { children: [
|
|
472
|
+
/* @__PURE__ */ jsx6(Text6, { color: "green", children: "\u2713" }),
|
|
473
|
+
" Provider: ",
|
|
474
|
+
selectedProvider.name
|
|
475
|
+
] }),
|
|
476
|
+
isOllama && checkingOllama && /* @__PURE__ */ jsxs5(Box6, { marginY: 1, children: [
|
|
477
|
+
/* @__PURE__ */ jsx6(Text6, { color: "cyan", children: /* @__PURE__ */ jsx6(Spinner, { type: "dots" }) }),
|
|
478
|
+
/* @__PURE__ */ jsx6(Text6, { children: " Checking Ollama status..." })
|
|
479
|
+
] }),
|
|
480
|
+
isOllama && ollamaStatus && ollamaStatus.running && /* @__PURE__ */ jsxs5(Text6, { color: "green", children: [
|
|
481
|
+
"\u2713 Ollama running (",
|
|
482
|
+
ollamaStatus.models.length,
|
|
483
|
+
" models installed)"
|
|
484
|
+
] }),
|
|
485
|
+
/* @__PURE__ */ jsx6(Box6, { marginTop: 1, marginBottom: 1, children: /* @__PURE__ */ jsx6(Text6, { color: "gray", dimColor: true, children: "Arrows to navigate, Enter to select, B to go back" }) }),
|
|
486
|
+
selectedProvider.models.map((model, index) => {
|
|
487
|
+
const isSelected = index === modelIndex;
|
|
488
|
+
const isCurrent = model.id === config.model && selectedProvider.id === config.provider;
|
|
489
|
+
let modelStatus = "";
|
|
490
|
+
if (isOllama && ollamaStatus) {
|
|
491
|
+
const available = hasModel(ollamaStatus, model.id);
|
|
492
|
+
modelStatus = available ? " (installed)" : " (not installed)";
|
|
493
|
+
}
|
|
494
|
+
return /* @__PURE__ */ jsxs5(Text6, { color: isSelected ? "cyan" : "white", children: [
|
|
495
|
+
isSelected ? "\u276F " : " ",
|
|
496
|
+
model.name,
|
|
497
|
+
model.recommended && /* @__PURE__ */ jsx6(Text6, { color: "yellow", children: " *" }),
|
|
498
|
+
isCurrent && /* @__PURE__ */ jsx6(Text6, { color: "green", children: " (current)" }),
|
|
499
|
+
isOllama && ollamaStatus && (hasModel(ollamaStatus, model.id) ? /* @__PURE__ */ jsx6(Text6, { color: "green", children: modelStatus }) : /* @__PURE__ */ jsx6(Text6, { color: "red", children: modelStatus }))
|
|
500
|
+
] }, model.id);
|
|
501
|
+
}),
|
|
502
|
+
isOllama && /* @__PURE__ */ jsxs5(Box6, { marginTop: 1, flexDirection: "column", children: [
|
|
503
|
+
/* @__PURE__ */ jsx6(Text6, { color: "gray", dimColor: true, children: "* = Recommended" }),
|
|
504
|
+
ollamaStatus && !hasModel(ollamaStatus, selectedProvider.models[modelIndex]?.id || "") && /* @__PURE__ */ jsxs5(Text6, { color: "yellow", children: [
|
|
505
|
+
"Run: ollama pull ",
|
|
506
|
+
selectedProvider.models[modelIndex]?.id
|
|
507
|
+
] })
|
|
508
|
+
] }),
|
|
509
|
+
/* @__PURE__ */ jsx6(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx6(Text6, { color: "gray", dimColor: true, children: "Press Esc to cancel" }) })
|
|
510
|
+
] });
|
|
511
|
+
}
|
|
512
|
+
if (step === "done" && selectedProvider) {
|
|
513
|
+
return /* @__PURE__ */ jsxs5(Box6, { flexDirection: "column", borderStyle: "round", borderColor: "green", padding: 1, width: 60, children: [
|
|
514
|
+
/* @__PURE__ */ jsx6(Text6, { color: "green", bold: true, children: "Configuration Updated!" }),
|
|
515
|
+
/* @__PURE__ */ jsxs5(Text6, { children: [
|
|
516
|
+
/* @__PURE__ */ jsx6(Text6, { color: "green", children: "\u2713" }),
|
|
517
|
+
" Provider: ",
|
|
518
|
+
selectedProvider.name
|
|
519
|
+
] }),
|
|
520
|
+
/* @__PURE__ */ jsxs5(Text6, { children: [
|
|
521
|
+
/* @__PURE__ */ jsx6(Text6, { color: "green", children: "\u2713" }),
|
|
522
|
+
" Model: ",
|
|
523
|
+
selectedProvider.models[modelIndex]?.name
|
|
524
|
+
] }),
|
|
525
|
+
selectedProvider.id === "ollama" && ollamaStatus && !hasModel(ollamaStatus, selectedProvider.models[modelIndex]?.id || "") && /* @__PURE__ */ jsxs5(Text6, { color: "yellow", children: [
|
|
526
|
+
"Remember to run: ollama pull ",
|
|
527
|
+
selectedProvider.models[modelIndex]?.id
|
|
528
|
+
] })
|
|
529
|
+
] });
|
|
530
|
+
}
|
|
531
|
+
return null;
|
|
326
532
|
}
|
|
327
533
|
|
|
328
534
|
// src/hooks/useChat.ts
|
|
329
|
-
import { useState as useState3, useCallback, useRef, useEffect } from "react";
|
|
535
|
+
import { useState as useState3, useCallback, useRef, useEffect as useEffect2 } from "react";
|
|
330
536
|
|
|
331
537
|
// src/lib/api.ts
|
|
332
538
|
var SYSTEM_PROMPT = `You are C-napse, a helpful AI assistant for PC automation running on the user's desktop.
|
|
@@ -460,24 +666,24 @@ async function chatOpenAI(messages, model) {
|
|
|
460
666
|
}
|
|
461
667
|
|
|
462
668
|
// src/lib/screen.ts
|
|
463
|
-
import { exec } from "child_process";
|
|
464
|
-
import { promisify } from "util";
|
|
465
|
-
var
|
|
669
|
+
import { exec as exec2 } from "child_process";
|
|
670
|
+
import { promisify as promisify2 } from "util";
|
|
671
|
+
var execAsync2 = promisify2(exec2);
|
|
466
672
|
async function getScreenDescription() {
|
|
467
673
|
try {
|
|
468
674
|
const platform = process.platform;
|
|
469
675
|
if (platform === "win32") {
|
|
470
|
-
const { stdout } = await
|
|
676
|
+
const { stdout } = await execAsync2(`
|
|
471
677
|
Add-Type -AssemblyName System.Windows.Forms
|
|
472
678
|
$screen = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds
|
|
473
679
|
Write-Output "$($screen.Width)x$($screen.Height)"
|
|
474
680
|
`, { shell: "powershell.exe" });
|
|
475
681
|
return `Screen ${stdout.trim()} captured`;
|
|
476
682
|
} else if (platform === "darwin") {
|
|
477
|
-
const { stdout } = await
|
|
683
|
+
const { stdout } = await execAsync2(`system_profiler SPDisplaysDataType | grep Resolution | head -1`);
|
|
478
684
|
return `Screen ${stdout.trim()}`;
|
|
479
685
|
} else {
|
|
480
|
-
const { stdout } = await
|
|
686
|
+
const { stdout } = await execAsync2(`xdpyinfo | grep dimensions | awk '{print $2}'`);
|
|
481
687
|
return `Screen ${stdout.trim()} captured`;
|
|
482
688
|
}
|
|
483
689
|
} catch {
|
|
@@ -497,7 +703,7 @@ function useChat(screenWatch = false) {
|
|
|
497
703
|
const [isProcessing, setIsProcessing] = useState3(false);
|
|
498
704
|
const [error, setError] = useState3(null);
|
|
499
705
|
const screenContextRef = useRef(null);
|
|
500
|
-
|
|
706
|
+
useEffect2(() => {
|
|
501
707
|
if (!screenWatch) {
|
|
502
708
|
screenContextRef.current = null;
|
|
503
709
|
return;
|
|
@@ -606,17 +812,17 @@ async function captureScreenshot() {
|
|
|
606
812
|
}
|
|
607
813
|
}
|
|
608
814
|
async function captureScreenFallback() {
|
|
609
|
-
const { exec:
|
|
610
|
-
const { promisify:
|
|
815
|
+
const { exec: exec6 } = await import("child_process");
|
|
816
|
+
const { promisify: promisify6 } = await import("util");
|
|
611
817
|
const { tmpdir } = await import("os");
|
|
612
818
|
const { join: join2 } = await import("path");
|
|
613
819
|
const { readFile, unlink } = await import("fs/promises");
|
|
614
|
-
const
|
|
820
|
+
const execAsync6 = promisify6(exec6);
|
|
615
821
|
const tempFile = join2(tmpdir(), `cnapse-screen-${Date.now()}.png`);
|
|
616
822
|
try {
|
|
617
823
|
const platform = process.platform;
|
|
618
824
|
if (platform === "win32") {
|
|
619
|
-
await
|
|
825
|
+
await execAsync6(`
|
|
620
826
|
Add-Type -AssemblyName System.Windows.Forms
|
|
621
827
|
$screen = [System.Windows.Forms.Screen]::PrimaryScreen.Bounds
|
|
622
828
|
$bitmap = New-Object System.Drawing.Bitmap($screen.Width, $screen.Height)
|
|
@@ -627,9 +833,9 @@ async function captureScreenFallback() {
|
|
|
627
833
|
$bitmap.Dispose()
|
|
628
834
|
`, { shell: "powershell.exe" });
|
|
629
835
|
} else if (platform === "darwin") {
|
|
630
|
-
await
|
|
836
|
+
await execAsync6(`screencapture -x "${tempFile}"`);
|
|
631
837
|
} else {
|
|
632
|
-
await
|
|
838
|
+
await execAsync6(`gnome-screenshot -f "${tempFile}" 2>/dev/null || scrot "${tempFile}" 2>/dev/null || import -window root "${tempFile}"`);
|
|
633
839
|
}
|
|
634
840
|
const imageBuffer = await readFile(tempFile);
|
|
635
841
|
await unlink(tempFile).catch(() => {
|
|
@@ -822,27 +1028,27 @@ function useVision() {
|
|
|
822
1028
|
}
|
|
823
1029
|
|
|
824
1030
|
// src/hooks/useTelegram.ts
|
|
825
|
-
import { useState as useState5, useCallback as useCallback3, useEffect as
|
|
1031
|
+
import { useState as useState5, useCallback as useCallback3, useEffect as useEffect3, useRef as useRef2 } from "react";
|
|
826
1032
|
|
|
827
1033
|
// src/services/telegram.ts
|
|
828
1034
|
import { EventEmitter } from "events";
|
|
829
1035
|
|
|
830
1036
|
// src/tools/shell.ts
|
|
831
|
-
import { exec as
|
|
832
|
-
import { promisify as
|
|
1037
|
+
import { exec as exec5 } from "child_process";
|
|
1038
|
+
import { promisify as promisify5 } from "util";
|
|
833
1039
|
|
|
834
1040
|
// src/tools/clipboard.ts
|
|
835
1041
|
import clipboardy from "clipboardy";
|
|
836
1042
|
|
|
837
1043
|
// src/tools/process.ts
|
|
838
|
-
import { exec as exec2 } from "child_process";
|
|
839
|
-
import { promisify as promisify2 } from "util";
|
|
840
|
-
var execAsync2 = promisify2(exec2);
|
|
841
|
-
|
|
842
|
-
// src/tools/computer.ts
|
|
843
1044
|
import { exec as exec3 } from "child_process";
|
|
844
1045
|
import { promisify as promisify3 } from "util";
|
|
845
1046
|
var execAsync3 = promisify3(exec3);
|
|
1047
|
+
|
|
1048
|
+
// src/tools/computer.ts
|
|
1049
|
+
import { exec as exec4 } from "child_process";
|
|
1050
|
+
import { promisify as promisify4 } from "util";
|
|
1051
|
+
var execAsync4 = promisify4(exec4);
|
|
846
1052
|
async function clickMouse(button = "left") {
|
|
847
1053
|
try {
|
|
848
1054
|
if (process.platform === "win32") {
|
|
@@ -852,12 +1058,12 @@ Add-Type -MemberDefinition @"
|
|
|
852
1058
|
public static extern void mouse_event(long dwFlags, long dx, long dy, long cButtons, long dwExtraInfo);
|
|
853
1059
|
"@ -Name Mouse -Namespace Win32
|
|
854
1060
|
${button === "left" ? "[Win32.Mouse]::mouse_event(0x02, 0, 0, 0, 0); [Win32.Mouse]::mouse_event(0x04, 0, 0, 0, 0)" : button === "right" ? "[Win32.Mouse]::mouse_event(0x08, 0, 0, 0, 0); [Win32.Mouse]::mouse_event(0x10, 0, 0, 0, 0)" : "[Win32.Mouse]::mouse_event(0x20, 0, 0, 0, 0); [Win32.Mouse]::mouse_event(0x40, 0, 0, 0, 0)"}`;
|
|
855
|
-
await
|
|
1061
|
+
await execAsync4(`powershell -Command "${script.replace(/\n/g, " ")}"`, { shell: "cmd.exe" });
|
|
856
1062
|
} else if (process.platform === "darwin") {
|
|
857
|
-
await
|
|
1063
|
+
await execAsync4(`cliclick c:.`);
|
|
858
1064
|
} else {
|
|
859
1065
|
const btn = button === "left" ? "1" : button === "right" ? "3" : "2";
|
|
860
|
-
await
|
|
1066
|
+
await execAsync4(`xdotool click ${btn}`);
|
|
861
1067
|
}
|
|
862
1068
|
return ok(`Clicked ${button} button`);
|
|
863
1069
|
} catch (error) {
|
|
@@ -868,13 +1074,13 @@ async function typeText(text) {
|
|
|
868
1074
|
try {
|
|
869
1075
|
if (process.platform === "win32") {
|
|
870
1076
|
const escapedText = text.replace(/'/g, "''").replace(/[+^%~(){}[\]]/g, "{$&}");
|
|
871
|
-
await
|
|
1077
|
+
await execAsync4(`powershell -Command "Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.SendKeys]::SendWait('${escapedText}')"`, { shell: "cmd.exe" });
|
|
872
1078
|
} else if (process.platform === "darwin") {
|
|
873
1079
|
const escaped = text.replace(/'/g, "'\\''");
|
|
874
|
-
await
|
|
1080
|
+
await execAsync4(`osascript -e 'tell application "System Events" to keystroke "${escaped}"'`);
|
|
875
1081
|
} else {
|
|
876
1082
|
const escaped = text.replace(/'/g, "'\\''");
|
|
877
|
-
await
|
|
1083
|
+
await execAsync4(`xdotool type '${escaped}'`);
|
|
878
1084
|
}
|
|
879
1085
|
return ok(`Typed: ${text}`);
|
|
880
1086
|
} catch (error) {
|
|
@@ -915,7 +1121,7 @@ async function pressKey(key) {
|
|
|
915
1121
|
"f12": "{F12}"
|
|
916
1122
|
};
|
|
917
1123
|
const winKey = winKeyMap[key.toLowerCase()] || key;
|
|
918
|
-
await
|
|
1124
|
+
await execAsync4(`powershell -Command "Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.SendKeys]::SendWait('${winKey}')"`, { shell: "cmd.exe" });
|
|
919
1125
|
} else if (process.platform === "darwin") {
|
|
920
1126
|
const macKeyMap = {
|
|
921
1127
|
"return": 36,
|
|
@@ -933,12 +1139,12 @@ async function pressKey(key) {
|
|
|
933
1139
|
};
|
|
934
1140
|
const keyCode = macKeyMap[key.toLowerCase()];
|
|
935
1141
|
if (keyCode) {
|
|
936
|
-
await
|
|
1142
|
+
await execAsync4(`osascript -e 'tell application "System Events" to key code ${keyCode}'`);
|
|
937
1143
|
} else {
|
|
938
|
-
await
|
|
1144
|
+
await execAsync4(`osascript -e 'tell application "System Events" to keystroke "${key}"'`);
|
|
939
1145
|
}
|
|
940
1146
|
} else {
|
|
941
|
-
await
|
|
1147
|
+
await execAsync4(`xdotool key ${key}`);
|
|
942
1148
|
}
|
|
943
1149
|
return ok(`Pressed: ${key}`);
|
|
944
1150
|
} catch (error) {
|
|
@@ -951,7 +1157,7 @@ async function keyCombo(keys) {
|
|
|
951
1157
|
const hasWin = keys.some((k) => k.toLowerCase() === "meta" || k.toLowerCase() === "win");
|
|
952
1158
|
const hasR = keys.some((k) => k.toLowerCase() === "r");
|
|
953
1159
|
if (hasWin && hasR) {
|
|
954
|
-
await
|
|
1160
|
+
await execAsync4(`powershell -Command "$shell = New-Object -ComObject WScript.Shell; $shell.Run('explorer shell:::{2559a1f3-21d7-11d4-bdaf-00c04f60b9f0}')"`, { shell: "cmd.exe" });
|
|
955
1161
|
return ok(`Pressed: ${keys.join("+")}`);
|
|
956
1162
|
}
|
|
957
1163
|
const modifierMap = {
|
|
@@ -971,7 +1177,7 @@ async function keyCombo(keys) {
|
|
|
971
1177
|
}
|
|
972
1178
|
}
|
|
973
1179
|
combo += regularKeys.join("");
|
|
974
|
-
await
|
|
1180
|
+
await execAsync4(`powershell -Command "Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.SendKeys]::SendWait('${combo}')"`, { shell: "cmd.exe" });
|
|
975
1181
|
} else if (process.platform === "darwin") {
|
|
976
1182
|
const modifiers = keys.filter((k) => ["control", "ctrl", "alt", "shift", "command", "meta"].includes(k.toLowerCase()));
|
|
977
1183
|
const regular = keys.filter((k) => !["control", "ctrl", "alt", "shift", "command", "meta"].includes(k.toLowerCase()));
|
|
@@ -987,9 +1193,9 @@ async function keyCombo(keys) {
|
|
|
987
1193
|
};
|
|
988
1194
|
cmd += " using {" + modifiers.map((m) => modMap[m.toLowerCase()]).join(", ") + "}";
|
|
989
1195
|
}
|
|
990
|
-
await
|
|
1196
|
+
await execAsync4(`osascript -e '${cmd}'`);
|
|
991
1197
|
} else {
|
|
992
|
-
await
|
|
1198
|
+
await execAsync4(`xdotool key ${keys.join("+")}`);
|
|
993
1199
|
}
|
|
994
1200
|
return ok(`Pressed: ${keys.join("+")}`);
|
|
995
1201
|
} catch (error) {
|
|
@@ -1000,11 +1206,11 @@ async function focusWindow(title) {
|
|
|
1000
1206
|
try {
|
|
1001
1207
|
if (process.platform === "win32") {
|
|
1002
1208
|
const escaped = title.replace(/'/g, "''");
|
|
1003
|
-
await
|
|
1209
|
+
await execAsync4(`powershell -Command "$wshell = New-Object -ComObject wscript.shell; $wshell.AppActivate('${escaped}')"`, { shell: "cmd.exe" });
|
|
1004
1210
|
} else if (process.platform === "darwin") {
|
|
1005
|
-
await
|
|
1211
|
+
await execAsync4(`osascript -e 'tell application "${title}" to activate'`);
|
|
1006
1212
|
} else {
|
|
1007
|
-
await
|
|
1213
|
+
await execAsync4(`wmctrl -a "${title}"`);
|
|
1008
1214
|
}
|
|
1009
1215
|
return ok(`Focused window: ${title}`);
|
|
1010
1216
|
} catch (error) {
|
|
@@ -1021,13 +1227,13 @@ function err(error) {
|
|
|
1021
1227
|
}
|
|
1022
1228
|
|
|
1023
1229
|
// src/tools/shell.ts
|
|
1024
|
-
var
|
|
1230
|
+
var execAsync5 = promisify5(exec5);
|
|
1025
1231
|
async function runCommand(cmd, timeout = 3e4) {
|
|
1026
1232
|
try {
|
|
1027
1233
|
const isWindows = process.platform === "win32";
|
|
1028
1234
|
const shell = isWindows ? "cmd.exe" : "/bin/sh";
|
|
1029
1235
|
const shellArg = isWindows ? "/C" : "-c";
|
|
1030
|
-
const { stdout, stderr } = await
|
|
1236
|
+
const { stdout, stderr } = await execAsync5(cmd, {
|
|
1031
1237
|
shell,
|
|
1032
1238
|
timeout,
|
|
1033
1239
|
maxBuffer: 10 * 1024 * 1024
|
|
@@ -1271,7 +1477,7 @@ function useTelegram(onMessage) {
|
|
|
1271
1477
|
const [error, setError] = useState5(null);
|
|
1272
1478
|
const [lastMessage, setLastMessage] = useState5(null);
|
|
1273
1479
|
const onMessageRef = useRef2(onMessage);
|
|
1274
|
-
|
|
1480
|
+
useEffect3(() => {
|
|
1275
1481
|
onMessageRef.current = onMessage;
|
|
1276
1482
|
}, [onMessage]);
|
|
1277
1483
|
const start = useCallback3(async () => {
|
|
@@ -1935,74 +2141,81 @@ ${tasks.format(task)}`);
|
|
|
1935
2141
|
// src/index.tsx
|
|
1936
2142
|
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
1937
2143
|
var args = process.argv.slice(2);
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
if (!provider || !key) {
|
|
1945
|
-
console.log("Usage: cnapse auth <provider> <api-key>");
|
|
1946
|
-
console.log("Providers: openrouter, anthropic, openai");
|
|
1947
|
-
process.exit(1);
|
|
1948
|
-
}
|
|
1949
|
-
if (!["openrouter", "anthropic", "openai"].includes(provider)) {
|
|
1950
|
-
console.log(`Invalid provider: ${provider}`);
|
|
1951
|
-
console.log("Valid providers: openrouter, anthropic, openai");
|
|
1952
|
-
process.exit(1);
|
|
1953
|
-
}
|
|
1954
|
-
setApiKey(provider, key);
|
|
1955
|
-
console.log(`\u2713 ${provider} API key saved`);
|
|
1956
|
-
process.exit(0);
|
|
1957
|
-
}
|
|
1958
|
-
case "config": {
|
|
1959
|
-
const subcommand = args[1];
|
|
1960
|
-
if (subcommand === "set") {
|
|
2144
|
+
async function main() {
|
|
2145
|
+
if (args.length > 0) {
|
|
2146
|
+
const command = args[0];
|
|
2147
|
+
switch (command) {
|
|
2148
|
+
case "auth": {
|
|
2149
|
+
const provider = args[1];
|
|
1961
2150
|
const key = args[2];
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
process.exit(1);
|
|
1967
|
-
}
|
|
1968
|
-
setProvider(value);
|
|
1969
|
-
console.log(`\u2713 Provider set to: ${value}`);
|
|
1970
|
-
} else if (key === "model") {
|
|
1971
|
-
setModel(value);
|
|
1972
|
-
console.log(`\u2713 Model set to: ${value}`);
|
|
1973
|
-
} else {
|
|
1974
|
-
console.log("Usage: cnapse config set <provider|model> <value>");
|
|
2151
|
+
if (!provider || !key) {
|
|
2152
|
+
console.log("Usage: cnapse auth <provider> <api-key>");
|
|
2153
|
+
console.log("Providers: openrouter, anthropic, openai");
|
|
2154
|
+
process.exit(1);
|
|
1975
2155
|
}
|
|
2156
|
+
if (!["openrouter", "anthropic", "openai"].includes(provider)) {
|
|
2157
|
+
console.log(`Invalid provider: ${provider}`);
|
|
2158
|
+
console.log("Valid providers: openrouter, anthropic, openai");
|
|
2159
|
+
process.exit(1);
|
|
2160
|
+
}
|
|
2161
|
+
setApiKey(provider, key);
|
|
2162
|
+
console.log(`\u2713 ${provider} API key saved`);
|
|
1976
2163
|
process.exit(0);
|
|
1977
2164
|
}
|
|
1978
|
-
|
|
1979
|
-
const
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
2165
|
+
case "config": {
|
|
2166
|
+
const subcommand = args[1];
|
|
2167
|
+
if (!subcommand) {
|
|
2168
|
+
const { ConfigUI } = await import("./ConfigUI-V5TM6KKS.js");
|
|
2169
|
+
render(/* @__PURE__ */ jsx8(ConfigUI, {}));
|
|
2170
|
+
return;
|
|
2171
|
+
}
|
|
2172
|
+
if (subcommand === "set") {
|
|
2173
|
+
const key = args[2];
|
|
2174
|
+
const value = args[3];
|
|
2175
|
+
if (key === "provider") {
|
|
2176
|
+
if (!["openrouter", "ollama", "anthropic", "openai"].includes(value)) {
|
|
2177
|
+
console.log("Valid providers: openrouter, ollama, anthropic, openai");
|
|
2178
|
+
process.exit(1);
|
|
2179
|
+
}
|
|
2180
|
+
setProvider(value);
|
|
2181
|
+
console.log(`\u2713 Provider set to: ${value}`);
|
|
2182
|
+
} else if (key === "model") {
|
|
2183
|
+
setModel(value);
|
|
2184
|
+
console.log(`\u2713 Model set to: ${value}`);
|
|
2185
|
+
} else {
|
|
2186
|
+
console.log("Usage: cnapse config set <provider|model> <value>");
|
|
2187
|
+
}
|
|
2188
|
+
process.exit(0);
|
|
2189
|
+
}
|
|
2190
|
+
if (subcommand === "show") {
|
|
2191
|
+
const config = getConfig();
|
|
2192
|
+
console.log("\nC-napse Configuration:");
|
|
2193
|
+
console.log(` Provider: ${config.provider}`);
|
|
2194
|
+
console.log(` Model: ${config.model}`);
|
|
2195
|
+
console.log(` Ollama Host: ${config.ollamaHost}`);
|
|
2196
|
+
console.log(` API Keys configured:`);
|
|
2197
|
+
console.log(` - OpenRouter: ${config.apiKeys.openrouter ? "\u2713" : "\u2717"}`);
|
|
2198
|
+
console.log(` - Anthropic: ${config.apiKeys.anthropic ? "\u2713" : "\u2717"}`);
|
|
2199
|
+
console.log(` - OpenAI: ${config.apiKeys.openai ? "\u2713" : "\u2717"}`);
|
|
2200
|
+
console.log("");
|
|
2201
|
+
process.exit(0);
|
|
2202
|
+
}
|
|
2203
|
+
console.log("Usage: cnapse config [show|set <key> <value>]");
|
|
2204
|
+
process.exit(1);
|
|
1990
2205
|
}
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
case "--help":
|
|
1996
|
-
case "-h": {
|
|
1997
|
-
console.log(`
|
|
2206
|
+
case "help":
|
|
2207
|
+
case "--help":
|
|
2208
|
+
case "-h": {
|
|
2209
|
+
console.log(`
|
|
1998
2210
|
C-napse - Autonomous PC Intelligence
|
|
1999
2211
|
|
|
2000
2212
|
Usage:
|
|
2001
2213
|
cnapse Start interactive chat
|
|
2002
2214
|
cnapse init Interactive setup wizard
|
|
2003
|
-
cnapse
|
|
2004
|
-
cnapse config
|
|
2215
|
+
cnapse config Interactive configuration
|
|
2216
|
+
cnapse config show Show current configuration
|
|
2005
2217
|
cnapse config set <k> <v> Set config value
|
|
2218
|
+
cnapse auth <provider> <key> Set API key
|
|
2006
2219
|
cnapse help Show this help
|
|
2007
2220
|
|
|
2008
2221
|
Providers:
|
|
@@ -2013,28 +2226,31 @@ Providers:
|
|
|
2013
2226
|
|
|
2014
2227
|
Quick Start:
|
|
2015
2228
|
cnapse init # Interactive setup
|
|
2229
|
+
cnapse config # Change provider/model
|
|
2016
2230
|
|
|
2017
2231
|
Manual Setup:
|
|
2018
2232
|
cnapse auth openrouter sk-or-xxxxx
|
|
2019
2233
|
cnapse config set provider openrouter
|
|
2020
2234
|
cnapse config set model qwen/qwen-2.5-coder-32b-instruct
|
|
2021
2235
|
`);
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2236
|
+
process.exit(0);
|
|
2237
|
+
}
|
|
2238
|
+
case "version":
|
|
2239
|
+
case "--version":
|
|
2240
|
+
case "-v": {
|
|
2241
|
+
console.log("cnapse v0.5.0");
|
|
2242
|
+
process.exit(0);
|
|
2243
|
+
}
|
|
2244
|
+
case "init": {
|
|
2245
|
+
const { Setup } = await import("./Setup-Q32JPHGP.js");
|
|
2246
|
+
render(/* @__PURE__ */ jsx8(Setup, {}));
|
|
2247
|
+
return;
|
|
2248
|
+
}
|
|
2249
|
+
default: {
|
|
2250
|
+
break;
|
|
2251
|
+
}
|
|
2037
2252
|
}
|
|
2038
2253
|
}
|
|
2254
|
+
render(/* @__PURE__ */ jsx8(App, {}));
|
|
2039
2255
|
}
|
|
2040
|
-
|
|
2256
|
+
main();
|