quackstack 1.0.17 → 1.0.20

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/cli.cjs CHANGED
@@ -24,7 +24,7 @@ program
24
24
  .option("--readme", "Generate README.md from your codebase")
25
25
  .option("--cursor", "[DEPRECATED] Use --context instead")
26
26
  .option("-w, --watch", "Watch mode: auto-update context files on file changes")
27
- .option("-p, --provider <provider>", "AI provider: openai, anthropic, gemini, deepseek, mistral")
27
+ .option("-p, --provider <provider>", "AI provider: openai, anthropic, gemini, deepseek, mistral, grok")
28
28
  .option("-m, --model <model>", "Specific model to use")
29
29
  .option("--list-models", "List available providers and models")
30
30
  .action(async (options) => {
@@ -46,8 +46,9 @@ program
46
46
  });
47
47
  });
48
48
  console.log(chalk_1.default.cyan("\nUsage:"));
49
- console.log(chalk_1.default.white(" quack --provider anthropic --model claude-sonnet-4-20250514"));
50
- console.log(chalk_1.default.white(" quack -p openai -m gpt-4o\n"));
49
+ console.log(chalk_1.default.white(" quack --provider anthropic --model claude-sonnet-4-5-20250929"));
50
+ console.log(chalk_1.default.white(" quack -p openai -m gpt-5.2"));
51
+ console.log(chalk_1.default.white(" quack -p grok -m grok-4\n"));
51
52
  process.exit(0);
52
53
  }
53
54
  const title = chalk_animation_1.default.rainbow("QuackStack\n");
@@ -11,6 +11,7 @@ export class AIClient {
11
11
  gemini;
12
12
  deepseek;
13
13
  mistral;
14
+ grok;
14
15
  constructor(providerOverride, modelOverride) {
15
16
  const config = this.detectProvider(providerOverride);
16
17
  this.provider = config.provider;
@@ -30,7 +31,8 @@ export class AIClient {
30
31
  " QUACKSTACK_ANTHROPIC_KEY\n" +
31
32
  " QUACKSTACK_GEMINI_KEY\n" +
32
33
  " QUACKSTACK_DEEPSEEK_KEY\n" +
33
- " QUACKSTACK_MISTRAL_KEY");
34
+ " QUACKSTACK_MISTRAL_KEY\n" +
35
+ " QUACKSTACK_GROK_KEY");
34
36
  }
35
37
  if (override) {
36
38
  const providerConfig = availableProviders.find(p => p.provider === override);
@@ -58,6 +60,7 @@ export class AIClient {
58
60
  gemini: process.env.QUACKSTACK_GEMINI_KEY || "",
59
61
  deepseek: process.env.QUACKSTACK_DEEPSEEK_KEY || "",
60
62
  mistral: process.env.QUACKSTACK_MISTRAL_KEY || "",
63
+ grok: process.env.QUACKSTACK_GROK_KEY || "",
61
64
  };
62
65
  return keyMap[provider] || undefined;
63
66
  }
@@ -68,12 +71,20 @@ export class AIClient {
68
71
  provider: "openai",
69
72
  name: "OpenAI",
70
73
  models: [
74
+ "gpt-5.2",
75
+ "gpt-5.2-instant",
76
+ "gpt-5.2-thinking",
77
+ "gpt-5.2-pro",
78
+ "gpt-5.1",
79
+ "o3",
80
+ "o3-pro",
81
+ "o4-mini",
71
82
  "gpt-4o",
72
83
  "gpt-4o-mini",
73
84
  "gpt-4-turbo",
74
85
  "gpt-3.5-turbo"
75
86
  ],
76
- defaultModel: "gpt-4o-mini"
87
+ defaultModel: "gpt-5.2"
77
88
  });
78
89
  }
79
90
  if (process.env.QUACKSTACK_ANTHROPIC_KEY) {
@@ -81,12 +92,16 @@ export class AIClient {
81
92
  provider: "anthropic",
82
93
  name: "Anthropic",
83
94
  models: [
95
+ "claude-opus-4-5-20251124",
96
+ "claude-opus-4-1-20250805",
84
97
  "claude-opus-4-20250514",
98
+ "claude-sonnet-4-5-20250929",
85
99
  "claude-sonnet-4-20250514",
100
+ "claude-haiku-4-5-20251015",
86
101
  "claude-3-7-sonnet-20250219",
87
102
  "claude-3-5-haiku-20241022"
88
103
  ],
89
- defaultModel: "claude-sonnet-4-20250514"
104
+ defaultModel: "claude-sonnet-4-5-20250929"
90
105
  });
91
106
  }
92
107
  if (process.env.QUACKSTACK_GEMINI_KEY) {
@@ -94,12 +109,17 @@ export class AIClient {
94
109
  provider: "gemini",
95
110
  name: "Gemini",
96
111
  models: [
112
+ "gemini-3-pro",
113
+ "gemini-3-deep-think",
114
+ "gemini-2.5-pro",
115
+ "gemini-2.5-flash",
116
+ "gemini-2.5-flash-lite",
97
117
  "gemini-2.0-flash-exp",
98
118
  "gemini-1.5-pro",
99
119
  "gemini-1.5-flash",
100
120
  "gemini-1.5-flash-8b"
101
121
  ],
102
- defaultModel: "gemini-1.5-flash"
122
+ defaultModel: "gemini-3-pro"
103
123
  });
104
124
  }
105
125
  if (process.env.QUACKSTACK_DEEPSEEK_KEY) {
@@ -125,15 +145,36 @@ export class AIClient {
125
145
  defaultModel: "mistral-large-latest"
126
146
  });
127
147
  }
148
+ if (process.env.QUACKSTACK_GROK_KEY) {
149
+ providers.push({
150
+ provider: "grok",
151
+ name: "xAI Grok",
152
+ models: [
153
+ "grok-4-1-fast-reasoning",
154
+ "grok-4-1-fast-non-reasoning",
155
+ "grok-4-fast-reasoning",
156
+ "grok-4-fast-non-reasoning",
157
+ "grok-code-fast-1",
158
+ "grok-4",
159
+ "grok-3",
160
+ "grok-3-mini",
161
+ "grok-2-vision-1212",
162
+ "grok-2-image-1212",
163
+ "grok-2-1212"
164
+ ],
165
+ defaultModel: "grok-4"
166
+ });
167
+ }
128
168
  return providers;
129
169
  }
130
170
  getDefaultModel(provider) {
131
171
  const defaults = {
132
- openai: "gpt-4o-mini",
133
- anthropic: "claude-sonnet-4-20250514",
134
- gemini: "gemini-1.5-flash",
172
+ openai: "gpt-5.2",
173
+ anthropic: "claude-sonnet-4-5-20250929",
174
+ gemini: "gemini-3-pro",
135
175
  deepseek: "deepseek-chat",
136
176
  mistral: "mistral-large-latest",
177
+ grok: "grok-4",
137
178
  };
138
179
  return defaults[provider];
139
180
  }
@@ -160,6 +201,12 @@ export class AIClient {
160
201
  baseURL: "https://api.mistral.ai/v1",
161
202
  });
162
203
  break;
204
+ case "grok":
205
+ this.grok = new OpenAI({
206
+ apiKey: config.apiKey,
207
+ baseURL: "https://api.x.ai/v1",
208
+ });
209
+ break;
163
210
  }
164
211
  }
165
212
  async generateAnswer(query, context) {
@@ -178,6 +225,8 @@ export class AIClient {
178
225
  return await this.generateDeepSeek(systemPrompt, userPrompt);
179
226
  case "mistral":
180
227
  return await this.generateMistral(systemPrompt, userPrompt);
228
+ case "grok":
229
+ return await this.generateGrok(systemPrompt, userPrompt);
181
230
  default:
182
231
  throw new Error(`Unsupported provider: ${this.provider}`);
183
232
  }
@@ -249,6 +298,19 @@ export class AIClient {
249
298
  });
250
299
  return response.choices[0].message.content || "No response generated.";
251
300
  }
301
+ async generateGrok(systemPrompt, userPrompt) {
302
+ if (!this.grok)
303
+ throw new Error("Grok client not initialized");
304
+ const response = await this.grok.chat.completions.create({
305
+ model: this.model,
306
+ messages: [
307
+ { role: "system", content: systemPrompt },
308
+ { role: "user", content: userPrompt },
309
+ ],
310
+ temperature: 0.3,
311
+ });
312
+ return response.choices[0].message.content || "No response generated.";
313
+ }
252
314
  getProviderName() {
253
315
  const names = {
254
316
  openai: "OpenAI",
@@ -256,6 +318,7 @@ export class AIClient {
256
318
  gemini: "Gemini",
257
319
  deepseek: "DeepSeek",
258
320
  mistral: "Mistral",
321
+ grok: "xAI Grok",
259
322
  };
260
323
  return names[this.provider];
261
324
  }
package/dist/repl.js CHANGED
@@ -6,6 +6,31 @@ import { client } from "./lib/database.js";
6
6
  import path from "path";
7
7
  import { detectFileChanges, formatChangeMessage } from "./lib/file-change-detector.js";
8
8
  import { getAIClient, resetAIClient } from "./lib/ai-provider.js";
9
+ function wrapText(text, width = process.stdout.columns || 80) {
10
+ const lines = [];
11
+ const paragraphs = text.split('\n');
12
+ for (const paragraph of paragraphs) {
13
+ if (paragraph.length <= width) {
14
+ lines.push(paragraph);
15
+ continue;
16
+ }
17
+ const words = paragraph.split(' ');
18
+ let currentLine = '';
19
+ for (const word of words) {
20
+ if ((currentLine + word).length <= width) {
21
+ currentLine += (currentLine ? ' ' : '') + word;
22
+ }
23
+ else {
24
+ if (currentLine)
25
+ lines.push(currentLine);
26
+ currentLine = word;
27
+ }
28
+ }
29
+ if (currentLine)
30
+ lines.push(currentLine);
31
+ }
32
+ return lines.join('\n');
33
+ }
9
34
  const PROJECT_NAME = path.basename(process.cwd());
10
35
  export async function startREPL(forceReindex = false, provider, model) {
11
36
  console.log(chalk.cyan("\n🐄 Welcome to QuackStack!\n"));
@@ -13,7 +38,7 @@ export async function startREPL(forceReindex = false, provider, model) {
13
38
  const aiClient = getAIClient(provider, model);
14
39
  console.log(chalk.cyan(`Using: ${aiClient.getProviderName()} - ${aiClient.getModel()}`));
15
40
  console.log(chalk.gray("šŸ’” Tip: Type '/help' for commands or 'quack --list-models' to see all options"));
16
- console.log(chalk.cyan("⚔ Press Ctrl+C to exit\n"));
41
+ console.log(chalk.cyan("Press Ctrl+C to exit\n"));
17
42
  }
18
43
  catch (error) {
19
44
  console.error(chalk.red(`\nFailed to initialize AI provider: ${error.message}\n`));
@@ -73,13 +98,13 @@ export async function startREPL(forceReindex = false, provider, model) {
73
98
  }
74
99
  try {
75
100
  const { answer, sources } = await search(query, PROJECT_NAME, provider, model);
76
- console.log(chalk.white(`\n${answer}\n`));
101
+ console.log(chalk.white(`\n${wrapText(answer)}\n`));
77
102
  rl.question(chalk.cyan("šŸ’” Want more details? (y/n) > "), (showDetails) => {
78
103
  if (showDetails.toLowerCase() === "y") {
79
104
  console.log(chalk.blue("\nšŸ“š Relevant Code:\n"));
80
105
  sources.forEach((src, i) => {
81
106
  console.log(chalk.gray(`[${i + 1}] ${src.filePath} (relevance: ${(src.score * 100).toFixed(1)}%)`));
82
- console.log(chalk.white(src.content));
107
+ console.log(chalk.white(wrapText(src.content)));
83
108
  console.log(chalk.gray("\n---\n"));
84
109
  });
85
110
  }
@@ -104,7 +129,7 @@ async function handleCommand(command, rl) {
104
129
  if (args.length === 0) {
105
130
  try {
106
131
  const client = getAIClient();
107
- console.log(chalk.cyan(`\nCurrent: ${client.getProviderName()} - ${client.getModel()}\n`));
132
+ console.log(chalk.cyan(`\nšŸ¤– Current: ${client.getProviderName()} - ${client.getModel()}\n`));
108
133
  }
109
134
  catch (error) {
110
135
  console.log(chalk.red(`\nāŒ Error: ${error.message}\n`));
@@ -115,7 +140,7 @@ async function handleCommand(command, rl) {
115
140
  try {
116
141
  resetAIClient();
117
142
  const client = getAIClient(undefined, newModel);
118
- console.log(chalk.green(`\nSwitched to: ${client.getProviderName()} - ${client.getModel()}\n`));
143
+ console.log(chalk.green(`\nāœ… Switched to: ${client.getProviderName()} - ${client.getModel()}\n`));
119
144
  }
120
145
  catch (error) {
121
146
  console.log(chalk.red(`\nāŒ Error: ${error.message}\n`));
@@ -144,7 +169,7 @@ async function handleCommand(command, rl) {
144
169
  try {
145
170
  resetAIClient();
146
171
  const client = getAIClient(newProvider);
147
- console.log(chalk.green(`\nāœ… Switched to: ${client.getProviderName()} - ${client.getModel()}\n`));
172
+ console.log(chalk.green(`\nSwitched to: ${client.getProviderName()} - ${client.getModel()}\n`));
148
173
  }
149
174
  catch (error) {
150
175
  console.log(chalk.red(`\nāŒ Error: ${error.message}\n`));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quackstack",
3
- "version": "1.0.17",
3
+ "version": "1.0.20",
4
4
  "description": "Your cracked unpaid intern for all things codebase related! AI-powered codebase search and Q&A.",
5
5
  "type": "module",
6
6
  "main": "dist/cli.cjs",