geeto 0.9.1 → 0.10.0
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/README.md +77 -18
- package/lib/api/copilot-sdk.d.ts.map +1 -1
- package/lib/api/copilot-sdk.js +29 -24
- package/lib/api/copilot-sdk.js.map +1 -1
- package/lib/api/copilot.d.ts.map +1 -1
- package/lib/api/copilot.js +6 -6
- package/lib/api/copilot.js.map +1 -1
- package/lib/api/gemini.d.ts.map +1 -1
- package/lib/api/gemini.js +2 -2
- package/lib/api/gemini.js.map +1 -1
- package/lib/api/groq-sdk.d.ts +11 -0
- package/lib/api/groq-sdk.d.ts.map +1 -0
- package/lib/api/groq-sdk.js +131 -0
- package/lib/api/groq-sdk.js.map +1 -0
- package/lib/api/groq.d.ts +10 -0
- package/lib/api/groq.d.ts.map +1 -0
- package/lib/api/groq.js +36 -0
- package/lib/api/groq.js.map +1 -0
- package/lib/api/openrouter-sdk.d.ts.map +1 -1
- package/lib/api/openrouter-sdk.js +58 -73
- package/lib/api/openrouter-sdk.js.map +1 -1
- package/lib/api/openrouter.d.ts.map +1 -1
- package/lib/api/openrouter.js +2 -2
- package/lib/api/openrouter.js.map +1 -1
- package/lib/api/trello.d.ts +16 -1
- package/lib/api/trello.d.ts.map +1 -1
- package/lib/api/trello.js +90 -2
- package/lib/api/trello.js.map +1 -1
- package/lib/cli/input.d.ts +1 -9
- package/lib/cli/input.d.ts.map +1 -1
- package/lib/cli/input.js +428 -169
- package/lib/cli/input.js.map +1 -1
- package/lib/cli/menu.d.ts.map +1 -1
- package/lib/cli/menu.js +33 -20
- package/lib/cli/menu.js.map +1 -1
- package/lib/core/copilot-setup.d.ts +5 -0
- package/lib/core/copilot-setup.d.ts.map +1 -1
- package/lib/core/copilot-setup.js +18 -0
- package/lib/core/copilot-setup.js.map +1 -1
- package/lib/core/gemini-setup.d.ts.map +1 -1
- package/lib/core/gemini-setup.js +7 -13
- package/lib/core/gemini-setup.js.map +1 -1
- package/lib/core/github-setup.d.ts.map +1 -1
- package/lib/core/github-setup.js +13 -7
- package/lib/core/github-setup.js.map +1 -1
- package/lib/core/gitlab-setup.d.ts.map +1 -1
- package/lib/core/gitlab-setup.js +13 -6
- package/lib/core/gitlab-setup.js.map +1 -1
- package/lib/core/groq-setup.d.ts +5 -0
- package/lib/core/groq-setup.d.ts.map +1 -0
- package/lib/core/groq-setup.js +67 -0
- package/lib/core/groq-setup.js.map +1 -0
- package/lib/core/openrouter-setup.d.ts.map +1 -1
- package/lib/core/openrouter-setup.js +11 -21
- package/lib/core/openrouter-setup.js.map +1 -1
- package/lib/core/setup.d.ts +2 -1
- package/lib/core/setup.d.ts.map +1 -1
- package/lib/core/setup.js +44 -7
- package/lib/core/setup.js.map +1 -1
- package/lib/index.js +8 -0
- package/lib/index.js.map +1 -1
- package/lib/types/index.d.ts +9 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/utils/ai-workflow.d.ts +10 -2
- package/lib/utils/ai-workflow.d.ts.map +1 -1
- package/lib/utils/ai-workflow.js +15 -0
- package/lib/utils/ai-workflow.js.map +1 -1
- package/lib/utils/branch-naming.d.ts +2 -1
- package/lib/utils/branch-naming.d.ts.map +1 -1
- package/lib/utils/branch-naming.js +114 -68
- package/lib/utils/branch-naming.js.map +1 -1
- package/lib/utils/config.d.ts +11 -3
- package/lib/utils/config.d.ts.map +1 -1
- package/lib/utils/config.js +46 -18
- package/lib/utils/config.js.map +1 -1
- package/lib/utils/git-ai-errors.d.ts.map +1 -1
- package/lib/utils/git-ai-errors.js +5 -1
- package/lib/utils/git-ai-errors.js.map +1 -1
- package/lib/utils/git-ai.d.ts +8 -7
- package/lib/utils/git-ai.d.ts.map +1 -1
- package/lib/utils/git-ai.js +239 -117
- package/lib/utils/git-ai.js.map +1 -1
- package/lib/utils/logging.d.ts.map +1 -1
- package/lib/utils/logging.js +14 -3
- package/lib/utils/logging.js.map +1 -1
- package/lib/utils/menu-builders.js +1 -1
- package/lib/utils/menu-builders.js.map +1 -1
- package/lib/utils/prompts-embedded.d.ts.map +1 -1
- package/lib/utils/prompts-embedded.js +0 -81
- package/lib/utils/prompts-embedded.js.map +1 -1
- package/lib/utils/scramble.d.ts.map +1 -1
- package/lib/utils/scramble.js +14 -3
- package/lib/utils/scramble.js.map +1 -1
- package/lib/utils/state.d.ts.map +1 -1
- package/lib/utils/state.js +12 -1
- package/lib/utils/state.js.map +1 -1
- package/lib/version.d.ts +1 -1
- package/lib/version.d.ts.map +1 -1
- package/lib/version.js +1 -1
- package/lib/version.js.map +1 -1
- package/lib/workflows/ai-provider.d.ts +3 -1
- package/lib/workflows/ai-provider.d.ts.map +1 -1
- package/lib/workflows/ai-provider.js +8 -2
- package/lib/workflows/ai-provider.js.map +1 -1
- package/lib/workflows/branch-helpers.d.ts.map +1 -1
- package/lib/workflows/branch-helpers.js +142 -71
- package/lib/workflows/branch-helpers.js.map +1 -1
- package/lib/workflows/branch.d.ts.map +1 -1
- package/lib/workflows/branch.js +97 -58
- package/lib/workflows/branch.js.map +1 -1
- package/lib/workflows/commit.d.ts +1 -1
- package/lib/workflows/commit.d.ts.map +1 -1
- package/lib/workflows/commit.js +97 -35
- package/lib/workflows/commit.js.map +1 -1
- package/lib/workflows/dry-run.d.ts.map +1 -1
- package/lib/workflows/dry-run.js +6 -0
- package/lib/workflows/dry-run.js.map +1 -1
- package/lib/workflows/issue.d.ts.map +1 -1
- package/lib/workflows/issue.js +12 -12
- package/lib/workflows/issue.js.map +1 -1
- package/lib/workflows/main-helpers.d.ts +3 -1
- package/lib/workflows/main-helpers.d.ts.map +1 -1
- package/lib/workflows/main-helpers.js +30 -26
- package/lib/workflows/main-helpers.js.map +1 -1
- package/lib/workflows/main.d.ts.map +1 -1
- package/lib/workflows/main.js +164 -13
- package/lib/workflows/main.js.map +1 -1
- package/lib/workflows/pr.d.ts.map +1 -1
- package/lib/workflows/pr.js +12 -12
- package/lib/workflows/pr.js.map +1 -1
- package/lib/workflows/release-merge.d.ts.map +1 -1
- package/lib/workflows/release-merge.js +40 -10
- package/lib/workflows/release-merge.js.map +1 -1
- package/lib/workflows/release-sync.d.ts.map +1 -1
- package/lib/workflows/release-sync.js +25 -7
- package/lib/workflows/release-sync.js.map +1 -1
- package/lib/workflows/release.d.ts.map +1 -1
- package/lib/workflows/release.js +130 -15
- package/lib/workflows/release.js.map +1 -1
- package/lib/workflows/repo-settings.d.ts.map +1 -1
- package/lib/workflows/repo-settings.js +35 -8
- package/lib/workflows/repo-settings.js.map +1 -1
- package/lib/workflows/reword.d.ts.map +1 -1
- package/lib/workflows/reword.js +60 -17
- package/lib/workflows/reword.js.map +1 -1
- package/lib/workflows/settings.d.ts +2 -1
- package/lib/workflows/settings.d.ts.map +1 -1
- package/lib/workflows/settings.js +364 -76
- package/lib/workflows/settings.js.map +1 -1
- package/lib/workflows/trello-menu.d.ts +0 -3
- package/lib/workflows/trello-menu.d.ts.map +1 -1
- package/lib/workflows/trello-menu.js +349 -19
- package/lib/workflows/trello-menu.js.map +1 -1
- package/package.json +12 -2
- package/lib/workflows/security-gate.d.ts +0 -8
- package/lib/workflows/security-gate.d.ts.map +0 -1
- package/lib/workflows/security-gate.js +0 -455
- package/lib/workflows/security-gate.js.map +0 -1
- package/prompts/security-gate-prompt.md +0 -80
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Settings workflow - handles all settings menu interactions
|
|
3
3
|
*/
|
|
4
|
-
import { existsSync, unlinkSync } from 'node:fs';
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs';
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { askQuestion, confirm } from '../cli/input.js';
|
|
7
7
|
import { multiSelect, select } from '../cli/menu.js';
|
|
8
8
|
import { colors } from '../utils/colors.js';
|
|
9
|
-
import { getBranchStrategyConfig, getProtectedBranches, hasGeminiConfig, hasTrelloConfig, saveBranchStrategyConfig, } from '../utils/config.js';
|
|
9
|
+
import { getBranchStrategyConfig, getProtectedBranches, GLOBAL_GEETO_DIR, hasGeminiConfig, hasTrelloConfig, saveBranchStrategyConfig, } from '../utils/config.js';
|
|
10
10
|
import { log } from '../utils/logging.js';
|
|
11
11
|
import { ScrambleProgress } from '../utils/scramble.js';
|
|
12
12
|
const configDirPath = () => path.join(process.cwd(), '.geeto');
|
|
@@ -19,6 +19,121 @@ const removeConfigFile = (name) => {
|
|
|
19
19
|
}
|
|
20
20
|
return false;
|
|
21
21
|
};
|
|
22
|
+
const isConfigLocal = (name) => existsSync(configFilePath(name));
|
|
23
|
+
const moveConfigToGlobal = (name) => {
|
|
24
|
+
const localPath = configFilePath(name);
|
|
25
|
+
if (!existsSync(localPath))
|
|
26
|
+
return false;
|
|
27
|
+
try {
|
|
28
|
+
if (!existsSync(GLOBAL_GEETO_DIR))
|
|
29
|
+
mkdirSync(GLOBAL_GEETO_DIR, { recursive: true });
|
|
30
|
+
writeFileSync(path.join(GLOBAL_GEETO_DIR, `${name}.toml`), readFileSync(localPath, 'utf8'), 'utf8');
|
|
31
|
+
unlinkSync(localPath);
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
const AI_PROVIDERS = ['gemini', 'openrouter', 'groq', 'github', 'gitlab'];
|
|
39
|
+
const globalConfigPath = (name) => path.join(GLOBAL_GEETO_DIR, `${name}.toml`);
|
|
40
|
+
const isConfigGlobal = (name) => existsSync(globalConfigPath(name));
|
|
41
|
+
const globalProviders = () => AI_PROVIDERS.filter((p) => isConfigGlobal(p));
|
|
42
|
+
const maskValue = (val) => val.length <= 8 ? '***' : `${val.slice(0, 4)}...${val.slice(-4)}`;
|
|
43
|
+
const readGlobalConfigInfo = (name) => {
|
|
44
|
+
try {
|
|
45
|
+
const content = readFileSync(globalConfigPath(name), 'utf8');
|
|
46
|
+
const match = content.match(/(?:gemini_api_key|openrouter_api_key|api_key|token)\s*=\s*["']([^"']+)["']/);
|
|
47
|
+
return match?.[1] ? maskValue(match[1]) : '(configured)';
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return '(configured)';
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const handleGlobalConfigSetting = async () => {
|
|
54
|
+
while (true) {
|
|
55
|
+
const configured = globalProviders();
|
|
56
|
+
if (configured.length === 0) {
|
|
57
|
+
log.info('No global AI config found in ~/.geeto/');
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
const action = await select('Global config (~/.geeto/):', [
|
|
61
|
+
{ label: 'View info', value: 'view' },
|
|
62
|
+
{ label: 'Configure a provider globally', value: 'configure' },
|
|
63
|
+
{ label: 'Remove a provider from global', value: 'remove' },
|
|
64
|
+
{ label: 'Back to settings menu', value: 'back' },
|
|
65
|
+
]);
|
|
66
|
+
if (action === 'back')
|
|
67
|
+
return true;
|
|
68
|
+
if (action === 'view') {
|
|
69
|
+
log.info(`Global config directory: ${GLOBAL_GEETO_DIR}\n`);
|
|
70
|
+
for (const p of configured) {
|
|
71
|
+
log.info(` ${p.padEnd(12)} ${readGlobalConfigInfo(p)}`);
|
|
72
|
+
}
|
|
73
|
+
askQuestion(`\n ${colors.gray}Press Enter to go back${colors.reset}`);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (action === 'configure') {
|
|
77
|
+
const provider = await select('Which provider to configure globally?', [
|
|
78
|
+
{ label: 'Gemini', value: 'gemini' },
|
|
79
|
+
{ label: 'OpenRouter', value: 'openrouter' },
|
|
80
|
+
{ label: 'Groq', value: 'groq' },
|
|
81
|
+
{ label: 'GitHub Copilot', value: 'github' },
|
|
82
|
+
{ label: 'GitLab', value: 'gitlab' },
|
|
83
|
+
{ label: 'Back', value: 'back' },
|
|
84
|
+
]);
|
|
85
|
+
if (provider === 'back')
|
|
86
|
+
continue;
|
|
87
|
+
const gp = globalConfigPath(provider);
|
|
88
|
+
if (existsSync(gp))
|
|
89
|
+
unlinkSync(gp);
|
|
90
|
+
switch (provider) {
|
|
91
|
+
case 'gemini': {
|
|
92
|
+
const { setupGeminiConfigInteractive } = await import('../core/gemini-setup.js');
|
|
93
|
+
setupGeminiConfigInteractive();
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
case 'openrouter': {
|
|
97
|
+
const { setupOpenRouterConfigInteractive } = await import('../core/openrouter-setup.js');
|
|
98
|
+
setupOpenRouterConfigInteractive();
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
case 'groq': {
|
|
102
|
+
const { setupGroqConfigInteractive } = await import('../core/groq-setup.js');
|
|
103
|
+
setupGroqConfigInteractive();
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
case 'github': {
|
|
107
|
+
const { setupGithubConfigInteractive } = await import('../core/github-setup.js');
|
|
108
|
+
setupGithubConfigInteractive();
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
case 'gitlab': {
|
|
112
|
+
const { setupGitlabConfigInteractive } = await import('../core/gitlab-setup.js');
|
|
113
|
+
setupGitlabConfigInteractive();
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (action === 'remove') {
|
|
120
|
+
const choices = configured.map((p) => ({
|
|
121
|
+
label: p,
|
|
122
|
+
value: p,
|
|
123
|
+
}));
|
|
124
|
+
choices.push({ label: 'Back', value: 'back' });
|
|
125
|
+
const provider = await select('Which provider to remove from global?', choices);
|
|
126
|
+
if (provider === 'back')
|
|
127
|
+
continue;
|
|
128
|
+
const gp = globalConfigPath(provider);
|
|
129
|
+
if (existsSync(gp)) {
|
|
130
|
+
unlinkSync(gp);
|
|
131
|
+
log.success(`Removed ${provider} from ~/.geeto/`);
|
|
132
|
+
}
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
};
|
|
22
137
|
const runInteractiveSetup = async (name) => {
|
|
23
138
|
if (name === 'trello') {
|
|
24
139
|
const { setupTrelloConfigInteractive } = await import('../core/trello-setup.js');
|
|
@@ -42,6 +157,17 @@ const runInteractiveSetup = async (name) => {
|
|
|
42
157
|
}
|
|
43
158
|
return;
|
|
44
159
|
}
|
|
160
|
+
if (name === 'groq') {
|
|
161
|
+
const { setupGroqConfigInteractive } = await import('../core/groq-setup.js');
|
|
162
|
+
const groqSetupSuccess = setupGroqConfigInteractive();
|
|
163
|
+
if (groqSetupSuccess) {
|
|
164
|
+
log.success('Groq integration configured!');
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
log.warn('Groq setup failed or cancelled.');
|
|
168
|
+
}
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
45
171
|
const { setupOpenRouterConfigInteractive } = await import('../core/openrouter-setup.js');
|
|
46
172
|
const openRouterSetupSuccess = setupOpenRouterConfigInteractive();
|
|
47
173
|
if (openRouterSetupSuccess) {
|
|
@@ -166,9 +292,6 @@ const syncOpenRouterModels = async () => {
|
|
|
166
292
|
const detailed = (await sdk.getAvailableModelChoices());
|
|
167
293
|
spinner.stop();
|
|
168
294
|
if (Array.isArray(detailed) && detailed.length > 0) {
|
|
169
|
-
// Persist detailed sync file
|
|
170
|
-
const syncFile = path.join(outDir, 'openrouter-model-live-sample.json');
|
|
171
|
-
await fs.promises.writeFile(syncFile, JSON.stringify(detailed, null, 2));
|
|
172
295
|
// Filter out image-generation-only models (geeto is for text/code tasks)
|
|
173
296
|
const imageOnlyPrefixes = [
|
|
174
297
|
'stabilityai/',
|
|
@@ -241,8 +364,7 @@ const syncOpenRouterModels = async () => {
|
|
|
241
364
|
});
|
|
242
365
|
const outModelFile = path.join(outDir, 'openrouter-model.json');
|
|
243
366
|
await fs.promises.writeFile(outModelFile, JSON.stringify(simple, null, 2));
|
|
244
|
-
log.info(`Saved ${simple.length} OpenRouter model(s) to .geeto/openrouter-model.json
|
|
245
|
-
'(and _live-sample.json).');
|
|
367
|
+
log.info(`Saved ${simple.length} OpenRouter model(s) to .geeto/openrouter-model.json`);
|
|
246
368
|
return;
|
|
247
369
|
}
|
|
248
370
|
}
|
|
@@ -251,18 +373,31 @@ const syncOpenRouterModels = async () => {
|
|
|
251
373
|
log.warn(`Failed to fetch OpenRouter models from SDK: ${msg}`);
|
|
252
374
|
}
|
|
253
375
|
}
|
|
254
|
-
// SDK unavailable or no models;
|
|
376
|
+
// SDK unavailable or returned no models; use saved models with multiSelect
|
|
255
377
|
const modelFilePath = path.join(outDir, 'openrouter-model.json');
|
|
256
378
|
if (fs.existsSync(modelFilePath)) {
|
|
257
379
|
try {
|
|
258
380
|
const raw = fs.readFileSync(modelFilePath, 'utf8');
|
|
259
381
|
const parsed = JSON.parse(raw);
|
|
260
382
|
if (Array.isArray(parsed) && parsed.length > 0) {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
383
|
+
const choices = parsed.map((m) => ({
|
|
384
|
+
label: String(m.label ?? m.value ?? ''),
|
|
385
|
+
value: String(m.value ?? ''),
|
|
386
|
+
}));
|
|
387
|
+
const defaults = choices.map((c) => c.value);
|
|
388
|
+
const selected = await multiSelect('Pick your favorite OpenRouter models (from saved list):', choices, defaults);
|
|
389
|
+
if (!selected || selected.length === 0) {
|
|
390
|
+
log.info('No models selected. Sync cancelled.');
|
|
391
|
+
return;
|
|
264
392
|
}
|
|
265
|
-
|
|
393
|
+
const simple = selected.map((val, idx) => {
|
|
394
|
+
const detail = parsed.find((m) => m.value === val);
|
|
395
|
+
const rawLabel = String(detail?.label ?? val);
|
|
396
|
+
const label = rawLabel.replace(/^\s*\d+\.\s*/, `${idx + 1}. `);
|
|
397
|
+
return { label, value: val };
|
|
398
|
+
});
|
|
399
|
+
await fs.promises.writeFile(modelFilePath, JSON.stringify(simple, null, 2));
|
|
400
|
+
log.success(`Saved ${simple.length} OpenRouter model(s) to .geeto/openrouter-model.json`);
|
|
266
401
|
return;
|
|
267
402
|
}
|
|
268
403
|
}
|
|
@@ -271,8 +406,7 @@ const syncOpenRouterModels = async () => {
|
|
|
271
406
|
log.warn(`Could not read OpenRouter model config: ${msg}`);
|
|
272
407
|
}
|
|
273
408
|
}
|
|
274
|
-
log.
|
|
275
|
-
log.info('Run the sync again after installing/configuring the OpenRouter SDK to fetch models.');
|
|
409
|
+
log.warn('No OpenRouter models available. Run --sync-models after configuring OpenRouter.');
|
|
276
410
|
}
|
|
277
411
|
catch (error) {
|
|
278
412
|
const msg = error instanceof Error ? error.message : String(error);
|
|
@@ -369,6 +503,65 @@ const syncGeminiModels = async () => {
|
|
|
369
503
|
log.warn(`Gemini model sync failed: ${msg}`);
|
|
370
504
|
}
|
|
371
505
|
};
|
|
506
|
+
// Sync Groq models (fetch live, pre-select free ones as defaults)
|
|
507
|
+
const syncGroqModels = async () => {
|
|
508
|
+
try {
|
|
509
|
+
let sdkModule = null;
|
|
510
|
+
try {
|
|
511
|
+
sdkModule = await import('../api/groq-sdk.js');
|
|
512
|
+
}
|
|
513
|
+
catch {
|
|
514
|
+
log.warn('Groq SDK unavailable. Configure Groq first with --setup-groq.');
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
const sdk = sdkModule;
|
|
518
|
+
if (!sdk || typeof sdk.getGroqModels !== 'function') {
|
|
519
|
+
log.warn('Groq SDK unavailable. Configure Groq first with --setup-groq.');
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
if (typeof sdk.isAvailable === 'function' && !sdk.isAvailable()) {
|
|
523
|
+
const { setupGroqConfigInteractive } = await import('../core/groq-setup.js');
|
|
524
|
+
const setupOk = setupGroqConfigInteractive();
|
|
525
|
+
if (!setupOk)
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
const spinner = new ScrambleProgress();
|
|
529
|
+
spinner.start(['Fetching Groq models...']);
|
|
530
|
+
const models = (await sdk.getGroqModels());
|
|
531
|
+
spinner.stop();
|
|
532
|
+
if (!Array.isArray(models) || models.length === 0) {
|
|
533
|
+
log.warn('No Groq models found.');
|
|
534
|
+
return;
|
|
535
|
+
}
|
|
536
|
+
// Pre-select all free models as defaults
|
|
537
|
+
const freeModels = new Set([
|
|
538
|
+
'llama-3.3-70b-versatile',
|
|
539
|
+
'llama-3.1-8b-instant',
|
|
540
|
+
'gemma2-9b-it',
|
|
541
|
+
'mixtral-8x7b-32768',
|
|
542
|
+
]);
|
|
543
|
+
const defaults = models.filter((m) => freeModels.has(m.value)).map((m) => m.value);
|
|
544
|
+
const selected = await multiSelect('Pick your favorite Groq models:', models, defaults);
|
|
545
|
+
if (!selected || selected.length === 0) {
|
|
546
|
+
log.info('No models selected. Sync cancelled.');
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
const simple = selected.map((val, idx) => {
|
|
550
|
+
const detail = models.find((m) => m.value === val);
|
|
551
|
+
return { label: `${idx + 1}. ${detail?.label ?? val}`, value: val };
|
|
552
|
+
});
|
|
553
|
+
const fsModule = await import('node:fs');
|
|
554
|
+
const outDir = path.join(process.cwd(), '.geeto');
|
|
555
|
+
await fsModule.promises.mkdir(outDir, { recursive: true });
|
|
556
|
+
const outFile = path.join(outDir, 'groq-model.json');
|
|
557
|
+
await fsModule.promises.writeFile(outFile, JSON.stringify(simple, null, 2));
|
|
558
|
+
log.success(`Saved ${simple.length} Groq model(s) to .geeto/groq-model.json`);
|
|
559
|
+
}
|
|
560
|
+
catch (error) {
|
|
561
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
562
|
+
log.warn(`Groq model sync failed: ${msg}`);
|
|
563
|
+
}
|
|
564
|
+
};
|
|
372
565
|
// Sync Copilot models (fetch from SDK & persist user favorites)
|
|
373
566
|
const syncCopilotModels = async () => {
|
|
374
567
|
try {
|
|
@@ -448,9 +641,10 @@ const syncCopilotModels = async () => {
|
|
|
448
641
|
};
|
|
449
642
|
const handleModelResetSetting = async () => {
|
|
450
643
|
const resetChoice = await select('Saved AI models — choose provider:', [
|
|
451
|
-
{ label: 'Copilot', value: 'copilot' },
|
|
644
|
+
{ label: 'GitHub Copilot', value: 'copilot' },
|
|
452
645
|
{ label: 'Gemini', value: 'gemini' },
|
|
453
646
|
{ label: 'OpenRouter', value: 'openrouter' },
|
|
647
|
+
{ label: 'Groq', value: 'groq' },
|
|
454
648
|
{ label: 'Back to settings menu', value: 'back' },
|
|
455
649
|
]);
|
|
456
650
|
if (resetChoice === 'back') {
|
|
@@ -466,6 +660,9 @@ const handleModelResetSetting = async () => {
|
|
|
466
660
|
if (resetChoice === 'copilot') {
|
|
467
661
|
await syncCopilotModels();
|
|
468
662
|
}
|
|
663
|
+
if (resetChoice === 'groq') {
|
|
664
|
+
await syncGroqModels();
|
|
665
|
+
}
|
|
469
666
|
log.success('Model sync completed!');
|
|
470
667
|
}
|
|
471
668
|
catch (error) {
|
|
@@ -481,8 +678,9 @@ const handleChangeModelSetting = async () => {
|
|
|
481
678
|
const { chooseModelForProvider } = await import('../utils/git-ai.js');
|
|
482
679
|
const provOptions = [
|
|
483
680
|
{ label: 'Gemini', value: 'gemini' },
|
|
484
|
-
{ label: 'Copilot', value: 'copilot' },
|
|
681
|
+
{ label: 'GitHub Copilot', value: 'copilot' },
|
|
485
682
|
{ label: 'OpenRouter', value: 'openrouter' },
|
|
683
|
+
{ label: 'Groq', value: 'groq' },
|
|
486
684
|
{ label: 'Back to settings menu', value: 'back' },
|
|
487
685
|
];
|
|
488
686
|
const chosenProv = await select('Choose provider to change model for:', provOptions);
|
|
@@ -535,13 +733,21 @@ const handleChangeModelSetting = async () => {
|
|
|
535
733
|
base.openrouterModel = undefined;
|
|
536
734
|
break;
|
|
537
735
|
}
|
|
736
|
+
case 'groq': {
|
|
737
|
+
base.groqModel = picked;
|
|
738
|
+
base.copilotModel = undefined;
|
|
739
|
+
base.openrouterModel = undefined;
|
|
740
|
+
base.geminiModel = undefined;
|
|
741
|
+
break;
|
|
742
|
+
}
|
|
538
743
|
default: {
|
|
539
744
|
break;
|
|
540
745
|
}
|
|
541
746
|
}
|
|
542
747
|
base.timestamp = now;
|
|
543
748
|
saveState(base);
|
|
544
|
-
const providerLabel =
|
|
749
|
+
const providerLabel = { gemini: 'Gemini', copilot: 'Copilot', openrouter: 'OpenRouter', groq: 'Groq' }[chosenProv] ??
|
|
750
|
+
chosenProv;
|
|
545
751
|
log.success(`Set ${providerLabel} model to: ${picked}`);
|
|
546
752
|
// Done; do not go back to settings menu
|
|
547
753
|
return false;
|
|
@@ -583,33 +789,36 @@ const handleGeminiSetting = async () => {
|
|
|
583
789
|
{ label: 'Remove configuration', value: 'remove' },
|
|
584
790
|
{ label: 'Back to settings menu', value: 'back' },
|
|
585
791
|
]);
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
}
|
|
596
|
-
else {
|
|
597
|
-
log.warn('Gemini setup failed or cancelled.');
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
else if (action === 'remove') {
|
|
601
|
-
const confirmRemove = confirm('Are you sure you want to remove Gemini configuration?');
|
|
602
|
-
if (confirmRemove) {
|
|
603
|
-
if (removeConfigFile('gemini')) {
|
|
604
|
-
log.success('Gemini configuration removed!');
|
|
792
|
+
switch (action) {
|
|
793
|
+
case 'reconfigure': {
|
|
794
|
+
log.info('Reconfiguring Gemini AI integration...');
|
|
795
|
+
if (removeConfigFile('gemini'))
|
|
796
|
+
log.info('Cleared existing Gemini configuration');
|
|
797
|
+
const { setupGeminiConfigInteractive } = await import('../core/gemini-setup.js');
|
|
798
|
+
const setupSuccess = setupGeminiConfigInteractive();
|
|
799
|
+
if (setupSuccess) {
|
|
800
|
+
log.success('Gemini AI integration reconfigured!');
|
|
605
801
|
}
|
|
606
802
|
else {
|
|
607
|
-
log.warn('
|
|
803
|
+
log.warn('Gemini setup failed or cancelled.');
|
|
608
804
|
}
|
|
805
|
+
break;
|
|
806
|
+
}
|
|
807
|
+
case 'remove': {
|
|
808
|
+
const confirmRemove = confirm('Are you sure you want to remove Gemini configuration?');
|
|
809
|
+
if (confirmRemove) {
|
|
810
|
+
if (removeConfigFile('gemini')) {
|
|
811
|
+
log.success('Gemini configuration removed!');
|
|
812
|
+
}
|
|
813
|
+
else {
|
|
814
|
+
log.warn('Failed to remove Gemini configuration.');
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
break;
|
|
818
|
+
}
|
|
819
|
+
case 'back': {
|
|
820
|
+
return true;
|
|
609
821
|
}
|
|
610
|
-
}
|
|
611
|
-
if (action === 'back') {
|
|
612
|
-
return true;
|
|
613
822
|
}
|
|
614
823
|
// Completed without returning to settings menu
|
|
615
824
|
return false;
|
|
@@ -669,53 +878,117 @@ const handleOpenRouterSetting = async () => {
|
|
|
669
878
|
{ label: 'Remove configuration', value: 'remove' },
|
|
670
879
|
{ label: 'Back to settings menu', value: 'back' },
|
|
671
880
|
]);
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
881
|
+
switch (action) {
|
|
882
|
+
case 'reconfigure': {
|
|
883
|
+
log.info('Reconfiguring OpenRouter integration...');
|
|
884
|
+
if (removeConfigFile('openrouter'))
|
|
885
|
+
log.info('Cleared existing OpenRouter configuration');
|
|
886
|
+
await runInteractiveSetup('openrouter');
|
|
887
|
+
log.success('OpenRouter integration reconfigured!');
|
|
888
|
+
break;
|
|
889
|
+
}
|
|
890
|
+
case 'remove': {
|
|
891
|
+
const confirmRemove = confirm('Are you sure you want to remove OpenRouter configuration?');
|
|
892
|
+
if (!confirmRemove)
|
|
893
|
+
return false;
|
|
894
|
+
if (removeConfigFile('openrouter')) {
|
|
895
|
+
log.success('OpenRouter configuration removed!');
|
|
896
|
+
}
|
|
897
|
+
else {
|
|
898
|
+
log.info('No OpenRouter configuration found to remove');
|
|
899
|
+
}
|
|
900
|
+
break;
|
|
901
|
+
}
|
|
902
|
+
case 'back': {
|
|
903
|
+
return true;
|
|
676
904
|
}
|
|
677
|
-
await runInteractiveSetup('openrouter');
|
|
678
|
-
log.success('OpenRouter integration reconfigured!');
|
|
679
905
|
}
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
906
|
+
// Completed without returning to settings menu
|
|
907
|
+
return false;
|
|
908
|
+
};
|
|
909
|
+
const handleGroqSetting = async () => {
|
|
910
|
+
const { hasGroqConfig } = await import('../utils/config.js');
|
|
911
|
+
const hasConfig = hasGroqConfig();
|
|
912
|
+
if (!hasConfig) {
|
|
913
|
+
await runInteractiveSetup('groq');
|
|
914
|
+
return false;
|
|
915
|
+
}
|
|
916
|
+
const action = await select('Groq integration is already configured. What would you like to do?', [
|
|
917
|
+
{ label: 'Reconfigure (replace existing config)', value: 'reconfigure' },
|
|
918
|
+
{ label: 'Remove configuration', value: 'remove' },
|
|
919
|
+
{ label: 'Back to settings menu', value: 'back' },
|
|
920
|
+
]);
|
|
921
|
+
switch (action) {
|
|
922
|
+
case 'reconfigure': {
|
|
923
|
+
log.info('Reconfiguring Groq integration...');
|
|
924
|
+
if (removeConfigFile('groq'))
|
|
925
|
+
log.info('Cleared existing Groq configuration');
|
|
926
|
+
await runInteractiveSetup('groq');
|
|
927
|
+
log.success('Groq integration reconfigured!');
|
|
928
|
+
break;
|
|
684
929
|
}
|
|
685
|
-
|
|
686
|
-
|
|
930
|
+
case 'remove': {
|
|
931
|
+
const confirmRemove = confirm('Are you sure you want to remove Groq configuration?');
|
|
932
|
+
if (!confirmRemove)
|
|
933
|
+
return false;
|
|
934
|
+
if (removeConfigFile('groq')) {
|
|
935
|
+
log.success('Groq configuration removed!');
|
|
936
|
+
}
|
|
937
|
+
else {
|
|
938
|
+
log.info('No Groq configuration found to remove');
|
|
939
|
+
}
|
|
940
|
+
break;
|
|
687
941
|
}
|
|
688
|
-
|
|
689
|
-
|
|
942
|
+
case 'back': {
|
|
943
|
+
return true;
|
|
690
944
|
}
|
|
691
945
|
}
|
|
692
|
-
|
|
693
|
-
|
|
946
|
+
return false;
|
|
947
|
+
};
|
|
948
|
+
const handleSaveGlobalAiConfig = () => {
|
|
949
|
+
const providers = ['gemini', 'openrouter', 'groq'];
|
|
950
|
+
const local = providers.filter((p) => isConfigLocal(p));
|
|
951
|
+
if (local.length === 0) {
|
|
952
|
+
log.info('No local AI config found — already global or not configured.');
|
|
953
|
+
return false;
|
|
694
954
|
}
|
|
695
|
-
|
|
955
|
+
log.info(`Local AI config found: ${local.join(', ')}`);
|
|
956
|
+
const ok = confirm(`Save all to ~/.geeto/ and use across all projects?`);
|
|
957
|
+
if (!ok)
|
|
958
|
+
return false;
|
|
959
|
+
let saved = 0;
|
|
960
|
+
for (const p of local) {
|
|
961
|
+
if (moveConfigToGlobal(p)) {
|
|
962
|
+
log.success(`${p}: saved to ${GLOBAL_GEETO_DIR}/${p}.toml`);
|
|
963
|
+
saved++;
|
|
964
|
+
}
|
|
965
|
+
else {
|
|
966
|
+
log.error(`${p}: failed`);
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
if (saved > 0)
|
|
970
|
+
log.success(`Done — ${saved} config(s) saved to ${GLOBAL_GEETO_DIR}`);
|
|
696
971
|
return false;
|
|
697
972
|
};
|
|
698
973
|
export const showSettingsMenu = async () => {
|
|
699
974
|
while (true) {
|
|
700
975
|
log.info('Settings Menu');
|
|
701
|
-
const
|
|
702
|
-
|
|
703
|
-
{ label: 'Branch
|
|
704
|
-
{ label: 'Branch
|
|
705
|
-
{ label: '
|
|
706
|
-
{ label: '
|
|
707
|
-
{ label: '
|
|
708
|
-
{ label: 'Active
|
|
709
|
-
{ label: '
|
|
710
|
-
{ label: '
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
{ label: '
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
{ label: 'Back to main menu', value: 'back' },
|
|
718
|
-
]);
|
|
976
|
+
const hasGlobalConfig = globalProviders().length > 0;
|
|
977
|
+
const menuOptions = [
|
|
978
|
+
{ label: 'Branch', value: '_branch', disabled: true },
|
|
979
|
+
{ label: ' Branch prefix (dev#name / dev/name)', value: 'prefix' },
|
|
980
|
+
{ label: ' Branch separator (hyphen / underscore)', value: 'separator' },
|
|
981
|
+
{ label: ' Protected branches', value: 'protected' },
|
|
982
|
+
{ label: 'AI', value: '_ai', disabled: true },
|
|
983
|
+
{ label: ' Active model (switch provider & model)', value: 'change-model' },
|
|
984
|
+
{ label: ' Saved models (manage favorites per provider)', value: 'models' },
|
|
985
|
+
{ label: ' Move local AI config to global (~/.geeto/)', value: 'save-global' },
|
|
986
|
+
];
|
|
987
|
+
if (hasGlobalConfig) {
|
|
988
|
+
menuOptions.push({ label: ' Manage global config (~/.geeto/)', value: 'global-config' });
|
|
989
|
+
}
|
|
990
|
+
menuOptions.push({ label: 'Setup', value: '_setup', disabled: true }, { label: ' GitHub Copilot', value: 'copilot' }, { label: ' Gemini', value: 'gemini' }, { label: ' OpenRouter', value: 'openrouter' }, { label: ' Groq', value: 'groq' }, { label: ' Trello', value: 'trello' }, { label: 'System', value: '_system', disabled: true }, { label: ' Installation info', value: 'where' }, { label: ' Uninstall geeto', value: 'uninstall' }, { label: 'Back', value: 'back' });
|
|
991
|
+
const settingChoice = await select('Settings:', menuOptions);
|
|
719
992
|
if (settingChoice === 'back') {
|
|
720
993
|
break;
|
|
721
994
|
}
|
|
@@ -743,6 +1016,15 @@ export const showSettingsMenu = async () => {
|
|
|
743
1016
|
continue;
|
|
744
1017
|
}
|
|
745
1018
|
}
|
|
1019
|
+
if (settingChoice === 'save-global') {
|
|
1020
|
+
handleSaveGlobalAiConfig();
|
|
1021
|
+
}
|
|
1022
|
+
if (settingChoice === 'global-config') {
|
|
1023
|
+
const back = await handleGlobalConfigSetting();
|
|
1024
|
+
if (back) {
|
|
1025
|
+
continue;
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
746
1028
|
if (settingChoice === 'change-model') {
|
|
747
1029
|
const back = await handleChangeModelSetting();
|
|
748
1030
|
if (back) {
|
|
@@ -774,6 +1056,12 @@ export const showSettingsMenu = async () => {
|
|
|
774
1056
|
continue;
|
|
775
1057
|
}
|
|
776
1058
|
}
|
|
1059
|
+
if (settingChoice === 'groq') {
|
|
1060
|
+
const back = await handleGroqSetting();
|
|
1061
|
+
if (back) {
|
|
1062
|
+
continue;
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
777
1065
|
if (settingChoice === 'where') {
|
|
778
1066
|
const { handleWhereInstalled } = await import('./doctor.js');
|
|
779
1067
|
await handleWhereInstalled();
|
|
@@ -793,5 +1081,5 @@ export const showSettingsMenu = async () => {
|
|
|
793
1081
|
}
|
|
794
1082
|
}
|
|
795
1083
|
};
|
|
796
|
-
export { handlePrefixFormatSetting, handleSeparatorSetting, handleProtectedBranchesSetting, handleModelResetSetting, handleChangeModelSetting, handleCopilotSetting, handleGeminiSetting, handleOpenRouterSetting, handleTrelloSetting, };
|
|
1084
|
+
export { handlePrefixFormatSetting, handleSeparatorSetting, handleProtectedBranchesSetting, handleModelResetSetting, handleChangeModelSetting, handleCopilotSetting, handleGeminiSetting, handleOpenRouterSetting, handleGroqSetting, handleTrelloSetting, };
|
|
797
1085
|
//# sourceMappingURL=settings.js.map
|